1
0
Fork 0
forked from len0rd/rockbox

sdl: remove non-rockbox drivers

We never use any of these other drivers, so having them around just takes
up space.

Change-Id: Iced812162df1fef3fd55522b7e700acb6c3bcd41
This commit is contained in:
Franklin Wei 2018-02-07 20:04:46 -05:00
parent ef373c03b9
commit 6039eb05ba
530 changed files with 0 additions and 138647 deletions

View file

@ -1,619 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
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 library 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
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
/* Allow access to a raw mixing buffer */
#include <sys/types.h>
#include <signal.h> /* For kill() */
#include "SDL_timer.h"
#include "SDL_audio.h"
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
#include "SDL_alsa_audio.h"
#ifdef SDL_AUDIO_DRIVER_ALSA_DYNAMIC
#include "SDL_name.h"
#include "SDL_loadso.h"
#else
#define SDL_NAME(X) X
#endif
/* The tag name used by ALSA audio */
#define DRIVER_NAME "alsa"
/* Audio driver functions */
static int ALSA_OpenAudio(_THIS, SDL_AudioSpec *spec);
static void ALSA_WaitAudio(_THIS);
static void ALSA_PlayAudio(_THIS);
static Uint8 *ALSA_GetAudioBuf(_THIS);
static void ALSA_CloseAudio(_THIS);
#ifdef SDL_AUDIO_DRIVER_ALSA_DYNAMIC
static const char *alsa_library = SDL_AUDIO_DRIVER_ALSA_DYNAMIC;
static void *alsa_handle = NULL;
static int alsa_loaded = 0;
static int (*SDL_NAME(snd_pcm_open))(snd_pcm_t **pcm, const char *name, snd_pcm_stream_t stream, int mode);
static int (*SDL_NAME(snd_pcm_close))(snd_pcm_t *pcm);
static snd_pcm_sframes_t (*SDL_NAME(snd_pcm_writei))(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size);
static int (*SDL_NAME(snd_pcm_recover))(snd_pcm_t *pcm, int err, int silent);
static int (*SDL_NAME(snd_pcm_prepare))(snd_pcm_t *pcm);
static int (*SDL_NAME(snd_pcm_drain))(snd_pcm_t *pcm);
static const char *(*SDL_NAME(snd_strerror))(int errnum);
static size_t (*SDL_NAME(snd_pcm_hw_params_sizeof))(void);
static size_t (*SDL_NAME(snd_pcm_sw_params_sizeof))(void);
static void (*SDL_NAME(snd_pcm_hw_params_copy))(snd_pcm_hw_params_t *dst, const snd_pcm_hw_params_t *src);
static int (*SDL_NAME(snd_pcm_hw_params_any))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params);
static int (*SDL_NAME(snd_pcm_hw_params_set_access))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_t access);
static int (*SDL_NAME(snd_pcm_hw_params_set_format))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_t val);
static int (*SDL_NAME(snd_pcm_hw_params_set_channels))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val);
static int (*SDL_NAME(snd_pcm_hw_params_get_channels))(const snd_pcm_hw_params_t *params, unsigned int *val);
static int (*SDL_NAME(snd_pcm_hw_params_set_rate_near))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir);
static int (*SDL_NAME(snd_pcm_hw_params_set_period_size_near))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir);
static int (*SDL_NAME(snd_pcm_hw_params_get_period_size))(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *frames, int *dir);
static int (*SDL_NAME(snd_pcm_hw_params_set_periods_near))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir);
static int (*SDL_NAME(snd_pcm_hw_params_get_periods))(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir);
static int (*SDL_NAME(snd_pcm_hw_params_set_buffer_size_near))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val);
static int (*SDL_NAME(snd_pcm_hw_params_get_buffer_size))(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val);
static int (*SDL_NAME(snd_pcm_hw_params))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params);
/*
*/
static int (*SDL_NAME(snd_pcm_sw_params_set_avail_min))(snd_pcm_t *pcm, snd_pcm_sw_params_t *swparams, snd_pcm_uframes_t val);
static int (*SDL_NAME(snd_pcm_sw_params_current))(snd_pcm_t *pcm, snd_pcm_sw_params_t *swparams);
static int (*SDL_NAME(snd_pcm_sw_params_set_start_threshold))(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val);
static int (*SDL_NAME(snd_pcm_sw_params))(snd_pcm_t *pcm, snd_pcm_sw_params_t *params);
static int (*SDL_NAME(snd_pcm_nonblock))(snd_pcm_t *pcm, int nonblock);
static int (*SDL_NAME(snd_pcm_wait))(snd_pcm_t *pcm, int timeout);
#define snd_pcm_hw_params_sizeof SDL_NAME(snd_pcm_hw_params_sizeof)
#define snd_pcm_sw_params_sizeof SDL_NAME(snd_pcm_sw_params_sizeof)
/* cast funcs to char* first, to please GCC's strict aliasing rules. */
static struct {
const char *name;
void **func;
} alsa_functions[] = {
{ "snd_pcm_open", (void**)(char*)&SDL_NAME(snd_pcm_open) },
{ "snd_pcm_close", (void**)(char*)&SDL_NAME(snd_pcm_close) },
{ "snd_pcm_writei", (void**)(char*)&SDL_NAME(snd_pcm_writei) },
{ "snd_pcm_recover", (void**)(char*)&SDL_NAME(snd_pcm_recover) },
{ "snd_pcm_prepare", (void**)(char*)&SDL_NAME(snd_pcm_prepare) },
{ "snd_pcm_drain", (void**)(char*)&SDL_NAME(snd_pcm_drain) },
{ "snd_strerror", (void**)(char*)&SDL_NAME(snd_strerror) },
{ "snd_pcm_hw_params_sizeof", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_sizeof) },
{ "snd_pcm_sw_params_sizeof", (void**)(char*)&SDL_NAME(snd_pcm_sw_params_sizeof) },
{ "snd_pcm_hw_params_copy", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_copy) },
{ "snd_pcm_hw_params_any", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_any) },
{ "snd_pcm_hw_params_set_access", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_access) },
{ "snd_pcm_hw_params_set_format", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_format) },
{ "snd_pcm_hw_params_set_channels", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_channels) },
{ "snd_pcm_hw_params_get_channels", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_get_channels) },
{ "snd_pcm_hw_params_set_rate_near", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_rate_near) },
{ "snd_pcm_hw_params_set_period_size_near", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_period_size_near) },
{ "snd_pcm_hw_params_get_period_size", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_get_period_size) },
{ "snd_pcm_hw_params_set_periods_near", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_periods_near) },
{ "snd_pcm_hw_params_get_periods", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_get_periods) },
{ "snd_pcm_hw_params_set_buffer_size_near", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_buffer_size_near) },
{ "snd_pcm_hw_params_get_buffer_size", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_get_buffer_size) },
{ "snd_pcm_hw_params", (void**)(char*)&SDL_NAME(snd_pcm_hw_params) },
{ "snd_pcm_sw_params_set_avail_min", (void**)(char*)&SDL_NAME(snd_pcm_sw_params_set_avail_min) },
{ "snd_pcm_sw_params_current", (void**)(char*)&SDL_NAME(snd_pcm_sw_params_current) },
{ "snd_pcm_sw_params_set_start_threshold", (void**)(char*)&SDL_NAME(snd_pcm_sw_params_set_start_threshold) },
{ "snd_pcm_sw_params", (void**)(char*)&SDL_NAME(snd_pcm_sw_params) },
{ "snd_pcm_nonblock", (void**)(char*)&SDL_NAME(snd_pcm_nonblock) },
{ "snd_pcm_wait", (void**)(char*)&SDL_NAME(snd_pcm_wait) },
};
static void UnloadALSALibrary(void) {
if (alsa_loaded) {
SDL_UnloadObject(alsa_handle);
alsa_handle = NULL;
alsa_loaded = 0;
}
}
static int LoadALSALibrary(void) {
int i, retval = -1;
alsa_handle = SDL_LoadObject(alsa_library);
if (alsa_handle) {
alsa_loaded = 1;
retval = 0;
for (i = 0; i < SDL_arraysize(alsa_functions); i++) {
*alsa_functions[i].func = SDL_LoadFunction(alsa_handle,alsa_functions[i].name);
if (!*alsa_functions[i].func) {
retval = -1;
UnloadALSALibrary();
break;
}
}
}
return retval;
}
#else
static void UnloadALSALibrary(void) {
return;
}
static int LoadALSALibrary(void) {
return 0;
}
#endif /* SDL_AUDIO_DRIVER_ALSA_DYNAMIC */
static const char *get_audio_device(int channels)
{
const char *device;
device = SDL_getenv("AUDIODEV"); /* Is there a standard variable name? */
if ( device == NULL ) {
switch (channels) {
case 6:
device = "plug:surround51";
break;
case 4:
device = "plug:surround40";
break;
default:
device = "default";
break;
}
}
return device;
}
/* Audio driver bootstrap functions */
static int Audio_Available(void)
{
int available;
int status;
snd_pcm_t *handle;
available = 0;
if (LoadALSALibrary() < 0) {
return available;
}
status = SDL_NAME(snd_pcm_open)(&handle, get_audio_device(2), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
if ( status >= 0 ) {
available = 1;
SDL_NAME(snd_pcm_close)(handle);
}
UnloadALSALibrary();
return(available);
}
static void Audio_DeleteDevice(SDL_AudioDevice *device)
{
SDL_free(device->hidden);
SDL_free(device);
UnloadALSALibrary();
}
static SDL_AudioDevice *Audio_CreateDevice(int devindex)
{
SDL_AudioDevice *this;
/* Initialize all variables that we clean on shutdown */
LoadALSALibrary();
this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
if ( this ) {
SDL_memset(this, 0, (sizeof *this));
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
}
if ( (this == NULL) || (this->hidden == NULL) ) {
SDL_OutOfMemory();
if ( this ) {
SDL_free(this);
}
return(0);
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
/* Set the function pointers */
this->OpenAudio = ALSA_OpenAudio;
this->WaitAudio = ALSA_WaitAudio;
this->PlayAudio = ALSA_PlayAudio;
this->GetAudioBuf = ALSA_GetAudioBuf;
this->CloseAudio = ALSA_CloseAudio;
this->free = Audio_DeleteDevice;
return this;
}
AudioBootStrap ALSA_bootstrap = {
DRIVER_NAME, "ALSA PCM audio",
Audio_Available, Audio_CreateDevice
};
/* This function waits until it is possible to write a full sound buffer */
static void ALSA_WaitAudio(_THIS)
{
/* We're in blocking mode, so there's nothing to do here */
}
/*
* http://bugzilla.libsdl.org/show_bug.cgi?id=110
* "For Linux ALSA, this is FL-FR-RL-RR-C-LFE
* and for Windows DirectX [and CoreAudio], this is FL-FR-C-LFE-RL-RR"
*/
#define SWIZ6(T) \
T *ptr = (T *) mixbuf; \
Uint32 i; \
for (i = 0; i < this->spec.samples; i++, ptr += 6) { \
T tmp; \
tmp = ptr[2]; ptr[2] = ptr[4]; ptr[4] = tmp; \
tmp = ptr[3]; ptr[3] = ptr[5]; ptr[5] = tmp; \
}
static __inline__ void swizzle_alsa_channels_6_64bit(_THIS) { SWIZ6(Uint64); }
static __inline__ void swizzle_alsa_channels_6_32bit(_THIS) { SWIZ6(Uint32); }
static __inline__ void swizzle_alsa_channels_6_16bit(_THIS) { SWIZ6(Uint16); }
static __inline__ void swizzle_alsa_channels_6_8bit(_THIS) { SWIZ6(Uint8); }
#undef SWIZ6
/*
* Called right before feeding this->mixbuf to the hardware. Swizzle channels
* from Windows/Mac order to the format alsalib will want.
*/
static __inline__ void swizzle_alsa_channels(_THIS)
{
if (this->spec.channels == 6) {
const Uint16 fmtsize = (this->spec.format & 0xFF); /* bits/channel. */
if (fmtsize == 16)
swizzle_alsa_channels_6_16bit(this);
else if (fmtsize == 8)
swizzle_alsa_channels_6_8bit(this);
else if (fmtsize == 32)
swizzle_alsa_channels_6_32bit(this);
else if (fmtsize == 64)
swizzle_alsa_channels_6_64bit(this);
}
/* !!! FIXME: update this for 7.1 if needed, later. */
}
static void ALSA_PlayAudio(_THIS)
{
int status;
snd_pcm_uframes_t frames_left;
const Uint8 *sample_buf = (const Uint8 *) mixbuf;
const int frame_size = (((int) (this->spec.format & 0xFF)) / 8) * this->spec.channels;
swizzle_alsa_channels(this);
frames_left = ((snd_pcm_uframes_t) this->spec.samples);
while ( frames_left > 0 && this->enabled ) {
/* This works, but needs more testing before going live */
/*SDL_NAME(snd_pcm_wait)(pcm_handle, -1);*/
status = SDL_NAME(snd_pcm_writei)(pcm_handle, sample_buf, frames_left);
if ( status < 0 ) {
if ( status == -EAGAIN ) {
/* Apparently snd_pcm_recover() doesn't handle this case - does it assume snd_pcm_wait() above? */
SDL_Delay(1);
continue;
}
status = SDL_NAME(snd_pcm_recover)(pcm_handle, status, 0);
if ( status < 0 ) {
/* Hmm, not much we can do - abort */
fprintf(stderr, "ALSA write failed (unrecoverable): %s\n", SDL_NAME(snd_strerror)(status));
this->enabled = 0;
return;
}
continue;
}
sample_buf += status * frame_size;
frames_left -= status;
}
}
static Uint8 *ALSA_GetAudioBuf(_THIS)
{
return(mixbuf);
}
static void ALSA_CloseAudio(_THIS)
{
if ( mixbuf != NULL ) {
SDL_FreeAudioMem(mixbuf);
mixbuf = NULL;
}
if ( pcm_handle ) {
SDL_NAME(snd_pcm_drain)(pcm_handle);
SDL_NAME(snd_pcm_close)(pcm_handle);
pcm_handle = NULL;
}
}
static int ALSA_finalize_hardware(_THIS, SDL_AudioSpec *spec, snd_pcm_hw_params_t *hwparams, int override)
{
int status;
snd_pcm_uframes_t bufsize;
/* "set" the hardware with the desired parameters */
status = SDL_NAME(snd_pcm_hw_params)(pcm_handle, hwparams);
if ( status < 0 ) {
return(-1);
}
/* Get samples for the actual buffer size */
status = SDL_NAME(snd_pcm_hw_params_get_buffer_size)(hwparams, &bufsize);
if ( status < 0 ) {
return(-1);
}
if ( !override && bufsize != spec->samples * 2 ) {
return(-1);
}
/* FIXME: Is this safe to do? */
spec->samples = bufsize / 2;
/* This is useful for debugging */
if ( getenv("SDL_AUDIO_ALSA_DEBUG") ) {
snd_pcm_uframes_t persize = 0;
unsigned int periods = 0;
SDL_NAME(snd_pcm_hw_params_get_period_size)(hwparams, &persize, NULL);
SDL_NAME(snd_pcm_hw_params_get_periods)(hwparams, &periods, NULL);
fprintf(stderr, "ALSA: period size = %ld, periods = %u, buffer size = %lu\n", persize, periods, bufsize);
}
return(0);
}
static int ALSA_set_period_size(_THIS, SDL_AudioSpec *spec, snd_pcm_hw_params_t *params, int override)
{
const char *env;
int status;
snd_pcm_hw_params_t *hwparams;
snd_pcm_uframes_t frames;
unsigned int periods;
/* Copy the hardware parameters for this setup */
snd_pcm_hw_params_alloca(&hwparams);
SDL_NAME(snd_pcm_hw_params_copy)(hwparams, params);
if ( !override ) {
env = getenv("SDL_AUDIO_ALSA_SET_PERIOD_SIZE");
if ( env ) {
override = SDL_atoi(env);
if ( override == 0 ) {
return(-1);
}
}
}
frames = spec->samples;
status = SDL_NAME(snd_pcm_hw_params_set_period_size_near)(pcm_handle, hwparams, &frames, NULL);
if ( status < 0 ) {
return(-1);
}
periods = 2;
status = SDL_NAME(snd_pcm_hw_params_set_periods_near)(pcm_handle, hwparams, &periods, NULL);
if ( status < 0 ) {
return(-1);
}
return ALSA_finalize_hardware(this, spec, hwparams, override);
}
static int ALSA_set_buffer_size(_THIS, SDL_AudioSpec *spec, snd_pcm_hw_params_t *params, int override)
{
const char *env;
int status;
snd_pcm_hw_params_t *hwparams;
snd_pcm_uframes_t frames;
/* Copy the hardware parameters for this setup */
snd_pcm_hw_params_alloca(&hwparams);
SDL_NAME(snd_pcm_hw_params_copy)(hwparams, params);
if ( !override ) {
env = getenv("SDL_AUDIO_ALSA_SET_BUFFER_SIZE");
if ( env ) {
override = SDL_atoi(env);
if ( override == 0 ) {
return(-1);
}
}
}
frames = spec->samples * 2;
status = SDL_NAME(snd_pcm_hw_params_set_buffer_size_near)(pcm_handle, hwparams, &frames);
if ( status < 0 ) {
return(-1);
}
return ALSA_finalize_hardware(this, spec, hwparams, override);
}
static int ALSA_OpenAudio(_THIS, SDL_AudioSpec *spec)
{
int status;
snd_pcm_hw_params_t *hwparams;
snd_pcm_sw_params_t *swparams;
snd_pcm_format_t format;
unsigned int rate;
unsigned int channels;
Uint16 test_format;
/* Open the audio device */
/* Name of device should depend on # channels in spec */
status = SDL_NAME(snd_pcm_open)(&pcm_handle, get_audio_device(spec->channels), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
if ( status < 0 ) {
SDL_SetError("Couldn't open audio device: %s", SDL_NAME(snd_strerror)(status));
return(-1);
}
/* Figure out what the hardware is capable of */
snd_pcm_hw_params_alloca(&hwparams);
status = SDL_NAME(snd_pcm_hw_params_any)(pcm_handle, hwparams);
if ( status < 0 ) {
SDL_SetError("Couldn't get hardware config: %s", SDL_NAME(snd_strerror)(status));
ALSA_CloseAudio(this);
return(-1);
}
/* SDL only uses interleaved sample output */
status = SDL_NAME(snd_pcm_hw_params_set_access)(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED);
if ( status < 0 ) {
SDL_SetError("Couldn't set interleaved access: %s", SDL_NAME(snd_strerror)(status));
ALSA_CloseAudio(this);
return(-1);
}
/* Try for a closest match on audio format */
status = -1;
for ( test_format = SDL_FirstAudioFormat(spec->format);
test_format && (status < 0); ) {
switch ( test_format ) {
case AUDIO_U8:
format = SND_PCM_FORMAT_U8;
break;
case AUDIO_S8:
format = SND_PCM_FORMAT_S8;
break;
case AUDIO_S16LSB:
format = SND_PCM_FORMAT_S16_LE;
break;
case AUDIO_S16MSB:
format = SND_PCM_FORMAT_S16_BE;
break;
case AUDIO_U16LSB:
format = SND_PCM_FORMAT_U16_LE;
break;
case AUDIO_U16MSB:
format = SND_PCM_FORMAT_U16_BE;
break;
default:
format = 0;
break;
}
if ( format != 0 ) {
status = SDL_NAME(snd_pcm_hw_params_set_format)(pcm_handle, hwparams, format);
}
if ( status < 0 ) {
test_format = SDL_NextAudioFormat();
}
}
if ( status < 0 ) {
SDL_SetError("Couldn't find any hardware audio formats");
ALSA_CloseAudio(this);
return(-1);
}
spec->format = test_format;
/* Set the number of channels */
status = SDL_NAME(snd_pcm_hw_params_set_channels)(pcm_handle, hwparams, spec->channels);
channels = spec->channels;
if ( status < 0 ) {
status = SDL_NAME(snd_pcm_hw_params_get_channels)(hwparams, &channels);
if ( status < 0 ) {
SDL_SetError("Couldn't set audio channels");
ALSA_CloseAudio(this);
return(-1);
}
spec->channels = channels;
}
/* Set the audio rate */
rate = spec->freq;
status = SDL_NAME(snd_pcm_hw_params_set_rate_near)(pcm_handle, hwparams, &rate, NULL);
if ( status < 0 ) {
SDL_SetError("Couldn't set audio frequency: %s", SDL_NAME(snd_strerror)(status));
ALSA_CloseAudio(this);
return(-1);
}
spec->freq = rate;
/* Set the buffer size, in samples */
if ( ALSA_set_period_size(this, spec, hwparams, 0) < 0 &&
ALSA_set_buffer_size(this, spec, hwparams, 0) < 0 ) {
/* Failed to set desired buffer size, do the best you can... */
if ( ALSA_set_period_size(this, spec, hwparams, 1) < 0 ) {
SDL_SetError("Couldn't set hardware audio parameters: %s", SDL_NAME(snd_strerror)(status));
ALSA_CloseAudio(this);
return(-1);
}
}
/* Set the software parameters */
snd_pcm_sw_params_alloca(&swparams);
status = SDL_NAME(snd_pcm_sw_params_current)(pcm_handle, swparams);
if ( status < 0 ) {
SDL_SetError("Couldn't get software config: %s", SDL_NAME(snd_strerror)(status));
ALSA_CloseAudio(this);
return(-1);
}
status = SDL_NAME(snd_pcm_sw_params_set_avail_min)(pcm_handle, swparams, spec->samples);
if ( status < 0 ) {
SDL_SetError("Couldn't set minimum available samples: %s", SDL_NAME(snd_strerror)(status));
ALSA_CloseAudio(this);
return(-1);
}
status = SDL_NAME(snd_pcm_sw_params_set_start_threshold)(pcm_handle, swparams, 1);
if ( status < 0 ) {
SDL_SetError("Couldn't set start threshold: %s", SDL_NAME(snd_strerror)(status));
ALSA_CloseAudio(this);
return(-1);
}
status = SDL_NAME(snd_pcm_sw_params)(pcm_handle, swparams);
if ( status < 0 ) {
SDL_SetError("Couldn't set software audio parameters: %s", SDL_NAME(snd_strerror)(status));
ALSA_CloseAudio(this);
return(-1);
}
/* Calculate the final parameters for this audio specification */
SDL_CalculateAudioSpec(spec);
/* Allocate mixing buffer */
mixlen = spec->size;
mixbuf = (Uint8 *)SDL_AllocAudioMem(mixlen);
if ( mixbuf == NULL ) {
ALSA_CloseAudio(this);
return(-1);
}
SDL_memset(mixbuf, spec->silence, spec->size);
/* Switch to blocking mode for playback */
SDL_NAME(snd_pcm_nonblock)(pcm_handle, 0);
/* We're ready to rock and roll. :-) */
return(0);
}

View file

@ -1,48 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
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 library 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
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
#ifndef _ALSA_PCM_audio_h
#define _ALSA_PCM_audio_h
#include <alsa/asoundlib.h>
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the video functions */
#define _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData {
/* The audio device handle */
snd_pcm_t *pcm_handle;
/* Raw mixing buffer */
Uint8 *mixbuf;
int mixlen;
};
/* Old variable names */
#define pcm_handle (this->hidden->pcm_handle)
#define mixbuf (this->hidden->mixbuf)
#define mixlen (this->hidden->mixlen)
#endif /* _ALSA_PCM_audio_h */

View file

@ -1,362 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
/* Allow access to a raw mixing buffer */
#ifdef HAVE_SIGNAL_H
#include <signal.h>
#endif
#include <unistd.h>
#include "SDL_timer.h"
#include "SDL_audio.h"
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
#include "../SDL_audiodev_c.h"
#include "SDL_artsaudio.h"
#ifdef SDL_AUDIO_DRIVER_ARTS_DYNAMIC
#include "SDL_name.h"
#include "SDL_loadso.h"
#else
#define SDL_NAME(X) X
#endif
/* The tag name used by artsc audio */
#define ARTS_DRIVER_NAME "arts"
/* Audio driver functions */
static int ARTS_OpenAudio(_THIS, SDL_AudioSpec *spec);
static void ARTS_WaitAudio(_THIS);
static void ARTS_PlayAudio(_THIS);
static Uint8 *ARTS_GetAudioBuf(_THIS);
static void ARTS_CloseAudio(_THIS);
#ifdef SDL_AUDIO_DRIVER_ARTS_DYNAMIC
static const char *arts_library = SDL_AUDIO_DRIVER_ARTS_DYNAMIC;
static void *arts_handle = NULL;
static int arts_loaded = 0;
static int (*SDL_NAME(arts_init))(void);
static void (*SDL_NAME(arts_free))(void);
static arts_stream_t (*SDL_NAME(arts_play_stream))(int rate, int bits, int channels, const char *name);
static int (*SDL_NAME(arts_stream_set))(arts_stream_t s, arts_parameter_t param, int value);
static int (*SDL_NAME(arts_stream_get))(arts_stream_t s, arts_parameter_t param);
static int (*SDL_NAME(arts_write))(arts_stream_t s, const void *buffer, int count);
static void (*SDL_NAME(arts_close_stream))(arts_stream_t s);
static int (*SDL_NAME(arts_suspend))(void);
static int (*SDL_NAME(arts_suspended))(void);
static const char *(*SDL_NAME(arts_error_text))(int errorcode);
static struct {
const char *name;
void **func;
} arts_functions[] = {
{ "arts_init", (void **)&SDL_NAME(arts_init) },
{ "arts_free", (void **)&SDL_NAME(arts_free) },
{ "arts_play_stream", (void **)&SDL_NAME(arts_play_stream) },
{ "arts_stream_set", (void **)&SDL_NAME(arts_stream_set) },
{ "arts_stream_get", (void **)&SDL_NAME(arts_stream_get) },
{ "arts_write", (void **)&SDL_NAME(arts_write) },
{ "arts_close_stream", (void **)&SDL_NAME(arts_close_stream) },
{ "arts_suspend", (void **)&SDL_NAME(arts_suspend) },
{ "arts_suspended", (void **)&SDL_NAME(arts_suspended) },
{ "arts_error_text", (void **)&SDL_NAME(arts_error_text) },
};
static void UnloadARTSLibrary()
{
if ( arts_loaded ) {
SDL_UnloadObject(arts_handle);
arts_handle = NULL;
arts_loaded = 0;
}
}
static int LoadARTSLibrary(void)
{
int i, retval = -1;
arts_handle = SDL_LoadObject(arts_library);
if ( arts_handle ) {
arts_loaded = 1;
retval = 0;
for ( i=0; i<SDL_arraysize(arts_functions); ++i ) {
*arts_functions[i].func = SDL_LoadFunction(arts_handle, arts_functions[i].name);
if ( !*arts_functions[i].func ) {
retval = -1;
UnloadARTSLibrary();
break;
}
}
}
return retval;
}
#else
static void UnloadARTSLibrary()
{
return;
}
static int LoadARTSLibrary(void)
{
return 0;
}
#endif /* SDL_AUDIO_DRIVER_ARTS_DYNAMIC */
/* Audio driver bootstrap functions */
static int ARTS_Suspend(void)
{
const Uint32 abortms = SDL_GetTicks() + 3000; /* give up after 3 secs */
while ( (!SDL_NAME(arts_suspended)()) && (SDL_GetTicks() < abortms) ) {
if ( SDL_NAME(arts_suspend)() ) {
break;
}
}
return SDL_NAME(arts_suspended)();
}
static int Audio_Available(void)
{
int available = 0;
if ( LoadARTSLibrary() < 0 ) {
return available;
}
if ( SDL_NAME(arts_init)() == 0 ) {
if ( ARTS_Suspend() ) {
/* Play a stream so aRts doesn't crash */
arts_stream_t stream2;
stream2=SDL_NAME(arts_play_stream)(44100, 16, 2, "SDL");
SDL_NAME(arts_write)(stream2, "", 0);
SDL_NAME(arts_close_stream)(stream2);
available = 1;
}
SDL_NAME(arts_free)();
}
UnloadARTSLibrary();
return available;
}
static void Audio_DeleteDevice(SDL_AudioDevice *device)
{
SDL_free(device->hidden);
SDL_free(device);
UnloadARTSLibrary();
}
static SDL_AudioDevice *Audio_CreateDevice(int devindex)
{
SDL_AudioDevice *this;
/* Initialize all variables that we clean on shutdown */
LoadARTSLibrary();
this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
if ( this ) {
SDL_memset(this, 0, (sizeof *this));
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
}
if ( (this == NULL) || (this->hidden == NULL) ) {
SDL_OutOfMemory();
if ( this ) {
SDL_free(this);
}
return(0);
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
stream = 0;
/* Set the function pointers */
this->OpenAudio = ARTS_OpenAudio;
this->WaitAudio = ARTS_WaitAudio;
this->PlayAudio = ARTS_PlayAudio;
this->GetAudioBuf = ARTS_GetAudioBuf;
this->CloseAudio = ARTS_CloseAudio;
this->free = Audio_DeleteDevice;
return this;
}
AudioBootStrap ARTS_bootstrap = {
ARTS_DRIVER_NAME, "Analog Realtime Synthesizer",
Audio_Available, Audio_CreateDevice
};
/* This function waits until it is possible to write a full sound buffer */
static void ARTS_WaitAudio(_THIS)
{
Sint32 ticks;
/* Check to see if the thread-parent process is still alive */
{ static int cnt = 0;
/* Note that this only works with thread implementations
that use a different process id for each thread.
*/
if (parent && (((++cnt)%10) == 0)) { /* Check every 10 loops */
if ( kill(parent, 0) < 0 ) {
this->enabled = 0;
}
}
}
/* Use timer for general audio synchronization */
ticks = ((Sint32)(next_frame - SDL_GetTicks()))-FUDGE_TICKS;
if ( ticks > 0 ) {
SDL_Delay(ticks);
}
}
static void ARTS_PlayAudio(_THIS)
{
int written;
/* Write the audio data */
written = SDL_NAME(arts_write)(stream, mixbuf, mixlen);
/* If timer synchronization is enabled, set the next write frame */
if ( frame_ticks ) {
next_frame += frame_ticks;
}
/* If we couldn't write, assume fatal error for now */
if ( written < 0 ) {
this->enabled = 0;
}
#ifdef DEBUG_AUDIO
fprintf(stderr, "Wrote %d bytes of audio data\n", written);
#endif
}
static Uint8 *ARTS_GetAudioBuf(_THIS)
{
return(mixbuf);
}
static void ARTS_CloseAudio(_THIS)
{
if ( mixbuf != NULL ) {
SDL_FreeAudioMem(mixbuf);
mixbuf = NULL;
}
if ( stream ) {
SDL_NAME(arts_close_stream)(stream);
stream = 0;
}
SDL_NAME(arts_free)();
}
static int ARTS_OpenAudio(_THIS, SDL_AudioSpec *spec)
{
int bits, frag_spec;
Uint16 test_format, format;
int error_code;
/* Reset the timer synchronization flag */
frame_ticks = 0.0;
mixbuf = NULL;
/* Try for a closest match on audio format */
format = 0;
bits = 0;
for ( test_format = SDL_FirstAudioFormat(spec->format);
! format && test_format; ) {
#ifdef DEBUG_AUDIO
fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
#endif
switch ( test_format ) {
case AUDIO_U8:
bits = 8;
format = 1;
break;
case AUDIO_S16LSB:
bits = 16;
format = 1;
break;
default:
format = 0;
break;
}
if ( ! format ) {
test_format = SDL_NextAudioFormat();
}
}
if ( format == 0 ) {
SDL_SetError("Couldn't find any hardware audio formats");
return(-1);
}
spec->format = test_format;
error_code = SDL_NAME(arts_init)();
if ( error_code != 0 ) {
SDL_SetError("Unable to initialize ARTS: %s", SDL_NAME(arts_error_text)(error_code));
return(-1);
}
if ( ! ARTS_Suspend() ) {
SDL_SetError("ARTS can not open audio device");
return(-1);
}
stream = SDL_NAME(arts_play_stream)(spec->freq, bits, spec->channels, "SDL");
/* Calculate the final parameters for this audio specification */
SDL_CalculateAudioSpec(spec);
/* Determine the power of two of the fragment size */
for ( frag_spec = 0; (0x01<<frag_spec) < spec->size; ++frag_spec );
if ( (0x01<<frag_spec) != spec->size ) {
SDL_SetError("Fragment size must be a power of two");
return(-1);
}
frag_spec |= 0x00020000; /* two fragments, for low latency */
#ifdef ARTS_P_PACKET_SETTINGS
SDL_NAME(arts_stream_set)(stream, ARTS_P_PACKET_SETTINGS, frag_spec);
#else
SDL_NAME(arts_stream_set)(stream, ARTS_P_PACKET_SIZE, frag_spec&0xffff);
SDL_NAME(arts_stream_set)(stream, ARTS_P_PACKET_COUNT, frag_spec>>16);
#endif
spec->size = SDL_NAME(arts_stream_get)(stream, ARTS_P_PACKET_SIZE);
/* Allocate mixing buffer */
mixlen = spec->size;
mixbuf = (Uint8 *)SDL_AllocAudioMem(mixlen);
if ( mixbuf == NULL ) {
return(-1);
}
SDL_memset(mixbuf, spec->silence, spec->size);
/* Get the parent process id (we're the parent of the audio thread) */
parent = getpid();
/* We're ready to rock and roll. :-) */
return(0);
}

View file

@ -1,60 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
#ifndef _SDL_artscaudio_h
#define _SDL_artscaudio_h
#include <artsc.h>
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the video functions */
#define _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData {
/* The stream descriptor for the audio device */
arts_stream_t stream;
/* The parent process id, to detect when application quits */
pid_t parent;
/* Raw mixing buffer */
Uint8 *mixbuf;
int mixlen;
/* Support for audio timing using a timer, in addition to select() */
float frame_ticks;
float next_frame;
};
#define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */
/* Old variable names */
#define stream (this->hidden->stream)
#define parent (this->hidden->parent)
#define mixbuf (this->hidden->mixbuf)
#define mixlen (this->hidden->mixlen)
#define frame_ticks (this->hidden->frame_ticks)
#define next_frame (this->hidden->next_frame)
#endif /* _SDL_artscaudio_h */

View file

@ -1,225 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
/* Allow access to the audio stream on BeOS */
#include <SoundPlayer.h>
#include "../../main/beos/SDL_BeApp.h"
extern "C" {
#include "SDL_audio.h"
#include "../SDL_audio_c.h"
#include "../SDL_sysaudio.h"
#include "../../thread/beos/SDL_systhread_c.h"
#include "SDL_beaudio.h"
/* Audio driver functions */
static int BE_OpenAudio(_THIS, SDL_AudioSpec *spec);
static void BE_WaitAudio(_THIS);
static void BE_PlayAudio(_THIS);
static Uint8 *BE_GetAudioBuf(_THIS);
static void BE_CloseAudio(_THIS);
/* Audio driver bootstrap functions */
static int Audio_Available(void)
{
return(1);
}
static void Audio_DeleteDevice(SDL_AudioDevice *device)
{
SDL_free(device->hidden);
SDL_free(device);
}
static SDL_AudioDevice *Audio_CreateDevice(int devindex)
{
SDL_AudioDevice *device;
/* Initialize all variables that we clean on shutdown */
device = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
if ( device ) {
SDL_memset(device, 0, (sizeof *device));
device->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *device->hidden));
}
if ( (device == NULL) || (device->hidden == NULL) ) {
SDL_OutOfMemory();
if ( device ) {
SDL_free(device);
}
return(0);
}
SDL_memset(device->hidden, 0, (sizeof *device->hidden));
/* Set the function pointers */
device->OpenAudio = BE_OpenAudio;
device->WaitAudio = BE_WaitAudio;
device->PlayAudio = BE_PlayAudio;
device->GetAudioBuf = BE_GetAudioBuf;
device->CloseAudio = BE_CloseAudio;
device->free = Audio_DeleteDevice;
return device;
}
AudioBootStrap BAUDIO_bootstrap = {
"baudio", "BeOS BSoundPlayer",
Audio_Available, Audio_CreateDevice
};
/* The BeOS callback for handling the audio buffer */
static void FillSound(void *device, void *stream, size_t len,
const media_raw_audio_format &format)
{
SDL_AudioDevice *audio = (SDL_AudioDevice *)device;
/* Silence the buffer, since it's ours */
SDL_memset(stream, audio->spec.silence, len);
/* Only do soemthing if audio is enabled */
if ( ! audio->enabled )
return;
if ( ! audio->paused ) {
if ( audio->convert.needed ) {
SDL_mutexP(audio->mixer_lock);
(*audio->spec.callback)(audio->spec.userdata,
(Uint8 *)audio->convert.buf,audio->convert.len);
SDL_mutexV(audio->mixer_lock);
SDL_ConvertAudio(&audio->convert);
SDL_memcpy(stream,audio->convert.buf,audio->convert.len_cvt);
} else {
SDL_mutexP(audio->mixer_lock);
(*audio->spec.callback)(audio->spec.userdata,
(Uint8 *)stream, len);
SDL_mutexV(audio->mixer_lock);
}
}
return;
}
/* Dummy functions -- we don't use thread-based audio */
void BE_WaitAudio(_THIS)
{
return;
}
void BE_PlayAudio(_THIS)
{
return;
}
Uint8 *BE_GetAudioBuf(_THIS)
{
return(NULL);
}
void BE_CloseAudio(_THIS)
{
if ( audio_obj ) {
audio_obj->Stop();
delete audio_obj;
audio_obj = NULL;
}
/* Quit the Be Application, if there's nothing left to do */
SDL_QuitBeApp();
}
int BE_OpenAudio(_THIS, SDL_AudioSpec *spec)
{
int valid_datatype = 0;
media_raw_audio_format format;
Uint16 test_format = SDL_FirstAudioFormat(spec->format);
/* Parse the audio format and fill the Be raw audio format */
memset(&format, '\0', sizeof (media_raw_audio_format));
format.byte_order = B_MEDIA_LITTLE_ENDIAN;
format.frame_rate = (float) spec->freq;
format.channel_count = spec->channels; /* !!! FIXME: support > 2? */
while ((!valid_datatype) && (test_format)) {
valid_datatype = 1;
spec->format = test_format;
switch (test_format) {
case AUDIO_S8:
format.format = media_raw_audio_format::B_AUDIO_CHAR;
break;
case AUDIO_U8:
format.format = media_raw_audio_format::B_AUDIO_UCHAR;
break;
case AUDIO_S16LSB:
format.format = media_raw_audio_format::B_AUDIO_SHORT;
break;
case AUDIO_S16MSB:
format.format = media_raw_audio_format::B_AUDIO_SHORT;
format.byte_order = B_MEDIA_BIG_ENDIAN;
break;
default:
valid_datatype = 0;
test_format = SDL_NextAudioFormat();
break;
}
}
if (!valid_datatype) { /* shouldn't happen, but just in case... */
SDL_SetError("Unsupported audio format");
return (-1);
}
/* Initialize the Be Application, if it's not already started */
if (SDL_InitBeApp() < 0) {
return (-1);
}
format.buffer_size = spec->samples;
/* Calculate the final parameters for this audio specification */
SDL_CalculateAudioSpec(spec);
/* Subscribe to the audio stream (creates a new thread) */
{ sigset_t omask;
SDL_MaskSignals(&omask);
audio_obj = new BSoundPlayer(&format, "SDL Audio", FillSound,
NULL, _this);
SDL_UnmaskSignals(&omask);
}
if ( audio_obj->Start() == B_NO_ERROR ) {
audio_obj->SetHasData(true);
} else {
SDL_SetError("Unable to start Be audio");
return(-1);
}
/* We're running! */
return(1);
}
}; /* Extern C */

View file

@ -1,39 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
#ifndef _SDL_lowaudio_h
#define _SDL_lowaudio_h
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the video functions */
#define _THIS SDL_AudioDevice *_this
struct SDL_PrivateAudioData {
BSoundPlayer *audio_obj;
};
/* Old variable names */
#define audio_obj (_this->hidden->audio_obj)
#endif /* _SDL_lowaudio_h */

View file

@ -1,404 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
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 library 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
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
/*
* Driver for native OpenBSD/NetBSD audio(4).
* vedge@vedge.com.ar.
*/
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/audioio.h>
#include "SDL_timer.h"
#include "SDL_audio.h"
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
#include "../SDL_audiodev_c.h"
#include "SDL_bsdaudio.h"
/* The tag name used by NetBSD/OpenBSD audio */
#ifdef __NetBSD__
#define BSD_AUDIO_DRIVER_NAME "netbsd"
#define BSD_AUDIO_DRIVER_DESC "Native NetBSD audio"
#else
#define BSD_AUDIO_DRIVER_NAME "openbsd"
#define BSD_AUDIO_DRIVER_DESC "Native OpenBSD audio"
#endif
/* Open the audio device for playback, and don't block if busy */
/* #define USE_BLOCKING_WRITES */
/* Use timer for synchronization */
/* #define USE_TIMER_SYNC */
/* #define DEBUG_AUDIO */
/* #define DEBUG_AUDIO_STREAM */
#ifdef USE_BLOCKING_WRITES
#define OPEN_FLAGS O_WRONLY
#else
#define OPEN_FLAGS (O_WRONLY|O_NONBLOCK)
#endif
/* Audio driver functions */
static void OBSD_WaitAudio(_THIS);
static int OBSD_OpenAudio(_THIS, SDL_AudioSpec *spec);
static void OBSD_PlayAudio(_THIS);
static Uint8 *OBSD_GetAudioBuf(_THIS);
static void OBSD_CloseAudio(_THIS);
#ifdef DEBUG_AUDIO
static void OBSD_Status(_THIS);
#endif
/* Audio driver bootstrap functions */
static int
Audio_Available(void)
{
int fd;
int available;
available = 0;
fd = SDL_OpenAudioPath(NULL, 0, OPEN_FLAGS, 0);
if(fd >= 0) {
available = 1;
close(fd);
}
return(available);
}
static void
Audio_DeleteDevice(SDL_AudioDevice *device)
{
SDL_free(device->hidden);
SDL_free(device);
}
static SDL_AudioDevice
*Audio_CreateDevice(int devindex)
{
SDL_AudioDevice *this;
/* Initialize all variables that we clean on shutdown */
this = (SDL_AudioDevice*)SDL_malloc(sizeof(SDL_AudioDevice));
if(this) {
SDL_memset(this, 0, (sizeof *this));
this->hidden =
(struct SDL_PrivateAudioData*)SDL_malloc((sizeof *this->hidden));
}
if((this == NULL) || (this->hidden == NULL)) {
SDL_OutOfMemory();
if(this) SDL_free(this);
return(0);
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
audio_fd = -1;
/* Set the function pointers */
this->OpenAudio = OBSD_OpenAudio;
this->WaitAudio = OBSD_WaitAudio;
this->PlayAudio = OBSD_PlayAudio;
this->GetAudioBuf = OBSD_GetAudioBuf;
this->CloseAudio = OBSD_CloseAudio;
this->free = Audio_DeleteDevice;
return this;
}
AudioBootStrap BSD_AUDIO_bootstrap = {
BSD_AUDIO_DRIVER_NAME, BSD_AUDIO_DRIVER_DESC,
Audio_Available, Audio_CreateDevice
};
/* This function waits until it is possible to write a full sound buffer */
static void
OBSD_WaitAudio(_THIS)
{
#ifndef USE_BLOCKING_WRITES /* Not necessary when using blocking writes */
/* See if we need to use timed audio synchronization */
if ( frame_ticks ) {
/* Use timer for general audio synchronization */
Sint32 ticks;
ticks = ((Sint32)(next_frame - SDL_GetTicks()))-FUDGE_TICKS;
if ( ticks > 0 ) {
SDL_Delay(ticks);
}
} else {
/* Use select() for audio synchronization */
fd_set fdset;
struct timeval timeout;
FD_ZERO(&fdset);
FD_SET(audio_fd, &fdset);
timeout.tv_sec = 10;
timeout.tv_usec = 0;
#ifdef DEBUG_AUDIO
fprintf(stderr, "Waiting for audio to get ready\n");
#endif
if ( select(audio_fd+1, NULL, &fdset, NULL, &timeout) <= 0 ) {
const char *message =
"Audio timeout - buggy audio driver? (disabled)";
/* In general we should never print to the screen,
but in this case we have no other way of letting
the user know what happened.
*/
fprintf(stderr, "SDL: %s\n", message);
this->enabled = 0;
/* Don't try to close - may hang */
audio_fd = -1;
#ifdef DEBUG_AUDIO
fprintf(stderr, "Done disabling audio\n");
#endif
}
#ifdef DEBUG_AUDIO
fprintf(stderr, "Ready!\n");
#endif
}
#endif /* !USE_BLOCKING_WRITES */
}
static void
OBSD_PlayAudio(_THIS)
{
int written, p=0;
/* Write the audio data, checking for EAGAIN on broken audio drivers */
do {
written = write(audio_fd, &mixbuf[p], mixlen-p);
if (written>0)
p += written;
if (written == -1 && errno != 0 && errno != EAGAIN && errno != EINTR)
{
/* Non recoverable error has occurred. It should be reported!!! */
perror("audio");
break;
}
if ( p < written || ((written < 0) && ((errno == 0) || (errno == EAGAIN))) ) {
SDL_Delay(1); /* Let a little CPU time go by */
}
} while ( p < written );
/* If timer synchronization is enabled, set the next write frame */
if ( frame_ticks ) {
next_frame += frame_ticks;
}
/* If we couldn't write, assume fatal error for now */
if ( written < 0 ) {
this->enabled = 0;
}
#ifdef DEBUG_AUDIO
fprintf(stderr, "Wrote %d bytes of audio data\n", written);
#endif
}
static Uint8
*OBSD_GetAudioBuf(_THIS)
{
return(mixbuf);
}
static void
OBSD_CloseAudio(_THIS)
{
if(mixbuf != NULL) {
SDL_FreeAudioMem(mixbuf);
mixbuf = NULL;
}
if(audio_fd >= 0) {
close(audio_fd);
audio_fd = -1;
}
}
#ifdef DEBUG_AUDIO
void
OBSD_Status(_THIS)
{
audio_info_t info;
if(ioctl(audio_fd, AUDIO_GETINFO, &info) < 0) {
fprintf(stderr,"AUDIO_GETINFO failed.\n");
return;
}
fprintf(stderr,"\n"
"[play/record info]\n"
"buffer size : %d bytes\n"
"sample rate : %i Hz\n"
"channels : %i\n"
"precision : %i-bit\n"
"encoding : 0x%x\n"
"seek : %i\n"
"sample count : %i\n"
"EOF count : %i\n"
"paused : %s\n"
"error occured : %s\n"
"waiting : %s\n"
"active : %s\n"
"",
info.play.buffer_size,
info.play.sample_rate,
info.play.channels,
info.play.precision,
info.play.encoding,
info.play.seek,
info.play.samples,
info.play.eof,
info.play.pause ? "yes" : "no",
info.play.error ? "yes" : "no",
info.play.waiting ? "yes" : "no",
info.play.active ? "yes": "no");
fprintf(stderr,"\n"
"[audio info]\n"
"monitor_gain : %i\n"
"hw block size : %d bytes\n"
"hi watermark : %i\n"
"lo watermark : %i\n"
"audio mode : %s\n"
"",
info.monitor_gain,
info.blocksize,
info.hiwat, info.lowat,
(info.mode == AUMODE_PLAY) ? "PLAY"
: (info.mode = AUMODE_RECORD) ? "RECORD"
: (info.mode == AUMODE_PLAY_ALL ? "PLAY_ALL"
: "?"));
}
#endif /* DEBUG_AUDIO */
static int
OBSD_OpenAudio(_THIS, SDL_AudioSpec *spec)
{
char audiodev[64];
Uint16 format;
audio_info_t info;
AUDIO_INITINFO(&info);
/* Calculate the final parameters for this audio specification */
SDL_CalculateAudioSpec(spec);
#ifdef USE_TIMER_SYNC
frame_ticks = 0.0;
#endif
/* Open the audio device */
audio_fd = SDL_OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 0);
if(audio_fd < 0) {
SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno));
return(-1);
}
/* Set to play mode */
info.mode = AUMODE_PLAY;
if(ioctl(audio_fd, AUDIO_SETINFO, &info) < 0) {
SDL_SetError("Couldn't put device into play mode");
return(-1);
}
mixbuf = NULL;
AUDIO_INITINFO(&info);
for (format = SDL_FirstAudioFormat(spec->format);
format; format = SDL_NextAudioFormat())
{
switch(format) {
case AUDIO_U8:
info.play.encoding = AUDIO_ENCODING_ULINEAR;
info.play.precision = 8;
break;
case AUDIO_S8:
info.play.encoding = AUDIO_ENCODING_SLINEAR;
info.play.precision = 8;
break;
case AUDIO_S16LSB:
info.play.encoding = AUDIO_ENCODING_SLINEAR_LE;
info.play.precision = 16;
break;
case AUDIO_S16MSB:
info.play.encoding = AUDIO_ENCODING_SLINEAR_BE;
info.play.precision = 16;
break;
case AUDIO_U16LSB:
info.play.encoding = AUDIO_ENCODING_ULINEAR_LE;
info.play.precision = 16;
break;
case AUDIO_U16MSB:
info.play.encoding = AUDIO_ENCODING_ULINEAR_BE;
info.play.precision = 16;
break;
default:
continue;
}
if (ioctl(audio_fd, AUDIO_SETINFO, &info) == 0)
break;
}
if(!format) {
SDL_SetError("No supported encoding for 0x%x", spec->format);
return(-1);
}
spec->format = format;
AUDIO_INITINFO(&info);
info.play.channels = spec->channels;
if (ioctl(audio_fd, AUDIO_SETINFO, &info) == -1)
spec->channels = 1;
AUDIO_INITINFO(&info);
info.play.sample_rate = spec->freq;
info.blocksize = spec->size;
info.hiwat = 5;
info.lowat = 3;
(void)ioctl(audio_fd, AUDIO_SETINFO, &info);
(void)ioctl(audio_fd, AUDIO_GETINFO, &info);
spec->freq = info.play.sample_rate;
/* Allocate mixing buffer */
mixlen = spec->size;
mixbuf = (Uint8*)SDL_AllocAudioMem(mixlen);
if(mixbuf == NULL) {
return(-1);
}
SDL_memset(mixbuf, spec->silence, spec->size);
/* Get the parent process id (we're the parent of the audio thread) */
parent = getpid();
#ifdef DEBUG_AUDIO
OBSD_Status(this);
#endif
/* We're ready to rock and roll. :-) */
return(0);
}

View file

@ -1,58 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
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 library 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
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
#ifndef _SDL_openbsdaudio_h
#define _SDL_openbsdaudio_h
#include "../SDL_sysaudio.h"
#define _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData
{
/* The file descriptor for the audio device */
int audio_fd;
/* The parent process id, to detect when application quits */
pid_t parent;
/* Raw mixing buffer */
Uint8 *mixbuf;
int mixlen;
/* Support for audio timing using a timer, in addition to select() */
float frame_ticks;
float next_frame;
};
#define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */
/* Old variable names */
#define audio_fd (this->hidden->audio_fd)
#define parent (this->hidden->parent)
#define mixbuf (this->hidden->mixbuf)
#define mixlen (this->hidden->mixlen)
#define frame_ticks (this->hidden->frame_ticks)
#define next_frame (this->hidden->next_frame)
#endif /* _SDL_openbsdaudio_h */

View file

@ -1,441 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
/* Allow access to a raw mixing buffer */
#include "SDL_timer.h"
#include "SDL_audio.h"
#include "../SDL_audio_c.h"
#include "SDL_dart.h"
// Buffer states:
#define BUFFER_EMPTY 0
#define BUFFER_USED 1
typedef struct _tMixBufferDesc {
int iBufferUsage; // BUFFER_EMPTY or BUFFER_USED
SDL_AudioDevice *pSDLAudioDevice;
} tMixBufferDesc, *pMixBufferDesc;
//---------------------------------------------------------------------
// DARTEventFunc
//
// This function is called by DART, when an event occures, like end of
// playback of a buffer, etc...
//---------------------------------------------------------------------
LONG APIENTRY DARTEventFunc(ULONG ulStatus,
PMCI_MIX_BUFFER pBuffer,
ULONG ulFlags)
{
if (ulFlags && MIX_WRITE_COMPLETE)
{ // Playback of buffer completed!
// Get pointer to buffer description
pMixBufferDesc pBufDesc;
if (pBuffer)
{
pBufDesc = (pMixBufferDesc) (*pBuffer).ulUserParm;
if (pBufDesc)
{
SDL_AudioDevice *pSDLAudioDevice = pBufDesc->pSDLAudioDevice;
// Set the buffer to be empty
pBufDesc->iBufferUsage = BUFFER_EMPTY;
// And notify DART feeder thread that it will have to work a bit.
if (pSDLAudioDevice)
DosPostEventSem(pSDLAudioDevice->hidden->hevAudioBufferPlayed);
}
}
}
return TRUE;
}
int DART_OpenAudio(_THIS, SDL_AudioSpec *spec)
{
Uint16 test_format = SDL_FirstAudioFormat(spec->format);
int valid_datatype = 0;
MCI_AMP_OPEN_PARMS AmpOpenParms;
MCI_GENERIC_PARMS GenericParms;
int iDeviceOrd = 0; // Default device to be used
int bOpenShared = 1; // Try opening it shared
int iBits = 16; // Default is 16 bits signed
int iFreq = 44100; // Default is 44KHz
int iChannels = 2; // Default is 2 channels (Stereo)
int iNumBufs = 2; // Number of audio buffers: 2
int iBufSize;
int iOpenMode;
int iSilence;
int rc;
// First thing is to try to open a given DART device!
SDL_memset(&AmpOpenParms, 0, sizeof(MCI_AMP_OPEN_PARMS));
// pszDeviceType should contain the device type in low word, and device ordinal in high word!
AmpOpenParms.pszDeviceType = (PSZ) (MCI_DEVTYPE_AUDIO_AMPMIX | (iDeviceOrd << 16));
iOpenMode = MCI_WAIT | MCI_OPEN_TYPE_ID;
if (bOpenShared) iOpenMode |= MCI_OPEN_SHAREABLE;
rc = mciSendCommand( 0, MCI_OPEN,
iOpenMode,
(PVOID) &AmpOpenParms, 0);
if (rc!=MCIERR_SUCCESS) // No audio available??
return (-1);
// Save the device ID we got from DART!
// We will use this in the next calls!
iDeviceOrd = AmpOpenParms.usDeviceID;
// Determine the audio parameters from the AudioSpec
if (spec->channels > 2)
spec->channels = 2; // !!! FIXME: more than stereo support in OS/2?
while ((!valid_datatype) && (test_format)) {
spec->format = test_format;
valid_datatype = 1;
switch (test_format) {
case AUDIO_U8:
// Unsigned 8 bit audio data
iSilence = 0x80;
iBits = 8;
break;
case AUDIO_S16LSB:
// Signed 16 bit audio data
iSilence = 0x00;
iBits = 16;
break;
default:
valid_datatype = 0;
test_format = SDL_NextAudioFormat();
break;
}
}
if (!valid_datatype) { // shouldn't happen, but just in case...
// Close DART, and exit with error code!
mciSendCommand(iDeviceOrd, MCI_CLOSE, MCI_WAIT, &GenericParms, 0);
SDL_SetError("Unsupported audio format");
return (-1);
}
iFreq = spec->freq;
iChannels = spec->channels;
/* Update the fragment size as size in bytes */
SDL_CalculateAudioSpec(spec);
iBufSize = spec->size;
// Now query this device if it supports the given freq/bits/channels!
SDL_memset(&(_this->hidden->MixSetupParms), 0, sizeof(MCI_MIXSETUP_PARMS));
_this->hidden->MixSetupParms.ulBitsPerSample = iBits;
_this->hidden->MixSetupParms.ulFormatTag = MCI_WAVE_FORMAT_PCM;
_this->hidden->MixSetupParms.ulSamplesPerSec = iFreq;
_this->hidden->MixSetupParms.ulChannels = iChannels;
_this->hidden->MixSetupParms.ulFormatMode = MCI_PLAY;
_this->hidden->MixSetupParms.ulDeviceType = MCI_DEVTYPE_WAVEFORM_AUDIO;
_this->hidden->MixSetupParms.pmixEvent = DARTEventFunc;
rc = mciSendCommand (iDeviceOrd, MCI_MIXSETUP,
MCI_WAIT | MCI_MIXSETUP_QUERYMODE,
&(_this->hidden->MixSetupParms), 0);
if (rc!=MCIERR_SUCCESS)
{ // The device cannot handle this format!
// Close DART, and exit with error code!
mciSendCommand(iDeviceOrd, MCI_CLOSE, MCI_WAIT, &GenericParms, 0);
SDL_SetError("Audio device doesn't support requested audio format");
return(-1);
}
// The device can handle this format, so initialize!
rc = mciSendCommand(iDeviceOrd, MCI_MIXSETUP,
MCI_WAIT | MCI_MIXSETUP_INIT,
&(_this->hidden->MixSetupParms), 0);
if (rc!=MCIERR_SUCCESS)
{ // The device could not be opened!
// Close DART, and exit with error code!
mciSendCommand(iDeviceOrd, MCI_CLOSE, MCI_WAIT, &GenericParms, 0);
SDL_SetError("Audio device could not be set up");
return(-1);
}
// Ok, the device is initialized.
// Now we should allocate buffers. For this, we need a place where
// the buffer descriptors will be:
_this->hidden->pMixBuffers = (MCI_MIX_BUFFER *) SDL_malloc(sizeof(MCI_MIX_BUFFER)*iNumBufs);
if (!(_this->hidden->pMixBuffers))
{ // Not enough memory!
// Close DART, and exit with error code!
mciSendCommand(iDeviceOrd, MCI_CLOSE, MCI_WAIT, &GenericParms, 0);
SDL_SetError("Not enough memory for audio buffer descriptors");
return(-1);
}
// Now that we have the place for buffer list, we can ask DART for the
// buffers!
_this->hidden->BufferParms.ulNumBuffers = iNumBufs; // Number of buffers
_this->hidden->BufferParms.ulBufferSize = iBufSize; // each with this size
_this->hidden->BufferParms.pBufList = _this->hidden->pMixBuffers; // getting descriptorts into this list
// Allocate buffers!
rc = mciSendCommand(iDeviceOrd, MCI_BUFFER,
MCI_WAIT | MCI_ALLOCATE_MEMORY,
&(_this->hidden->BufferParms), 0);
if ((rc!=MCIERR_SUCCESS) || (iNumBufs != _this->hidden->BufferParms.ulNumBuffers) || (_this->hidden->BufferParms.ulBufferSize==0))
{ // Could not allocate memory!
// Close DART, and exit with error code!
SDL_free(_this->hidden->pMixBuffers); _this->hidden->pMixBuffers = NULL;
mciSendCommand(iDeviceOrd, MCI_CLOSE, MCI_WAIT, &GenericParms, 0);
SDL_SetError("DART could not allocate buffers");
return(-1);
}
// Ok, we have all the buffers allocated, let's mark them!
{
int i;
for (i=0; i<iNumBufs; i++)
{
pMixBufferDesc pBufferDesc = (pMixBufferDesc) SDL_malloc(sizeof(tMixBufferDesc));;
// Check if this buffer was really allocated by DART
if ((!(_this->hidden->pMixBuffers[i].pBuffer)) || (!pBufferDesc))
{ // Wrong buffer!
// Close DART, and exit with error code!
// Free buffer descriptions
{ int j;
for (j=0; j<i; j++) SDL_free((void *)(_this->hidden->pMixBuffers[j].ulUserParm));
}
// and cleanup
mciSendCommand(iDeviceOrd, MCI_BUFFER, MCI_WAIT | MCI_DEALLOCATE_MEMORY, &(_this->hidden->BufferParms), 0);
SDL_free(_this->hidden->pMixBuffers); _this->hidden->pMixBuffers = NULL;
mciSendCommand(iDeviceOrd, MCI_CLOSE, MCI_WAIT, &GenericParms, 0);
SDL_SetError("Error at internal buffer check");
return(-1);
}
pBufferDesc->iBufferUsage = BUFFER_EMPTY;
pBufferDesc->pSDLAudioDevice = _this;
_this->hidden->pMixBuffers[i].ulBufferLength = _this->hidden->BufferParms.ulBufferSize;
_this->hidden->pMixBuffers[i].ulUserParm = (ULONG) pBufferDesc; // User parameter: Description of buffer
_this->hidden->pMixBuffers[i].ulFlags = 0; // Some stuff should be flagged here for DART, like end of
// audio data, but as we will continously send
// audio data, there will be no end.:)
SDL_memset(_this->hidden->pMixBuffers[i].pBuffer, iSilence, iBufSize);
}
}
_this->hidden->iNextFreeBuffer = 0;
_this->hidden->iLastPlayedBuf = -1;
// Create event semaphore
if (DosCreateEventSem(NULL, &(_this->hidden->hevAudioBufferPlayed), 0, FALSE)!=NO_ERROR)
{
// Could not create event semaphore!
{
int i;
for (i=0; i<iNumBufs; i++) SDL_free((void *)(_this->hidden->pMixBuffers[i].ulUserParm));
}
mciSendCommand(iDeviceOrd, MCI_BUFFER, MCI_WAIT | MCI_DEALLOCATE_MEMORY, &(_this->hidden->BufferParms), 0);
SDL_free(_this->hidden->pMixBuffers); _this->hidden->pMixBuffers = NULL;
mciSendCommand(iDeviceOrd, MCI_CLOSE, MCI_WAIT, &GenericParms, 0);
SDL_SetError("Could not create event semaphore");
return(-1);
}
// Store the new settings in global variables
_this->hidden->iCurrDeviceOrd = iDeviceOrd;
_this->hidden->iCurrFreq = iFreq;
_this->hidden->iCurrBits = iBits;
_this->hidden->iCurrChannels = iChannels;
_this->hidden->iCurrNumBufs = iNumBufs;
_this->hidden->iCurrBufSize = iBufSize;
return (0);
}
void DART_ThreadInit(_THIS)
{
return;
}
/* This function waits until it is possible to write a full sound buffer */
void DART_WaitAudio(_THIS)
{
int i;
pMixBufferDesc pBufDesc;
ULONG ulPostCount;
DosResetEventSem(_this->hidden->hevAudioBufferPlayed, &ulPostCount);
// If there is already an empty buffer, then return now!
for (i=0; i<_this->hidden->iCurrNumBufs; i++)
{
pBufDesc = (pMixBufferDesc) _this->hidden->pMixBuffers[i].ulUserParm;
if (pBufDesc->iBufferUsage == BUFFER_EMPTY)
return;
}
// If there is no empty buffer, wait for one to be empty!
DosWaitEventSem(_this->hidden->hevAudioBufferPlayed, 1000); // Wait max 1 sec!!! Important!
return;
}
void DART_PlayAudio(_THIS)
{
int iFreeBuf = _this->hidden->iNextFreeBuffer;
pMixBufferDesc pBufDesc;
pBufDesc = (pMixBufferDesc) _this->hidden->pMixBuffers[iFreeBuf].ulUserParm;
pBufDesc->iBufferUsage = BUFFER_USED;
// Send it to DART to be queued
_this->hidden->MixSetupParms.pmixWrite(_this->hidden->MixSetupParms.ulMixHandle,
&(_this->hidden->pMixBuffers[iFreeBuf]), 1);
_this->hidden->iLastPlayedBuf = iFreeBuf;
iFreeBuf = (iFreeBuf+1) % _this->hidden->iCurrNumBufs;
_this->hidden->iNextFreeBuffer = iFreeBuf;
}
Uint8 *DART_GetAudioBuf(_THIS)
{
int iFreeBuf;
Uint8 *pResult;
pMixBufferDesc pBufDesc;
if (_this)
{
if (_this->hidden)
{
iFreeBuf = _this->hidden->iNextFreeBuffer;
pBufDesc = (pMixBufferDesc) _this->hidden->pMixBuffers[iFreeBuf].ulUserParm;
if (pBufDesc)
{
if (pBufDesc->iBufferUsage == BUFFER_EMPTY)
{
pResult = _this->hidden->pMixBuffers[iFreeBuf].pBuffer;
return pResult;
}
} else
printf("[DART_GetAudioBuf] : ERROR! pBufDesc = %p\n", pBufDesc);
} else
printf("[DART_GetAudioBuf] : ERROR! _this->hidden = %p\n", _this->hidden);
} else
printf("[DART_GetAudioBuf] : ERROR! _this = %p\n", _this);
return NULL;
}
void DART_WaitDone(_THIS)
{
pMixBufferDesc pBufDesc;
ULONG ulPostCount;
APIRET rc;
pBufDesc = (pMixBufferDesc) _this->hidden->pMixBuffers[_this->hidden->iLastPlayedBuf].ulUserParm;
rc = NO_ERROR;
while ((pBufDesc->iBufferUsage != BUFFER_EMPTY) && (rc==NO_ERROR))
{
DosResetEventSem(_this->hidden->hevAudioBufferPlayed, &ulPostCount);
rc = DosWaitEventSem(_this->hidden->hevAudioBufferPlayed, 1000); // 1 sec timeout! Important!
}
}
void DART_CloseAudio(_THIS)
{
MCI_GENERIC_PARMS GenericParms;
int rc;
// Stop DART playback
rc = mciSendCommand(_this->hidden->iCurrDeviceOrd, MCI_STOP, MCI_WAIT, &GenericParms, 0);
if (rc!=MCIERR_SUCCESS)
{
#ifdef SFX_DEBUG_BUILD
printf("Could not stop DART playback!\n");
fflush(stdout);
#endif
}
// Close event semaphore
DosCloseEventSem(_this->hidden->hevAudioBufferPlayed);
// Free memory of buffer descriptions
{
int i;
for (i=0; i<_this->hidden->iCurrNumBufs; i++) SDL_free((void *)(_this->hidden->pMixBuffers[i].ulUserParm));
}
// Deallocate buffers
rc = mciSendCommand(_this->hidden->iCurrDeviceOrd, MCI_BUFFER, MCI_WAIT | MCI_DEALLOCATE_MEMORY, &(_this->hidden->BufferParms), 0);
// Free bufferlist
SDL_free(_this->hidden->pMixBuffers); _this->hidden->pMixBuffers = NULL;
// Close dart
rc = mciSendCommand(_this->hidden->iCurrDeviceOrd, MCI_CLOSE, MCI_WAIT, &(GenericParms), 0);
}
/* Audio driver bootstrap functions */
int Audio_Available(void)
{
return(1);
}
void Audio_DeleteDevice(SDL_AudioDevice *device)
{
SDL_free(device->hidden);
SDL_free(device);
}
SDL_AudioDevice *Audio_CreateDevice(int devindex)
{
SDL_AudioDevice *this;
/* Initialize all variables that we clean on shutdown */
this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
if ( this )
{
SDL_memset(this, 0, (sizeof *this));
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
}
if ( (this == NULL) || (this->hidden == NULL) )
{
SDL_OutOfMemory();
if ( this )
SDL_free(this);
return(0);
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
/* Set the function pointers */
this->OpenAudio = DART_OpenAudio;
this->ThreadInit = DART_ThreadInit;
this->WaitAudio = DART_WaitAudio;
this->PlayAudio = DART_PlayAudio;
this->GetAudioBuf = DART_GetAudioBuf;
this->WaitDone = DART_WaitDone;
this->CloseAudio = DART_CloseAudio;
this->free = Audio_DeleteDevice;
return this;
}
AudioBootStrap DART_bootstrap = {
"dart", "OS/2 Direct Audio RouTines (DART)",
Audio_Available, Audio_CreateDevice
};

View file

@ -1,63 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
#ifndef _SDL_lowaudio_h
#define _SDL_lowaudio_h
#define INCL_TYPES
#define INCL_DOSSEMAPHORES
#define INCL_DOSRESOURCES
#define INCL_DOSMISC
#define INCL_DOSERRORS
#define INCL_OS2MM
#define INCL_MMIOOS2
#define INCL_MCIOS2
#include <os2.h>
#include <os2me.h> // DART stuff and MMIO stuff
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the audio functions */
#define _THIS SDL_AudioDevice *_this
/* The DirectSound objects */
struct SDL_PrivateAudioData
{
int iCurrDeviceOrd;
int iCurrFreq;
int iCurrBits;
int iCurrChannels;
int iCurrNumBufs;
int iCurrBufSize;
int iLastPlayedBuf;
int iNextFreeBuffer;
MCI_BUFFER_PARMS BufferParms; // Sound buffer parameters
MCI_MIX_BUFFER *pMixBuffers; // Sound buffers
MCI_MIXSETUP_PARMS MixSetupParms; // Mixer setup parameters
HEV hevAudioBufferPlayed; // Event semaphore to indicate that an audio buffer has been played by DART
};
#endif /* _SDL_lowaudio_h */

View file

@ -1,246 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
/* Output dreamcast aica */
#include "SDL_timer.h"
#include "SDL_audio.h"
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
#include "../SDL_audiodev_c.h"
#include "SDL_dcaudio.h"
#include "aica.h"
#include <dc/spu.h>
/* Audio driver functions */
static int DCAUD_OpenAudio(_THIS, SDL_AudioSpec *spec);
static void DCAUD_WaitAudio(_THIS);
static void DCAUD_PlayAudio(_THIS);
static Uint8 *DCAUD_GetAudioBuf(_THIS);
static void DCAUD_CloseAudio(_THIS);
/* Audio driver bootstrap functions */
static int DCAUD_Available(void)
{
return 1;
}
static void DCAUD_DeleteDevice(SDL_AudioDevice *device)
{
SDL_free(device->hidden);
SDL_free(device);
}
static SDL_AudioDevice *DCAUD_CreateDevice(int devindex)
{
SDL_AudioDevice *this;
/* Initialize all variables that we clean on shutdown */
this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
if ( this ) {
SDL_memset(this, 0, (sizeof *this));
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
}
if ( (this == NULL) || (this->hidden == NULL) ) {
SDL_OutOfMemory();
if ( this ) {
SDL_free(this);
}
return(0);
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
/* Set the function pointers */
this->OpenAudio = DCAUD_OpenAudio;
this->WaitAudio = DCAUD_WaitAudio;
this->PlayAudio = DCAUD_PlayAudio;
this->GetAudioBuf = DCAUD_GetAudioBuf;
this->CloseAudio = DCAUD_CloseAudio;
this->free = DCAUD_DeleteDevice;
spu_init();
return this;
}
AudioBootStrap DCAUD_bootstrap = {
"dcaudio", "Dreamcast AICA audio",
DCAUD_Available, DCAUD_CreateDevice
};
/* This function waits until it is possible to write a full sound buffer */
static void DCAUD_WaitAudio(_THIS)
{
if (this->hidden->playing) {
/* wait */
while(aica_get_pos(0)/this->spec.samples == this->hidden->nextbuf) {
thd_pass();
}
}
}
#define SPU_RAM_BASE 0xa0800000
static void spu_memload_stereo8(int leftpos,int rightpos,void *src0,size_t size)
{
uint8 *src = src0;
uint32 *left = (uint32*)(leftpos +SPU_RAM_BASE);
uint32 *right = (uint32*)(rightpos+SPU_RAM_BASE);
size = (size+7)/8;
while(size--) {
unsigned lval,rval;
lval = *src++;
rval = *src++;
lval|= (*src++)<<8;
rval|= (*src++)<<8;
lval|= (*src++)<<16;
rval|= (*src++)<<16;
lval|= (*src++)<<24;
rval|= (*src++)<<24;
g2_write_32(left++,lval);
g2_write_32(right++,rval);
g2_fifo_wait();
}
}
static void spu_memload_stereo16(int leftpos,int rightpos,void *src0,size_t size)
{
uint16 *src = src0;
uint32 *left = (uint32*)(leftpos +SPU_RAM_BASE);
uint32 *right = (uint32*)(rightpos+SPU_RAM_BASE);
size = (size+7)/8;
while(size--) {
unsigned lval,rval;
lval = *src++;
rval = *src++;
lval|= (*src++)<<16;
rval|= (*src++)<<16;
g2_write_32(left++,lval);
g2_write_32(right++,rval);
g2_fifo_wait();
}
}
static void DCAUD_PlayAudio(_THIS)
{
SDL_AudioSpec *spec = &this->spec;
unsigned int offset;
if (this->hidden->playing) {
/* wait */
while(aica_get_pos(0)/spec->samples == this->hidden->nextbuf) {
thd_pass();
}
}
offset = this->hidden->nextbuf*spec->size;
this->hidden->nextbuf^=1;
/* Write the audio data, checking for EAGAIN on broken audio drivers */
if (spec->channels==1) {
spu_memload(this->hidden->leftpos+offset,this->hidden->mixbuf,this->hidden->mixlen);
} else {
offset/=2;
if ((this->spec.format&255)==8) {
spu_memload_stereo8(this->hidden->leftpos+offset,this->hidden->rightpos+offset,this->hidden->mixbuf,this->hidden->mixlen);
} else {
spu_memload_stereo16(this->hidden->leftpos+offset,this->hidden->rightpos+offset,this->hidden->mixbuf,this->hidden->mixlen);
}
}
if (!this->hidden->playing) {
int mode;
this->hidden->playing = 1;
mode = (spec->format==AUDIO_S8)?SM_8BIT:SM_16BIT;
if (spec->channels==1) {
aica_play(0,mode,this->hidden->leftpos,0,spec->samples*2,spec->freq,255,128,1);
} else {
aica_play(0,mode,this->hidden->leftpos ,0,spec->samples*2,spec->freq,255,0,1);
aica_play(1,mode,this->hidden->rightpos,0,spec->samples*2,spec->freq,255,255,1);
}
}
}
static Uint8 *DCAUD_GetAudioBuf(_THIS)
{
return(this->hidden->mixbuf);
}
static void DCAUD_CloseAudio(_THIS)
{
aica_stop(0);
if (this->spec.channels==2) aica_stop(1);
if ( this->hidden->mixbuf != NULL ) {
SDL_FreeAudioMem(this->hidden->mixbuf);
this->hidden->mixbuf = NULL;
}
}
static int DCAUD_OpenAudio(_THIS, SDL_AudioSpec *spec)
{
Uint16 test_format = SDL_FirstAudioFormat(spec->format);
int valid_datatype = 0;
while ((!valid_datatype) && (test_format)) {
spec->format = test_format;
switch (test_format) {
/* only formats Dreamcast accepts... */
case AUDIO_S8:
case AUDIO_S16LSB:
valid_datatype = 1;
break;
default:
test_format = SDL_NextAudioFormat();
break;
}
}
if (!valid_datatype) { /* shouldn't happen, but just in case... */
SDL_SetError("Unsupported audio format");
return (-1);
}
if (spec->channels > 2)
spec->channels = 2; /* no more than stereo on the Dreamcast. */
/* Update the fragment size as size in bytes */
SDL_CalculateAudioSpec(spec);
/* Allocate mixing buffer */
this->hidden->mixlen = spec->size;
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
if ( this->hidden->mixbuf == NULL ) {
return(-1);
}
SDL_memset(this->hidden->mixbuf, spec->silence, spec->size);
this->hidden->leftpos = 0x11000;
this->hidden->rightpos = 0x11000+spec->size;
this->hidden->playing = 0;
this->hidden->nextbuf = 0;
/* We're ready to rock and roll. :-) */
return(0);
}

View file

@ -1,41 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
#ifndef _SDL_dcaudio_h
#define _SDL_dcaudio_h
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the video functions */
#define _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData {
/* The file descriptor for the audio device */
Uint8 *mixbuf;
Uint32 mixlen;
int playing;
int leftpos,rightpos;
int nextbuf;
};
#endif /* _SDL_dcaudio_h */

View file

@ -1,271 +0,0 @@
/* This file is part of the Dreamcast function library.
* Please see libdream.c for further details.
*
* (c)2000 Dan Potter
* modify BERO
*/
#include "aica.h"
#include <arch/irq.h>
#include <dc/spu.h>
/* #define dc_snd_base ((volatile unsigned char *)0x00800000) */ /* arm side */
#define dc_snd_base ((volatile unsigned char *)0xa0700000) /* dc side */
/* Some convienence macros */
#define SNDREGADDR(x) (0xa0700000 + (x))
#define CHNREGADDR(ch,x) SNDREGADDR(0x80*(ch)+(x))
#define SNDREG32(x) (*(volatile unsigned long *)SNDREGADDR(x))
#define SNDREG8(x) (*(volatile unsigned char *)SNDREGADDR(x))
#define CHNREG32(ch, x) (*(volatile unsigned long *)CHNREGADDR(ch,x))
#define CHNREG8(ch, x) (*(volatile unsigned long *)CHNREGADDR(ch,x))
#define G2_LOCK(OLD) \
do { \
if (!irq_inside_int()) \
OLD = irq_disable(); \
/* suspend any G2 DMA here... */ \
while((*(volatile unsigned int *)0xa05f688c) & 0x20) \
; \
} while(0)
#define G2_UNLOCK(OLD) \
do { \
/* resume any G2 DMA here... */ \
if (!irq_inside_int()) \
irq_restore(OLD); \
} while(0)
void aica_init() {
int i, j, old = 0;
/* Initialize AICA channels */
G2_LOCK(old);
SNDREG32(0x2800) = 0x0000;
for (i=0; i<64; i++) {
for (j=0; j<0x80; j+=4) {
if ((j&31)==0) g2_fifo_wait();
CHNREG32(i, j) = 0;
}
g2_fifo_wait();
CHNREG32(i,0) = 0x8000;
CHNREG32(i,20) = 0x1f;
}
SNDREG32(0x2800) = 0x000f;
g2_fifo_wait();
G2_UNLOCK(old);
}
/* Translates a volume from linear form to logarithmic form (required by
the AICA chip */
/* int logs[] = {
0, 40, 50, 58, 63, 68, 73, 77, 80, 83, 86, 89, 92, 94, 97, 99, 101, 103,
105, 107, 109, 111, 112, 114, 116, 117, 119, 120, 122, 123, 125, 126, 127,
129, 130, 131, 133, 134, 135, 136, 137, 139, 140, 141, 142, 143, 144, 145,
146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 156, 157, 158, 159,
160, 161, 162, 162, 163, 164, 165, 166, 166, 167, 168, 169, 170, 170, 171,
172, 172, 173, 174, 175, 175, 176, 177, 177, 178, 179, 180, 180, 181, 182,
182, 183, 183, 184, 185, 185, 186, 187, 187, 188, 188, 189, 190, 190, 191,
191, 192, 193, 193, 194, 194, 195, 196, 196, 197, 197, 198, 198, 199, 199,
200, 201, 201, 202, 202, 203, 203, 204, 204, 205, 205, 206, 206, 207, 207,
208, 208, 209, 209, 210, 210, 211, 211, 212, 212, 213, 213, 214, 214, 215,
215, 216, 216, 217, 217, 217, 218, 218, 219, 219, 220, 220, 221, 221, 222,
222, 222, 223, 223, 224, 224, 225, 225, 225, 226, 226, 227, 227, 228, 228,
228, 229, 229, 230, 230, 230, 231, 231, 232, 232, 232, 233, 233, 234, 234,
234, 235, 235, 236, 236, 236, 237, 237, 238, 238, 238, 239, 239, 240, 240,
240, 241, 241, 241, 242, 242, 243, 243, 243, 244, 244, 244, 245, 245, 245,
246, 246, 247, 247, 247, 248, 248, 248, 249, 249, 249, 250, 250, 250, 251,
251, 251, 252, 252, 252, 253, 253, 253, 254, 254, 254, 255
}; */
const static unsigned char logs[] = {
0, 15, 22, 27, 31, 35, 39, 42, 45, 47, 50, 52, 55, 57, 59, 61,
63, 65, 67, 69, 71, 73, 74, 76, 78, 79, 81, 82, 84, 85, 87, 88,
90, 91, 92, 94, 95, 96, 98, 99, 100, 102, 103, 104, 105, 106,
108, 109, 110, 111, 112, 113, 114, 116, 117, 118, 119, 120, 121,
122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134,
135, 136, 137, 138, 138, 139, 140, 141, 142, 143, 144, 145, 146,
146, 147, 148, 149, 150, 151, 152, 152, 153, 154, 155, 156, 156,
157, 158, 159, 160, 160, 161, 162, 163, 164, 164, 165, 166, 167,
167, 168, 169, 170, 170, 171, 172, 173, 173, 174, 175, 176, 176,
177, 178, 178, 179, 180, 181, 181, 182, 183, 183, 184, 185, 185,
186, 187, 187, 188, 189, 189, 190, 191, 191, 192, 193, 193, 194,
195, 195, 196, 197, 197, 198, 199, 199, 200, 200, 201, 202, 202,
203, 204, 204, 205, 205, 206, 207, 207, 208, 209, 209, 210, 210,
211, 212, 212, 213, 213, 214, 215, 215, 216, 216, 217, 217, 218,
219, 219, 220, 220, 221, 221, 222, 223, 223, 224, 224, 225, 225,
226, 227, 227, 228, 228, 229, 229, 230, 230, 231, 232, 232, 233,
233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 239, 239, 240,
240, 241, 241, 242, 242, 243, 243, 244, 244, 245, 245, 246, 246,
247, 247, 248, 248, 249, 249, 250, 250, 251, 251, 252, 252, 253, 254, 255
};
/* For the moment this is going to have to suffice, until we really
figure out what these mean. */
#define AICA_PAN(x) ((x)==0x80?(0):((x)<0x80?(0x1f):(0x0f)))
#define AICA_VOL(x) (0xff - logs[128 + (((x) & 0xff) / 2)])
//#define AICA_VOL(x) (0xff - logs[x&255])
static inline unsigned AICA_FREQ(unsigned freq) {
unsigned long freq_lo, freq_base = 5644800;
int freq_hi = 7;
/* Need to convert frequency to floating point format
(freq_hi is exponent, freq_lo is mantissa)
Formula is ferq = 44100*2^freq_hi*(1+freq_lo/1024) */
while (freq < freq_base && freq_hi > -8) {
freq_base >>= 1;
--freq_hi;
}
while (freq < freq_base && freq_hi > -8) {
freq_base >>= 1;
freq_hi--;
}
freq_lo = (freq<<10) / freq_base;
return (freq_hi << 11) | (freq_lo & 1023);
}
/* Sets up a sound channel completely. This is generally good if you want
a quick and dirty way to play notes. If you want a more comprehensive
set of routines (more like PC wavetable cards) see below.
ch is the channel to play on (0 - 63)
smpptr is the pointer to the sound data; if you're running off the
SH4, then this ought to be (ptr - 0xa0800000); otherwise it's just
ptr. Basically, it's an offset into sound ram.
mode is one of the mode constants (16 bit, 8 bit, ADPCM)
nsamp is the number of samples to play (not number of bytes!)
freq is the sampling rate of the sound
vol is the volume, 0 to 0xff (0xff is louder)
pan is a panning constant -- 0 is left, 128 is center, 255 is right.
This routine (and the similar ones) owe a lot to Marcus' sound example --
I hadn't gotten quite this far into dissecting the individual regs yet. */
void aica_play(int ch,int mode,unsigned long smpptr,int loopst,int loopend,int freq,int vol,int pan,int loopflag) {
/* int i;
*/
int val;
int old = 0;
/* Stop the channel (if it's already playing) */
aica_stop(ch);
/* doesn't seem to be needed, but it's here just in case */
/*
for (i=0; i<256; i++) {
asm("nop");
asm("nop");
asm("nop");
asm("nop");
}
*/
G2_LOCK(old);
/* Envelope setup. The first of these is the loop point,
e.g., where the sample starts over when it loops. The second
is the loop end. This is the full length of the sample when
you are not looping, or the loop end point when you are (though
storing more than that is a waste of memory if you're not doing
volume enveloping). */
CHNREG32(ch, 8) = loopst & 0xffff;
CHNREG32(ch, 12) = loopend & 0xffff;
/* Write resulting values */
CHNREG32(ch, 24) = AICA_FREQ(freq);
/* Set volume, pan, and some other things that we don't know what
they do =) */
CHNREG32(ch, 36) = AICA_PAN(pan) | (0xf<<8);
/* Convert the incoming volume and pan into hardware values */
/* Vol starts at zero so we can ramp */
vol = AICA_VOL(vol);
CHNREG32(ch, 40) = 0x24 | (vol<<8);
/* Convert the incoming volume and pan into hardware values */
/* Vol starts at zero so we can ramp */
/* If we supported volume envelopes (which we don't yet) then
this value would set that up. The top 4 bits determine the
envelope speed. f is the fastest, 1 is the slowest, and 0
seems to be an invalid value and does weird things). The
default (below) sets it into normal mode (play and terminate/loop).
CHNREG32(ch, 16) = 0xf010;
*/
CHNREG32(ch, 16) = 0x1f; /* No volume envelope */
/* Set sample format, buffer address, and looping control. If
0x0200 mask is set on reg 0, the sample loops infinitely. If
it's not set, the sample plays once and terminates. We'll
also set the bits to start playback here. */
CHNREG32(ch, 4) = smpptr & 0xffff;
val = 0xc000 | 0x0000 | (mode<<7) | (smpptr >> 16);
if (loopflag) val|=0x200;
CHNREG32(ch, 0) = val;
G2_UNLOCK(old);
/* Enable playback */
/* CHNREG32(ch, 0) |= 0xc000; */
g2_fifo_wait();
#if 0
for (i=0xff; i>=vol; i--) {
if ((i&7)==0) g2_fifo_wait();
CHNREG32(ch, 40) = 0x24 | (i<<8);;
}
g2_fifo_wait();
#endif
}
/* Stop the sound on a given channel */
void aica_stop(int ch) {
g2_write_32(CHNREGADDR(ch, 0),(g2_read_32(CHNREGADDR(ch, 0)) & ~0x4000) | 0x8000);
g2_fifo_wait();
}
/* The rest of these routines can change the channel in mid-stride so you
can do things like vibrato and panning effects. */
/* Set channel volume */
void aica_vol(int ch,int vol) {
// g2_write_8(CHNREGADDR(ch, 41),AICA_VOL(vol));
g2_write_32(CHNREGADDR(ch, 40),(g2_read_32(CHNREGADDR(ch, 40))&0xffff00ff)|(AICA_VOL(vol)<<8) );
g2_fifo_wait();
}
/* Set channel pan */
void aica_pan(int ch,int pan) {
// g2_write_8(CHNREGADDR(ch, 36),AICA_PAN(pan));
g2_write_32(CHNREGADDR(ch, 36),(g2_read_32(CHNREGADDR(ch, 36))&0xffffff00)|(AICA_PAN(pan)) );
g2_fifo_wait();
}
/* Set channel frequency */
void aica_freq(int ch,int freq) {
g2_write_32(CHNREGADDR(ch, 24),AICA_FREQ(freq));
g2_fifo_wait();
}
/* Get channel position */
int aica_get_pos(int ch) {
#if 1
/* Observe channel ch */
g2_write_32(SNDREGADDR(0x280c),(g2_read_32(SNDREGADDR(0x280c))&0xffff00ff) | (ch<<8));
g2_fifo_wait();
/* Update position counters */
return g2_read_32(SNDREGADDR(0x2814)) & 0xffff;
#else
/* Observe channel ch */
g2_write_8(SNDREGADDR(0x280d),ch);
/* Update position counters */
return g2_read_32(SNDREGADDR(0x2814)) & 0xffff;
#endif
}

View file

@ -1,40 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
#ifndef _AICA_H_
#define _AICA_H_
#define AICA_MEM 0xa0800000
#define SM_8BIT 1
#define SM_16BIT 0
#define SM_ADPCM 2
void aica_play(int ch,int mode,unsigned long smpptr,int looptst,int loopend,int freq,int vol,int pan,int loopflag);
void aica_stop(int ch);
void aica_vol(int ch,int vol);
void aica_pan(int ch,int pan);
void aica_freq(int ch,int freq);
int aica_get_pos(int ch);
#endif

View file

@ -1,186 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
This file written by Ryan C. Gordon (icculus@icculus.org)
*/
#include "SDL_config.h"
/* Output raw audio data to a file. */
#if HAVE_STDIO_H
#include <stdio.h>
#endif
#include "SDL_rwops.h"
#include "SDL_timer.h"
#include "SDL_audio.h"
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
#include "../SDL_audiodev_c.h"
#include "SDL_diskaudio.h"
/* The tag name used by DISK audio */
#define DISKAUD_DRIVER_NAME "disk"
/* environment variables and defaults. */
#define DISKENVR_OUTFILE "SDL_DISKAUDIOFILE"
#define DISKDEFAULT_OUTFILE "/sdlaudio.raw"
#define DISKENVR_WRITEDELAY "SDL_DISKAUDIODELAY"
#define DISKDEFAULT_WRITEDELAY 150
/* Audio driver functions */
static int DISKAUD_OpenAudio(_THIS, SDL_AudioSpec *spec);
static void DISKAUD_WaitAudio(_THIS);
static void DISKAUD_PlayAudio(_THIS);
static Uint8 *DISKAUD_GetAudioBuf(_THIS);
static void DISKAUD_CloseAudio(_THIS);
static const char *DISKAUD_GetOutputFilename(void)
{
const char *envr = SDL_getenv(DISKENVR_OUTFILE);
return((envr != NULL) ? envr : DISKDEFAULT_OUTFILE);
}
/* Audio driver bootstrap functions */
static int DISKAUD_Available(void)
{
//const char *envr = SDL_getenv("SDL_AUDIODRIVER");
// if (envr && (SDL_strcmp(envr, DISKAUD_DRIVER_NAME) == 0)) {
return(1);
// }
// return(0);
}
static void DISKAUD_DeleteDevice(SDL_AudioDevice *device)
{
SDL_free(device->hidden);
SDL_free(device);
}
static SDL_AudioDevice *DISKAUD_CreateDevice(int devindex)
{
SDL_AudioDevice *this;
const char *envr;
/* Initialize all variables that we clean on shutdown */
this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
if ( this ) {
SDL_memset(this, 0, (sizeof *this));
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
}
if ( (this == NULL) || (this->hidden == NULL) ) {
SDL_OutOfMemory();
if ( this ) {
SDL_free(this);
}
return(0);
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
envr = SDL_getenv(DISKENVR_WRITEDELAY);
this->hidden->write_delay = (envr) ? SDL_atoi(envr) : DISKDEFAULT_WRITEDELAY;
/* Set the function pointers */
this->OpenAudio = DISKAUD_OpenAudio;
this->WaitAudio = DISKAUD_WaitAudio;
this->PlayAudio = DISKAUD_PlayAudio;
this->GetAudioBuf = DISKAUD_GetAudioBuf;
this->CloseAudio = DISKAUD_CloseAudio;
this->free = DISKAUD_DeleteDevice;
return this;
}
AudioBootStrap DISKAUD_bootstrap = {
DISKAUD_DRIVER_NAME, "direct-to-disk audio",
DISKAUD_Available, DISKAUD_CreateDevice
};
/* This function waits until it is possible to write a full sound buffer */
static void DISKAUD_WaitAudio(_THIS)
{
SDL_Delay(this->hidden->write_delay);
}
static void DISKAUD_PlayAudio(_THIS)
{
int written;
/* Write the audio data */
written = SDL_RWwrite(this->hidden->output,
this->hidden->mixbuf, 1,
this->hidden->mixlen);
/* If we couldn't write, assume fatal error for now */
if ( (Uint32)written != this->hidden->mixlen ) {
this->enabled = 0;
}
#ifdef DEBUG_AUDIO
fprintf(stderr, "Wrote %d bytes of audio data\n", written);
#endif
}
static Uint8 *DISKAUD_GetAudioBuf(_THIS)
{
return(this->hidden->mixbuf);
}
static void DISKAUD_CloseAudio(_THIS)
{
if ( this->hidden->mixbuf != NULL ) {
SDL_FreeAudioMem(this->hidden->mixbuf);
this->hidden->mixbuf = NULL;
}
if ( this->hidden->output != NULL ) {
SDL_RWclose(this->hidden->output);
this->hidden->output = NULL;
}
}
static int DISKAUD_OpenAudio(_THIS, SDL_AudioSpec *spec)
{
const char *fname = DISKAUD_GetOutputFilename();
/* Open the audio device */
this->hidden->output = SDL_RWFromFile(fname, "wb");
if ( this->hidden->output == NULL ) {
return(-1);
}
#if HAVE_STDIO_H
fprintf(stderr, "WARNING: You are using the SDL disk writer"
" audio driver!\n Writing to file [%s].\n", fname);
#endif
/* Allocate mixing buffer */
this->hidden->mixlen = spec->size;
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
if ( this->hidden->mixbuf == NULL ) {
return(-1);
}
SDL_memset(this->hidden->mixbuf, spec->silence, spec->size);
/* We're ready to rock and roll. :-) */
return(0);
}

View file

@ -1,41 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
#ifndef _SDL_diskaudio_h
#define _SDL_diskaudio_h
#include "SDL_rwops.h"
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the video functions */
#define _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData {
/* The file descriptor for the audio device */
SDL_RWops *output;
Uint8 *mixbuf;
Uint32 mixlen;
Uint32 write_delay;
};
#endif /* _SDL_diskaudio_h */

View file

@ -1,455 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
/* Allow access to a raw mixing buffer */
#include <stdio.h>
#include <string.h> /* For strerror() */
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/mman.h>
#if SDL_AUDIO_DRIVER_OSS_SOUNDCARD_H
/* This is installed on some systems */
#include <soundcard.h>
#else
/* This is recommended by OSS */
#include <sys/soundcard.h>
#endif
#ifndef MAP_FAILED
#define MAP_FAILED ((Uint8 *)-1)
#endif
#include "SDL_timer.h"
#include "SDL_audio.h"
#include "../SDL_audio_c.h"
#include "../SDL_audiodev_c.h"
#include "SDL_dmaaudio.h"
/* The tag name used by DMA audio */
#define DMA_DRIVER_NAME "dma"
/* Open the audio device for playback, and don't block if busy */
#define OPEN_FLAGS (O_RDWR|O_NONBLOCK)
/* Audio driver functions */
static int DMA_OpenAudio(_THIS, SDL_AudioSpec *spec);
static void DMA_WaitAudio(_THIS);
static void DMA_PlayAudio(_THIS);
static Uint8 *DMA_GetAudioBuf(_THIS);
static void DMA_CloseAudio(_THIS);
/* Audio driver bootstrap functions */
static int Audio_Available(void)
{
int available;
int fd;
available = 0;
fd = SDL_OpenAudioPath(NULL, 0, OPEN_FLAGS, 0);
if ( fd >= 0 ) {
int caps;
struct audio_buf_info info;
if ( (ioctl(fd, SNDCTL_DSP_GETCAPS, &caps) == 0) &&
(caps & DSP_CAP_TRIGGER) && (caps & DSP_CAP_MMAP) &&
(ioctl(fd, SNDCTL_DSP_GETOSPACE, &info) == 0) ) {
available = 1;
}
close(fd);
}
return(available);
}
static void Audio_DeleteDevice(SDL_AudioDevice *device)
{
SDL_free(device->hidden);
SDL_free(device);
}
static SDL_AudioDevice *Audio_CreateDevice(int devindex)
{
SDL_AudioDevice *this;
/* Initialize all variables that we clean on shutdown */
this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
if ( this ) {
SDL_memset(this, 0, (sizeof *this));
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
}
if ( (this == NULL) || (this->hidden == NULL) ) {
SDL_OutOfMemory();
if ( this ) {
SDL_free(this);
}
return(0);
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
audio_fd = -1;
/* Set the function pointers */
this->OpenAudio = DMA_OpenAudio;
this->WaitAudio = DMA_WaitAudio;
this->PlayAudio = DMA_PlayAudio;
this->GetAudioBuf = DMA_GetAudioBuf;
this->CloseAudio = DMA_CloseAudio;
this->free = Audio_DeleteDevice;
return this;
}
AudioBootStrap DMA_bootstrap = {
DMA_DRIVER_NAME, "OSS /dev/dsp DMA audio",
Audio_Available, Audio_CreateDevice
};
/* This function waits until it is possible to write a full sound buffer */
static void DMA_WaitAudio(_THIS)
{
fd_set fdset;
/* Check to see if the thread-parent process is still alive */
{ static int cnt = 0;
/* Note that this only works with thread implementations
that use a different process id for each thread.
*/
if (parent && (((++cnt)%10) == 0)) { /* Check every 10 loops */
if ( kill(parent, 0) < 0 ) {
this->enabled = 0;
}
}
}
/* See if we need to use timed audio synchronization */
if ( frame_ticks ) {
/* Use timer for general audio synchronization */
Sint32 ticks;
ticks = ((Sint32)(next_frame - SDL_GetTicks()))-FUDGE_TICKS;
if ( ticks > 0 ) {
SDL_Delay(ticks);
}
} else {
/* Use select() for audio synchronization */
struct timeval timeout;
FD_ZERO(&fdset);
FD_SET(audio_fd, &fdset);
timeout.tv_sec = 10;
timeout.tv_usec = 0;
#ifdef DEBUG_AUDIO
fprintf(stderr, "Waiting for audio to get ready\n");
#endif
if ( select(audio_fd+1, NULL, &fdset, NULL, &timeout) <= 0 ) {
const char *message =
#ifdef AUDIO_OSPACE_HACK
"Audio timeout - buggy audio driver? (trying ospace)";
#else
"Audio timeout - buggy audio driver? (disabled)";
#endif
/* In general we should never print to the screen,
but in this case we have no other way of letting
the user know what happened.
*/
fprintf(stderr, "SDL: %s\n", message);
#ifdef AUDIO_OSPACE_HACK
/* We may be able to use GET_OSPACE trick */
frame_ticks = (float)(this->spec->samples*1000) /
this->spec->freq;
next_frame = SDL_GetTicks()+frame_ticks;
#else
this->enabled = 0;
/* Don't try to close - may hang */
audio_fd = -1;
#ifdef DEBUG_AUDIO
fprintf(stderr, "Done disabling audio\n");
#endif
#endif /* AUDIO_OSPACE_HACK */
}
#ifdef DEBUG_AUDIO
fprintf(stderr, "Ready!\n");
#endif
}
}
static void DMA_PlayAudio(_THIS)
{
/* If timer synchronization is enabled, set the next write frame */
if ( frame_ticks ) {
next_frame += frame_ticks;
}
return;
}
static Uint8 *DMA_GetAudioBuf(_THIS)
{
count_info info;
int playing;
int filling;
/* Get number of blocks, looping if we're not using select() */
do {
if ( ioctl(audio_fd, SNDCTL_DSP_GETOPTR, &info) < 0 ) {
/* Uh oh... */
this->enabled = 0;
return(NULL);
}
} while ( frame_ticks && (info.blocks < 1) );
#ifdef DEBUG_AUDIO
if ( info.blocks > 1 ) {
printf("Warning: audio underflow (%d frags)\n", info.blocks-1);
}
#endif
playing = info.ptr / this->spec.size;
filling = (playing + 1)%num_buffers;
return (dma_buf + (filling * this->spec.size));
}
static void DMA_CloseAudio(_THIS)
{
if ( dma_buf != NULL ) {
munmap(dma_buf, dma_len);
dma_buf = NULL;
}
if ( audio_fd >= 0 ) {
close(audio_fd);
audio_fd = -1;
}
}
static int DMA_ReopenAudio(_THIS, const char *audiodev, int format, int stereo,
SDL_AudioSpec *spec)
{
int frag_spec;
int value;
/* Close and then reopen the audio device */
close(audio_fd);
audio_fd = open(audiodev, O_RDWR, 0);
if ( audio_fd < 0 ) {
SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno));
return(-1);
}
/* Calculate the final parameters for this audio specification */
SDL_CalculateAudioSpec(spec);
/* Determine the power of two of the fragment size */
for ( frag_spec = 0; (0x01<<frag_spec) < spec->size; ++frag_spec );
if ( (0x01<<frag_spec) != spec->size ) {
SDL_SetError("Fragment size must be a power of two");
return(-1);
}
/* Set the audio buffering parameters */
if ( ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &frag_spec) < 0 ) {
SDL_SetError("Couldn't set audio fragment spec");
return(-1);
}
/* Set the audio format */
value = format;
if ( (ioctl(audio_fd, SNDCTL_DSP_SETFMT, &value) < 0) ||
(value != format) ) {
SDL_SetError("Couldn't set audio format");
return(-1);
}
/* Set mono or stereo audio */
value = (spec->channels > 1);
if ( (ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo) < 0) ||
(value != stereo) ) {
SDL_SetError("Couldn't set audio channels");
return(-1);
}
/* Set the DSP frequency */
value = spec->freq;
if ( ioctl(audio_fd, SNDCTL_DSP_SPEED, &value) < 0 ) {
SDL_SetError("Couldn't set audio frequency");
return(-1);
}
spec->freq = value;
/* We successfully re-opened the audio */
return(0);
}
static int DMA_OpenAudio(_THIS, SDL_AudioSpec *spec)
{
char audiodev[1024];
int format;
int stereo;
int value;
Uint16 test_format;
struct audio_buf_info info;
/* Reset the timer synchronization flag */
frame_ticks = 0.0;
/* Open the audio device */
audio_fd = SDL_OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 0);
if ( audio_fd < 0 ) {
SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno));
return(-1);
}
dma_buf = NULL;
ioctl(audio_fd, SNDCTL_DSP_RESET, 0);
/* Get a list of supported hardware formats */
if ( ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &value) < 0 ) {
SDL_SetError("Couldn't get audio format list");
return(-1);
}
/* Try for a closest match on audio format */
format = 0;
for ( test_format = SDL_FirstAudioFormat(spec->format);
! format && test_format; ) {
#ifdef DEBUG_AUDIO
fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
#endif
switch ( test_format ) {
case AUDIO_U8:
if ( value & AFMT_U8 ) {
format = AFMT_U8;
}
break;
case AUDIO_S8:
if ( value & AFMT_S8 ) {
format = AFMT_S8;
}
break;
case AUDIO_S16LSB:
if ( value & AFMT_S16_LE ) {
format = AFMT_S16_LE;
}
break;
case AUDIO_S16MSB:
if ( value & AFMT_S16_BE ) {
format = AFMT_S16_BE;
}
break;
case AUDIO_U16LSB:
if ( value & AFMT_U16_LE ) {
format = AFMT_U16_LE;
}
break;
case AUDIO_U16MSB:
if ( value & AFMT_U16_BE ) {
format = AFMT_U16_BE;
}
break;
default:
format = 0;
break;
}
if ( ! format ) {
test_format = SDL_NextAudioFormat();
}
}
if ( format == 0 ) {
SDL_SetError("Couldn't find any hardware audio formats");
return(-1);
}
spec->format = test_format;
/* Set the audio format */
value = format;
if ( (ioctl(audio_fd, SNDCTL_DSP_SETFMT, &value) < 0) ||
(value != format) ) {
SDL_SetError("Couldn't set audio format");
return(-1);
}
/* Set mono or stereo audio (currently only two channels supported) */
stereo = (spec->channels > 1);
ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo);
if ( stereo ) {
spec->channels = 2;
} else {
spec->channels = 1;
}
/* Because some drivers don't allow setting the buffer size
after setting the format, we must re-open the audio device
once we know what format and channels are supported
*/
if ( DMA_ReopenAudio(this, audiodev, format, stereo, spec) < 0 ) {
/* Error is set by DMA_ReopenAudio() */
return(-1);
}
/* Memory map the audio buffer */
if ( ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &info) < 0 ) {
SDL_SetError("Couldn't get OSPACE parameters");
return(-1);
}
spec->size = info.fragsize;
spec->samples = spec->size / ((spec->format & 0xFF) / 8);
spec->samples /= spec->channels;
num_buffers = info.fragstotal;
dma_len = num_buffers*spec->size;
dma_buf = (Uint8 *)mmap(NULL, dma_len, PROT_WRITE, MAP_SHARED,
audio_fd, 0);
if ( dma_buf == MAP_FAILED ) {
SDL_SetError("DMA memory map failed");
dma_buf = NULL;
return(-1);
}
SDL_memset(dma_buf, spec->silence, dma_len);
/* Check to see if we need to use select() workaround */
{ char *workaround;
workaround = SDL_getenv("SDL_DSP_NOSELECT");
if ( workaround ) {
frame_ticks = (float)(spec->samples*1000)/spec->freq;
next_frame = SDL_GetTicks()+frame_ticks;
}
}
/* Trigger audio playback */
value = 0;
ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &value);
value = PCM_ENABLE_OUTPUT;
if ( ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &value) < 0 ) {
SDL_SetError("Couldn't trigger audio output");
return(-1);
}
/* Get the parent process id (we're the parent of the audio thread) */
parent = getpid();
/* We're ready to rock and roll. :-) */
return(0);
}

View file

@ -1,59 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
#ifndef _SDL_dspaudio_h
#define _SDL_dspaudio_h
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the video functions */
#define _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData {
/* The file descriptor for the audio device */
int audio_fd;
/* The parent process id, to detect when application quits */
pid_t parent;
/* Raw mixing buffer */
Uint8 *dma_buf;
int dma_len;
int num_buffers;
/* Support for audio timing using a timer, in addition to select() */
float frame_ticks;
float next_frame;
};
#define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */
/* Old variable names */
#define audio_fd (this->hidden->audio_fd)
#define parent (this->hidden->parent)
#define dma_buf (this->hidden->dma_buf)
#define dma_len (this->hidden->dma_len)
#define num_buffers (this->hidden->num_buffers)
#define frame_ticks (this->hidden->frame_ticks)
#define next_frame (this->hidden->next_frame)
#endif /* _SDL_dspaudio_h */

View file

@ -1,242 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
/* Allow access to a raw mixing buffer (For IRIX 6.5 and higher) */
/* patch for IRIX 5 by Georg Schwarz 18/07/2004 */
#include "SDL_timer.h"
#include "SDL_audio.h"
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
#include "SDL_irixaudio.h"
#ifndef AL_RESOURCE /* as a test whether we use the old IRIX audio libraries */
#define OLD_IRIX_AUDIO
#define alClosePort(x) ALcloseport(x)
#define alFreeConfig(x) ALfreeconfig(x)
#define alGetFillable(x) ALgetfillable(x)
#define alNewConfig() ALnewconfig()
#define alOpenPort(x,y,z) ALopenport(x,y,z)
#define alSetChannels(x,y) ALsetchannels(x,y)
#define alSetQueueSize(x,y) ALsetqueuesize(x,y)
#define alSetSampFmt(x,y) ALsetsampfmt(x,y)
#define alSetWidth(x,y) ALsetwidth(x,y)
#endif
/* Audio driver functions */
static int AL_OpenAudio(_THIS, SDL_AudioSpec *spec);
static void AL_WaitAudio(_THIS);
static void AL_PlayAudio(_THIS);
static Uint8 *AL_GetAudioBuf(_THIS);
static void AL_CloseAudio(_THIS);
/* Audio driver bootstrap functions */
static int Audio_Available(void)
{
return 1;
}
static void Audio_DeleteDevice(SDL_AudioDevice *device)
{
SDL_free(device->hidden);
SDL_free(device);
}
static SDL_AudioDevice *Audio_CreateDevice(int devindex)
{
SDL_AudioDevice *this;
/* Initialize all variables that we clean on shutdown */
this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
if ( this ) {
SDL_memset(this, 0, (sizeof *this));
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
}
if ( (this == NULL) || (this->hidden == NULL) ) {
SDL_OutOfMemory();
if ( this ) {
SDL_free(this);
}
return(0);
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
/* Set the function pointers */
this->OpenAudio = AL_OpenAudio;
this->WaitAudio = AL_WaitAudio;
this->PlayAudio = AL_PlayAudio;
this->GetAudioBuf = AL_GetAudioBuf;
this->CloseAudio = AL_CloseAudio;
this->free = Audio_DeleteDevice;
return this;
}
AudioBootStrap DMEDIA_bootstrap = {
"AL", "IRIX DMedia audio",
Audio_Available, Audio_CreateDevice
};
void static AL_WaitAudio(_THIS)
{
Sint32 timeleft;
timeleft = this->spec.samples - alGetFillable(audio_port);
if ( timeleft > 0 ) {
timeleft /= (this->spec.freq/1000);
SDL_Delay((Uint32)timeleft);
}
}
static void AL_PlayAudio(_THIS)
{
/* Write the audio data out */
if ( alWriteFrames(audio_port, mixbuf, this->spec.samples) < 0 ) {
/* Assume fatal error, for now */
this->enabled = 0;
}
}
static Uint8 *AL_GetAudioBuf(_THIS)
{
return(mixbuf);
}
static void AL_CloseAudio(_THIS)
{
if ( mixbuf != NULL ) {
SDL_FreeAudioMem(mixbuf);
mixbuf = NULL;
}
if ( audio_port != NULL ) {
alClosePort(audio_port);
audio_port = NULL;
}
}
static int AL_OpenAudio(_THIS, SDL_AudioSpec * spec)
{
Uint16 test_format = SDL_FirstAudioFormat(spec->format);
long width = 0;
long fmt = 0;
int valid = 0;
#ifdef OLD_IRIX_AUDIO
{
long audio_param[2];
audio_param[0] = AL_OUTPUT_RATE;
audio_param[1] = spec->freq;
valid = (ALsetparams(AL_DEFAULT_DEVICE, audio_param, 2) < 0);
}
#else
{
ALpv audio_param;
audio_param.param = AL_RATE;
audio_param.value.i = spec->freq;
valid = (alSetParams(AL_DEFAULT_OUTPUT, &audio_param, 1) < 0);
}
#endif
while ((!valid) && (test_format)) {
valid = 1;
spec->format = test_format;
switch (test_format) {
case AUDIO_S8:
width = AL_SAMPLE_8;
fmt = AL_SAMPFMT_TWOSCOMP;
break;
case AUDIO_S16SYS:
width = AL_SAMPLE_16;
fmt = AL_SAMPFMT_TWOSCOMP;
break;
default:
valid = 0;
test_format = SDL_NextAudioFormat();
break;
}
if (valid) {
ALconfig audio_config = alNewConfig();
valid = 0;
if (audio_config) {
if (alSetChannels(audio_config, spec->channels) < 0) {
if (spec->channels > 2) { /* can't handle > stereo? */
spec->channels = 2; /* try again below. */
}
}
if ((alSetSampFmt(audio_config, fmt) >= 0) &&
((!width) || (alSetWidth(audio_config, width) >= 0)) &&
(alSetQueueSize(audio_config, spec->samples * 2) >= 0) &&
(alSetChannels(audio_config, spec->channels) >= 0)) {
audio_port = alOpenPort("SDL audio", "w", audio_config);
if (audio_port == NULL) {
/* docs say AL_BAD_CHANNELS happens here, too. */
int err = oserror();
if (err == AL_BAD_CHANNELS) {
spec->channels = 2;
alSetChannels(audio_config, spec->channels);
audio_port = alOpenPort("SDL audio", "w",
audio_config);
}
}
if (audio_port != NULL) {
valid = 1;
}
}
alFreeConfig(audio_config);
}
}
}
if (!valid) {
SDL_SetError("Unsupported audio format");
return (-1);
}
/* Update the fragment size as size in bytes */
SDL_CalculateAudioSpec(spec);
/* Allocate mixing buffer */
mixbuf = (Uint8 *) SDL_AllocAudioMem(spec->size);
if (mixbuf == NULL) {
SDL_OutOfMemory();
return (-1);
}
SDL_memset(mixbuf, spec->silence, spec->size);
/* We're ready to rock and roll. :-) */
return (0);
}

View file

@ -1,45 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
#ifndef _SDL_lowaudio_h
#define _SDL_lowaudio_h
#include <dmedia/audio.h>
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the audio functions */
#define _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData {
/* The handle for the audio device */
ALport audio_port;
Uint8 *mixbuf; /* The app mixing buffer */
};
/* Old variable names */
#define audio_port (this->hidden->audio_port)
#define mixbuf (this->hidden->mixbuf)
#endif /* _SDL_lowaudio_h */

View file

@ -1,340 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
Modified in Oct 2004 by Hannu Savolainen
hannu@opensound.com
*/
#include "SDL_config.h"
/* Allow access to a raw mixing buffer */
#include <stdio.h> /* For perror() */
#include <string.h> /* For strerror() */
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#if SDL_AUDIO_DRIVER_OSS_SOUNDCARD_H
/* This is installed on some systems */
#include <soundcard.h>
#else
/* This is recommended by OSS */
#include <sys/soundcard.h>
#endif
#include "SDL_timer.h"
#include "SDL_audio.h"
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
#include "../SDL_audiodev_c.h"
#include "SDL_dspaudio.h"
/* The tag name used by DSP audio */
#define DSP_DRIVER_NAME "dsp"
/* Open the audio device for playback, and don't block if busy */
#define OPEN_FLAGS (O_WRONLY|O_NONBLOCK)
/* Audio driver functions */
static int DSP_OpenAudio(_THIS, SDL_AudioSpec *spec);
static void DSP_WaitAudio(_THIS);
static void DSP_PlayAudio(_THIS);
static Uint8 *DSP_GetAudioBuf(_THIS);
static void DSP_CloseAudio(_THIS);
/* Audio driver bootstrap functions */
static int Audio_Available(void)
{
int fd;
int available;
available = 0;
fd = SDL_OpenAudioPath(NULL, 0, OPEN_FLAGS, 0);
if ( fd >= 0 ) {
available = 1;
close(fd);
}
return(available);
}
static void Audio_DeleteDevice(SDL_AudioDevice *device)
{
SDL_free(device->hidden);
SDL_free(device);
}
static SDL_AudioDevice *Audio_CreateDevice(int devindex)
{
SDL_AudioDevice *this;
/* Initialize all variables that we clean on shutdown */
this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
if ( this ) {
SDL_memset(this, 0, (sizeof *this));
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
}
if ( (this == NULL) || (this->hidden == NULL) ) {
SDL_OutOfMemory();
if ( this ) {
SDL_free(this);
}
return(0);
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
audio_fd = -1;
/* Set the function pointers */
this->OpenAudio = DSP_OpenAudio;
this->WaitAudio = DSP_WaitAudio;
this->PlayAudio = DSP_PlayAudio;
this->GetAudioBuf = DSP_GetAudioBuf;
this->CloseAudio = DSP_CloseAudio;
this->free = Audio_DeleteDevice;
return this;
}
AudioBootStrap DSP_bootstrap = {
DSP_DRIVER_NAME, "OSS /dev/dsp standard audio",
Audio_Available, Audio_CreateDevice
};
/* This function waits until it is possible to write a full sound buffer */
static void DSP_WaitAudio(_THIS)
{
/* Not needed at all since OSS handles waiting automagically */
}
static void DSP_PlayAudio(_THIS)
{
if (write(audio_fd, mixbuf, mixlen)==-1)
{
perror("Audio write");
this->enabled = 0;
}
#ifdef DEBUG_AUDIO
fprintf(stderr, "Wrote %d bytes of audio data\n", mixlen);
#endif
}
static Uint8 *DSP_GetAudioBuf(_THIS)
{
return(mixbuf);
}
static void DSP_CloseAudio(_THIS)
{
if ( mixbuf != NULL ) {
SDL_FreeAudioMem(mixbuf);
mixbuf = NULL;
}
if ( audio_fd >= 0 ) {
close(audio_fd);
audio_fd = -1;
}
}
static int DSP_OpenAudio(_THIS, SDL_AudioSpec *spec)
{
char audiodev[1024];
int format;
int value;
int frag_spec;
Uint16 test_format;
/* Make sure fragment size stays a power of 2, or OSS fails. */
/* I don't know which of these are actually legal values, though... */
if (spec->channels > 8)
spec->channels = 8;
else if (spec->channels > 4)
spec->channels = 4;
else if (spec->channels > 2)
spec->channels = 2;
/* Open the audio device */
audio_fd = SDL_OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 0);
if ( audio_fd < 0 ) {
SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno));
return(-1);
}
mixbuf = NULL;
/* Make the file descriptor use blocking writes with fcntl() */
{ long flags;
flags = fcntl(audio_fd, F_GETFL);
flags &= ~O_NONBLOCK;
if ( fcntl(audio_fd, F_SETFL, flags) < 0 ) {
SDL_SetError("Couldn't set audio blocking mode");
DSP_CloseAudio(this);
return(-1);
}
}
/* Get a list of supported hardware formats */
if ( ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &value) < 0 ) {
perror("SNDCTL_DSP_GETFMTS");
SDL_SetError("Couldn't get audio format list");
DSP_CloseAudio(this);
return(-1);
}
/* Try for a closest match on audio format */
format = 0;
for ( test_format = SDL_FirstAudioFormat(spec->format);
! format && test_format; ) {
#ifdef DEBUG_AUDIO
fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
#endif
switch ( test_format ) {
case AUDIO_U8:
if ( value & AFMT_U8 ) {
format = AFMT_U8;
}
break;
case AUDIO_S16LSB:
if ( value & AFMT_S16_LE ) {
format = AFMT_S16_LE;
}
break;
case AUDIO_S16MSB:
if ( value & AFMT_S16_BE ) {
format = AFMT_S16_BE;
}
break;
#if 0
/*
* These formats are not used by any real life systems so they are not
* needed here.
*/
case AUDIO_S8:
if ( value & AFMT_S8 ) {
format = AFMT_S8;
}
break;
case AUDIO_U16LSB:
if ( value & AFMT_U16_LE ) {
format = AFMT_U16_LE;
}
break;
case AUDIO_U16MSB:
if ( value & AFMT_U16_BE ) {
format = AFMT_U16_BE;
}
break;
#endif
default:
format = 0;
break;
}
if ( ! format ) {
test_format = SDL_NextAudioFormat();
}
}
if ( format == 0 ) {
SDL_SetError("Couldn't find any hardware audio formats");
DSP_CloseAudio(this);
return(-1);
}
spec->format = test_format;
/* Set the audio format */
value = format;
if ( (ioctl(audio_fd, SNDCTL_DSP_SETFMT, &value) < 0) ||
(value != format) ) {
perror("SNDCTL_DSP_SETFMT");
SDL_SetError("Couldn't set audio format");
DSP_CloseAudio(this);
return(-1);
}
/* Set the number of channels of output */
value = spec->channels;
if ( ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &value) < 0 ) {
perror("SNDCTL_DSP_CHANNELS");
SDL_SetError("Cannot set the number of channels");
DSP_CloseAudio(this);
return(-1);
}
spec->channels = value;
/* Set the DSP frequency */
value = spec->freq;
if ( ioctl(audio_fd, SNDCTL_DSP_SPEED, &value) < 0 ) {
perror("SNDCTL_DSP_SPEED");
SDL_SetError("Couldn't set audio frequency");
DSP_CloseAudio(this);
return(-1);
}
spec->freq = value;
/* Calculate the final parameters for this audio specification */
SDL_CalculateAudioSpec(spec);
/* Determine the power of two of the fragment size */
for ( frag_spec = 0; (0x01U<<frag_spec) < spec->size; ++frag_spec );
if ( (0x01U<<frag_spec) != spec->size ) {
SDL_SetError("Fragment size must be a power of two");
DSP_CloseAudio(this);
return(-1);
}
frag_spec |= 0x00020000; /* two fragments, for low latency */
/* Set the audio buffering parameters */
#ifdef DEBUG_AUDIO
fprintf(stderr, "Requesting %d fragments of size %d\n",
(frag_spec >> 16), 1<<(frag_spec&0xFFFF));
#endif
if ( ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &frag_spec) < 0 ) {
perror("SNDCTL_DSP_SETFRAGMENT");
}
#ifdef DEBUG_AUDIO
{ audio_buf_info info;
ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &info);
fprintf(stderr, "fragments = %d\n", info.fragments);
fprintf(stderr, "fragstotal = %d\n", info.fragstotal);
fprintf(stderr, "fragsize = %d\n", info.fragsize);
fprintf(stderr, "bytes = %d\n", info.bytes);
}
#endif
/* Allocate mixing buffer */
mixlen = spec->size;
mixbuf = (Uint8 *)SDL_AllocAudioMem(mixlen);
if ( mixbuf == NULL ) {
DSP_CloseAudio(this);
return(-1);
}
SDL_memset(mixbuf, spec->silence, spec->size);
/* Get the parent process id (we're the parent of the audio thread) */
parent = getpid();
/* We're ready to rock and roll. :-) */
return(0);
}

View file

@ -1,53 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
#ifndef _SDL_dspaudio_h
#define _SDL_dspaudio_h
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the video functions */
#define _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData {
/* The file descriptor for the audio device */
int audio_fd;
/* The parent process id, to detect when application quits */
pid_t parent;
/* Raw mixing buffer */
Uint8 *mixbuf;
int mixlen;
};
#define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */
/* Old variable names */
#define audio_fd (this->hidden->audio_fd)
#define parent (this->hidden->parent)
#define mixbuf (this->hidden->mixbuf)
#define mixlen (this->hidden->mixlen)
#define frame_ticks (this->hidden->frame_ticks)
#define next_frame (this->hidden->next_frame)
#endif /* _SDL_dspaudio_h */

View file

@ -1,323 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
/* Allow access to an ESD network stream mixing buffer */
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <esd.h>
#include "SDL_timer.h"
#include "SDL_audio.h"
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
#include "../SDL_audiodev_c.h"
#include "SDL_esdaudio.h"
#ifdef SDL_AUDIO_DRIVER_ESD_DYNAMIC
#include "SDL_name.h"
#include "SDL_loadso.h"
#else
#define SDL_NAME(X) X
#endif
/* The tag name used by ESD audio */
#define ESD_DRIVER_NAME "esd"
/* Audio driver functions */
static int ESD_OpenAudio(_THIS, SDL_AudioSpec *spec);
static void ESD_WaitAudio(_THIS);
static void ESD_PlayAudio(_THIS);
static Uint8 *ESD_GetAudioBuf(_THIS);
static void ESD_CloseAudio(_THIS);
#ifdef SDL_AUDIO_DRIVER_ESD_DYNAMIC
static const char *esd_library = SDL_AUDIO_DRIVER_ESD_DYNAMIC;
static void *esd_handle = NULL;
static int esd_loaded = 0;
static int (*SDL_NAME(esd_open_sound))( const char *host );
static int (*SDL_NAME(esd_close))( int esd );
static int (*SDL_NAME(esd_play_stream))( esd_format_t format, int rate,
const char *host, const char *name );
static struct {
const char *name;
void **func;
} esd_functions[] = {
{ "esd_open_sound", (void **)&SDL_NAME(esd_open_sound) },
{ "esd_close", (void **)&SDL_NAME(esd_close) },
{ "esd_play_stream", (void **)&SDL_NAME(esd_play_stream) },
};
static void UnloadESDLibrary()
{
if ( esd_loaded ) {
SDL_UnloadObject(esd_handle);
esd_handle = NULL;
esd_loaded = 0;
}
}
static int LoadESDLibrary(void)
{
int i, retval = -1;
esd_handle = SDL_LoadObject(esd_library);
if ( esd_handle ) {
esd_loaded = 1;
retval = 0;
for ( i=0; i<SDL_arraysize(esd_functions); ++i ) {
*esd_functions[i].func = SDL_LoadFunction(esd_handle, esd_functions[i].name);
if ( !*esd_functions[i].func ) {
retval = -1;
UnloadESDLibrary();
break;
}
}
}
return retval;
}
#else
static void UnloadESDLibrary()
{
return;
}
static int LoadESDLibrary(void)
{
return 0;
}
#endif /* SDL_AUDIO_DRIVER_ESD_DYNAMIC */
/* Audio driver bootstrap functions */
static int Audio_Available(void)
{
int connection;
int available;
available = 0;
if ( LoadESDLibrary() < 0 ) {
return available;
}
connection = SDL_NAME(esd_open_sound)(NULL);
if ( connection >= 0 ) {
available = 1;
SDL_NAME(esd_close)(connection);
}
UnloadESDLibrary();
return(available);
}
static void Audio_DeleteDevice(SDL_AudioDevice *device)
{
SDL_free(device->hidden);
SDL_free(device);
UnloadESDLibrary();
}
static SDL_AudioDevice *Audio_CreateDevice(int devindex)
{
SDL_AudioDevice *this;
/* Initialize all variables that we clean on shutdown */
LoadESDLibrary();
this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
if ( this ) {
SDL_memset(this, 0, (sizeof *this));
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
}
if ( (this == NULL) || (this->hidden == NULL) ) {
SDL_OutOfMemory();
if ( this ) {
SDL_free(this);
}
return(0);
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
audio_fd = -1;
/* Set the function pointers */
this->OpenAudio = ESD_OpenAudio;
this->WaitAudio = ESD_WaitAudio;
this->PlayAudio = ESD_PlayAudio;
this->GetAudioBuf = ESD_GetAudioBuf;
this->CloseAudio = ESD_CloseAudio;
this->free = Audio_DeleteDevice;
return this;
}
AudioBootStrap ESD_bootstrap = {
ESD_DRIVER_NAME, "Enlightened Sound Daemon",
Audio_Available, Audio_CreateDevice
};
/* This function waits until it is possible to write a full sound buffer */
static void ESD_WaitAudio(_THIS)
{
Sint32 ticks;
/* Check to see if the thread-parent process is still alive */
{ static int cnt = 0;
/* Note that this only works with thread implementations
that use a different process id for each thread.
*/
if (parent && (((++cnt)%10) == 0)) { /* Check every 10 loops */
if ( kill(parent, 0) < 0 ) {
this->enabled = 0;
}
}
}
/* Use timer for general audio synchronization */
ticks = ((Sint32)(next_frame - SDL_GetTicks()))-FUDGE_TICKS;
if ( ticks > 0 ) {
SDL_Delay(ticks);
}
}
static void ESD_PlayAudio(_THIS)
{
int written;
/* Write the audio data, checking for EAGAIN on broken audio drivers */
do {
written = write(audio_fd, mixbuf, mixlen);
if ( (written < 0) && ((errno == 0) || (errno == EAGAIN)) ) {
SDL_Delay(1); /* Let a little CPU time go by */
}
} while ( (written < 0) &&
((errno == 0) || (errno == EAGAIN) || (errno == EINTR)) );
/* Set the next write frame */
next_frame += frame_ticks;
/* If we couldn't write, assume fatal error for now */
if ( written < 0 ) {
this->enabled = 0;
}
}
static Uint8 *ESD_GetAudioBuf(_THIS)
{
return(mixbuf);
}
static void ESD_CloseAudio(_THIS)
{
if ( mixbuf != NULL ) {
SDL_FreeAudioMem(mixbuf);
mixbuf = NULL;
}
if ( audio_fd >= 0 ) {
SDL_NAME(esd_close)(audio_fd);
audio_fd = -1;
}
}
/* Try to get the name of the program */
static char *get_progname(void)
{
char *progname = NULL;
#ifdef __LINUX__
FILE *fp;
static char temp[BUFSIZ];
SDL_snprintf(temp, SDL_arraysize(temp), "/proc/%d/cmdline", getpid());
fp = fopen(temp, "r");
if ( fp != NULL ) {
if ( fgets(temp, sizeof(temp)-1, fp) ) {
progname = SDL_strrchr(temp, '/');
if ( progname == NULL ) {
progname = temp;
} else {
progname = progname+1;
}
}
fclose(fp);
}
#endif
return(progname);
}
static int ESD_OpenAudio(_THIS, SDL_AudioSpec *spec)
{
esd_format_t format;
/* Convert audio spec to the ESD audio format */
format = (ESD_STREAM | ESD_PLAY);
switch ( spec->format & 0xFF ) {
case 8:
format |= ESD_BITS8;
break;
case 16:
format |= ESD_BITS16;
break;
default:
SDL_SetError("Unsupported ESD audio format");
return(-1);
}
if ( spec->channels == 1 ) {
format |= ESD_MONO;
} else {
format |= ESD_STEREO;
}
#if 0
spec->samples = ESD_BUF_SIZE; /* Darn, no way to change this yet */
#endif
/* Open a connection to the ESD audio server */
audio_fd = SDL_NAME(esd_play_stream)(format, spec->freq, NULL, get_progname());
if ( audio_fd < 0 ) {
SDL_SetError("Couldn't open ESD connection");
return(-1);
}
/* Calculate the final parameters for this audio specification */
SDL_CalculateAudioSpec(spec);
frame_ticks = (float)(spec->samples*1000)/spec->freq;
next_frame = SDL_GetTicks()+frame_ticks;
/* Allocate mixing buffer */
mixlen = spec->size;
mixbuf = (Uint8 *)SDL_AllocAudioMem(mixlen);
if ( mixbuf == NULL ) {
return(-1);
}
SDL_memset(mixbuf, spec->silence, spec->size);
/* Get the parent process id (we're the parent of the audio thread) */
parent = getpid();
/* We're ready to rock and roll. :-) */
return(0);
}

View file

@ -1,57 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
#ifndef _SDL_esdaudio_h
#define _SDL_esdaudio_h
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the video functions */
#define _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData {
/* The file descriptor for the audio device */
int audio_fd;
/* The parent process id, to detect when application quits */
pid_t parent;
/* Raw mixing buffer */
Uint8 *mixbuf;
int mixlen;
/* Support for audio timing using a timer */
float frame_ticks;
float next_frame;
};
#define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */
/* Old variable names */
#define audio_fd (this->hidden->audio_fd)
#define parent (this->hidden->parent)
#define mixbuf (this->hidden->mixbuf)
#define mixlen (this->hidden->mixlen)
#define frame_ticks (this->hidden->frame_ticks)
#define next_frame (this->hidden->next_frame)
#endif /* _SDL_esdaudio_h */

View file

@ -1,291 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
#include <CoreAudio/CoreAudio.h>
#include <CoreServices/CoreServices.h>
#include <AudioUnit/AudioUnit.h>
#if MAC_OS_X_VERSION_MAX_ALLOWED <= 1050
#include <AudioUnit/AUNTComponent.h>
#endif
#include "SDL_audio.h"
#include "../SDL_audio_c.h"
#include "../SDL_sysaudio.h"
#include "SDL_coreaudio.h"
/* Audio driver functions */
static int Core_OpenAudio(_THIS, SDL_AudioSpec *spec);
static void Core_WaitAudio(_THIS);
static void Core_PlayAudio(_THIS);
static Uint8 *Core_GetAudioBuf(_THIS);
static void Core_CloseAudio(_THIS);
/* Audio driver bootstrap functions */
static int Audio_Available(void)
{
return(1);
}
static void Audio_DeleteDevice(SDL_AudioDevice *device)
{
SDL_free(device->hidden);
SDL_free(device);
}
static SDL_AudioDevice *Audio_CreateDevice(int devindex)
{
SDL_AudioDevice *this;
/* Initialize all variables that we clean on shutdown */
this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
if ( this ) {
SDL_memset(this, 0, (sizeof *this));
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
}
if ( (this == NULL) || (this->hidden == NULL) ) {
SDL_OutOfMemory();
if ( this ) {
SDL_free(this);
}
return(0);
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
/* Set the function pointers */
this->OpenAudio = Core_OpenAudio;
this->WaitAudio = Core_WaitAudio;
this->PlayAudio = Core_PlayAudio;
this->GetAudioBuf = Core_GetAudioBuf;
this->CloseAudio = Core_CloseAudio;
this->free = Audio_DeleteDevice;
return this;
}
AudioBootStrap COREAUDIO_bootstrap = {
"coreaudio", "Mac OS X CoreAudio",
Audio_Available, Audio_CreateDevice
};
/* The CoreAudio callback */
static OSStatus audioCallback (void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList *ioData)
{
SDL_AudioDevice *this = (SDL_AudioDevice *)inRefCon;
UInt32 remaining, len;
AudioBuffer *abuf;
void *ptr;
UInt32 i;
/* Only do anything if audio is enabled and not paused */
if ( ! this->enabled || this->paused ) {
for (i = 0; i < ioData->mNumberBuffers; i++) {
abuf = &ioData->mBuffers[i];
SDL_memset(abuf->mData, this->spec.silence, abuf->mDataByteSize);
}
return 0;
}
/* No SDL conversion should be needed here, ever, since we accept
any input format in OpenAudio, and leave the conversion to CoreAudio.
*/
/*
assert(!this->convert.needed);
assert(this->spec.channels == ioData->mNumberChannels);
*/
for (i = 0; i < ioData->mNumberBuffers; i++) {
abuf = &ioData->mBuffers[i];
remaining = abuf->mDataByteSize;
ptr = abuf->mData;
while (remaining > 0) {
if (bufferOffset >= bufferSize) {
/* Generate the data */
SDL_memset(buffer, this->spec.silence, bufferSize);
SDL_mutexP(this->mixer_lock);
(*this->spec.callback)(this->spec.userdata,
buffer, bufferSize);
SDL_mutexV(this->mixer_lock);
bufferOffset = 0;
}
len = bufferSize - bufferOffset;
if (len > remaining)
len = remaining;
SDL_memcpy(ptr, (char *)buffer + bufferOffset, len);
ptr = (char *)ptr + len;
remaining -= len;
bufferOffset += len;
}
}
return 0;
}
/* Dummy functions -- we don't use thread-based audio */
void Core_WaitAudio(_THIS)
{
return;
}
void Core_PlayAudio(_THIS)
{
return;
}
Uint8 *Core_GetAudioBuf(_THIS)
{
return(NULL);
}
void Core_CloseAudio(_THIS)
{
OSStatus result;
struct AURenderCallbackStruct callback;
/* stop processing the audio unit */
result = AudioOutputUnitStop (outputAudioUnit);
if (result != noErr) {
SDL_SetError("Core_CloseAudio: AudioOutputUnitStop");
return;
}
/* Remove the input callback */
callback.inputProc = 0;
callback.inputProcRefCon = 0;
result = AudioUnitSetProperty (outputAudioUnit,
kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Input,
0,
&callback,
sizeof(callback));
if (result != noErr) {
SDL_SetError("Core_CloseAudio: AudioUnitSetProperty (kAudioUnitProperty_SetInputCallback)");
return;
}
result = CloseComponent(outputAudioUnit);
if (result != noErr) {
SDL_SetError("Core_CloseAudio: CloseComponent");
return;
}
SDL_free(buffer);
}
#define CHECK_RESULT(msg) \
if (result != noErr) { \
SDL_SetError("Failed to start CoreAudio: " msg); \
return -1; \
}
int Core_OpenAudio(_THIS, SDL_AudioSpec *spec)
{
OSStatus result = noErr;
Component comp;
ComponentDescription desc;
struct AURenderCallbackStruct callback;
AudioStreamBasicDescription requestedDesc;
/* Setup a AudioStreamBasicDescription with the requested format */
requestedDesc.mFormatID = kAudioFormatLinearPCM;
requestedDesc.mFormatFlags = kLinearPCMFormatFlagIsPacked;
requestedDesc.mChannelsPerFrame = spec->channels;
requestedDesc.mSampleRate = spec->freq;
requestedDesc.mBitsPerChannel = spec->format & 0xFF;
if (spec->format & 0x8000)
requestedDesc.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
if (spec->format & 0x1000)
requestedDesc.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
requestedDesc.mFramesPerPacket = 1;
requestedDesc.mBytesPerFrame = requestedDesc.mBitsPerChannel * requestedDesc.mChannelsPerFrame / 8;
requestedDesc.mBytesPerPacket = requestedDesc.mBytesPerFrame * requestedDesc.mFramesPerPacket;
/* Locate the default output audio unit */
desc.componentType = kAudioUnitType_Output;
desc.componentSubType = kAudioUnitSubType_DefaultOutput;
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
desc.componentFlags = 0;
desc.componentFlagsMask = 0;
comp = FindNextComponent (NULL, &desc);
if (comp == NULL) {
SDL_SetError ("Failed to start CoreAudio: FindNextComponent returned NULL");
return -1;
}
/* Open & initialize the default output audio unit */
result = OpenAComponent (comp, &outputAudioUnit);
CHECK_RESULT("OpenAComponent")
result = AudioUnitInitialize (outputAudioUnit);
CHECK_RESULT("AudioUnitInitialize")
/* Set the input format of the audio unit. */
result = AudioUnitSetProperty (outputAudioUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
0,
&requestedDesc,
sizeof (requestedDesc));
CHECK_RESULT("AudioUnitSetProperty (kAudioUnitProperty_StreamFormat)")
/* Set the audio callback */
callback.inputProc = audioCallback;
callback.inputProcRefCon = this;
result = AudioUnitSetProperty (outputAudioUnit,
kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Input,
0,
&callback,
sizeof(callback));
CHECK_RESULT("AudioUnitSetProperty (kAudioUnitProperty_SetInputCallback)")
/* Calculate the final parameters for this audio specification */
SDL_CalculateAudioSpec(spec);
/* Allocate a sample buffer */
bufferOffset = bufferSize = this->spec.size;
buffer = SDL_malloc(bufferSize);
/* Finally, start processing of the audio unit */
result = AudioOutputUnitStart (outputAudioUnit);
CHECK_RESULT("AudioOutputUnitStart")
/* We're running! */
return(1);
}

View file

@ -1,45 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
#ifndef _SDL_coreaudio_h
#define _SDL_coreaudio_h
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the video functions */
#define _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData {
AudioUnit outputAudioUnit;
void *buffer;
UInt32 bufferOffset;
UInt32 bufferSize;
};
/* Old variable names */
#define outputAudioUnit (this->hidden->outputAudioUnit)
#define buffer (this->hidden->buffer)
#define bufferOffset (this->hidden->bufferOffset)
#define bufferSize (this->hidden->bufferSize)
#endif /* _SDL_coreaudio_h */

View file

@ -1,496 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
#if defined(__APPLE__) && defined(__MACH__)
# include <Carbon/Carbon.h>
#elif TARGET_API_MAC_CARBON && (UNIVERSAL_INTERFACES_VERSION > 0x0335)
# include <Carbon.h>
#else
# include <Sound.h> /* SoundManager interface */
# include <Gestalt.h>
# include <DriverServices.h>
#endif
#if !defined(NewSndCallBackUPP) && (UNIVERSAL_INTERFACES_VERSION < 0x0335)
#if !defined(NewSndCallBackProc) /* avoid circular redefinition... */
#define NewSndCallBackUPP NewSndCallBackProc
#endif
#if !defined(NewSndCallBackUPP)
#define NewSndCallBackUPP NewSndCallBackProc
#endif
#endif
#include "SDL_audio.h"
#include "../SDL_audio_c.h"
#include "../SDL_sysaudio.h"
#include "SDL_romaudio.h"
/* Audio driver functions */
static void Mac_CloseAudio(_THIS);
static int Mac_OpenAudio(_THIS, SDL_AudioSpec *spec);
static void Mac_LockAudio(_THIS);
static void Mac_UnlockAudio(_THIS);
/* Audio driver bootstrap functions */
static int Audio_Available(void)
{
return(1);
}
static void Audio_DeleteDevice(SDL_AudioDevice *device)
{
SDL_free(device->hidden);
SDL_free(device);
}
static SDL_AudioDevice *Audio_CreateDevice(int devindex)
{
SDL_AudioDevice *this;
/* Initialize all variables that we clean on shutdown */
this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
if ( this ) {
SDL_memset(this, 0, (sizeof *this));
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
}
if ( (this == NULL) || (this->hidden == NULL) ) {
SDL_OutOfMemory();
if ( this ) {
SDL_free(this);
}
return(0);
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
/* Set the function pointers */
this->OpenAudio = Mac_OpenAudio;
this->CloseAudio = Mac_CloseAudio;
this->LockAudio = Mac_LockAudio;
this->UnlockAudio = Mac_UnlockAudio;
this->free = Audio_DeleteDevice;
#ifdef __MACOSX__ /* Mac OS X uses threaded audio, so normal thread code is okay */
this->LockAudio = NULL;
this->UnlockAudio = NULL;
#endif
return this;
}
AudioBootStrap SNDMGR_bootstrap = {
"sndmgr", "MacOS SoundManager 3.0",
Audio_Available, Audio_CreateDevice
};
#if defined(TARGET_API_MAC_CARBON) || defined(USE_RYANS_SOUNDCODE)
/* This works correctly on Mac OS X */
#pragma options align=power
static volatile SInt32 audio_is_locked = 0;
static volatile SInt32 need_to_mix = 0;
static UInt8 *buffer[2];
static volatile UInt32 running = 0;
static CmpSoundHeader header;
static volatile Uint32 fill_me = 0;
static void mix_buffer(SDL_AudioDevice *audio, UInt8 *buffer)
{
if ( ! audio->paused ) {
#ifdef __MACOSX__
SDL_mutexP(audio->mixer_lock);
#endif
if ( audio->convert.needed ) {
audio->spec.callback(audio->spec.userdata,
(Uint8 *)audio->convert.buf,audio->convert.len);
SDL_ConvertAudio(&audio->convert);
if ( audio->convert.len_cvt != audio->spec.size ) {
/* Uh oh... probably crashes here */;
}
SDL_memcpy(buffer, audio->convert.buf, audio->convert.len_cvt);
} else {
audio->spec.callback(audio->spec.userdata, buffer, audio->spec.size);
}
#ifdef __MACOSX__
SDL_mutexV(audio->mixer_lock);
#endif
}
DecrementAtomic((SInt32 *) &need_to_mix);
}
static void Mac_LockAudio(_THIS)
{
IncrementAtomic((SInt32 *) &audio_is_locked);
}
static void Mac_UnlockAudio(_THIS)
{
SInt32 oldval;
oldval = DecrementAtomic((SInt32 *) &audio_is_locked);
if ( oldval != 1 ) /* != 1 means audio is still locked. */
return;
/* Did we miss the chance to mix in an interrupt? Do it now. */
if ( BitAndAtomic (0xFFFFFFFF, (UInt32 *) &need_to_mix) ) {
/*
* Note that this could be a problem if you missed an interrupt
* while the audio was locked, and get preempted by a second
* interrupt here, but that means you locked for way too long anyhow.
*/
mix_buffer (this, buffer[fill_me]);
}
}
static void callBackProc (SndChannel *chan, SndCommand *cmd_passed ) {
UInt32 play_me;
SndCommand cmd;
SDL_AudioDevice *audio = (SDL_AudioDevice *)chan->userInfo;
IncrementAtomic((SInt32 *) &need_to_mix);
fill_me = cmd_passed->param2; /* buffer that has just finished playing, so fill it */
play_me = ! fill_me; /* filled buffer to play _now_ */
if ( ! audio->enabled ) {
return;
}
/* queue previously mixed buffer for playback. */
header.samplePtr = (Ptr)buffer[play_me];
cmd.cmd = bufferCmd;
cmd.param1 = 0;
cmd.param2 = (long)&header;
SndDoCommand (chan, &cmd, 0);
memset (buffer[fill_me], 0, audio->spec.size);
/*
* if audio device isn't locked, mix the next buffer to be queued in
* the memory block that just finished playing.
*/
if ( ! BitAndAtomic(0xFFFFFFFF, (UInt32 *) &audio_is_locked) ) {
mix_buffer (audio, buffer[fill_me]);
}
/* set this callback to run again when current buffer drains. */
if ( running ) {
cmd.cmd = callBackCmd;
cmd.param1 = 0;
cmd.param2 = play_me;
SndDoCommand (chan, &cmd, 0);
}
}
static int Mac_OpenAudio(_THIS, SDL_AudioSpec *spec) {
SndCallBackUPP callback;
int sample_bits;
int i;
long initOptions;
/* Very few conversions are required, but... */
switch (spec->format) {
case AUDIO_S8:
spec->format = AUDIO_U8;
break;
case AUDIO_U16LSB:
spec->format = AUDIO_S16LSB;
break;
case AUDIO_U16MSB:
spec->format = AUDIO_S16MSB;
break;
}
SDL_CalculateAudioSpec(spec);
/* initialize bufferCmd header */
memset (&header, 0, sizeof(header));
callback = (SndCallBackUPP) NewSndCallBackUPP (callBackProc);
sample_bits = spec->size / spec->samples / spec->channels * 8;
#ifdef DEBUG_AUDIO
fprintf(stderr,
"Audio format 0x%x, channels = %d, sample_bits = %d, frequency = %d\n",
spec->format, spec->channels, sample_bits, spec->freq);
#endif /* DEBUG_AUDIO */
header.numChannels = spec->channels;
header.sampleSize = sample_bits;
header.sampleRate = spec->freq << 16;
header.numFrames = spec->samples;
header.encode = cmpSH;
/* Note that we install the 16bitLittleEndian Converter if needed. */
if ( spec->format == 0x8010 ) {
header.compressionID = fixedCompression;
header.format = k16BitLittleEndianFormat;
}
/* allocate 2 buffers */
for (i=0; i<2; i++) {
buffer[i] = (UInt8*)malloc (sizeof(UInt8) * spec->size);
if (buffer[i] == NULL) {
SDL_OutOfMemory();
return (-1);
}
memset (buffer[i], 0, spec->size);
}
/* Create the sound manager channel */
channel = (SndChannelPtr)SDL_malloc(sizeof(*channel));
if ( channel == NULL ) {
SDL_OutOfMemory();
return(-1);
}
if ( spec->channels >= 2 ) {
initOptions = initStereo;
} else {
initOptions = initMono;
}
channel->userInfo = (long)this;
channel->qLength = 128;
if ( SndNewChannel(&channel, sampledSynth, initOptions, callback) != noErr ) {
SDL_SetError("Unable to create audio channel");
SDL_free(channel);
channel = NULL;
return(-1);
}
/* start playback */
{
SndCommand cmd;
cmd.cmd = callBackCmd;
cmd.param2 = 0;
running = 1;
SndDoCommand (channel, &cmd, 0);
}
return 1;
}
static void Mac_CloseAudio(_THIS) {
int i;
running = 0;
if (channel) {
SndDisposeChannel (channel, true);
channel = NULL;
}
for ( i=0; i<2; ++i ) {
if ( buffer[i] ) {
SDL_free(buffer[i]);
buffer[i] = NULL;
}
}
}
#else /* !TARGET_API_MAC_CARBON && !USE_RYANS_SOUNDCODE */
static void Mac_LockAudio(_THIS)
{
/* no-op. */
}
static void Mac_UnlockAudio(_THIS)
{
/* no-op. */
}
/* This function is called by Sound Manager when it has exhausted one of
the buffers, so we'll zero it to silence and fill it with audio if
we're not paused.
*/
static pascal
void sndDoubleBackProc (SndChannelPtr chan, SndDoubleBufferPtr newbuf)
{
SDL_AudioDevice *audio = (SDL_AudioDevice *)newbuf->dbUserInfo[0];
/* If audio is quitting, don't do anything */
if ( ! audio->enabled ) {
return;
}
memset (newbuf->dbSoundData, 0, audio->spec.size);
newbuf->dbNumFrames = audio->spec.samples;
if ( ! audio->paused ) {
if ( audio->convert.needed ) {
audio->spec.callback(audio->spec.userdata,
(Uint8 *)audio->convert.buf,audio->convert.len);
SDL_ConvertAudio(&audio->convert);
#if 0
if ( audio->convert.len_cvt != audio->spec.size ) {
/* Uh oh... probably crashes here */;
}
#endif
SDL_memcpy(newbuf->dbSoundData, audio->convert.buf,
audio->convert.len_cvt);
} else {
audio->spec.callback(audio->spec.userdata,
(Uint8 *)newbuf->dbSoundData, audio->spec.size);
}
}
newbuf->dbFlags |= dbBufferReady;
}
static int DoubleBufferAudio_Available(void)
{
int available;
NumVersion sndversion;
long response;
available = 0;
sndversion = SndSoundManagerVersion();
if ( sndversion.majorRev >= 3 ) {
if ( Gestalt(gestaltSoundAttr, &response) == noErr ) {
if ( (response & (1 << gestaltSndPlayDoubleBuffer)) ) {
available = 1;
}
}
} else {
if ( Gestalt(gestaltSoundAttr, &response) == noErr ) {
if ( (response & (1 << gestaltHasASC)) ) {
available = 1;
}
}
}
return(available);
}
static void Mac_CloseAudio(_THIS)
{
int i;
if ( channel != NULL ) {
/* Clean up the audio channel */
SndDisposeChannel(channel, true);
channel = NULL;
}
for ( i=0; i<2; ++i ) {
if ( audio_buf[i] ) {
SDL_free(audio_buf[i]);
audio_buf[i] = NULL;
}
}
}
static int Mac_OpenAudio(_THIS, SDL_AudioSpec *spec)
{
SndDoubleBufferHeader2 audio_dbh;
int i;
long initOptions;
int sample_bits;
SndDoubleBackUPP doubleBackProc;
/* Check to make sure double-buffered audio is available */
if ( ! DoubleBufferAudio_Available() ) {
SDL_SetError("Sound manager doesn't support double-buffering");
return(-1);
}
/* Very few conversions are required, but... */
switch (spec->format) {
case AUDIO_S8:
spec->format = AUDIO_U8;
break;
case AUDIO_U16LSB:
spec->format = AUDIO_S16LSB;
break;
case AUDIO_U16MSB:
spec->format = AUDIO_S16MSB;
break;
}
SDL_CalculateAudioSpec(spec);
/* initialize the double-back header */
SDL_memset(&audio_dbh, 0, sizeof(audio_dbh));
doubleBackProc = NewSndDoubleBackProc (sndDoubleBackProc);
sample_bits = spec->size / spec->samples / spec->channels * 8;
audio_dbh.dbhNumChannels = spec->channels;
audio_dbh.dbhSampleSize = sample_bits;
audio_dbh.dbhCompressionID = 0;
audio_dbh.dbhPacketSize = 0;
audio_dbh.dbhSampleRate = spec->freq << 16;
audio_dbh.dbhDoubleBack = doubleBackProc;
audio_dbh.dbhFormat = 0;
/* Note that we install the 16bitLittleEndian Converter if needed. */
if ( spec->format == 0x8010 ) {
audio_dbh.dbhCompressionID = fixedCompression;
audio_dbh.dbhFormat = k16BitLittleEndianFormat;
}
/* allocate the 2 double-back buffers */
for ( i=0; i<2; ++i ) {
audio_buf[i] = SDL_calloc(1, sizeof(SndDoubleBuffer)+spec->size);
if ( audio_buf[i] == NULL ) {
SDL_OutOfMemory();
return(-1);
}
audio_buf[i]->dbNumFrames = spec->samples;
audio_buf[i]->dbFlags = dbBufferReady;
audio_buf[i]->dbUserInfo[0] = (long)this;
audio_dbh.dbhBufferPtr[i] = audio_buf[i];
}
/* Create the sound manager channel */
channel = (SndChannelPtr)SDL_malloc(sizeof(*channel));
if ( channel == NULL ) {
SDL_OutOfMemory();
return(-1);
}
if ( spec->channels >= 2 ) {
initOptions = initStereo;
} else {
initOptions = initMono;
}
channel->userInfo = 0;
channel->qLength = 128;
if ( SndNewChannel(&channel, sampledSynth, initOptions, 0L) != noErr ) {
SDL_SetError("Unable to create audio channel");
SDL_free(channel);
channel = NULL;
return(-1);
}
/* Start playback */
if ( SndPlayDoubleBuffer(channel, (SndDoubleBufferHeaderPtr)&audio_dbh)
!= noErr ) {
SDL_SetError("Unable to play double buffered audio");
return(-1);
}
return 1;
}
#endif /* TARGET_API_MAC_CARBON || USE_RYANS_SOUNDCODE */

View file

@ -1,50 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
#ifndef _SDL_romaudio_h
#define _SDL_romaudio_h
#include "../SDL_sysaudio.h"
/* This is Ryan's improved MacOS sound code, with locking support */
#define USE_RYANS_SOUNDCODE
/* Hidden "this" pointer for the video functions */
#define _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData {
/* Sound manager audio channel */
SndChannelPtr channel;
#if defined(TARGET_API_MAC_CARBON) || defined(USE_RYANS_SOUNDCODE)
/* FIXME: Add Ryan's static data here */
#else
/* Double buffering variables */
SndDoubleBufferPtr audio_buf[2];
#endif
};
/* Old variable names */
#define channel (this->hidden->channel)
#define audio_buf (this->hidden->audio_buf)
#endif /* _SDL_romaudio_h */

View file

@ -1,215 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
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 library 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
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
/*
Audio interrupt variables and callback function
Patrice Mandin
*/
#include <unistd.h>
#include <mint/osbind.h>
#include <mint/falcon.h>
#include <mint/mintbind.h>
#include <mint/cookie.h>
#include "SDL_audio.h"
#include "SDL_mintaudio.h"
#include "SDL_mintaudio_stfa.h"
/* The audio device */
SDL_AudioDevice *SDL_MintAudio_device;
Uint8 *SDL_MintAudio_audiobuf[2]; /* Pointers to buffers */
unsigned long SDL_MintAudio_audiosize; /* Length of audio buffer=spec->size */
volatile unsigned short SDL_MintAudio_numbuf; /* Buffer to play */
volatile unsigned short SDL_MintAudio_mutex;
volatile unsigned long SDL_MintAudio_clocktics;
cookie_stfa_t *SDL_MintAudio_stfa;
unsigned short SDL_MintAudio_hasfpu;
/* MiNT thread variables */
SDL_bool SDL_MintAudio_mint_present;
SDL_bool SDL_MintAudio_quit_thread;
SDL_bool SDL_MintAudio_thread_finished;
long SDL_MintAudio_thread_pid;
/* The callback function, called by each driver whenever needed */
void SDL_MintAudio_Callback(void)
{
Uint8 *buffer;
SDL_AudioDevice *audio = SDL_MintAudio_device;
buffer = SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf];
SDL_memset(buffer, audio->spec.silence, audio->spec.size);
if (audio->paused)
return;
if (audio->convert.needed) {
int silence;
if ( audio->convert.src_format == AUDIO_U8 ) {
silence = 0x80;
} else {
silence = 0;
}
SDL_memset(audio->convert.buf, silence, audio->convert.len);
audio->spec.callback(audio->spec.userdata,
(Uint8 *)audio->convert.buf,audio->convert.len);
SDL_ConvertAudio(&audio->convert);
SDL_memcpy(buffer, audio->convert.buf, audio->convert.len_cvt);
} else {
audio->spec.callback(audio->spec.userdata, buffer, audio->spec.size);
}
}
/* Add a new frequency/clock/predivisor to the current list */
void SDL_MintAudio_AddFrequency(_THIS, Uint32 frequency, Uint32 clock,
Uint32 prediv, int gpio_bits)
{
int i, p;
if (MINTAUDIO_freqcount==MINTAUDIO_maxfreqs) {
return;
}
/* Search where to insert the frequency (highest first) */
for (p=0; p<MINTAUDIO_freqcount; p++) {
if (frequency > MINTAUDIO_frequencies[p].frequency) {
break;
}
}
/* Put all following ones farer */
if (MINTAUDIO_freqcount>0) {
for (i=MINTAUDIO_freqcount; i>p; i--) {
SDL_memcpy(&MINTAUDIO_frequencies[i], &MINTAUDIO_frequencies[i-1], sizeof(mint_frequency_t));
}
}
/* And insert new one */
MINTAUDIO_frequencies[p].frequency = frequency;
MINTAUDIO_frequencies[p].masterclock = clock;
MINTAUDIO_frequencies[p].predivisor = prediv;
MINTAUDIO_frequencies[p].gpio_bits = gpio_bits;
MINTAUDIO_freqcount++;
}
/* Search for the nearest frequency */
int SDL_MintAudio_SearchFrequency(_THIS, int desired_freq)
{
int i;
/* Only 1 freq ? */
if (MINTAUDIO_freqcount==1) {
return 0;
}
/* Check the array */
for (i=0; i<MINTAUDIO_freqcount; i++) {
if (desired_freq >= ((MINTAUDIO_frequencies[i].frequency+
MINTAUDIO_frequencies[i+1].frequency)>>1)) {
return i;
}
}
/* Not in the array, give the latest */
return MINTAUDIO_freqcount-1;
}
/* Check if FPU is present */
void SDL_MintAudio_CheckFpu(void)
{
long cookie_fpu;
SDL_MintAudio_hasfpu = 0;
if (Getcookie(C__FPU, &cookie_fpu) != C_FOUND) {
return;
}
switch ((cookie_fpu>>16)&0xfffe) {
case 2:
case 4:
case 6:
case 8:
case 16:
SDL_MintAudio_hasfpu = 1;
break;
}
}
/* The thread function, used under MiNT with xbios */
int SDL_MintAudio_Thread(long param)
{
SndBufPtr pointers;
SDL_bool buffers_filled[2] = {SDL_FALSE, SDL_FALSE};
SDL_MintAudio_thread_finished = SDL_FALSE;
while (!SDL_MintAudio_quit_thread) {
if (Buffptr(&pointers)!=0)
continue;
if (( (unsigned long)pointers.play>=(unsigned long)SDL_MintAudio_audiobuf[0])
&& ( (unsigned long)pointers.play<=(unsigned long)SDL_MintAudio_audiobuf[1]))
{
/* DMA is reading buffer #0, setup buffer #1 if not already done */
if (!buffers_filled[1]) {
SDL_MintAudio_numbuf = 1;
SDL_MintAudio_Callback();
Setbuffer(0, SDL_MintAudio_audiobuf[1], SDL_MintAudio_audiobuf[1] + SDL_MintAudio_audiosize);
buffers_filled[1]=SDL_TRUE;
buffers_filled[0]=SDL_FALSE;
}
} else {
/* DMA is reading buffer #1, setup buffer #0 if not already done */
if (!buffers_filled[0]) {
SDL_MintAudio_numbuf = 0;
SDL_MintAudio_Callback();
Setbuffer(0, SDL_MintAudio_audiobuf[0], SDL_MintAudio_audiobuf[0] + SDL_MintAudio_audiosize);
buffers_filled[0]=SDL_TRUE;
buffers_filled[1]=SDL_FALSE;
}
}
usleep(100);
}
SDL_MintAudio_thread_finished = SDL_TRUE;
return 0;
}
void SDL_MintAudio_WaitThread(void)
{
if (!SDL_MintAudio_mint_present)
return;
if (SDL_MintAudio_thread_finished)
return;
SDL_MintAudio_quit_thread = SDL_TRUE;
while (!SDL_MintAudio_thread_finished) {
Syield();
}
}

View file

@ -1,121 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
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 library 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
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
/*
MiNT audio driver
Patrice Mandin
*/
#ifndef _SDL_mintaudio_h
#define _SDL_mintaudio_h
#include "../SDL_sysaudio.h"
#include "SDL_mintaudio_stfa.h"
/* Hidden "this" pointer for the audio functions */
#define _THIS SDL_AudioDevice *this
/* 16 predivisors with 3 clocks max. */
#define MINTAUDIO_maxfreqs (16*3)
typedef struct {
Uint32 frequency;
Uint32 masterclock;
Uint32 predivisor;
int gpio_bits; /* in case of external clock */
} mint_frequency_t;
struct SDL_PrivateAudioData {
mint_frequency_t frequencies[MINTAUDIO_maxfreqs];
int freq_count; /* Number of frequencies in the array */
int numfreq; /* Number of selected frequency */
};
/* Old variable names */
#define MINTAUDIO_frequencies (this->hidden->frequencies)
#define MINTAUDIO_freqcount (this->hidden->freq_count)
#define MINTAUDIO_numfreq (this->hidden->numfreq)
/* _MCH cookie (values>>16) */
enum {
MCH_ST=0,
MCH_STE,
MCH_TT,
MCH_F30,
MCH_CLONE,
MCH_ARANYM
};
/* Master clocks for replay frequencies */
#define MASTERCLOCK_STE 8010666 /* Not sure of this one */
#define MASTERCLOCK_TT 16107953 /* Not sure of this one */
#define MASTERCLOCK_FALCON1 25175000
#define MASTERCLOCK_FALCON2 32000000 /* Only usable for DSP56K */
#define MASTERCLOCK_FALCONEXT -1 /* Clock on DSP56K port, unknown */
#define MASTERCLOCK_44K 22579200 /* Standard clock for 44.1 Khz */
#define MASTERCLOCK_48K 24576000 /* Standard clock for 48 Khz */
/* Master clock predivisors */
#define MASTERPREDIV_STE 160
#define MASTERPREDIV_TT 320
#define MASTERPREDIV_FALCON 256
#define MASTERPREDIV_MILAN 256
/* Variables */
extern SDL_AudioDevice *SDL_MintAudio_device;
extern Uint8 *SDL_MintAudio_audiobuf[2]; /* Pointers to buffers */
extern unsigned long SDL_MintAudio_audiosize; /* Length of audio buffer=spec->size */
extern volatile unsigned short SDL_MintAudio_numbuf; /* Buffer to play */
extern volatile unsigned short SDL_MintAudio_mutex;
extern cookie_stfa_t *SDL_MintAudio_stfa;
extern volatile unsigned long SDL_MintAudio_clocktics;
extern unsigned short SDL_MintAudio_hasfpu; /* To preserve fpu registers if needed */
/* MiNT thread variables */
extern SDL_bool SDL_MintAudio_mint_present;
extern SDL_bool SDL_MintAudio_quit_thread;
extern SDL_bool SDL_MintAudio_thread_finished;
extern long SDL_MintAudio_thread_pid;
/* Functions */
void SDL_MintAudio_Callback(void);
void SDL_MintAudio_AddFrequency(_THIS, Uint32 frequency, Uint32 clock,
Uint32 prediv, int gpio_bits);
int SDL_MintAudio_SearchFrequency(_THIS, int desired_freq);
void SDL_MintAudio_CheckFpu(void);
/* MiNT thread functions */
int SDL_MintAudio_Thread(long param);
void SDL_MintAudio_WaitThread(void);
/* ASM interrupt functions */
void SDL_MintAudio_GsxbInterrupt(void);
void SDL_MintAudio_EmptyGsxbInterrupt(void);
void SDL_MintAudio_XbiosInterruptMeasureClock(void);
void SDL_MintAudio_XbiosInterrupt(void);
void SDL_MintAudio_Dma8Interrupt(void);
void SDL_MintAudio_StfaInterrupt(void);
#endif /* _SDL_mintaudio_h */

View file

@ -1,357 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
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 library 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
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
/*
MiNT audio driver
using DMA 8bits (hardware access)
Patrice Mandin
*/
/* Mint includes */
#include <mint/osbind.h>
#include <mint/falcon.h>
#include <mint/cookie.h>
#include "SDL_audio.h"
#include "../SDL_audio_c.h"
#include "../SDL_sysaudio.h"
#include "../../video/ataricommon/SDL_atarimxalloc_c.h"
#include "SDL_mintaudio.h"
#include "SDL_mintaudio_dma8.h"
/*--- Defines ---*/
#define MINT_AUDIO_DRIVER_NAME "mint_dma8"
/* Debug print info */
#define DEBUG_NAME "audio:dma8: "
#if 0
#define DEBUG_PRINT(what) \
{ \
printf what; \
}
#else
#define DEBUG_PRINT(what)
#endif
/*--- Static variables ---*/
static long cookie_snd, cookie_mch;
/*--- Audio driver functions ---*/
static void Mint_CloseAudio(_THIS);
static int Mint_OpenAudio(_THIS, SDL_AudioSpec *spec);
static void Mint_LockAudio(_THIS);
static void Mint_UnlockAudio(_THIS);
/* To check/init hardware audio */
static int Mint_CheckAudio(_THIS, SDL_AudioSpec *spec);
/* Functions called in supervisor mode */
static void Mint_InitDma(void);
static void Mint_StopReplay(void);
static void Mint_StartReplay(void);
/*--- Audio driver bootstrap functions ---*/
static int Audio_Available(void)
{
const char *envr = SDL_getenv("SDL_AUDIODRIVER");
/* Check if user asked a different audio driver */
if ((envr) && (SDL_strcmp(envr, MINT_AUDIO_DRIVER_NAME)!=0)) {
DEBUG_PRINT((DEBUG_NAME "user asked a different audio driver\n"));
return 0;
}
/* Cookie _MCH present ? if not, assume ST machine */
if (Getcookie(C__MCH, &cookie_mch) == C_NOTFOUND) {
cookie_mch = MCH_ST;
}
/* Cookie _SND present ? if not, assume ST machine */
if (Getcookie(C__SND, &cookie_snd) == C_NOTFOUND) {
cookie_snd = SND_PSG;
}
/* Check if we have 8 bits audio */
if ((cookie_snd & SND_8BIT)==0) {
DEBUG_PRINT((DEBUG_NAME "no 8 bits sound\n"));
return(0);
}
/* Check if audio is lockable */
if (cookie_snd & SND_16BIT) {
if (Locksnd()!=1) {
DEBUG_PRINT((DEBUG_NAME "audio locked by other application\n"));
return(0);
}
Unlocksnd();
}
DEBUG_PRINT((DEBUG_NAME "8 bits audio available!\n"));
return(1);
}
static void Audio_DeleteDevice(SDL_AudioDevice *device)
{
SDL_free(device->hidden);
SDL_free(device);
}
static SDL_AudioDevice *Audio_CreateDevice(int devindex)
{
SDL_AudioDevice *this;
/* Initialize all variables that we clean on shutdown */
this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
if ( this ) {
SDL_memset(this, 0, (sizeof *this));
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
}
if ( (this == NULL) || (this->hidden == NULL) ) {
SDL_OutOfMemory();
if ( this ) {
SDL_free(this);
}
return(0);
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
/* Set the function pointers */
this->OpenAudio = Mint_OpenAudio;
this->CloseAudio = Mint_CloseAudio;
this->LockAudio = Mint_LockAudio;
this->UnlockAudio = Mint_UnlockAudio;
this->free = Audio_DeleteDevice;
return this;
}
AudioBootStrap MINTAUDIO_DMA8_bootstrap = {
MINT_AUDIO_DRIVER_NAME, "MiNT DMA 8 bits audio driver",
Audio_Available, Audio_CreateDevice
};
static void Mint_LockAudio(_THIS)
{
Supexec(Mint_StopReplay);
}
static void Mint_UnlockAudio(_THIS)
{
Supexec(Mint_StartReplay);
}
static void Mint_CloseAudio(_THIS)
{
Supexec(Mint_StopReplay);
DEBUG_PRINT((DEBUG_NAME "closeaudio: replay stopped\n"));
/* Disable interrupt */
Jdisint(MFP_DMASOUND);
DEBUG_PRINT((DEBUG_NAME "closeaudio: interrupt disabled\n"));
/* Wait if currently playing sound */
while (SDL_MintAudio_mutex != 0) {
}
DEBUG_PRINT((DEBUG_NAME "closeaudio: no more interrupt running\n"));
/* Clear buffers */
if (SDL_MintAudio_audiobuf[0]) {
Mfree(SDL_MintAudio_audiobuf[0]);
SDL_MintAudio_audiobuf[0] = SDL_MintAudio_audiobuf[1] = NULL;
}
DEBUG_PRINT((DEBUG_NAME "closeaudio: buffers freed\n"));
}
static int Mint_CheckAudio(_THIS, SDL_AudioSpec *spec)
{
int i, masterprediv, sfreq;
unsigned long masterclock;
DEBUG_PRINT((DEBUG_NAME "asked: %d bits, ",spec->format & 0x00ff));
DEBUG_PRINT(("signed=%d, ", ((spec->format & 0x8000)!=0)));
DEBUG_PRINT(("big endian=%d, ", ((spec->format & 0x1000)!=0)));
DEBUG_PRINT(("channels=%d, ", spec->channels));
DEBUG_PRINT(("freq=%d\n", spec->freq));
if (spec->channels > 2)
spec->channels = 2;
/* Check formats available */
spec->format = AUDIO_S8;
/* Calculate and select the closest frequency */
sfreq=0;
masterclock=MASTERCLOCK_STE;
masterprediv=MASTERPREDIV_STE;
switch(cookie_mch>>16) {
/*
case MCH_STE:
masterclock=MASTERCLOCK_STE;
masterprediv=MASTERPREDIV_STE;
break;
*/
case MCH_TT:
masterclock=MASTERCLOCK_TT;
masterprediv=MASTERPREDIV_TT;
break;
case MCH_F30:
case MCH_ARANYM:
masterclock=MASTERCLOCK_FALCON1;
masterprediv=MASTERPREDIV_FALCON;
sfreq=1;
break;
}
MINTAUDIO_freqcount=0;
for (i=sfreq;i<4;i++) {
SDL_MintAudio_AddFrequency(this, masterclock/(masterprediv*(1<<i)),
masterclock, i-sfreq, -1);
}
#if 1
for (i=0; i<MINTAUDIO_freqcount; i++) {
DEBUG_PRINT((DEBUG_NAME "freq %d: %lu Hz, clock %lu, prediv %d\n",
i, MINTAUDIO_frequencies[i].frequency, MINTAUDIO_frequencies[i].masterclock,
MINTAUDIO_frequencies[i].predivisor
));
}
#endif
MINTAUDIO_numfreq=SDL_MintAudio_SearchFrequency(this, spec->freq);
spec->freq=MINTAUDIO_frequencies[MINTAUDIO_numfreq].frequency;
DEBUG_PRINT((DEBUG_NAME "obtained: %d bits, ",spec->format & 0x00ff));
DEBUG_PRINT(("signed=%d, ", ((spec->format & 0x8000)!=0)));
DEBUG_PRINT(("big endian=%d, ", ((spec->format & 0x1000)!=0)));
DEBUG_PRINT(("channels=%d, ", spec->channels));
DEBUG_PRINT(("freq=%d\n", spec->freq));
return 0;
}
static int Mint_OpenAudio(_THIS, SDL_AudioSpec *spec)
{
SDL_MintAudio_device = this;
/* Check audio capabilities */
if (Mint_CheckAudio(this, spec)==-1) {
return -1;
}
SDL_CalculateAudioSpec(spec);
/* Allocate memory for audio buffers in DMA-able RAM */
DEBUG_PRINT((DEBUG_NAME "buffer size=%d\n", spec->size));
SDL_MintAudio_audiobuf[0] = Atari_SysMalloc(spec->size *2, MX_STRAM);
if (SDL_MintAudio_audiobuf[0]==NULL) {
SDL_SetError("MINT_OpenAudio: Not enough memory for audio buffer");
return (-1);
}
SDL_MintAudio_audiobuf[1] = SDL_MintAudio_audiobuf[0] + spec->size ;
SDL_MintAudio_numbuf=0;
SDL_memset(SDL_MintAudio_audiobuf[0], spec->silence, spec->size *2);
SDL_MintAudio_audiosize = spec->size;
SDL_MintAudio_mutex = 0;
DEBUG_PRINT((DEBUG_NAME "buffer 0 at 0x%08x\n", SDL_MintAudio_audiobuf[0]));
DEBUG_PRINT((DEBUG_NAME "buffer 1 at 0x%08x\n", SDL_MintAudio_audiobuf[1]));
SDL_MintAudio_CheckFpu();
/* Set replay tracks */
if (cookie_snd & SND_16BIT) {
Settracks(0,0);
Setmontracks(0);
}
Supexec(Mint_InitDma);
/* Set interrupt */
Jdisint(MFP_DMASOUND);
Xbtimer(XB_TIMERA, 8, 1, SDL_MintAudio_Dma8Interrupt);
Jenabint(MFP_DMASOUND);
if (cookie_snd & SND_16BIT) {
if (Setinterrupt(SI_TIMERA, SI_PLAY)<0) {
DEBUG_PRINT((DEBUG_NAME "Setinterrupt() failed\n"));
}
}
Supexec(Mint_StartReplay);
return(1); /* We don't use threaded audio */
}
/* Functions called in supervisor mode */
static void Mint_InitDma(void)
{
unsigned long buffer;
unsigned char mode;
SDL_AudioDevice *this = SDL_MintAudio_device;
Mint_StopReplay();
/* Set buffer */
buffer = (unsigned long) SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf];
DMAAUDIO_IO.start_high = (buffer>>16) & 255;
DMAAUDIO_IO.start_mid = (buffer>>8) & 255;
DMAAUDIO_IO.start_low = buffer & 255;
buffer += SDL_MintAudio_audiosize;
DMAAUDIO_IO.end_high = (buffer>>16) & 255;
DMAAUDIO_IO.end_mid = (buffer>>8) & 255;
DMAAUDIO_IO.end_low = buffer & 255;
mode = 3-MINTAUDIO_frequencies[MINTAUDIO_numfreq].predivisor;
if (this->spec.channels==1) {
mode |= 1<<7;
}
DMAAUDIO_IO.sound_ctrl = mode;
}
static void Mint_StopReplay(void)
{
/* Stop replay */
DMAAUDIO_IO.control=0;
}
static void Mint_StartReplay(void)
{
/* Start replay */
DMAAUDIO_IO.control=3;
}

View file

@ -1,85 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
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 library 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
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
/*
DMA 8bits and Falcon Codec audio definitions
Patrice Mandin, Didier Méquignon
*/
#ifndef _SDL_mintaudio_dma8_h
#define _SDL_mintaudio_dma8_h
#define DMAAUDIO_IO_BASE (0xffff8900)
struct DMAAUDIO_IO_S {
unsigned char int_ctrl;
unsigned char control;
unsigned char dummy1;
unsigned char start_high;
unsigned char dummy2;
unsigned char start_mid;
unsigned char dummy3;
unsigned char start_low;
unsigned char dummy4;
unsigned char cur_high;
unsigned char dummy5;
unsigned char cur_mid;
unsigned char dummy6;
unsigned char cur_low;
unsigned char dummy7;
unsigned char end_high;
unsigned char dummy8;
unsigned char end_mid;
unsigned char dummy9;
unsigned char end_low;
unsigned char dummy10[12];
unsigned char track_ctrl; /* CODEC only */
unsigned char sound_ctrl;
unsigned short sound_data;
unsigned short sound_mask;
unsigned char dummy11[10];
unsigned short dev_ctrl;
unsigned short dest_ctrl;
unsigned short sync_div;
unsigned char track_rec;
unsigned char adderin_input;
unsigned char channel_input;
unsigned char channel_amplification;
unsigned char channel_reduction;
unsigned char dummy12[6];
unsigned char data_direction;
unsigned char dummy13;
unsigned char dev_data;
};
#define DMAAUDIO_IO ((*(volatile struct DMAAUDIO_IO_S *)DMAAUDIO_IO_BASE))
#endif /* _SDL_mintaudio_dma8_h */

View file

@ -1,436 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
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 library 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
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
/*
MiNT audio driver
using XBIOS functions (GSXB compatible driver)
Patrice Mandin
*/
/* Mint includes */
#include <mint/osbind.h>
#include <mint/falcon.h>
#include <mint/cookie.h>
#include "SDL_audio.h"
#include "../SDL_audio_c.h"
#include "../SDL_sysaudio.h"
#include "../../video/ataricommon/SDL_atarimxalloc_c.h"
#include "SDL_mintaudio.h"
#include "SDL_mintaudio_gsxb.h"
/*--- Defines ---*/
#define MINT_AUDIO_DRIVER_NAME "mint_gsxb"
/* Debug print info */
#define DEBUG_NAME "audio:gsxb: "
#if 0
#define DEBUG_PRINT(what) \
{ \
printf what; \
}
#else
#define DEBUG_PRINT(what)
#endif
/*--- Static variables ---*/
static long cookie_snd, cookie_gsxb;
/*--- Audio driver functions ---*/
static void Mint_CloseAudio(_THIS);
static int Mint_OpenAudio(_THIS, SDL_AudioSpec *spec);
static void Mint_LockAudio(_THIS);
static void Mint_UnlockAudio(_THIS);
/* To check/init hardware audio */
static int Mint_CheckAudio(_THIS, SDL_AudioSpec *spec);
static void Mint_InitAudio(_THIS, SDL_AudioSpec *spec);
/* GSXB callbacks */
static void Mint_GsxbInterrupt(void);
static void Mint_GsxbNullInterrupt(void);
/*--- Audio driver bootstrap functions ---*/
static int Audio_Available(void)
{
const char *envr = SDL_getenv("SDL_AUDIODRIVER");
/* Check if user asked a different audio driver */
if ((envr) && (SDL_strcmp(envr, MINT_AUDIO_DRIVER_NAME)!=0)) {
DEBUG_PRINT((DEBUG_NAME "user asked a different audio driver\n"));
return(0);
}
/* Cookie _SND present ? if not, assume ST machine */
if (Getcookie(C__SND, &cookie_snd) == C_NOTFOUND) {
cookie_snd = SND_PSG;
}
/* Check if we have 16 bits audio */
if ((cookie_snd & SND_16BIT)==0) {
DEBUG_PRINT((DEBUG_NAME "no 16 bits sound\n"));
return(0);
}
/* Cookie GSXB present ? */
cookie_gsxb = (Getcookie(C_GSXB, &cookie_gsxb) == C_FOUND);
/* Is it GSXB ? */
if (((cookie_snd & SND_GSXB)==0) || (cookie_gsxb==0)) {
DEBUG_PRINT((DEBUG_NAME "no GSXB audio\n"));
return(0);
}
/* Check if audio is lockable */
if (Locksnd()!=1) {
DEBUG_PRINT((DEBUG_NAME "audio locked by other application\n"));
return(0);
}
Unlocksnd();
DEBUG_PRINT((DEBUG_NAME "GSXB audio available!\n"));
return(1);
}
static void Audio_DeleteDevice(SDL_AudioDevice *device)
{
SDL_free(device->hidden);
SDL_free(device);
}
static SDL_AudioDevice *Audio_CreateDevice(int devindex)
{
SDL_AudioDevice *this;
/* Initialize all variables that we clean on shutdown */
this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
if ( this ) {
SDL_memset(this, 0, (sizeof *this));
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
}
if ( (this == NULL) || (this->hidden == NULL) ) {
SDL_OutOfMemory();
if ( this ) {
SDL_free(this);
}
return(0);
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
/* Set the function pointers */
this->OpenAudio = Mint_OpenAudio;
this->CloseAudio = Mint_CloseAudio;
this->LockAudio = Mint_LockAudio;
this->UnlockAudio = Mint_UnlockAudio;
this->free = Audio_DeleteDevice;
return this;
}
AudioBootStrap MINTAUDIO_GSXB_bootstrap = {
MINT_AUDIO_DRIVER_NAME, "MiNT GSXB audio driver",
Audio_Available, Audio_CreateDevice
};
static void Mint_LockAudio(_THIS)
{
/* Stop replay */
Buffoper(0);
}
static void Mint_UnlockAudio(_THIS)
{
/* Restart replay */
Buffoper(SB_PLA_ENA|SB_PLA_RPT);
}
static void Mint_CloseAudio(_THIS)
{
/* Stop replay */
Buffoper(0);
/* Uninstall interrupt */
if (NSetinterrupt(2, SI_NONE, Mint_GsxbNullInterrupt)<0) {
DEBUG_PRINT((DEBUG_NAME "NSetinterrupt() failed in close\n"));
}
/* Wait if currently playing sound */
while (SDL_MintAudio_mutex != 0) {
}
/* Clear buffers */
if (SDL_MintAudio_audiobuf[0]) {
Mfree(SDL_MintAudio_audiobuf[0]);
SDL_MintAudio_audiobuf[0] = SDL_MintAudio_audiobuf[1] = NULL;
}
/* Unlock sound system */
Unlocksnd();
}
static int Mint_CheckAudio(_THIS, SDL_AudioSpec *spec)
{
long snd_format = 0;
int i, resolution, format_signed, format_bigendian;
Uint16 test_format = SDL_FirstAudioFormat(spec->format);
int valid_datatype = 0;
resolution = spec->format & 0x00ff;
format_signed = ((spec->format & 0x8000)!=0);
format_bigendian = ((spec->format & 0x1000)!=0);
DEBUG_PRINT((DEBUG_NAME "asked: %d bits, ",spec->format & 0x00ff));
DEBUG_PRINT(("signed=%d, ", ((spec->format & 0x8000)!=0)));
DEBUG_PRINT(("big endian=%d, ", ((spec->format & 0x1000)!=0)));
DEBUG_PRINT(("channels=%d, ", spec->channels));
DEBUG_PRINT(("freq=%d\n", spec->freq));
if (spec->channels > 2) {
spec->channels = 2; /* no more than stereo! */
}
while ((!valid_datatype) && (test_format)) {
/* Check formats available */
snd_format = Sndstatus(SND_QUERYFORMATS);
spec->format = test_format;
resolution = spec->format & 0xff;
format_signed = (spec->format & (1<<15));
format_bigendian = (spec->format & (1<<12));
switch (test_format) {
case AUDIO_U8:
case AUDIO_S8:
if (snd_format & SND_FORMAT8) {
valid_datatype = 1;
snd_format = Sndstatus(SND_QUERY8BIT);
}
break;
case AUDIO_U16LSB:
case AUDIO_S16LSB:
case AUDIO_U16MSB:
case AUDIO_S16MSB:
if (snd_format & SND_FORMAT16) {
valid_datatype = 1;
snd_format = Sndstatus(SND_QUERY16BIT);
}
break;
default:
test_format = SDL_NextAudioFormat();
break;
}
}
if (!valid_datatype) {
SDL_SetError("Unsupported audio format");
return (-1);
}
/* Check signed/unsigned format */
if (format_signed) {
if (snd_format & SND_FORMATSIGNED) {
/* Ok */
} else if (snd_format & SND_FORMATUNSIGNED) {
/* Give unsigned format */
spec->format = spec->format & (~0x8000);
}
} else {
if (snd_format & SND_FORMATUNSIGNED) {
/* Ok */
} else if (snd_format & SND_FORMATSIGNED) {
/* Give signed format */
spec->format |= 0x8000;
}
}
if (format_bigendian) {
if (snd_format & SND_FORMATBIGENDIAN) {
/* Ok */
} else if (snd_format & SND_FORMATLITTLEENDIAN) {
/* Give little endian format */
spec->format = spec->format & (~0x1000);
}
} else {
if (snd_format & SND_FORMATLITTLEENDIAN) {
/* Ok */
} else if (snd_format & SND_FORMATBIGENDIAN) {
/* Give big endian format */
spec->format |= 0x1000;
}
}
/* Calculate and select the closest frequency */
MINTAUDIO_freqcount=0;
for (i=1;i<4;i++) {
SDL_MintAudio_AddFrequency(this,
MASTERCLOCK_44K/(MASTERPREDIV_MILAN*(1<<i)), MASTERCLOCK_44K,
(1<<i)-1, -1);
}
#if 1
for (i=0; i<MINTAUDIO_freqcount; i++) {
DEBUG_PRINT((DEBUG_NAME "freq %d: %lu Hz, clock %lu, prediv %d\n",
i, MINTAUDIO_frequencies[i].frequency, MINTAUDIO_frequencies[i].masterclock,
MINTAUDIO_frequencies[i].predivisor
));
}
#endif
MINTAUDIO_numfreq=SDL_MintAudio_SearchFrequency(this, spec->freq);
spec->freq=MINTAUDIO_frequencies[MINTAUDIO_numfreq].frequency;
DEBUG_PRINT((DEBUG_NAME "obtained: %d bits, ",spec->format & 0x00ff));
DEBUG_PRINT(("signed=%d, ", ((spec->format & 0x8000)!=0)));
DEBUG_PRINT(("big endian=%d, ", ((spec->format & 0x1000)!=0)));
DEBUG_PRINT(("channels=%d, ", spec->channels));
DEBUG_PRINT(("freq=%d\n", spec->freq));
return 0;
}
static void Mint_InitAudio(_THIS, SDL_AudioSpec *spec)
{
int channels_mode, prediv;
void *buffer;
/* Stop currently playing sound */
Buffoper(0);
/* Set replay tracks */
Settracks(0,0);
Setmontracks(0);
/* Select replay format */
switch (spec->format & 0xff) {
case 8:
if (spec->channels==2) {
channels_mode=STEREO8;
} else {
channels_mode=MONO8;
}
break;
case 16:
if (spec->channels==2) {
channels_mode=STEREO16;
} else {
channels_mode=MONO16;
}
break;
default:
channels_mode=STEREO16;
break;
}
if (Setmode(channels_mode)<0) {
DEBUG_PRINT((DEBUG_NAME "Setmode() failed\n"));
}
prediv = MINTAUDIO_frequencies[MINTAUDIO_numfreq].predivisor;
Devconnect(DMAPLAY, DAC, CLKEXT, prediv, 1);
/* Set buffer */
buffer = SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf];
if (Setbuffer(0, buffer, buffer + spec->size)<0) {
DEBUG_PRINT((DEBUG_NAME "Setbuffer() failed\n"));
}
/* Install interrupt */
if (NSetinterrupt(2, SI_PLAY, Mint_GsxbInterrupt)<0) {
DEBUG_PRINT((DEBUG_NAME "NSetinterrupt() failed\n"));
}
/* Go */
Buffoper(SB_PLA_ENA|SB_PLA_RPT);
DEBUG_PRINT((DEBUG_NAME "hardware initialized\n"));
}
static int Mint_OpenAudio(_THIS, SDL_AudioSpec *spec)
{
/* Lock sound system */
if (Locksnd()!=1) {
SDL_SetError("Mint_OpenAudio: Audio system already in use");
return(-1);
}
SDL_MintAudio_device = this;
/* Check audio capabilities */
if (Mint_CheckAudio(this, spec)==-1) {
return -1;
}
SDL_CalculateAudioSpec(spec);
/* Allocate memory for audio buffers in DMA-able RAM */
DEBUG_PRINT((DEBUG_NAME "buffer size=%d\n", spec->size));
SDL_MintAudio_audiobuf[0] = Atari_SysMalloc(spec->size *2, MX_STRAM);
if (SDL_MintAudio_audiobuf[0]==NULL) {
SDL_SetError("MINT_OpenAudio: Not enough memory for audio buffer");
return (-1);
}
SDL_MintAudio_audiobuf[1] = SDL_MintAudio_audiobuf[0] + spec->size ;
SDL_MintAudio_numbuf=0;
SDL_memset(SDL_MintAudio_audiobuf[0], spec->silence, spec->size *2);
SDL_MintAudio_audiosize = spec->size;
SDL_MintAudio_mutex = 0;
DEBUG_PRINT((DEBUG_NAME "buffer 0 at 0x%08x\n", SDL_MintAudio_audiobuf[0]));
DEBUG_PRINT((DEBUG_NAME "buffer 1 at 0x%08x\n", SDL_MintAudio_audiobuf[1]));
SDL_MintAudio_CheckFpu();
/* Setup audio hardware */
Mint_InitAudio(this, spec);
return(1); /* We don't use threaded audio */
}
static void Mint_GsxbInterrupt(void)
{
Uint8 *newbuf;
if (SDL_MintAudio_mutex)
return;
SDL_MintAudio_mutex=1;
SDL_MintAudio_numbuf ^= 1;
SDL_MintAudio_Callback();
newbuf = SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf];
Setbuffer(0, newbuf, newbuf + SDL_MintAudio_audiosize);
SDL_MintAudio_mutex=0;
}
static void Mint_GsxbNullInterrupt(void)
{
}

View file

@ -1,104 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
/*
* GSXB audio definitions
*
* Patrice Mandin
*/
#ifndef _SDL_mintaudio_gsxb_h
#define _SDL_mintaudio_gsxb_h
#include <mint/falcon.h> /* for trap_14_xxx macros */
/* Bit 5 in cookie _SND */
#define SND_GSXB (1<<5)
/* NSoundcmd modes */
#define SETRATE 7 /* Set sample rate */
#define SET8BITFORMAT 8 /* 8 bits format */
#define SET16BITFORMAT 9 /* 16 bits format */
#define SET24BITFORMAT 10 /* 24 bits format */
#define SET32BITFORMAT 11 /* 32 bits format */
#define LTATTEN_MASTER 12 /* Attenuation */
#define RTATTEN_MASTER 13
#define LTATTEN_MICIN 14
#define RTATTEN_MICIN 15
#define LTATTEN_FMGEN 16
#define RTATTEN_FMGEN 17
#define LTATTEN_LINEIN 18
#define RTATTEN_LINEIN 19
#define LTATTEN_CDIN 20
#define RTATTEN_CDIN 21
#define LTATTEN_VIDIN 22
#define RTATTEN_VIDIN 23
#define LTATTEN_AUXIN 24
#define RTATTEN_AUXIN 25
/* Setmode modes */
#define MONO16 3
#define STEREO24 4
#define STEREO32 5
#define MONO24 6
#define MONO32 7
/* Sndstatus modes */
#define SND_QUERYFORMATS 2
#define SND_QUERYMIXERS 3
#define SND_QUERYSOURCES 4
#define SND_QUERYDUPLEX 5
#define SND_QUERY8BIT 8
#define SND_QUERY16BIT 9
#define SND_QUERY24BIT 10
#define SND_QUERY32BIT 11
#define SND_FORMAT8 (1<<0)
#define SND_FORMAT16 (1<<1)
#define SND_FORMAT24 (1<<2)
#define SND_FORMAT32 (1<<3)
#define SND_FORMATSIGNED (1<<0)
#define SND_FORMATUNSIGNED (1<<1)
#define SND_FORMATBIGENDIAN (1<<2)
#define SND_FORMATLITTLEENDIAN (1<<3)
/* Devconnect prescalers */
#define CLK_44K 1
#define CLK_22K 3
#define CLK_11K 7
/* Extra xbios functions */
#define NSoundcmd(mode,data,data2) \
(long)trap_14_wwl((short)130,(short)(mode),(short)(data),(long)(data2))
#define NSetinterrupt(src_inter,cause,inth_addr) \
(long)trap_14_wwwl((short)135,(short)(src_inter),(short)(cause), \
(long)(inth_addr))
#endif /* _SDL_mintaudio_gsxb_h */

View file

@ -1,386 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
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 library 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
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
*/
/*
Audio interrupts
Patrice Mandin, Didier Méquignon
*/
.text
.globl _SDL_MintAudio_Callback
.globl _SDL_MintAudio_XbiosInterrupt
.globl _SDL_MintAudio_XbiosInterruptMeasureClock
.globl _SDL_MintAudio_Dma8Interrupt
.globl _SDL_MintAudio_StfaInterrupt
.globl _SDL_MintAudio_mutex
.globl _SDL_MintAudio_audiobuf
.globl _SDL_MintAudio_numbuf
.globl _SDL_MintAudio_audiosize
.globl _SDL_MintAudio_clocktics
.globl _SDL_MintAudio_hasfpu
.globl _SDL_MintAudio_stfa
/*
How it works:
- Audio is playing buffer #0 (resp. #1)
- We must calculate a sample in buffer #1 (resp. #0)
so we first call the callback to do it
- Then we swap the buffers
*/
#define savptr 0x4a2
#define savamt 0x46
/*--- Save/restore FPU context ---*/
#if defined(__mcoldfire__)
#define SAVE_FPU_CONTEXT \
lea sp@(-216),sp; \
fsave sp@; \
fmovel fpiar,sp@-; \
lea sp@(-64),sp; \
fmovemd fp0-fp7,sp@
#define RESTORE_FPU_CONTEXT \
fmovemd sp@,fp0-fp7; \
lea sp@(64),sp; \
fmovel sp@+,fpiar; \
frestore sp@; \
lea sp@(216),sp
#else
#define SAVE_FPU_CONTEXT \
.chip 68k/68881; \
fsave sp@-; \
fmoveml fpcr/fpsr/fpiar,sp@-; \
fmovemx fp0-fp7,sp@-; \
.chip 68k
#define RESTORE_FPU_CONTEXT \
.chip 68k/68881; \
fmovemx sp@+,fp0-fp7; \
fmoveml sp@+,fpcr/fpsr/fpiar; \
frestore sp@+; \
.chip 68k
#endif
/*--- Xbios interrupt vector to measure Falcon external clock ---*/
_SDL_MintAudio_XbiosInterruptMeasureClock: /* 1 mS */
#if defined(__mcoldfire__)
movel d0,sp@-
moveql #0,d0
btst d0,0xFFFF8901:w /* state DMA sound */
#else
btst #0,0xFFFF8901:w /* state DMA sound */
#endif
beqs SDL_MintAudio_EndIntMeasure
addql #1,_SDL_MintAudio_clocktics
SDL_MintAudio_EndIntMeasure:
#if defined(__mcoldfire__)
moveql #5,d0
bclr d0,0xFFFFFA0F:w /* Clear service bit */
movel sp@+,d0
#else
bclr #5,0xFFFFFA0F:w /* Clear service bit */
#endif
rte
/*--- Xbios interrupt vector ---*/
_SDL_MintAudio_XbiosInterrupt:
#if defined(__mcoldfire__)
lea sp@(-60),sp
moveml d0-d7/a0-a6,sp@
#else
moveml d0-d7/a0-a6,sp@-
#endif
/* Reenable interrupts, so other interrupts can work */
movew #0x2300,sr
/* Clear service bit, so other MFP interrupts can work */
#if defined(__mcoldfire__)
moveql #5,d0
bclr d0,0xfffffa0f:w
#else
bclr #5,0xfffffa0f:w
#endif
/* Check if we are not already running */
tstw _SDL_MintAudio_mutex
bne SDL_MintAudio_XbiosEnd
#if defined(__mcoldfire__)
movew _SDL_MintAudio_mutex,d0
notl d0
movew d0,_SDL_MintAudio_mutex
movew _SDL_MintAudio_numbuf,d1
eorl #1,d1
movew d1,_SDL_MintAudio_numbuf
#else
notw _SDL_MintAudio_mutex
/* Swap buffers */
eorw #1,_SDL_MintAudio_numbuf
#endif
/* Save FPU if needed */
tstw _SDL_MintAudio_hasfpu
beqs SDL_MintAudio_Xbios_nofpu1
SAVE_FPU_CONTEXT
SDL_MintAudio_Xbios_nofpu1:
/* Callback */
jsr _SDL_MintAudio_Callback
/* Restore FPU if needed */
tstw _SDL_MintAudio_hasfpu
beqs SDL_MintAudio_Xbios_nofpu2
RESTORE_FPU_CONTEXT
SDL_MintAudio_Xbios_nofpu2:
/* Reserve space for registers */
#if defined(__mcoldfire__)
movel #savamt,d0
subl d0,savptr
#else
subl #savamt,savptr
#endif
/* Set new buffer */
moveq #0,d0
movel _SDL_MintAudio_audiosize,d1
movew _SDL_MintAudio_numbuf,d0
lsll #2,d0
lea _SDL_MintAudio_audiobuf,a0
movel a0@(d0:l),a1
lea a1@(d1:l),a2
movel a2,sp@-
movel a1,sp@-
clrw sp@-
movew #131,sp@-
trap #14
lea sp@(12),sp
/* Restore registers space */
#if defined(__mcoldfire__)
movel #savamt,d0
addl d0,savptr
#else
addl #savamt,savptr
#endif
clrw _SDL_MintAudio_mutex
SDL_MintAudio_XbiosEnd:
#if defined(__mcoldfire__)
moveml sp@,d0-d7/a0-a6
lea sp@(60),sp
#else
moveml sp@+,d0-d7/a0-a6
#endif
rte
/*--- DMA 8 bits interrupt vector ---*/
_SDL_MintAudio_Dma8Interrupt:
#if defined(__mcoldfire__)
lea sp@(-16),sp
moveml d0-d1/a0-a1,sp@
#else
moveml d0-d1/a0-a1,sp@-
#endif
/* Reenable interrupts, so other interrupts can work */
movew #0x2300,sr
/* Clear service bit, so other MFP interrupts can work */
#if defined(__mcoldfire__)
moveql #5,d0
bclr d0,0xfffffa0f:w
#else
bclr #5,0xfffffa0f:w
#endif
/* Check if we are not already running */
tstw _SDL_MintAudio_mutex
bne SDL_MintAudio_Dma8End
#if defined(__mcoldfire__)
movew _SDL_MintAudio_mutex,d0
notl d0
movew d0,_SDL_MintAudio_mutex
movew _SDL_MintAudio_numbuf,d1
eorl #1,d1
movew d1,_SDL_MintAudio_numbuf
#else
notw _SDL_MintAudio_mutex
/* Swap buffers */
eorw #1,_SDL_MintAudio_numbuf
#endif
/* Save FPU if needed */
tstw _SDL_MintAudio_hasfpu
beqs SDL_MintAudio_Dma8_nofpu1
SAVE_FPU_CONTEXT
SDL_MintAudio_Dma8_nofpu1:
/* Callback */
jsr _SDL_MintAudio_Callback
/* Restore FPU if needed */
tstw _SDL_MintAudio_hasfpu
beqs SDL_MintAudio_Dma8_nofpu2
RESTORE_FPU_CONTEXT
SDL_MintAudio_Dma8_nofpu2:
/* Set new buffer */
moveq #0,d0
movew _SDL_MintAudio_numbuf,d0
lsll #2,d0
lea _SDL_MintAudio_audiobuf,a0
movel a0@(d0:l),d1
/* Modify DMA addresses */
lea 0xffff8900:w,a0
movel d1,d0
moveb d0,a0@(0x07) /* Start address */
lsrl #8,d0
moveb d0,a0@(0x05)
lsrl #8,d0
moveb d0,a0@(0x03)
addl _SDL_MintAudio_audiosize,d1
movel d1,d0
moveb d0,a0@(0x13) /* End address */
lsrl #8,d0
moveb d0,a0@(0x11)
lsrl #8,d0
moveb d0,a0@(0x0f)
clrw _SDL_MintAudio_mutex
SDL_MintAudio_Dma8End:
#if defined(__mcoldfire__)
moveml sp@,d0-d1/a0-a1
lea sp@(16),sp
#else
moveml sp@+,d0-d1/a0-a1
#endif
rte
/*--- STFA interrupt vector ---*/
STFA_SOUND_START = 6
STFA_SOUND_END = STFA_SOUND_START+8
_SDL_MintAudio_StfaInterrupt:
/* Reenable interrupts, so other interrupts can work */
movew #0x2300,sr
/* Check if we are not already running */
tstw _SDL_MintAudio_mutex
#if defined(__mcoldfire__)
bne SDL_MintAudio_StfaEnd
lea sp@(-60),sp
moveml d0-d7/a0-a6,sp@
movew _SDL_MintAudio_mutex,d0
notl d0
movew d0,_SDL_MintAudio_mutex
movew _SDL_MintAudio_numbuf,d1
eorl #1,d1
movew d1,_SDL_MintAudio_numbuf
#else
bnes SDL_MintAudio_StfaEnd
moveml d0-d7/a0-a6,sp@-
notw _SDL_MintAudio_mutex
/* Swap buffers */
eorw #1,_SDL_MintAudio_numbuf
#endif
/* Save FPU if needed */
tstw _SDL_MintAudio_hasfpu
beqs SDL_MintAudio_Stfa_nofpu1
SAVE_FPU_CONTEXT
SDL_MintAudio_Stfa_nofpu1:
/* Callback */
jsr _SDL_MintAudio_Callback
/* Restore FPU if needed */
tstw _SDL_MintAudio_hasfpu
beqs SDL_MintAudio_Stfa_nofpu2
RESTORE_FPU_CONTEXT
SDL_MintAudio_Stfa_nofpu2:
/* Set new buffer */
moveq #0,d0
movel _SDL_MintAudio_stfa,a1
movew _SDL_MintAudio_numbuf,d0
lsll #2,d0
lea _SDL_MintAudio_audiobuf,a0
movel a0@(d0:l),d1
/* Modify STFA replay buffers */
movel d1,a1@(STFA_SOUND_START)
addl _SDL_MintAudio_audiosize,d1
movel d1,a1@(STFA_SOUND_END)
#if defined(__mcoldfire__)
moveml sp@,d0-d7/a0-a6
lea sp@(60),sp
#else
moveml sp@+,d0-d7/a0-a6
#endif
clrw _SDL_MintAudio_mutex
SDL_MintAudio_StfaEnd:
rte

View file

@ -1,405 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
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 library 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
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
/*
MiNT audio driver
using XBIOS functions (MacSound compatible driver)
Patrice Mandin
*/
#include <support.h>
/* Mint includes */
#include <mint/osbind.h>
#include <mint/falcon.h>
#include <mint/cookie.h>
#include "SDL_audio.h"
#include "../SDL_audio_c.h"
#include "../SDL_sysaudio.h"
#include "../../video/ataricommon/SDL_atarimxalloc_c.h"
#include "SDL_mintaudio.h"
#include "SDL_mintaudio_mcsn.h"
/*--- Defines ---*/
#define MINT_AUDIO_DRIVER_NAME "mint_mcsn"
/* Debug print info */
#define DEBUG_NAME "audio:mcsn: "
#if 0
#define DEBUG_PRINT(what) \
{ \
printf what; \
}
#else
#define DEBUG_PRINT(what)
#endif
/*--- Static variables ---*/
static long cookie_snd, cookie_mch;
static cookie_mcsn_t *cookie_mcsn;
/*--- Audio driver functions ---*/
static void Mint_CloseAudio(_THIS);
static int Mint_OpenAudio(_THIS, SDL_AudioSpec *spec);
static void Mint_LockAudio(_THIS);
static void Mint_UnlockAudio(_THIS);
/* To check/init hardware audio */
static int Mint_CheckAudio(_THIS, SDL_AudioSpec *spec);
static void Mint_InitAudio(_THIS, SDL_AudioSpec *spec);
/*--- Audio driver bootstrap functions ---*/
static int Audio_Available(void)
{
long dummy;
const char *envr = SDL_getenv("SDL_AUDIODRIVER");
SDL_MintAudio_mint_present = (Getcookie(C_MiNT, &dummy) == C_FOUND);
/* We can't use XBIOS in interrupt with Magic, don't know about thread */
if (Getcookie(C_MagX, &dummy) == C_FOUND) {
return(0);
}
/* Check if user asked a different audio driver */
if ((envr) && (SDL_strcmp(envr, MINT_AUDIO_DRIVER_NAME)!=0)) {
DEBUG_PRINT((DEBUG_NAME "user asked a different audio driver\n"));
return(0);
}
/* Cookie _MCH present ? if not, assume ST machine */
if (Getcookie(C__MCH, &cookie_mch) == C_NOTFOUND) {
cookie_mch = MCH_ST;
}
/* Cookie _SND present ? if not, assume ST machine */
if (Getcookie(C__SND, &cookie_snd) == C_NOTFOUND) {
cookie_snd = SND_PSG;
}
/* Check if we have 16 bits audio */
if ((cookie_snd & SND_16BIT)==0) {
DEBUG_PRINT((DEBUG_NAME "no 16 bits sound\n"));
return(0);
}
/* Cookie MCSN present ? */
if (Getcookie(C_McSn, &dummy) != C_FOUND) {
DEBUG_PRINT((DEBUG_NAME "no MCSN audio\n"));
return(0);
}
cookie_mcsn = (cookie_mcsn_t *) dummy;
/* Check if interrupt at end of replay */
if (cookie_mcsn->pint == 0) {
DEBUG_PRINT((DEBUG_NAME "no interrupt at end of replay\n"));
return(0);
}
/* Check if audio is lockable */
if (Locksnd()!=1) {
DEBUG_PRINT((DEBUG_NAME "audio locked by other application\n"));
return(0);
}
Unlocksnd();
DEBUG_PRINT((DEBUG_NAME "MCSN audio available!\n"));
return(1);
}
static void Audio_DeleteDevice(SDL_AudioDevice *device)
{
SDL_free(device->hidden);
SDL_free(device);
}
static SDL_AudioDevice *Audio_CreateDevice(int devindex)
{
SDL_AudioDevice *this;
/* Initialize all variables that we clean on shutdown */
this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
if ( this ) {
SDL_memset(this, 0, (sizeof *this));
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
}
if ( (this == NULL) || (this->hidden == NULL) ) {
SDL_OutOfMemory();
if ( this ) {
SDL_free(this);
}
return(0);
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
/* Set the function pointers */
this->OpenAudio = Mint_OpenAudio;
this->CloseAudio = Mint_CloseAudio;
this->LockAudio = Mint_LockAudio;
this->UnlockAudio = Mint_UnlockAudio;
this->free = Audio_DeleteDevice;
return this;
}
AudioBootStrap MINTAUDIO_MCSN_bootstrap = {
MINT_AUDIO_DRIVER_NAME, "MiNT MCSN audio driver",
Audio_Available, Audio_CreateDevice
};
static void Mint_LockAudio(_THIS)
{
/* Stop replay */
Buffoper(0);
}
static void Mint_UnlockAudio(_THIS)
{
/* Restart replay */
Buffoper(SB_PLA_ENA|SB_PLA_RPT);
}
static void Mint_CloseAudio(_THIS)
{
/* Stop replay */
SDL_MintAudio_WaitThread();
Buffoper(0);
if (!SDL_MintAudio_mint_present) {
/* Uninstall interrupt */
Jdisint(MFP_DMASOUND);
}
/* Wait if currently playing sound */
while (SDL_MintAudio_mutex != 0) {
}
/* Clear buffers */
if (SDL_MintAudio_audiobuf[0]) {
Mfree(SDL_MintAudio_audiobuf[0]);
SDL_MintAudio_audiobuf[0] = SDL_MintAudio_audiobuf[1] = NULL;
}
/* Unlock sound system */
Unlocksnd();
}
static int Mint_CheckAudio(_THIS, SDL_AudioSpec *spec)
{
int i;
unsigned long masterclock, masterprediv;
DEBUG_PRINT((DEBUG_NAME "asked: %d bits, ",spec->format & 0x00ff));
DEBUG_PRINT(("signed=%d, ", ((spec->format & 0x8000)!=0)));
DEBUG_PRINT(("big endian=%d, ", ((spec->format & 0x1000)!=0)));
DEBUG_PRINT(("channels=%d, ", spec->channels));
DEBUG_PRINT(("freq=%d\n", spec->freq));
if (spec->channels > 2) {
spec->channels = 2; /* no more than stereo! */
}
/* Check formats available */
MINTAUDIO_freqcount=0;
switch(cookie_mcsn->play) {
case MCSN_ST:
spec->channels=1;
spec->format=8; /* FIXME: is it signed or unsigned ? */
SDL_MintAudio_AddFrequency(this, 12500, 0, 0, -1);
break;
case MCSN_TT: /* Also STE, Mega STE */
spec->format=AUDIO_S8;
masterclock=MASTERCLOCK_STE;
masterprediv=MASTERPREDIV_STE;
if ((cookie_mch>>16)==MCH_TT) {
masterclock=MASTERCLOCK_TT;
masterprediv=MASTERPREDIV_TT;
}
for (i=0; i<4; i++) {
SDL_MintAudio_AddFrequency(this, masterclock/(masterprediv*(1<<i)),
masterclock, 3-i, -1);
}
break;
case MCSN_FALCON: /* Also Mac */
for (i=1; i<12; i++) {
/* Remove unusable Falcon codec predivisors */
if ((i==6) || (i==8) || (i==10)) {
continue;
}
SDL_MintAudio_AddFrequency(this, MASTERCLOCK_FALCON1/(MASTERPREDIV_FALCON*(i+1)),
CLK25M, i+1, -1);
}
if (cookie_mcsn->res1 != 0) {
for (i=1; i<4; i++) {
SDL_MintAudio_AddFrequency(this, (cookie_mcsn->res1)/(MASTERPREDIV_FALCON*(1<<i)),
CLKEXT, (1<<i)-1, -1);
}
}
spec->format |= 0x8000; /* Audio is always signed */
if ((spec->format & 0x00ff)==16) {
spec->format |= 0x1000; /* Audio is always big endian */
spec->channels=2; /* 16 bits always stereo */
}
break;
}
#if 0
for (i=0; i<MINTAUDIO_freqcount; i++) {
DEBUG_PRINT((DEBUG_NAME "freq %d: %lu Hz, clock %lu, prediv %d\n",
i, MINTAUDIO_frequencies[i].frequency, MINTAUDIO_frequencies[i].masterclock,
MINTAUDIO_frequencies[i].predivisor
));
}
#endif
MINTAUDIO_numfreq=SDL_MintAudio_SearchFrequency(this, spec->freq);
spec->freq=MINTAUDIO_frequencies[MINTAUDIO_numfreq].frequency;
DEBUG_PRINT((DEBUG_NAME "obtained: %d bits, ",spec->format & 0x00ff));
DEBUG_PRINT(("signed=%d, ", ((spec->format & 0x8000)!=0)));
DEBUG_PRINT(("big endian=%d, ", ((spec->format & 0x1000)!=0)));
DEBUG_PRINT(("channels=%d, ", spec->channels));
DEBUG_PRINT(("freq=%d\n", spec->freq));
return 0;
}
static void Mint_InitAudio(_THIS, SDL_AudioSpec *spec)
{
int channels_mode, prediv, dmaclock;
void *buffer;
/* Stop currently playing sound */
SDL_MintAudio_quit_thread = SDL_FALSE;
SDL_MintAudio_thread_finished = SDL_TRUE;
SDL_MintAudio_WaitThread();
Buffoper(0);
/* Set replay tracks */
Settracks(0,0);
Setmontracks(0);
/* Select replay format */
channels_mode=STEREO16;
switch (spec->format & 0xff) {
case 8:
if (spec->channels==2) {
channels_mode=STEREO8;
} else {
channels_mode=MONO8;
}
break;
}
if (Setmode(channels_mode)<0) {
DEBUG_PRINT((DEBUG_NAME "Setmode() failed\n"));
}
dmaclock = MINTAUDIO_frequencies[MINTAUDIO_numfreq].masterclock;
prediv = MINTAUDIO_frequencies[MINTAUDIO_numfreq].predivisor;
switch(cookie_mcsn->play) {
case MCSN_TT:
Devconnect(DMAPLAY, DAC, CLK25M, CLKOLD, 1);
Soundcmd(SETPRESCALE, prediv);
DEBUG_PRINT((DEBUG_NAME "STE/TT prescaler selected\n"));
break;
case MCSN_FALCON:
Devconnect(DMAPLAY, DAC, dmaclock, prediv, 1);
DEBUG_PRINT((DEBUG_NAME "Falcon prescaler selected\n"));
break;
}
/* Set buffer */
buffer = SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf];
if (Setbuffer(0, buffer, buffer + spec->size)<0) {
DEBUG_PRINT((DEBUG_NAME "Setbuffer() failed\n"));
}
if (SDL_MintAudio_mint_present) {
SDL_MintAudio_thread_pid = tfork(SDL_MintAudio_Thread, 0);
} else {
/* Install interrupt */
Jdisint(MFP_DMASOUND);
Xbtimer(XB_TIMERA, 8, 1, SDL_MintAudio_XbiosInterrupt);
Jenabint(MFP_DMASOUND);
if (Setinterrupt(SI_TIMERA, SI_PLAY)<0) {
DEBUG_PRINT((DEBUG_NAME "Setinterrupt() failed\n"));
}
}
/* Go */
Buffoper(SB_PLA_ENA|SB_PLA_RPT);
DEBUG_PRINT((DEBUG_NAME "hardware initialized\n"));
}
static int Mint_OpenAudio(_THIS, SDL_AudioSpec *spec)
{
/* Lock sound system */
if (Locksnd()!=1) {
SDL_SetError("Mint_OpenAudio: Audio system already in use");
return(-1);
}
SDL_MintAudio_device = this;
/* Check audio capabilities */
if (Mint_CheckAudio(this, spec)==-1) {
return -1;
}
SDL_CalculateAudioSpec(spec);
/* Allocate memory for audio buffers in DMA-able RAM */
DEBUG_PRINT((DEBUG_NAME "buffer size=%d\n", spec->size));
SDL_MintAudio_audiobuf[0] = Atari_SysMalloc(spec->size *2, MX_STRAM);
if (SDL_MintAudio_audiobuf[0]==NULL) {
SDL_SetError("MINT_OpenAudio: Not enough memory for audio buffer");
return (-1);
}
SDL_MintAudio_audiobuf[1] = SDL_MintAudio_audiobuf[0] + spec->size ;
SDL_MintAudio_numbuf=0;
SDL_memset(SDL_MintAudio_audiobuf[0], spec->silence, spec->size *2);
SDL_MintAudio_audiosize = spec->size;
SDL_MintAudio_mutex = 0;
DEBUG_PRINT((DEBUG_NAME "buffer 0 at 0x%08x\n", SDL_MintAudio_audiobuf[0]));
DEBUG_PRINT((DEBUG_NAME "buffer 1 at 0x%08x\n", SDL_MintAudio_audiobuf[1]));
SDL_MintAudio_CheckFpu();
/* Setup audio hardware */
Mint_InitAudio(this, spec);
return(1); /* We don't use SDL threaded audio */
}

View file

@ -1,59 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
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 library 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
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
/*
MCSN control structure
Patrice Mandin
*/
#ifndef _SDL_mintaudio_mcsh_h
#define _SDL_mintaudio_mcsh_h
typedef struct {
unsigned short version; /* Version */
unsigned short size; /* Size of structure */
unsigned short play; /* Replay capability */
unsigned short record; /* Record capability */
unsigned short dsp; /* DSP56K present */
unsigned short pint; /* Interrupt at end of replay */
unsigned short rint; /* Interrupt at end of record */
unsigned long res1; /* Frequency of external clock */
unsigned long res2;
unsigned long res3;
unsigned long res4;
} cookie_mcsn_t;
enum {
MCSN_ST=0,
MCSN_TT,
MCSN_STE=MCSN_TT,
MCSN_FALCON,
MCSN_MAC=MCSN_FALCON
};
#define SETSMPFREQ 7 /* Set sample frequency */
#endif /* _SDL_mintaudio_mcsh_h */

View file

@ -1,326 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
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 library 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
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
/*
MiNT audio driver
using XBIOS functions (STFA driver)
Patrice Mandin
*/
/* Mint includes */
#include <mint/osbind.h>
#include <mint/falcon.h>
#include <mint/cookie.h>
#include "SDL_audio.h"
#include "../SDL_audio_c.h"
#include "../SDL_sysaudio.h"
#include "../../video/ataricommon/SDL_atarimxalloc_c.h"
#include "../../video/ataricommon/SDL_atarisuper.h"
#include "SDL_mintaudio.h"
#include "SDL_mintaudio_stfa.h"
/*--- Defines ---*/
#define MINT_AUDIO_DRIVER_NAME "mint_stfa"
/* Debug print info */
#define DEBUG_NAME "audio:stfa: "
#if 0
#define DEBUG_PRINT(what) \
{ \
printf what; \
}
#else
#define DEBUG_PRINT(what)
#endif
/*--- Static variables ---*/
static long cookie_snd, cookie_mch;
static cookie_stfa_t *cookie_stfa;
static const int freqs[16]={
4995, 6269, 7493, 8192,
9830, 10971, 12538, 14985,
16384, 19819, 21943, 24576,
30720, 32336, 43885, 49152
};
/*--- Audio driver functions ---*/
static void Mint_CloseAudio(_THIS);
static int Mint_OpenAudio(_THIS, SDL_AudioSpec *spec);
static void Mint_LockAudio(_THIS);
static void Mint_UnlockAudio(_THIS);
/* To check/init hardware audio */
static int Mint_CheckAudio(_THIS, SDL_AudioSpec *spec);
static void Mint_InitAudio(_THIS, SDL_AudioSpec *spec);
/*--- Audio driver bootstrap functions ---*/
static int Audio_Available(void)
{
long dummy;
const char *envr = SDL_getenv("SDL_AUDIODRIVER");
/* Check if user asked a different audio driver */
if ((envr) && (SDL_strcmp(envr, MINT_AUDIO_DRIVER_NAME)!=0)) {
DEBUG_PRINT((DEBUG_NAME "user asked a different audio driver\n"));
return(0);
}
/* Cookie _MCH present ? if not, assume ST machine */
if (Getcookie(C__MCH, &cookie_mch) == C_NOTFOUND) {
cookie_mch = MCH_ST;
}
/* Cookie _SND present ? if not, assume ST machine */
if (Getcookie(C__SND, &cookie_snd) == C_NOTFOUND) {
cookie_snd = SND_PSG;
}
/* Cookie STFA present ? */
if (Getcookie(C_STFA, &dummy) != C_FOUND) {
DEBUG_PRINT((DEBUG_NAME "no STFA audio\n"));
return(0);
}
cookie_stfa = (cookie_stfa_t *) dummy;
SDL_MintAudio_stfa = cookie_stfa;
DEBUG_PRINT((DEBUG_NAME "STFA audio available!\n"));
return(1);
}
static void Audio_DeleteDevice(SDL_AudioDevice *device)
{
SDL_free(device->hidden);
SDL_free(device);
}
static SDL_AudioDevice *Audio_CreateDevice(int devindex)
{
SDL_AudioDevice *this;
/* Initialize all variables that we clean on shutdown */
this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
if ( this ) {
SDL_memset(this, 0, (sizeof *this));
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
}
if ( (this == NULL) || (this->hidden == NULL) ) {
SDL_OutOfMemory();
if ( this ) {
SDL_free(this);
}
return(0);
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
/* Set the function pointers */
this->OpenAudio = Mint_OpenAudio;
this->CloseAudio = Mint_CloseAudio;
this->LockAudio = Mint_LockAudio;
this->UnlockAudio = Mint_UnlockAudio;
this->free = Audio_DeleteDevice;
return this;
}
AudioBootStrap MINTAUDIO_STFA_bootstrap = {
MINT_AUDIO_DRIVER_NAME, "MiNT STFA audio driver",
Audio_Available, Audio_CreateDevice
};
static void Mint_LockAudio(_THIS)
{
void *oldpile;
/* Stop replay */
oldpile=(void *)Super(0);
cookie_stfa->sound_enable=STFA_PLAY_DISABLE;
SuperToUser(oldpile);
}
static void Mint_UnlockAudio(_THIS)
{
void *oldpile;
/* Restart replay */
oldpile=(void *)Super(0);
cookie_stfa->sound_enable=STFA_PLAY_ENABLE|STFA_PLAY_REPEAT;
SuperToUser(oldpile);
}
static void Mint_CloseAudio(_THIS)
{
void *oldpile;
/* Stop replay */
oldpile=(void *)Super(0);
cookie_stfa->sound_enable=STFA_PLAY_DISABLE;
SuperToUser(oldpile);
/* Wait if currently playing sound */
while (SDL_MintAudio_mutex != 0) {
}
/* Clear buffers */
if (SDL_MintAudio_audiobuf[0]) {
Mfree(SDL_MintAudio_audiobuf[0]);
SDL_MintAudio_audiobuf[0] = SDL_MintAudio_audiobuf[1] = NULL;
}
}
static int Mint_CheckAudio(_THIS, SDL_AudioSpec *spec)
{
int i;
DEBUG_PRINT((DEBUG_NAME "asked: %d bits, ",spec->format & 0x00ff));
DEBUG_PRINT(("signed=%d, ", ((spec->format & 0x8000)!=0)));
DEBUG_PRINT(("big endian=%d, ", ((spec->format & 0x1000)!=0)));
DEBUG_PRINT(("channels=%d, ", spec->channels));
DEBUG_PRINT(("freq=%d\n", spec->freq));
if (spec->channels > 2) {
spec->channels = 2; /* no more than stereo! */
}
/* Check formats available */
MINTAUDIO_freqcount=0;
for (i=0;i<16;i++) {
SDL_MintAudio_AddFrequency(this, freqs[i], 0, i, -1);
}
#if 1
for (i=0; i<MINTAUDIO_freqcount; i++) {
DEBUG_PRINT((DEBUG_NAME "freq %d: %lu Hz, clock %lu, prediv %d\n",
i, MINTAUDIO_frequencies[i].frequency, MINTAUDIO_frequencies[i].masterclock,
MINTAUDIO_frequencies[i].predivisor
));
}
#endif
MINTAUDIO_numfreq=SDL_MintAudio_SearchFrequency(this, spec->freq);
spec->freq=MINTAUDIO_frequencies[MINTAUDIO_numfreq].frequency;
DEBUG_PRINT((DEBUG_NAME "obtained: %d bits, ",spec->format & 0x00ff));
DEBUG_PRINT(("signed=%d, ", ((spec->format & 0x8000)!=0)));
DEBUG_PRINT(("big endian=%d, ", ((spec->format & 0x1000)!=0)));
DEBUG_PRINT(("channels=%d, ", spec->channels));
DEBUG_PRINT(("freq=%d\n", spec->freq));
return 0;
}
static void Mint_InitAudio(_THIS, SDL_AudioSpec *spec)
{
void *buffer;
void *oldpile;
buffer = SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf];
oldpile=(void *)Super(0);
/* Stop replay */
cookie_stfa->sound_enable=STFA_PLAY_DISABLE;
/* Select replay format */
cookie_stfa->sound_control = MINTAUDIO_frequencies[MINTAUDIO_numfreq].predivisor;
if ((spec->format & 0xff)==8) {
cookie_stfa->sound_control |= STFA_FORMAT_8BIT;
} else {
cookie_stfa->sound_control |= STFA_FORMAT_16BIT;
}
if (spec->channels==2) {
cookie_stfa->sound_control |= STFA_FORMAT_STEREO;
} else {
cookie_stfa->sound_control |= STFA_FORMAT_MONO;
}
if ((spec->format & 0x8000)!=0) {
cookie_stfa->sound_control |= STFA_FORMAT_SIGNED;
} else {
cookie_stfa->sound_control |= STFA_FORMAT_UNSIGNED;
}
if ((spec->format & 0x1000)!=0) {
cookie_stfa->sound_control |= STFA_FORMAT_BIGENDIAN;
} else {
cookie_stfa->sound_control |= STFA_FORMAT_LITENDIAN;
}
/* Set buffer */
cookie_stfa->sound_start = (unsigned long) buffer;
cookie_stfa->sound_end = (unsigned long) (buffer + spec->size);
/* Set interrupt */
cookie_stfa->stfa_it = SDL_MintAudio_StfaInterrupt;
/* Restart replay */
cookie_stfa->sound_enable=STFA_PLAY_ENABLE|STFA_PLAY_REPEAT;
SuperToUser(oldpile);
DEBUG_PRINT((DEBUG_NAME "hardware initialized\n"));
}
static int Mint_OpenAudio(_THIS, SDL_AudioSpec *spec)
{
SDL_MintAudio_device = this;
/* Check audio capabilities */
if (Mint_CheckAudio(this, spec)==-1) {
return -1;
}
SDL_CalculateAudioSpec(spec);
/* Allocate memory for audio buffers in DMA-able RAM */
DEBUG_PRINT((DEBUG_NAME "buffer size=%d\n", spec->size));
SDL_MintAudio_audiobuf[0] = Atari_SysMalloc(spec->size *2, MX_STRAM);
if (SDL_MintAudio_audiobuf[0]==NULL) {
SDL_SetError("MINT_OpenAudio: Not enough memory for audio buffer");
return (-1);
}
SDL_MintAudio_audiobuf[1] = SDL_MintAudio_audiobuf[0] + spec->size ;
SDL_MintAudio_numbuf=0;
SDL_memset(SDL_MintAudio_audiobuf[0], spec->silence, spec->size *2);
SDL_MintAudio_audiosize = spec->size;
SDL_MintAudio_mutex = 0;
DEBUG_PRINT((DEBUG_NAME "buffer 0 at 0x%08x\n", SDL_MintAudio_audiobuf[0]));
DEBUG_PRINT((DEBUG_NAME "buffer 1 at 0x%08x\n", SDL_MintAudio_audiobuf[1]));
SDL_MintAudio_CheckFpu();
/* Setup audio hardware */
Mint_InitAudio(this, spec);
return(1); /* We don't use threaded audio */
}

View file

@ -1,97 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
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 library 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
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
/*
STFA control structure
Patrice Mandin
*/
#ifndef _SDL_mintaudio_stfa_h
#define _SDL_mintaudio_stfa_h
/*--- Defines ---*/
#define STFA_PLAY_ENABLE (1<<0)
#define STFA_PLAY_DISABLE (0<<0)
#define STFA_PLAY_REPEAT (1<<1)
#define STFA_PLAY_SINGLE (0<<1)
#define STFA_FORMAT_SIGNED (1<<15)
#define STFA_FORMAT_UNSIGNED (0<<15)
#define STFA_FORMAT_STEREO (1<<14)
#define STFA_FORMAT_MONO (0<<14)
#define STFA_FORMAT_16BIT (1<<13)
#define STFA_FORMAT_8BIT (0<<13)
#define STFA_FORMAT_LITENDIAN (1<<9)
#define STFA_FORMAT_BIGENDIAN (0<<9)
#define STFA_FORMAT_FREQ_MASK 0x0f
enum {
STFA_FORMAT_F4995=0,
STFA_FORMAT_F6269,
STFA_FORMAT_F7493,
STFA_FORMAT_F8192,
STFA_FORMAT_F9830,
STFA_FORMAT_F10971,
STFA_FORMAT_F12538,
STFA_FORMAT_F14985,
STFA_FORMAT_F16384,
STFA_FORMAT_F19819,
STFA_FORMAT_F21943,
STFA_FORMAT_F24576,
STFA_FORMAT_F30720,
STFA_FORMAT_F32336,
STFA_FORMAT_F43885,
STFA_FORMAT_F49152
};
/*--- Types ---*/
typedef struct {
unsigned short sound_enable;
unsigned short sound_control;
unsigned short sound_output;
unsigned long sound_start;
unsigned long sound_current;
unsigned long sound_end;
unsigned short version;
void *old_vbl;
void *old_timera;
unsigned long old_mfp_status;
void *new_vbl;
void *drivers_list;
void *play_stop;
unsigned short frequency;
void *set_frequency;
unsigned short frequency_threshold;
unsigned short *custom_freq_table;
unsigned short stfa_on_off;
void *new_drivers_list;
unsigned long old_bit_2_of_cookie_snd;
void (*stfa_it)(void);
} cookie_stfa_t;
#endif /* _SDL_mintaudio_stfa_h */

View file

@ -1,490 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
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 library 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
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
/*
MiNT audio driver
using XBIOS functions (Falcon)
Patrice Mandin, Didier Méquignon
*/
#include <unistd.h>
#include <support.h>
/* Mint includes */
#include <mint/osbind.h>
#include <mint/falcon.h>
#include <mint/cookie.h>
#include "SDL_audio.h"
#include "../SDL_audio_c.h"
#include "../SDL_sysaudio.h"
#include "../../video/ataricommon/SDL_atarimxalloc_c.h"
#include "../../video/ataricommon/SDL_atarisuper.h"
#include "SDL_mintaudio.h"
#include "SDL_mintaudio_dma8.h"
/*--- Defines ---*/
#define MINT_AUDIO_DRIVER_NAME "mint_xbios"
/* Debug print info */
#define DEBUG_NAME "audio:xbios: "
#if 0
#define DEBUG_PRINT(what) \
{ \
printf what; \
}
#else
#define DEBUG_PRINT(what)
#endif
/*--- Static variables ---*/
static long cookie_snd;
/*--- Audio driver functions ---*/
static void Mint_CloseAudio(_THIS);
static int Mint_OpenAudio(_THIS, SDL_AudioSpec *spec);
static void Mint_LockAudio(_THIS);
static void Mint_UnlockAudio(_THIS);
/* To check/init hardware audio */
static int Mint_CheckAudio(_THIS, SDL_AudioSpec *spec);
static void Mint_InitAudio(_THIS, SDL_AudioSpec *spec);
/*--- Audio driver bootstrap functions ---*/
static int Audio_Available(void)
{
/* unsigned long dummy;*/
const char *envr = SDL_getenv("SDL_AUDIODRIVER");
/*SDL_MintAudio_mint_present = (Getcookie(C_MiNT, &dummy) == C_FOUND);*/
SDL_MintAudio_mint_present = SDL_FALSE;
/* We can't use XBIOS in interrupt with Magic, don't know about thread */
/*if (Getcookie(C_MagX, &dummy) == C_FOUND) {
return(0);
}*/
/* Check if user asked a different audio driver */
if ((envr) && (SDL_strcmp(envr, MINT_AUDIO_DRIVER_NAME)!=0)) {
DEBUG_PRINT((DEBUG_NAME "user asked a different audio driver\n"));
return(0);
}
/* Cookie _SND present ? if not, assume ST machine */
if (Getcookie(C__SND, &cookie_snd) == C_NOTFOUND) {
cookie_snd = SND_PSG;
}
/* Check if we have 16 bits audio */
if ((cookie_snd & SND_16BIT)==0) {
DEBUG_PRINT((DEBUG_NAME "no 16 bits sound\n"));
return(0);
}
/* Check if audio is lockable */
if (Locksnd()!=1) {
DEBUG_PRINT((DEBUG_NAME "audio locked by other application\n"));
return(0);
}
Unlocksnd();
DEBUG_PRINT((DEBUG_NAME "XBIOS audio available!\n"));
return(1);
}
static void Audio_DeleteDevice(SDL_AudioDevice *device)
{
SDL_free(device->hidden);
SDL_free(device);
}
static SDL_AudioDevice *Audio_CreateDevice(int devindex)
{
SDL_AudioDevice *this;
/* Initialize all variables that we clean on shutdown */
this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
if ( this ) {
SDL_memset(this, 0, (sizeof *this));
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
}
if ( (this == NULL) || (this->hidden == NULL) ) {
SDL_OutOfMemory();
if ( this ) {
SDL_free(this);
}
return(0);
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
/* Set the function pointers */
this->OpenAudio = Mint_OpenAudio;
this->CloseAudio = Mint_CloseAudio;
this->LockAudio = Mint_LockAudio;
this->UnlockAudio = Mint_UnlockAudio;
this->free = Audio_DeleteDevice;
return this;
}
AudioBootStrap MINTAUDIO_XBIOS_bootstrap = {
MINT_AUDIO_DRIVER_NAME, "MiNT XBIOS audio driver",
Audio_Available, Audio_CreateDevice
};
static void Mint_LockAudio(_THIS)
{
/* Stop replay */
Buffoper(0);
}
static void Mint_UnlockAudio(_THIS)
{
/* Restart replay */
Buffoper(SB_PLA_ENA|SB_PLA_RPT);
}
static void Mint_CloseAudio(_THIS)
{
/* Stop replay */
SDL_MintAudio_WaitThread();
Buffoper(0);
if (!SDL_MintAudio_mint_present) {
/* Uninstall interrupt */
Jdisint(MFP_DMASOUND);
}
/* Wait if currently playing sound */
while (SDL_MintAudio_mutex != 0) {
}
/* Clear buffers */
if (SDL_MintAudio_audiobuf[0]) {
Mfree(SDL_MintAudio_audiobuf[0]);
SDL_MintAudio_audiobuf[0] = SDL_MintAudio_audiobuf[1] = NULL;
}
/* Unlock sound system */
Unlocksnd();
}
/* Falcon XBIOS implementation of Devconnect() is buggy with external clock */
static void Devconnect2(int src, int dst, int sclk, int pre)
{
static const unsigned short MASK1[3] = { 0, 0x6000, 0 };
static const unsigned short MASK2[4] = { 0xFFF0, 0xFF8F, 0xF0FF, 0x0FFF };
static const unsigned short INDEX1[4] = { 1, 3, 5, 7 };
static const unsigned short INDEX2[4] = { 0, 2, 4, 6 };
unsigned short sync_div,dev_ctrl,dest_ctrl;
void *oldstack;
if (dst==0) {
return;
}
oldstack=(void *)Super(0);
dev_ctrl = DMAAUDIO_IO.dev_ctrl;
dest_ctrl = DMAAUDIO_IO.dest_ctrl;
dev_ctrl &= MASK2[src];
if (src==ADC) {
dev_ctrl |= MASK1[sclk];
} else {
dev_ctrl |= (INDEX1[sclk] << (src<<4));
}
if (dst & DMAREC) {
dest_ctrl &= 0xFFF0;
dest_ctrl |= INDEX1[src];
}
if (dst & DSPRECV) {
dest_ctrl &= 0xFF8F;
dest_ctrl |= (INDEX1[src]<<4);
}
if (dst & EXTOUT) {
dest_ctrl &= 0xF0FF;
dest_ctrl |= (INDEX1[src]<<8);
}
if (dst & DAC) {
dev_ctrl &= 0x0FFF;
dev_ctrl |= MASK1[sclk];
dest_ctrl &= 0x0FFF;
dest_ctrl |= (INDEX2[src]<<12);
}
sync_div = DMAAUDIO_IO.sync_div;
if (sclk==CLKEXT) {
pre<<=8;
sync_div &= 0xF0FF;
} else {
sync_div &= 0xFFF0;
}
sync_div |= pre;
DMAAUDIO_IO.dev_ctrl = dev_ctrl;
DMAAUDIO_IO.dest_ctrl = dest_ctrl;
DMAAUDIO_IO.sync_div = sync_div;
SuperToUser(oldstack);
}
static void Mint_CheckExternalClock(_THIS)
{
#define SIZE_BUF_CLOCK_MEASURE (44100/10)
char *buffer;
int i, j;
/* DSP present with its GPIO port ? */
if ((cookie_snd & SND_DSP)==0) {
return;
}
buffer = Atari_SysMalloc(SIZE_BUF_CLOCK_MEASURE, MX_STRAM);
if (buffer==NULL) {
DEBUG_PRINT((DEBUG_NAME "Not enough memory for the measure\n"));
return;
}
SDL_memset(buffer, 0, SIZE_BUF_CLOCK_MEASURE);
Buffoper(0);
Settracks(0,0);
Setmontracks(0);
Setmode(MONO8);
Jdisint(MFP_TIMERA);
for (i=0; i<2; i++) {
Gpio(GPIO_SET,7); /* DSP port gpio outputs */
Gpio(GPIO_WRITE,2+i); /* 22.5792/24.576 MHz for 44.1/48KHz */
Devconnect2(DMAPLAY, DAC, CLKEXT, CLK50K); /* Matrix and clock source */
Setbuffer(0, buffer, buffer + SIZE_BUF_CLOCK_MEASURE); /* Set buffer */
Xbtimer(XB_TIMERA, 5, 38, SDL_MintAudio_XbiosInterruptMeasureClock); /* delay mode timer A, prediv /64, 1KHz */
Jenabint(MFP_TIMERA);
SDL_MintAudio_clocktics = 0;
Buffoper(SB_PLA_ENA);
usleep(110000);
if((Buffoper(-1) & 1)==0) {
if (SDL_MintAudio_clocktics) {
unsigned long khz;
khz = ((SIZE_BUF_CLOCK_MEASURE/SDL_MintAudio_clocktics) +1) & 0xFFFFFFFE;
DEBUG_PRINT((DEBUG_NAME "measure %d: freq=%lu KHz\n", i+1, khz));
if(khz==44) {
for (j=1; j<4; j++) {
SDL_MintAudio_AddFrequency(this, MASTERCLOCK_44K/(MASTERPREDIV_FALCON*(1<<j)), MASTERCLOCK_44K, (1<<j)-1, 2+i);
}
} else if (khz==48) {
for (j=1; j<4; j++) {
SDL_MintAudio_AddFrequency(this, MASTERCLOCK_48K/(MASTERPREDIV_FALCON*(1<<j)), MASTERCLOCK_48K, (1<<j)-1, 2+i);
}
}
} else {
DEBUG_PRINT((DEBUG_NAME "No measure\n"));
}
} else {
DEBUG_PRINT((DEBUG_NAME "No SDMA clock\n"));
}
Buffoper(0); /* stop */
Jdisint(MFP_TIMERA); /* Uninstall interrupt */
}
Mfree(buffer);
}
static int Mint_CheckAudio(_THIS, SDL_AudioSpec *spec)
{
int i;
DEBUG_PRINT((DEBUG_NAME "asked: %d bits, ",spec->format & 0x00ff));
DEBUG_PRINT(("signed=%d, ", ((spec->format & 0x8000)!=0)));
DEBUG_PRINT(("big endian=%d, ", ((spec->format & 0x1000)!=0)));
DEBUG_PRINT(("channels=%d, ", spec->channels));
DEBUG_PRINT(("freq=%d\n", spec->freq));
if (spec->channels > 2) {
spec->channels = 2; /* no more than stereo! */
}
spec->format |= 0x8000; /* Audio is always signed */
if ((spec->format & 0x00ff)==16) {
spec->format |= 0x1000; /* Audio is always big endian */
spec->channels=2; /* 16 bits always stereo */
}
MINTAUDIO_freqcount=0;
/* Add external clocks if present */
Mint_CheckExternalClock(this);
/* Standard clocks */
for (i=1;i<12;i++) {
/* Remove unusable Falcon codec predivisors */
if ((i==6) || (i==8) || (i==10)) {
continue;
}
SDL_MintAudio_AddFrequency(this, MASTERCLOCK_FALCON1/(MASTERPREDIV_FALCON*(i+1)), MASTERCLOCK_FALCON1, i, -1);
}
#if 1
for (i=0; i<MINTAUDIO_freqcount; i++) {
DEBUG_PRINT((DEBUG_NAME "freq %d: %lu Hz, clock %lu, prediv %d\n",
i, MINTAUDIO_frequencies[i].frequency, MINTAUDIO_frequencies[i].masterclock,
MINTAUDIO_frequencies[i].predivisor
));
}
#endif
MINTAUDIO_numfreq=SDL_MintAudio_SearchFrequency(this, spec->freq);
spec->freq=MINTAUDIO_frequencies[MINTAUDIO_numfreq].frequency;
DEBUG_PRINT((DEBUG_NAME "obtained: %d bits, ",spec->format & 0x00ff));
DEBUG_PRINT(("signed=%d, ", ((spec->format & 0x8000)!=0)));
DEBUG_PRINT(("big endian=%d, ", ((spec->format & 0x1000)!=0)));
DEBUG_PRINT(("channels=%d, ", spec->channels));
DEBUG_PRINT(("freq=%d\n", spec->freq));
return 0;
}
static void Mint_InitAudio(_THIS, SDL_AudioSpec *spec)
{
int channels_mode, prediv;
void *buffer;
/* Stop currently playing sound */
SDL_MintAudio_quit_thread = SDL_FALSE;
SDL_MintAudio_thread_finished = SDL_TRUE;
SDL_MintAudio_WaitThread();
Buffoper(0);
/* Set replay tracks */
Settracks(0,0);
Setmontracks(0);
/* Select replay format */
channels_mode=STEREO16;
switch (spec->format & 0xff) {
case 8:
if (spec->channels==2) {
channels_mode=STEREO8;
} else {
channels_mode=MONO8;
}
break;
}
if (Setmode(channels_mode)<0) {
DEBUG_PRINT((DEBUG_NAME "Setmode() failed\n"));
}
prediv = MINTAUDIO_frequencies[MINTAUDIO_numfreq].predivisor;
if (MINTAUDIO_frequencies[MINTAUDIO_numfreq].gpio_bits != -1) {
Gpio(GPIO_SET,7); /* DSP port gpio outputs */
Gpio(GPIO_WRITE, MINTAUDIO_frequencies[MINTAUDIO_numfreq].gpio_bits);
Devconnect2(DMAPLAY, DAC|EXTOUT, CLKEXT, prediv);
} else {
Devconnect2(DMAPLAY, DAC, CLK25M, prediv);
}
/* Set buffer */
buffer = SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf];
if (Setbuffer(0, buffer, buffer + spec->size)<0) {
DEBUG_PRINT((DEBUG_NAME "Setbuffer() failed\n"));
}
if (SDL_MintAudio_mint_present) {
SDL_MintAudio_thread_pid = tfork(SDL_MintAudio_Thread, 0);
} else {
/* Install interrupt */
Jdisint(MFP_DMASOUND);
/*Xbtimer(XB_TIMERA, 8, 1, SDL_MintAudio_XbiosInterrupt);*/
Xbtimer(XB_TIMERA, 8, 1, SDL_MintAudio_Dma8Interrupt);
Jenabint(MFP_DMASOUND);
if (Setinterrupt(SI_TIMERA, SI_PLAY)<0) {
DEBUG_PRINT((DEBUG_NAME "Setinterrupt() failed\n"));
}
}
/* Go */
Buffoper(SB_PLA_ENA|SB_PLA_RPT);
DEBUG_PRINT((DEBUG_NAME "hardware initialized\n"));
}
static int Mint_OpenAudio(_THIS, SDL_AudioSpec *spec)
{
/* Lock sound system */
if (Locksnd()!=1) {
SDL_SetError("Mint_OpenAudio: Audio system already in use");
return(-1);
}
SDL_MintAudio_device = this;
/* Check audio capabilities */
if (Mint_CheckAudio(this, spec)==-1) {
return -1;
}
SDL_CalculateAudioSpec(spec);
/* Allocate memory for audio buffers in DMA-able RAM */
DEBUG_PRINT((DEBUG_NAME "buffer size=%d\n", spec->size));
SDL_MintAudio_audiobuf[0] = Atari_SysMalloc(spec->size *2, MX_STRAM);
if (SDL_MintAudio_audiobuf[0]==NULL) {
SDL_SetError("MINT_OpenAudio: Not enough memory for audio buffer");
return (-1);
}
SDL_MintAudio_audiobuf[1] = SDL_MintAudio_audiobuf[0] + spec->size ;
SDL_MintAudio_numbuf=0;
SDL_memset(SDL_MintAudio_audiobuf[0], spec->silence, spec->size *2);
SDL_MintAudio_audiosize = spec->size;
SDL_MintAudio_mutex = 0;
DEBUG_PRINT((DEBUG_NAME "buffer 0 at 0x%08x\n", SDL_MintAudio_audiobuf[0]));
DEBUG_PRINT((DEBUG_NAME "buffer 1 at 0x%08x\n", SDL_MintAudio_audiobuf[1]));
SDL_MintAudio_CheckFpu();
/* Setup audio hardware */
Mint_InitAudio(this, spec);
return(1); /* We don't use SDL threaded audio */
}

View file

@ -1,264 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
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 library 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
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
/* Tru64 UNIX MME support */
#include <mme_api.h>
#include "SDL_timer.h"
#include "SDL_audio.h"
#include "../SDL_audio_c.h"
#include "SDL_mmeaudio.h"
static BOOL inUse[NUM_BUFFERS];
/* Audio driver functions */
static int MME_OpenAudio(_THIS, SDL_AudioSpec *spec);
static void MME_WaitAudio(_THIS);
static Uint8 *MME_GetAudioBuf(_THIS);
static void MME_PlayAudio(_THIS);
static void MME_WaitDone(_THIS);
static void MME_CloseAudio(_THIS);
/* Audio driver bootstrap functions */
static int Audio_Available(void)
{
return(1);
}
static void Audio_DeleteDevice(SDL_AudioDevice *device)
{
if ( device ) {
if ( device->hidden ) {
SDL_free(device->hidden);
device->hidden = NULL;
}
SDL_free(device);
device = NULL;
}
}
static SDL_AudioDevice *Audio_CreateDevice(int devindex)
{
SDL_AudioDevice *this;
/* Initialize all variables that we clean on shutdown */
this = SDL_malloc(sizeof(SDL_AudioDevice));
if ( this ) {
SDL_memset(this, 0, (sizeof *this));
this->hidden = SDL_malloc((sizeof *this->hidden));
}
if ( (this == NULL) || (this->hidden == NULL) ) {
SDL_OutOfMemory();
if ( this ) {
SDL_free(this);
}
return(0);
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
/* Set the function pointers */
this->OpenAudio = MME_OpenAudio;
this->WaitAudio = MME_WaitAudio;
this->PlayAudio = MME_PlayAudio;
this->GetAudioBuf = MME_GetAudioBuf;
this->WaitDone = MME_WaitDone;
this->CloseAudio = MME_CloseAudio;
this->free = Audio_DeleteDevice;
return this;
}
AudioBootStrap MMEAUDIO_bootstrap = {
"waveout", "Tru64 MME WaveOut",
Audio_Available, Audio_CreateDevice
};
static void SetMMerror(char *function, MMRESULT code)
{
int len;
char errbuf[MAXERRORLENGTH];
SDL_snprintf(errbuf, SDL_arraysize(errbuf), "%s: ", function);
len = SDL_strlen(errbuf);
waveOutGetErrorText(code, errbuf+len, MAXERRORLENGTH-len);
SDL_SetError("%s",errbuf);
}
static void CALLBACK MME_CALLBACK(HWAVEOUT hwo,
UINT uMsg,
DWORD dwInstance,
LPARAM dwParam1,
LPARAM dwParam2)
{
WAVEHDR *wp = (WAVEHDR *) dwParam1;
if ( uMsg == WOM_DONE )
inUse[wp->dwUser] = FALSE;
}
static int MME_OpenAudio(_THIS, SDL_AudioSpec *spec)
{
MMRESULT result;
int i;
mixbuf = NULL;
/* Set basic WAVE format parameters */
shm = mmeAllocMem(sizeof(*shm));
if ( shm == NULL ) {
SDL_SetError("Out of memory: shm");
return(-1);
}
shm->sound = 0;
shm->wFmt.wf.wFormatTag = WAVE_FORMAT_PCM;
/* Determine the audio parameters from the AudioSpec */
switch ( spec->format & 0xFF ) {
case 8:
/* Unsigned 8 bit audio data */
spec->format = AUDIO_U8;
shm->wFmt.wBitsPerSample = 8;
break;
case 16:
/* Signed 16 bit audio data */
spec->format = AUDIO_S16;
shm->wFmt.wBitsPerSample = 16;
break;
default:
SDL_SetError("Unsupported audio format");
return(-1);
}
shm->wFmt.wf.nChannels = spec->channels;
shm->wFmt.wf.nSamplesPerSec = spec->freq;
shm->wFmt.wf.nBlockAlign =
shm->wFmt.wf.nChannels * shm->wFmt.wBitsPerSample / 8;
shm->wFmt.wf.nAvgBytesPerSec =
shm->wFmt.wf.nSamplesPerSec * shm->wFmt.wf.nBlockAlign;
/* Check the buffer size -- minimum of 1/4 second (word aligned) */
if ( spec->samples < (spec->freq/4) )
spec->samples = ((spec->freq/4)+3)&~3;
/* Update the fragment size as size in bytes */
SDL_CalculateAudioSpec(spec);
/* Open the audio device */
result = waveOutOpen(&(shm->sound),
WAVE_MAPPER,
&(shm->wFmt.wf),
MME_CALLBACK,
NULL,
(CALLBACK_FUNCTION|WAVE_OPEN_SHAREABLE));
if ( result != MMSYSERR_NOERROR ) {
SetMMerror("waveOutOpen()", result);
return(-1);
}
/* Create the sound buffers */
mixbuf = (Uint8 *)mmeAllocBuffer(NUM_BUFFERS * (spec->size));
if ( mixbuf == NULL ) {
SDL_SetError("Out of memory: mixbuf");
return(-1);
}
for (i = 0; i < NUM_BUFFERS; i++) {
shm->wHdr[i].lpData = &mixbuf[i * (spec->size)];
shm->wHdr[i].dwBufferLength = spec->size;
shm->wHdr[i].dwFlags = 0;
shm->wHdr[i].dwUser = i;
shm->wHdr[i].dwLoops = 0; /* loop control counter */
shm->wHdr[i].lpNext = NULL; /* reserved for driver */
shm->wHdr[i].reserved = 0;
inUse[i] = FALSE;
}
next_buffer = 0;
return 0;
}
static void MME_WaitAudio(_THIS)
{
while ( inUse[next_buffer] ) {
mmeWaitForCallbacks();
mmeProcessCallbacks();
}
}
static Uint8 *MME_GetAudioBuf(_THIS)
{
Uint8 *retval;
inUse[next_buffer] = TRUE;
retval = (Uint8 *)(shm->wHdr[next_buffer].lpData);
return retval;
}
static void MME_PlayAudio(_THIS)
{
/* Queue it up */
waveOutWrite(shm->sound, &(shm->wHdr[next_buffer]), sizeof(WAVEHDR));
next_buffer = (next_buffer+1)%NUM_BUFFERS;
}
static void MME_WaitDone(_THIS)
{
MMRESULT result;
int i;
if ( shm->sound ) {
for (i = 0; i < NUM_BUFFERS; i++)
while ( inUse[i] ) {
mmeWaitForCallbacks();
mmeProcessCallbacks();
}
result = waveOutReset(shm->sound);
if ( result != MMSYSERR_NOERROR )
SetMMerror("waveOutReset()", result);
mmeProcessCallbacks();
}
}
static void MME_CloseAudio(_THIS)
{
MMRESULT result;
if ( mixbuf ) {
result = mmeFreeBuffer(mixbuf);
if (result != MMSYSERR_NOERROR )
SetMMerror("mmeFreeBuffer", result);
mixbuf = NULL;
}
if ( shm ) {
if ( shm->sound ) {
result = waveOutClose(shm->sound);
if (result != MMSYSERR_NOERROR )
SetMMerror("waveOutClose()", result);
mmeProcessCallbacks();
}
result = mmeFreeMem(shm);
if (result != MMSYSERR_NOERROR )
SetMMerror("mmeFreeMem()", result);
shm = NULL;
}
}

View file

@ -1,51 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
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 library 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
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
/* Allow access to a raw mixing buffer */
#ifndef _SDL_lowaudio_h
#define _SDL_lowaudio_h
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the video functions */
#define _THIS SDL_AudioDevice *this
#define NUM_BUFFERS 2
struct SharedMem {
HWAVEOUT sound;
WAVEHDR wHdr[NUM_BUFFERS];
PCMWAVEFORMAT wFmt;
};
struct SDL_PrivateAudioData {
Uint8 *mixbuf; /* The raw allocated mixing buffer */
struct SharedMem *shm;
int next_buffer;
};
#define shm (this->hidden->shm)
#define mixbuf (this->hidden->mixbuf)
#define next_buffer (this->hidden->next_buffer)
/* Old variable names */
#endif /* _SDL_lowaudio_h */

View file

@ -1,423 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
This driver was written by:
Erik Inge Bolsø
knan@mo.himolde.no
*/
#include "SDL_config.h"
/* Allow access to a raw mixing buffer */
#include <signal.h>
#include <unistd.h>
#include "SDL_timer.h"
#include "SDL_audio.h"
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
#include "../SDL_audiodev_c.h"
#include "SDL_nasaudio.h"
#ifdef SDL_AUDIO_DRIVER_NAS_DYNAMIC
#include "SDL_loadso.h"
#endif
/* The tag name used by artsc audio */
#define NAS_DRIVER_NAME "nas"
static struct SDL_PrivateAudioData *this2 = NULL;
static void (*NAS_AuCloseServer) (AuServer *);
static void (*NAS_AuNextEvent) (AuServer *, AuBool, AuEvent *);
static AuBool(*NAS_AuDispatchEvent) (AuServer *, AuEvent *);
static AuFlowID(*NAS_AuCreateFlow) (AuServer *, AuStatus *);
static void (*NAS_AuStartFlow) (AuServer *, AuFlowID, AuStatus *);
static void (*NAS_AuSetElements)
(AuServer *, AuFlowID, AuBool, int, AuElement *, AuStatus *);
static void (*NAS_AuWriteElement)
(AuServer *, AuFlowID, int, AuUint32, AuPointer, AuBool, AuStatus *);
static AuServer *(*NAS_AuOpenServer)
(_AuConst char *, int, _AuConst char *, int, _AuConst char *, char **);
static AuEventHandlerRec *(*NAS_AuRegisterEventHandler)
(AuServer *, AuMask, int, AuID, AuEventHandlerCallback, AuPointer);
#ifdef SDL_AUDIO_DRIVER_NAS_DYNAMIC
static const char *nas_library = SDL_AUDIO_DRIVER_NAS_DYNAMIC;
static void *nas_handle = NULL;
static int
load_nas_sym(const char *fn, void **addr)
{
*addr = SDL_LoadFunction(nas_handle, fn);
if (*addr == NULL) {
return 0;
}
return 1;
}
/* cast funcs to char* first, to please GCC's strict aliasing rules. */
#define SDL_NAS_SYM(x) \
if (!load_nas_sym(#x, (void **) (char *) &NAS_##x)) return -1
#else
#define SDL_NAS_SYM(x) NAS_##x = x
#endif
static int
load_nas_syms(void)
{
SDL_NAS_SYM(AuCloseServer);
SDL_NAS_SYM(AuNextEvent);
SDL_NAS_SYM(AuDispatchEvent);
SDL_NAS_SYM(AuCreateFlow);
SDL_NAS_SYM(AuStartFlow);
SDL_NAS_SYM(AuSetElements);
SDL_NAS_SYM(AuWriteElement);
SDL_NAS_SYM(AuOpenServer);
SDL_NAS_SYM(AuRegisterEventHandler);
return 0;
}
#undef SDL_NAS_SYM
#ifdef SDL_AUDIO_DRIVER_NAS_DYNAMIC
static void
UnloadNASLibrary(void)
{
if (nas_handle != NULL) {
SDL_UnloadObject(nas_handle);
nas_handle = NULL;
}
}
static int
LoadNASLibrary(void)
{
int retval = 0;
if (nas_handle == NULL) {
nas_handle = SDL_LoadObject(nas_library);
if (nas_handle == NULL) {
/* Copy error string so we can use it in a new SDL_SetError(). */
char *origerr = SDL_GetError();
size_t len = SDL_strlen(origerr) + 1;
char *err = (char *) alloca(len);
SDL_strlcpy(err, origerr, len);
retval = -1;
SDL_SetError("NAS: SDL_LoadObject('%s') failed: %s\n",
nas_library, err);
} else {
retval = load_nas_syms();
if (retval < 0) {
UnloadNASLibrary();
}
}
}
return retval;
}
#else
static void
UnloadNASLibrary(void)
{
}
static int
LoadNASLibrary(void)
{
load_nas_syms();
return 0;
}
#endif /* SDL_AUDIO_DRIVER_NAS_DYNAMIC */
/* Audio driver functions */
static int NAS_OpenAudio(_THIS, SDL_AudioSpec *spec);
static void NAS_WaitAudio(_THIS);
static void NAS_PlayAudio(_THIS);
static Uint8 *NAS_GetAudioBuf(_THIS);
static void NAS_CloseAudio(_THIS);
/* Audio driver bootstrap functions */
static int Audio_Available(void)
{
if (LoadNASLibrary() == 0) {
AuServer *aud = NAS_AuOpenServer("", 0, NULL, 0, NULL, NULL);
if (!aud) {
UnloadNASLibrary();
return 0;
}
NAS_AuCloseServer(aud);
UnloadNASLibrary();
return 1;
}
return 0;
}
static void Audio_DeleteDevice(SDL_AudioDevice *device)
{
UnloadNASLibrary();
SDL_free(device->hidden);
SDL_free(device);
}
static SDL_AudioDevice *Audio_CreateDevice(int devindex)
{
SDL_AudioDevice *this;
if (LoadNASLibrary() < 0) {
return NULL;
}
/* Initialize all variables that we clean on shutdown */
this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
if ( this ) {
SDL_memset(this, 0, (sizeof *this));
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
}
if ( (this == NULL) || (this->hidden == NULL) ) {
SDL_OutOfMemory();
if ( this ) {
SDL_free(this);
}
return NULL;
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
/* Set the function pointers */
this->OpenAudio = NAS_OpenAudio;
this->WaitAudio = NAS_WaitAudio;
this->PlayAudio = NAS_PlayAudio;
this->GetAudioBuf = NAS_GetAudioBuf;
this->CloseAudio = NAS_CloseAudio;
this->free = Audio_DeleteDevice;
return this;
}
AudioBootStrap NAS_bootstrap = {
NAS_DRIVER_NAME, "Network Audio System",
Audio_Available, Audio_CreateDevice
};
/* This function waits until it is possible to write a full sound buffer */
static void NAS_WaitAudio(_THIS)
{
while ( this->hidden->buf_free < this->hidden->mixlen ) {
AuEvent ev;
NAS_AuNextEvent(this->hidden->aud, AuTrue, &ev);
NAS_AuDispatchEvent(this->hidden->aud, &ev);
}
}
static void NAS_PlayAudio(_THIS)
{
while (this->hidden->mixlen > this->hidden->buf_free) { /* We think the buffer is full? Yikes! Ask the server for events,
in the hope that some of them is LowWater events telling us more
of the buffer is free now than what we think. */
AuEvent ev;
NAS_AuNextEvent(this->hidden->aud, AuTrue, &ev);
NAS_AuDispatchEvent(this->hidden->aud, &ev);
}
this->hidden->buf_free -= this->hidden->mixlen;
/* Write the audio data */
NAS_AuWriteElement(this->hidden->aud, this->hidden->flow, 0, this->hidden->mixlen, this->hidden->mixbuf, AuFalse, NULL);
this->hidden->written += this->hidden->mixlen;
#ifdef DEBUG_AUDIO
fprintf(stderr, "Wrote %d bytes of audio data\n", this->hidden->mixlen);
#endif
}
static Uint8 *NAS_GetAudioBuf(_THIS)
{
return(this->hidden->mixbuf);
}
static void NAS_CloseAudio(_THIS)
{
if ( this->hidden->mixbuf != NULL ) {
SDL_FreeAudioMem(this->hidden->mixbuf);
this->hidden->mixbuf = NULL;
}
if ( this->hidden->aud ) {
NAS_AuCloseServer(this->hidden->aud);
this->hidden->aud = 0;
}
}
static unsigned char sdlformat_to_auformat(unsigned int fmt)
{
switch (fmt)
{
case AUDIO_U8:
return AuFormatLinearUnsigned8;
case AUDIO_S8:
return AuFormatLinearSigned8;
case AUDIO_U16LSB:
return AuFormatLinearUnsigned16LSB;
case AUDIO_U16MSB:
return AuFormatLinearUnsigned16MSB;
case AUDIO_S16LSB:
return AuFormatLinearSigned16LSB;
case AUDIO_S16MSB:
return AuFormatLinearSigned16MSB;
}
return AuNone;
}
static AuBool
event_handler(AuServer* aud, AuEvent* ev, AuEventHandlerRec* hnd)
{
switch (ev->type) {
case AuEventTypeElementNotify: {
AuElementNotifyEvent* event = (AuElementNotifyEvent *)ev;
switch (event->kind) {
case AuElementNotifyKindLowWater:
if (this2->buf_free >= 0) {
this2->really += event->num_bytes;
gettimeofday(&this2->last_tv, 0);
this2->buf_free += event->num_bytes;
} else {
this2->buf_free = event->num_bytes;
}
break;
case AuElementNotifyKindState:
switch (event->cur_state) {
case AuStatePause:
if (event->reason != AuReasonUser) {
if (this2->buf_free >= 0) {
this2->really += event->num_bytes;
gettimeofday(&this2->last_tv, 0);
this2->buf_free += event->num_bytes;
} else {
this2->buf_free = event->num_bytes;
}
}
break;
}
}
}
}
return AuTrue;
}
static AuDeviceID
find_device(_THIS, int nch)
{
/* These "Au" things are all macros, not functions... */
int i;
for (i = 0; i < AuServerNumDevices(this->hidden->aud); i++) {
if ((AuDeviceKind(AuServerDevice(this->hidden->aud, i)) ==
AuComponentKindPhysicalOutput) &&
AuDeviceNumTracks(AuServerDevice(this->hidden->aud, i)) == nch) {
return AuDeviceIdentifier(AuServerDevice(this->hidden->aud, i));
}
}
return AuNone;
}
static int NAS_OpenAudio(_THIS, SDL_AudioSpec *spec)
{
AuElement elms[3];
int buffer_size;
Uint16 test_format, format;
this->hidden->mixbuf = NULL;
/* Try for a closest match on audio format */
format = 0;
for ( test_format = SDL_FirstAudioFormat(spec->format);
! format && test_format; ) {
format = sdlformat_to_auformat(test_format);
if (format == AuNone) {
test_format = SDL_NextAudioFormat();
}
}
if ( format == 0 ) {
SDL_SetError("Couldn't find any hardware audio formats");
return(-1);
}
spec->format = test_format;
this->hidden->aud = NAS_AuOpenServer("", 0, NULL, 0, NULL, NULL);
if (this->hidden->aud == 0)
{
SDL_SetError("Couldn't open connection to NAS server");
return (-1);
}
this->hidden->dev = find_device(this, spec->channels);
if ((this->hidden->dev == AuNone) || (!(this->hidden->flow = NAS_AuCreateFlow(this->hidden->aud, NULL)))) {
NAS_AuCloseServer(this->hidden->aud);
this->hidden->aud = 0;
SDL_SetError("Couldn't find a fitting playback device on NAS server");
return (-1);
}
buffer_size = spec->freq;
if (buffer_size < 4096)
buffer_size = 4096;
if (buffer_size > 32768)
buffer_size = 32768; /* So that the buffer won't get unmanageably big. */
/* Calculate the final parameters for this audio specification */
SDL_CalculateAudioSpec(spec);
this2 = this->hidden;
/* These "Au" things without a NAS_ prefix are macros, not functions... */
AuMakeElementImportClient(elms, spec->freq, format, spec->channels, AuTrue,
buffer_size, buffer_size / 4, 0, NULL);
AuMakeElementExportDevice(elms+1, 0, this->hidden->dev, spec->freq,
AuUnlimitedSamples, 0, NULL);
NAS_AuSetElements(this->hidden->aud, this->hidden->flow, AuTrue, 2, elms, NULL);
NAS_AuRegisterEventHandler(this->hidden->aud, AuEventHandlerIDMask, 0, this->hidden->flow,
event_handler, (AuPointer) NULL);
NAS_AuStartFlow(this->hidden->aud, this->hidden->flow, NULL);
/* Allocate mixing buffer */
this->hidden->mixlen = spec->size;
this->hidden->mixbuf = (Uint8 *)SDL_AllocAudioMem(this->hidden->mixlen);
if ( this->hidden->mixbuf == NULL ) {
return(-1);
}
SDL_memset(this->hidden->mixbuf, spec->silence, spec->size);
/* Get the parent process id (we're the parent of the audio thread) */
this->hidden->parent = getpid();
/* We're ready to rock and roll. :-) */
return(0);
}

View file

@ -1,62 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
This driver was written by:
Erik Inge Bolsø
knan@mo.himolde.no
*/
#include "SDL_config.h"
#ifndef _SDL_nasaudio_h
#define _SDL_nasaudio_h
#ifdef __sgi
#include <nas/audiolib.h>
#else
#include <audio/audiolib.h>
#endif
#include <sys/time.h>
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the video functions */
#define _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData {
AuServer* aud;
AuFlowID flow;
AuDeviceID dev;
/* The parent process id, to detect when application quits */
pid_t parent;
/* Raw mixing buffer */
Uint8 *mixbuf;
int mixlen;
int written;
int really;
int bps;
struct timeval last_tv;
int buf_free;
};
#endif /* _SDL_nasaudio_h */

View file

@ -1,335 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
/* Allow access to a raw mixing buffer */
#include <nds.h>
#include "SDL.h"
#include "SDL_endian.h"
#include "SDL_timer.h"
#include "SDL_audio.h"
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
#include "SDL_ndsaudio.h"
#include "soundcommon.h"
/* Audio driver functions */
static int NDS_OpenAudio(_THIS, SDL_AudioSpec *spec);
static void NDS_WaitAudio(_THIS);
static void NDS_PlayAudio(_THIS);
static Uint8 *NDS_GetAudioBuf(_THIS);
static void NDS_CloseAudio(_THIS);
/* Audio driver bootstrap functions */
u32 framecounter = 0,soundoffset = 0;
static SDL_AudioDevice *sdl_nds_audiodevice;
//void SoundMixCallback(void *stream,u32 size)
//{
// //printf("SoundMixCallback\n");
//
// Uint8 *buffer;
//
// buffer = sdl_nds_audiodevice->hidden->mixbuf;
// memset(buffer, sdl_nds_audiodevice->spec.silence, size);
//
// if (!sdl_nds_audiodevice->paused){
//
//
// //if (sdl_nds_audiodevice->convert.needed) {
// // int silence;
//
// // if (sdl_nds_audiodevice->convert.src_format == AUDIO_U8 ) {
// // silence = 0x80;
// // } else {
// // silence = 0;
// // }
// // memset(sdl_nds_audiodevice->convert.buf, silence, sdl_nds_audiodevice->convert.len);
// // sdl_nds_audiodevice->spec.callback(sdl_nds_audiodevice->spec.userdata,
// // (Uint8 *)sdl_nds_audiodevice->convert.buf,sdl_nds_audiodevice->convert.len);
// // SDL_ConvertAudio(&sdl_nds_audiodevice->convert);
// // memcpy(buffer, sdl_nds_audiodevice->convert.buf, sdl_nds_audiodevice->convert.len_cvt);
// //} else
// {
// sdl_nds_audiodevice->spec.callback(sdl_nds_audiodevice->spec.userdata, buffer, size);
// //memcpy((Sint16 *)stream,buffer, size);
// }
//
// }
//
// if(soundsystem->format == 8)
// {
// int i;
// s32 *buffer32 = (s32 *)buffer;
// s32 *stream32 = (s32 *)stream;
// for(i=0;i<size/4;i++){ *stream32++ = buffer32[i] ^ 0x80808080;}
// //for(i = 0; i < size; i++)
// // ((s8*)stream)[i]=(buffer[i]^0x80);
// }
// else
// {
// int i;
// for(i = 0; i < size; i++){
// //((short*)stream)[i] =(short)buffer[i] << 8; // sound 8bit ---> buffer 16bit
// //if (buffer[i] &0x80)
// //((Sint16*)stream)[i] = 0xff00 | buffer[i];
// ((Sint16*)stream)[i] = (buffer[i] - 128) << 8;
//
// //else
// // ((Sint16*)stream)[i] = buffer[i];
// }
// //register signed char *pSrc =buffer;
// //register short *pDest =stream;
// //int x;
// // for (x=size; x>0; x--)
// // {
// // register short temp = (((short)*pSrc)-128)<<8;
// // pSrc++;
// // *pDest++ = temp;
// // }
//
// //memcpy((Sint16 *)stream,buffer, size);
// }
//}
void SoundMixCallback(void *stream,u32 len)
{
SDL_AudioDevice *audio = (SDL_AudioDevice *)sdl_nds_audiodevice;
/* Silence the buffer, since it's ours */
SDL_memset(stream, audio->spec.silence, len);
/* Only do soemthing if audio is enabled */
if ( ! audio->enabled )
return;
if ( ! audio->paused ) {
if ( audio->convert.needed ) {
//fprintf(stderr,"converting audio\n");
SDL_mutexP(audio->mixer_lock);
(*audio->spec.callback)(audio->spec.userdata,
(Uint8 *)audio->convert.buf,audio->convert.len);
SDL_mutexV(audio->mixer_lock);
SDL_ConvertAudio(&audio->convert);
SDL_memcpy(stream,audio->convert.buf,audio->convert.len_cvt);
} else {
SDL_mutexP(audio->mixer_lock);
(*audio->spec.callback)(audio->spec.userdata,
(Uint8 *)stream, len);
SDL_mutexV(audio->mixer_lock);
}
}
return;
}
void MixSound(void)
{
int remain;
if(soundsystem->format == 8)
{
if((soundsystem->soundcursor + soundsystem->numsamples) > soundsystem->buffersize)
{
SoundMixCallback(&soundsystem->mixbuffer[soundsystem->soundcursor],soundsystem->buffersize - soundsystem->soundcursor);
remain = soundsystem->numsamples - (soundsystem->buffersize - soundsystem->soundcursor);
SoundMixCallback(soundsystem->mixbuffer,remain);
}
else
{
SoundMixCallback(&soundsystem->mixbuffer[soundsystem->soundcursor],soundsystem->numsamples);
}
}
else
{
if((soundsystem->soundcursor + soundsystem->numsamples) > (soundsystem->buffersize >> 1))
{
SoundMixCallback(&soundsystem->mixbuffer[soundsystem->soundcursor << 1],(soundsystem->buffersize >> 1) - soundsystem->soundcursor);
remain = soundsystem->numsamples - ((soundsystem->buffersize >> 1) - soundsystem->soundcursor);
SoundMixCallback(soundsystem->mixbuffer,remain);
}
else
{
SoundMixCallback(&soundsystem->mixbuffer[soundsystem->soundcursor << 1],soundsystem->numsamples);
}
}
}
void InterruptHandler(void)
{
framecounter++;
}
void FiFoHandler(void)
{
u32 command;
while ( !(REG_IPC_FIFO_CR & (IPC_FIFO_RECV_EMPTY)) )
{
command = REG_IPC_FIFO_RX;
switch(command)
{
case FIFO_NONE:
break;
case UPDATEON_ARM9:
REG_IME = 0;
MixSound();
REG_IME = 1;
SendCommandToArm7(MIXCOMPLETE_ONARM9);
break;
}
}
}
static int Audio_Available(void)
{
return(1);
}
static void Audio_DeleteDevice(SDL_AudioDevice *device)
{
}
static SDL_AudioDevice *Audio_CreateDevice(int devindex)
{
SDL_AudioDevice *this;
/* Initialize all variables that we clean on shutdown */
this = (SDL_AudioDevice *)malloc(sizeof(SDL_AudioDevice));
if ( this ) {
SDL_memset(this, 0, (sizeof *this));
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
}
if ( (this == NULL) || (this->hidden == NULL) ) {
SDL_OutOfMemory();
if ( this ) {
SDL_free(this);
}
return(0);
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
/* Set the function pointers */
this->OpenAudio = NDS_OpenAudio;
this->WaitAudio = NDS_WaitAudio;
this->PlayAudio = NDS_PlayAudio;
this->GetAudioBuf = NDS_GetAudioBuf;
this->CloseAudio = NDS_CloseAudio;
this->free = Audio_DeleteDevice;
//fprintf(stderr,"Audio_CreateDevice\n");
return this;
}
AudioBootStrap NDSAUD_bootstrap = {
"nds", "NDS audio",
Audio_Available, Audio_CreateDevice
};
void static NDS_WaitAudio(_THIS)
{
//printf("NDS_WaitAudio\n");
}
static void NDS_PlayAudio(_THIS)
{
//printf("playing audio\n");
if (this->paused)
return;
}
static Uint8 *NDS_GetAudioBuf(_THIS)
{
return NULL;//(this->hidden->mixbuf);
}
static void NDS_CloseAudio(_THIS)
{
/* if ( this->hidden->mixbuf != NULL ) {
SDL_FreeAudioMem(this->hidden->mixbuf);
this->hidden->mixbuf = NULL;
}*/
}
static int NDS_OpenAudio(_THIS, SDL_AudioSpec *spec)
{
//printf("NDS_OpenAudio\n");
int format = 0;
//switch(spec->format&0xff) {
//case 8: spec->format = AUDIO_S8;format=8; break;
//case 16: spec->format = AUDIO_S16LSB;format=16; break;
//default:
// SDL_SetError("Unsupported audio format");
// return(-1);
//}
switch (spec->format&~0x1000) {
case AUDIO_S8:
/* Signed 8-bit audio supported */
format=8;
break;
case AUDIO_U8:
spec->format ^= 0x80;format=8;
break;
case AUDIO_U16:
/* Unsigned 16-bit audio unsupported, convert to S16 */
spec->format ^=0x8000;format=16;
case AUDIO_S16:
/* Signed 16-bit audio supported */
format=16;
break;
}
/* Update the fragment size as size in bytes */
SDL_CalculateAudioSpec(spec);
/* Allocate mixing buffer */
//this->hidden->mixlen = spec->size;
//this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
//if ( this->hidden->mixbuf == NULL ) {
// SDL_SetError("Out of Memory");
// return(-1);
//}
SDL_NDSAudio_mutex = 0;
sdl_nds_audiodevice=this;
irqInit();
irqSet(IRQ_VBLANK,&InterruptHandler);
irqSet(IRQ_FIFO_NOT_EMPTY,&FiFoHandler);
irqEnable(IRQ_FIFO_NOT_EMPTY);
REG_IPC_FIFO_CR = IPC_FIFO_ENABLE | IPC_FIFO_SEND_CLEAR | IPC_FIFO_RECV_IRQ;
SoundSystemInit(spec->freq,spec->size,0,format);
SoundStartMixer();
return(1);
}

View file

@ -1,40 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
#ifndef _SDL_lowaudio_h
#define _SDL_lowaudio_h
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the audio functions */
#define _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData {
/* The file descriptor for the audio device */
//Uint8 *mixbuf;
//Uint32 mixlen;
};
unsigned short SDL_NDSAudio_mutex=0;
#endif /* _SDL_lowaudio_h */

View file

@ -1,61 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
#include "SDL_stdinc.h"
#include "soundcommon.h"
void SoundSystemInit(u32 rate,u32 buffersize,u8 channel,u8 format)
{
soundsystem->rate = rate;
if(format == 8)
soundsystem->buffersize = buffersize;
else if(format == 16)
soundsystem->buffersize = buffersize * sizeof(short);
soundsystem->mixbuffer = (s8*)SDL_malloc(soundsystem->buffersize);
//soundsystem->soundbuffer = soundsystem->mixbuffer;
soundsystem->format = format;
soundsystem->channel = channel;
soundsystem->prevtimer = 0;
soundsystem->soundcursor = 0;
soundsystem->numsamples = 0;
soundsystem->period = 0x1000000 / rate;
soundsystem->cmd = INIT;
}
void SoundStartMixer(void)
{
soundsystem->cmd |= MIX;
}
void SendCommandToArm7(u32 command)
{
while (REG_IPC_FIFO_CR & IPC_FIFO_SEND_FULL);
if (REG_IPC_FIFO_CR & IPC_FIFO_ERROR)
{
REG_IPC_FIFO_CR |= IPC_FIFO_SEND_CLEAR;
}
REG_IPC_FIFO_TX = command;
}

View file

@ -1,80 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
#ifndef __SOUNDCOMMON_H
#define __SOUNDCOMMON_H
#include <nds.h>
#define CLOCK (1 << 25)
#ifdef __cplusplus
extern "C" {
#endif
typedef enum
{
NONE = 0,
INIT = 1,
MIX = 2,
MIXING = 4,
STOP = 8
}CommandType;
typedef enum
{
FIFO_NONE = 0,
UPDATEON_ARM9 = 1,
MIXCOMPLETE_ONARM9 = 2,
}FifoType;
typedef struct
{
s8 *mixbuffer;//,*soundbuffer;
u32 rate;
u32 buffersize;
u32 cmd;
u8 channel,format;
u32 soundcursor,numsamples;
s32 prevtimer;
s16 period;
}S_SoundSystem;
#define soundsystem ((S_SoundSystem*)((u32)(IPC)+sizeof(TransferRegion)))
#ifdef ARM9
extern void SoundSystemInit(u32 rate,u32 buffersize,u8 channel,u8 format);
extern void SoundStartMixer(void);
extern void SendCommandToArm7(u32 command);
#else
extern void SoundVBlankIrq(void);
extern void SoundSwapAndMix(void);
extern void SoundSetTimer(int period);
extern void SoundFifoHandler(void);
extern void SendCommandToArm9(u32 command);
#endif
#ifdef __cplusplus
}
#endif
#endif

View file

@ -1,507 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
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 library 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
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sched.h>
#include <sys/select.h>
#include <sys/neutrino.h>
#include <sys/asoundlib.h>
#include "SDL_timer.h"
#include "SDL_audio.h"
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
#include "SDL_nto_audio.h"
/* The tag name used by NTO audio */
#define DRIVER_NAME "qsa-nto"
/* default channel communication parameters */
#define DEFAULT_CPARAMS_RATE 22050
#define DEFAULT_CPARAMS_VOICES 1
/* FIXME: need to add in the near future flexible logic with frag_size and frags count */
#define DEFAULT_CPARAMS_FRAG_SIZE 4096
#define DEFAULT_CPARAMS_FRAGS_MIN 1
#define DEFAULT_CPARAMS_FRAGS_MAX 1
/* Open the audio device for playback, and don't block if busy */
#define OPEN_FLAGS SND_PCM_OPEN_PLAYBACK
#define QSA_NO_WORKAROUNDS 0x00000000
#define QSA_MMAP_WORKAROUND 0x00000001
struct BuggyCards
{
char* cardname;
unsigned long bugtype;
};
#define QSA_WA_CARDS 3
struct BuggyCards buggycards[QSA_WA_CARDS]=
{
{"Sound Blaster Live!", QSA_MMAP_WORKAROUND},
{"Vortex 8820", QSA_MMAP_WORKAROUND},
{"Vortex 8830", QSA_MMAP_WORKAROUND},
};
/* Audio driver functions */
static void NTO_ThreadInit(_THIS);
static int NTO_OpenAudio(_THIS, SDL_AudioSpec* spec);
static void NTO_WaitAudio(_THIS);
static void NTO_PlayAudio(_THIS);
static Uint8* NTO_GetAudioBuf(_THIS);
static void NTO_CloseAudio(_THIS);
/* card names check to apply the workarounds */
static int NTO_CheckBuggyCards(_THIS, unsigned long checkfor)
{
char scardname[33];
int it;
if (snd_card_get_name(cardno, scardname, 32)<0)
{
return 0;
}
for (it=0; it<QSA_WA_CARDS; it++)
{
if (SDL_strcmp(buggycards[it].cardname, scardname)==0)
{
if (buggycards[it].bugtype==checkfor)
{
return 1;
}
}
}
return 0;
}
static void NTO_ThreadInit(_THIS)
{
int status;
struct sched_param param;
/* increasing default 10 priority to 25 to avoid jerky sound */
status=SchedGet(0, 0, &param);
param.sched_priority=param.sched_curpriority+15;
status=SchedSet(0, 0, SCHED_NOCHANGE, &param);
}
/* PCM transfer channel parameters initialize function */
static void NTO_InitAudioParams(snd_pcm_channel_params_t* cpars)
{
SDL_memset(cpars, 0, sizeof(snd_pcm_channel_params_t));
cpars->channel = SND_PCM_CHANNEL_PLAYBACK;
cpars->mode = SND_PCM_MODE_BLOCK;
cpars->start_mode = SND_PCM_START_DATA;
cpars->stop_mode = SND_PCM_STOP_STOP;
cpars->format.format = SND_PCM_SFMT_S16_LE;
cpars->format.interleave = 1;
cpars->format.rate = DEFAULT_CPARAMS_RATE;
cpars->format.voices = DEFAULT_CPARAMS_VOICES;
cpars->buf.block.frag_size = DEFAULT_CPARAMS_FRAG_SIZE;
cpars->buf.block.frags_min = DEFAULT_CPARAMS_FRAGS_MIN;
cpars->buf.block.frags_max = DEFAULT_CPARAMS_FRAGS_MAX;
}
static int NTO_AudioAvailable(void)
{
/* See if we can open a nonblocking channel.
Return value '1' means we can.
Return value '0' means we cannot. */
int available;
int rval;
snd_pcm_t* handle;
available = 0;
handle = NULL;
rval = snd_pcm_open_preferred(&handle, NULL, NULL, OPEN_FLAGS);
if (rval >= 0)
{
available = 1;
if ((rval = snd_pcm_close(handle)) < 0)
{
SDL_SetError("NTO_AudioAvailable(): snd_pcm_close failed: %s\n", snd_strerror(rval));
available = 0;
}
}
else
{
SDL_SetError("NTO_AudioAvailable(): there are no available audio devices.\n");
}
return (available);
}
static void NTO_DeleteAudioDevice(SDL_AudioDevice *device)
{
if ((device)&&(device->hidden))
{
SDL_free(device->hidden);
}
if (device)
{
SDL_free(device);
}
}
static SDL_AudioDevice* NTO_CreateAudioDevice(int devindex)
{
SDL_AudioDevice *this;
/* Initialize all variables that we clean on shutdown */
this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
if (this)
{
SDL_memset(this, 0, sizeof(SDL_AudioDevice));
this->hidden = (struct SDL_PrivateAudioData *)SDL_malloc(sizeof(struct SDL_PrivateAudioData));
}
if ((this == NULL) || (this->hidden == NULL))
{
SDL_OutOfMemory();
if (this)
{
SDL_free(this);
}
return (0);
}
SDL_memset(this->hidden, 0, sizeof(struct SDL_PrivateAudioData));
audio_handle = NULL;
/* Set the function pointers */
this->ThreadInit = NTO_ThreadInit;
this->OpenAudio = NTO_OpenAudio;
this->WaitAudio = NTO_WaitAudio;
this->PlayAudio = NTO_PlayAudio;
this->GetAudioBuf = NTO_GetAudioBuf;
this->CloseAudio = NTO_CloseAudio;
this->free = NTO_DeleteAudioDevice;
return this;
}
AudioBootStrap QNXNTOAUDIO_bootstrap =
{
DRIVER_NAME, "QNX6 QSA-NTO Audio",
NTO_AudioAvailable,
NTO_CreateAudioDevice
};
/* This function waits until it is possible to write a full sound buffer */
static void NTO_WaitAudio(_THIS)
{
fd_set wfds;
int selectret;
FD_ZERO(&wfds);
FD_SET(audio_fd, &wfds);
do {
selectret=select(audio_fd + 1, NULL, &wfds, NULL, NULL);
switch (selectret)
{
case -1:
case 0: SDL_SetError("NTO_WaitAudio(): select() failed: %s\n", strerror(errno));
return;
default: if (FD_ISSET(audio_fd, &wfds))
{
return;
}
break;
}
} while(1);
}
static void NTO_PlayAudio(_THIS)
{
int written, rval;
int towrite;
void* pcmbuffer;
if (!this->enabled)
{
return;
}
towrite = this->spec.size;
pcmbuffer = pcm_buf;
/* Write the audio data, checking for EAGAIN (buffer full) and underrun */
do {
written = snd_pcm_plugin_write(audio_handle, pcm_buf, towrite);
if (written != towrite)
{
if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
{
/* Let a little CPU time go by and try to write again */
SDL_Delay(1);
/* if we wrote some data */
towrite -= written;
pcmbuffer += written * this->spec.channels;
continue;
}
else
{
if ((errno == EINVAL) || (errno == EIO))
{
SDL_memset(&cstatus, 0, sizeof(cstatus));
cstatus.channel = SND_PCM_CHANNEL_PLAYBACK;
if ((rval = snd_pcm_plugin_status(audio_handle, &cstatus)) < 0)
{
SDL_SetError("NTO_PlayAudio(): snd_pcm_plugin_status failed: %s\n", snd_strerror(rval));
return;
}
if ((cstatus.status == SND_PCM_STATUS_UNDERRUN) || (cstatus.status == SND_PCM_STATUS_READY))
{
if ((rval = snd_pcm_plugin_prepare(audio_handle, SND_PCM_CHANNEL_PLAYBACK)) < 0)
{
SDL_SetError("NTO_PlayAudio(): snd_pcm_plugin_prepare failed: %s\n", snd_strerror(rval));
return;
}
}
continue;
}
else
{
return;
}
}
}
else
{
/* we wrote all remaining data */
towrite -= written;
pcmbuffer += written * this->spec.channels;
}
} while ((towrite > 0) && (this->enabled));
/* If we couldn't write, assume fatal error for now */
if (towrite != 0)
{
this->enabled = 0;
}
return;
}
static Uint8* NTO_GetAudioBuf(_THIS)
{
return pcm_buf;
}
static void NTO_CloseAudio(_THIS)
{
int rval;
this->enabled = 0;
if (audio_handle != NULL)
{
if ((rval = snd_pcm_plugin_flush(audio_handle, SND_PCM_CHANNEL_PLAYBACK)) < 0)
{
SDL_SetError("NTO_CloseAudio(): snd_pcm_plugin_flush failed: %s\n", snd_strerror(rval));
return;
}
if ((rval = snd_pcm_close(audio_handle)) < 0)
{
SDL_SetError("NTO_CloseAudio(): snd_pcm_close failed: %s\n",snd_strerror(rval));
return;
}
audio_handle = NULL;
}
}
static int NTO_OpenAudio(_THIS, SDL_AudioSpec* spec)
{
int rval;
int format;
Uint16 test_format;
int found;
audio_handle = NULL;
this->enabled = 0;
if (pcm_buf != NULL)
{
SDL_FreeAudioMem(pcm_buf);
pcm_buf = NULL;
}
/* initialize channel transfer parameters to default */
NTO_InitAudioParams(&cparams);
/* Open the audio device */
rval = snd_pcm_open_preferred(&audio_handle, &cardno, &deviceno, OPEN_FLAGS);
if (rval < 0)
{
SDL_SetError("NTO_OpenAudio(): snd_pcm_open failed: %s\n", snd_strerror(rval));
return (-1);
}
if (!NTO_CheckBuggyCards(this, QSA_MMAP_WORKAROUND))
{
/* enable count status parameter */
if ((rval = snd_pcm_plugin_set_disable(audio_handle, PLUGIN_DISABLE_MMAP)) < 0)
{
SDL_SetError("snd_pcm_plugin_set_disable failed: %s\n", snd_strerror(rval));
return (-1);
}
}
/* Try for a closest match on audio format */
format = 0;
/* can't use format as SND_PCM_SFMT_U8 = 0 in nto */
found = 0;
for (test_format=SDL_FirstAudioFormat(spec->format); !found ;)
{
/* if match found set format to equivalent ALSA format */
switch (test_format)
{
case AUDIO_U8:
format = SND_PCM_SFMT_U8;
found = 1;
break;
case AUDIO_S8:
format = SND_PCM_SFMT_S8;
found = 1;
break;
case AUDIO_S16LSB:
format = SND_PCM_SFMT_S16_LE;
found = 1;
break;
case AUDIO_S16MSB:
format = SND_PCM_SFMT_S16_BE;
found = 1;
break;
case AUDIO_U16LSB:
format = SND_PCM_SFMT_U16_LE;
found = 1;
break;
case AUDIO_U16MSB:
format = SND_PCM_SFMT_U16_BE;
found = 1;
break;
default:
break;
}
if (!found)
{
test_format = SDL_NextAudioFormat();
}
}
/* assumes test_format not 0 on success */
if (test_format == 0)
{
SDL_SetError("NTO_OpenAudio(): Couldn't find any hardware audio formats");
return (-1);
}
spec->format = test_format;
/* Set the audio format */
cparams.format.format = format;
/* Set mono or stereo audio (currently only two channels supported) */
cparams.format.voices = spec->channels;
/* Set rate */
cparams.format.rate = spec->freq;
/* Setup the transfer parameters according to cparams */
rval = snd_pcm_plugin_params(audio_handle, &cparams);
if (rval < 0)
{
SDL_SetError("NTO_OpenAudio(): snd_pcm_channel_params failed: %s\n", snd_strerror(rval));
return (-1);
}
/* Make sure channel is setup right one last time */
SDL_memset(&csetup, 0x00, sizeof(csetup));
csetup.channel = SND_PCM_CHANNEL_PLAYBACK;
if (snd_pcm_plugin_setup(audio_handle, &csetup) < 0)
{
SDL_SetError("NTO_OpenAudio(): Unable to setup playback channel\n");
return -1;
}
/* Calculate the final parameters for this audio specification */
SDL_CalculateAudioSpec(spec);
pcm_len = spec->size;
if (pcm_len==0)
{
pcm_len = csetup.buf.block.frag_size * spec->channels * (snd_pcm_format_width(format)/8);
}
/* Allocate memory to the audio buffer and initialize with silence (Note that
buffer size must be a multiple of fragment size, so find closest multiple)
*/
pcm_buf = (Uint8*)SDL_AllocAudioMem(pcm_len);
if (pcm_buf == NULL)
{
SDL_SetError("NTO_OpenAudio(): pcm buffer allocation failed\n");
return (-1);
}
SDL_memset(pcm_buf, spec->silence, pcm_len);
/* get the file descriptor */
if ((audio_fd = snd_pcm_file_descriptor(audio_handle, SND_PCM_CHANNEL_PLAYBACK)) < 0)
{
SDL_SetError("NTO_OpenAudio(): snd_pcm_file_descriptor failed with error code: %s\n", snd_strerror(rval));
return (-1);
}
/* Trigger audio playback */
rval = snd_pcm_plugin_prepare(audio_handle, SND_PCM_CHANNEL_PLAYBACK);
if (rval < 0)
{
SDL_SetError("snd_pcm_plugin_prepare failed: %s\n", snd_strerror(rval));
return (-1);
}
this->enabled = 1;
/* Get the parent process id (we're the parent of the audio thread) */
parent = getpid();
/* We're really ready to rock and roll. :-) */
return (0);
}

View file

@ -1,68 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
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 library 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
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
#ifndef __SDL_NTO_AUDIO_H__
#define __SDL_NTO_AUDIO_H__
#include <sys/asoundlib.h>
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the audio functions */
#define _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData
{
/* The audio device handle */
int cardno;
int deviceno;
snd_pcm_t* audio_handle;
/* The audio file descriptor */
int audio_fd;
/* The parent process id, to detect when application quits */
pid_t parent;
/* Raw mixing buffer */
Uint8* pcm_buf;
Uint32 pcm_len;
/* QSA parameters */
snd_pcm_channel_status_t cstatus;
snd_pcm_channel_params_t cparams;
snd_pcm_channel_setup_t csetup;
};
#define cardno (this->hidden->cardno)
#define deviceno (this->hidden->deviceno)
#define audio_handle (this->hidden->audio_handle)
#define audio_fd (this->hidden->audio_fd)
#define parent (this->hidden->parent)
#define pcm_buf (this->hidden->pcm_buf)
#define pcm_len (this->hidden->pcm_len)
#define cstatus (this->hidden->cstatus)
#define cparams (this->hidden->cparams)
#define csetup (this->hidden->csetup)
#endif /* __SDL_NTO_AUDIO_H__ */

View file

@ -1,511 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Carsten Griwodz
griff@kom.tu-darmstadt.de
based on linux/SDL_dspaudio.c by Sam Lantinga
*/
#include "SDL_config.h"
/* Allow access to a raw mixing buffer */
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include "SDL_timer.h"
#include "SDL_audio.h"
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
#include "../SDL_audiodev_c.h"
#include "SDL_paudio.h"
#define DEBUG_AUDIO 1
/* A conflict within AIX 4.3.3 <sys/> headers and probably others as well.
* I guess nobody ever uses audio... Shame over AIX header files. */
#include <sys/machine.h>
#undef BIG_ENDIAN
#include <sys/audio.h>
/* The tag name used by paud audio */
#define Paud_DRIVER_NAME "paud"
/* Open the audio device for playback, and don't block if busy */
/* #define OPEN_FLAGS (O_WRONLY|O_NONBLOCK) */
#define OPEN_FLAGS O_WRONLY
/* Audio driver functions */
static int Paud_OpenAudio(_THIS, SDL_AudioSpec *spec);
static void Paud_WaitAudio(_THIS);
static void Paud_PlayAudio(_THIS);
static Uint8 *Paud_GetAudioBuf(_THIS);
static void Paud_CloseAudio(_THIS);
/* Audio driver bootstrap functions */
static int Audio_Available(void)
{
int fd;
int available;
available = 0;
fd = SDL_OpenAudioPath(NULL, 0, OPEN_FLAGS, 0);
if ( fd >= 0 ) {
available = 1;
close(fd);
}
return(available);
}
static void Audio_DeleteDevice(SDL_AudioDevice *device)
{
SDL_free(device->hidden);
SDL_free(device);
}
static SDL_AudioDevice *Audio_CreateDevice(int devindex)
{
SDL_AudioDevice *this;
/* Initialize all variables that we clean on shutdown */
this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
if ( this ) {
SDL_memset(this, 0, (sizeof *this));
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
}
if ( (this == NULL) || (this->hidden == NULL) ) {
SDL_OutOfMemory();
if ( this ) {
SDL_free(this);
}
return(0);
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
audio_fd = -1;
/* Set the function pointers */
this->OpenAudio = Paud_OpenAudio;
this->WaitAudio = Paud_WaitAudio;
this->PlayAudio = Paud_PlayAudio;
this->GetAudioBuf = Paud_GetAudioBuf;
this->CloseAudio = Paud_CloseAudio;
this->free = Audio_DeleteDevice;
return this;
}
AudioBootStrap Paud_bootstrap = {
Paud_DRIVER_NAME, "AIX Paudio",
Audio_Available, Audio_CreateDevice
};
/* This function waits until it is possible to write a full sound buffer */
static void Paud_WaitAudio(_THIS)
{
fd_set fdset;
/* See if we need to use timed audio synchronization */
if ( frame_ticks ) {
/* Use timer for general audio synchronization */
Sint32 ticks;
ticks = ((Sint32)(next_frame - SDL_GetTicks()))-FUDGE_TICKS;
if ( ticks > 0 ) {
SDL_Delay(ticks);
}
} else {
audio_buffer paud_bufinfo;
/* Use select() for audio synchronization */
struct timeval timeout;
FD_ZERO(&fdset);
FD_SET(audio_fd, &fdset);
if ( ioctl(audio_fd, AUDIO_BUFFER, &paud_bufinfo) < 0 ) {
#ifdef DEBUG_AUDIO
fprintf(stderr, "Couldn't get audio buffer information\n");
#endif
timeout.tv_sec = 10;
timeout.tv_usec = 0;
} else {
long ms_in_buf = paud_bufinfo.write_buf_time;
timeout.tv_sec = ms_in_buf/1000;
ms_in_buf = ms_in_buf - timeout.tv_sec*1000;
timeout.tv_usec = ms_in_buf*1000;
#ifdef DEBUG_AUDIO
fprintf( stderr,
"Waiting for write_buf_time=%ld,%ld\n",
timeout.tv_sec,
timeout.tv_usec );
#endif
}
#ifdef DEBUG_AUDIO
fprintf(stderr, "Waiting for audio to get ready\n");
#endif
if ( select(audio_fd+1, NULL, &fdset, NULL, &timeout) <= 0 ) {
const char *message = "Audio timeout - buggy audio driver? (disabled)";
/*
* In general we should never print to the screen,
* but in this case we have no other way of letting
* the user know what happened.
*/
fprintf(stderr, "SDL: %s - %s\n", strerror(errno), message);
this->enabled = 0;
/* Don't try to close - may hang */
audio_fd = -1;
#ifdef DEBUG_AUDIO
fprintf(stderr, "Done disabling audio\n");
#endif
}
#ifdef DEBUG_AUDIO
fprintf(stderr, "Ready!\n");
#endif
}
}
static void Paud_PlayAudio(_THIS)
{
int written;
/* Write the audio data, checking for EAGAIN on broken audio drivers */
do {
written = write(audio_fd, mixbuf, mixlen);
if ( (written < 0) && ((errno == 0) || (errno == EAGAIN)) ) {
SDL_Delay(1); /* Let a little CPU time go by */
}
} while ( (written < 0) &&
((errno == 0) || (errno == EAGAIN) || (errno == EINTR)) );
/* If timer synchronization is enabled, set the next write frame */
if ( frame_ticks ) {
next_frame += frame_ticks;
}
/* If we couldn't write, assume fatal error for now */
if ( written < 0 ) {
this->enabled = 0;
}
#ifdef DEBUG_AUDIO
fprintf(stderr, "Wrote %d bytes of audio data\n", written);
#endif
}
static Uint8 *Paud_GetAudioBuf(_THIS)
{
return mixbuf;
}
static void Paud_CloseAudio(_THIS)
{
if ( mixbuf != NULL ) {
SDL_FreeAudioMem(mixbuf);
mixbuf = NULL;
}
if ( audio_fd >= 0 ) {
close(audio_fd);
audio_fd = -1;
}
}
static int Paud_OpenAudio(_THIS, SDL_AudioSpec *spec)
{
char audiodev[1024];
int format;
int bytes_per_sample;
Uint16 test_format;
audio_init paud_init;
audio_buffer paud_bufinfo;
audio_status paud_status;
audio_control paud_control;
audio_change paud_change;
/* Reset the timer synchronization flag */
frame_ticks = 0.0;
/* Open the audio device */
audio_fd = SDL_OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 0);
if ( audio_fd < 0 ) {
SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno));
return -1;
}
/*
* We can't set the buffer size - just ask the device for the maximum
* that we can have.
*/
if ( ioctl(audio_fd, AUDIO_BUFFER, &paud_bufinfo) < 0 ) {
SDL_SetError("Couldn't get audio buffer information");
return -1;
}
mixbuf = NULL;
if ( spec->channels > 1 )
spec->channels = 2;
else
spec->channels = 1;
/*
* Fields in the audio_init structure:
*
* Ignored by us:
*
* paud.loadpath[LOAD_PATH]; * DSP code to load, MWave chip only?
* paud.slot_number; * slot number of the adapter
* paud.device_id; * adapter identification number
*
* Input:
*
* paud.srate; * the sampling rate in Hz
* paud.bits_per_sample; * 8, 16, 32, ...
* paud.bsize; * block size for this rate
* paud.mode; * ADPCM, PCM, MU_LAW, A_LAW, SOURCE_MIX
* paud.channels; * 1=mono, 2=stereo
* paud.flags; * FIXED - fixed length data
* * LEFT_ALIGNED, RIGHT_ALIGNED (var len only)
* * TWOS_COMPLEMENT - 2's complement data
* * SIGNED - signed? comment seems wrong in sys/audio.h
* * BIG_ENDIAN
* paud.operation; * PLAY, RECORD
*
* Output:
*
* paud.flags; * PITCH - pitch is supported
* * INPUT - input is supported
* * OUTPUT - output is supported
* * MONITOR - monitor is supported
* * VOLUME - volume is supported
* * VOLUME_DELAY - volume delay is supported
* * BALANCE - balance is supported
* * BALANCE_DELAY - balance delay is supported
* * TREBLE - treble control is supported
* * BASS - bass control is supported
* * BESTFIT_PROVIDED - best fit returned
* * LOAD_CODE - DSP load needed
* paud.rc; * NO_PLAY - DSP code can't do play requests
* * NO_RECORD - DSP code can't do record requests
* * INVALID_REQUEST - request was invalid
* * CONFLICT - conflict with open's flags
* * OVERLOADED - out of DSP MIPS or memory
* paud.position_resolution; * smallest increment for position
*/
paud_init.srate = spec->freq;
paud_init.mode = PCM;
paud_init.operation = PLAY;
paud_init.channels = spec->channels;
/* Try for a closest match on audio format */
format = 0;
for ( test_format = SDL_FirstAudioFormat(spec->format);
! format && test_format; ) {
#ifdef DEBUG_AUDIO
fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
#endif
switch ( test_format ) {
case AUDIO_U8:
bytes_per_sample = 1;
paud_init.bits_per_sample = 8;
paud_init.flags = TWOS_COMPLEMENT | FIXED;
format = 1;
break;
case AUDIO_S8:
bytes_per_sample = 1;
paud_init.bits_per_sample = 8;
paud_init.flags = SIGNED |
TWOS_COMPLEMENT | FIXED;
format = 1;
break;
case AUDIO_S16LSB:
bytes_per_sample = 2;
paud_init.bits_per_sample = 16;
paud_init.flags = SIGNED |
TWOS_COMPLEMENT | FIXED;
format = 1;
break;
case AUDIO_S16MSB:
bytes_per_sample = 2;
paud_init.bits_per_sample = 16;
paud_init.flags = BIG_ENDIAN |
SIGNED |
TWOS_COMPLEMENT | FIXED;
format = 1;
break;
case AUDIO_U16LSB:
bytes_per_sample = 2;
paud_init.bits_per_sample = 16;
paud_init.flags = TWOS_COMPLEMENT | FIXED;
format = 1;
break;
case AUDIO_U16MSB:
bytes_per_sample = 2;
paud_init.bits_per_sample = 16;
paud_init.flags = BIG_ENDIAN |
TWOS_COMPLEMENT | FIXED;
format = 1;
break;
default:
break;
}
if ( ! format ) {
test_format = SDL_NextAudioFormat();
}
}
if ( format == 0 ) {
#ifdef DEBUG_AUDIO
fprintf(stderr, "Couldn't find any hardware audio formats\n");
#endif
SDL_SetError("Couldn't find any hardware audio formats");
return -1;
}
spec->format = test_format;
/*
* We know the buffer size and the max number of subsequent writes
* that can be pending. If more than one can pend, allow the application
* to do something like double buffering between our write buffer and
* the device's own buffer that we are filling with write() anyway.
*
* We calculate spec->samples like this because SDL_CalculateAudioSpec()
* will give put paud_bufinfo.write_buf_cap (or paud_bufinfo.write_buf_cap/2)
* into spec->size in return.
*/
if ( paud_bufinfo.request_buf_cap == 1 )
{
spec->samples = paud_bufinfo.write_buf_cap
/ bytes_per_sample
/ spec->channels;
}
else
{
spec->samples = paud_bufinfo.write_buf_cap
/ bytes_per_sample
/ spec->channels
/ 2;
}
paud_init.bsize = bytes_per_sample * spec->channels;
SDL_CalculateAudioSpec(spec);
/*
* The AIX paud device init can't modify the values of the audio_init
* structure that we pass to it. So we don't need any recalculation
* of this stuff and no reinit call as in linux dsp and dma code.
*
* /dev/paud supports all of the encoding formats, so we don't need
* to do anything like reopening the device, either.
*/
if ( ioctl(audio_fd, AUDIO_INIT, &paud_init) < 0 ) {
switch ( paud_init.rc )
{
case 1 :
SDL_SetError("Couldn't set audio format: DSP can't do play requests");
return -1;
break;
case 2 :
SDL_SetError("Couldn't set audio format: DSP can't do record requests");
return -1;
break;
case 4 :
SDL_SetError("Couldn't set audio format: request was invalid");
return -1;
break;
case 5 :
SDL_SetError("Couldn't set audio format: conflict with open's flags");
return -1;
break;
case 6 :
SDL_SetError("Couldn't set audio format: out of DSP MIPS or memory");
return -1;
break;
default :
SDL_SetError("Couldn't set audio format: not documented in sys/audio.h");
return -1;
break;
}
}
/* Allocate mixing buffer */
mixlen = spec->size;
mixbuf = (Uint8 *)SDL_AllocAudioMem(mixlen);
if ( mixbuf == NULL ) {
return -1;
}
SDL_memset(mixbuf, spec->silence, spec->size);
/*
* Set some paramters: full volume, first speaker that we can find.
* Ignore the other settings for now.
*/
paud_change.input = AUDIO_IGNORE; /* the new input source */
paud_change.output = OUTPUT_1; /* EXTERNAL_SPEAKER,INTERNAL_SPEAKER,OUTPUT_1 */
paud_change.monitor = AUDIO_IGNORE; /* the new monitor state */
paud_change.volume = 0x7fffffff; /* volume level [0-0x7fffffff] */
paud_change.volume_delay = AUDIO_IGNORE; /* the new volume delay */
paud_change.balance = 0x3fffffff; /* the new balance */
paud_change.balance_delay = AUDIO_IGNORE; /* the new balance delay */
paud_change.treble = AUDIO_IGNORE; /* the new treble state */
paud_change.bass = AUDIO_IGNORE; /* the new bass state */
paud_change.pitch = AUDIO_IGNORE; /* the new pitch state */
paud_control.ioctl_request = AUDIO_CHANGE;
paud_control.request_info = (char*)&paud_change;
if ( ioctl(audio_fd, AUDIO_CONTROL, &paud_control) < 0 ) {
#ifdef DEBUG_AUDIO
fprintf(stderr, "Can't change audio display settings\n" );
#endif
}
/*
* Tell the device to expect data. Actual start will wait for
* the first write() call.
*/
paud_control.ioctl_request = AUDIO_START;
paud_control.position = 0;
if ( ioctl(audio_fd, AUDIO_CONTROL, &paud_control) < 0 ) {
#ifdef DEBUG_AUDIO
fprintf(stderr, "Can't start audio play\n" );
#endif
SDL_SetError("Can't start audio play");
return -1;
}
/* Check to see if we need to use select() workaround */
{ char *workaround;
workaround = SDL_getenv("SDL_DSP_NOSELECT");
if ( workaround ) {
frame_ticks = (float)(spec->samples*1000)/spec->freq;
next_frame = SDL_GetTicks()+frame_ticks;
}
}
/* Get the parent process id (we're the parent of the audio thread) */
parent = getpid();
/* We're ready to rock and roll. :-) */
return 0;
}

View file

@ -1,57 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
#ifndef _SDL_paudaudio_h
#define _SDL_paudaudio_h
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the video functions */
#define _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData {
/* The file descriptor for the audio device */
int audio_fd;
/* The parent process id, to detect when application quits */
pid_t parent;
/* Raw mixing buffer */
Uint8 *mixbuf;
int mixlen;
/* Support for audio timing using a timer, in addition to select() */
float frame_ticks;
float next_frame;
};
#define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */
/* Old variable names */
#define audio_fd (this->hidden->audio_fd)
#define parent (this->hidden->parent)
#define mixbuf (this->hidden->mixbuf)
#define mixlen (this->hidden->mixlen)
#define frame_ticks (this->hidden->frame_ticks)
#define next_frame (this->hidden->next_frame)
#endif /* _SDL_paudaudio_h */

View file

@ -1,570 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Stéphan Kochen
stephan@kochen.nl
Based on parts of the ALSA and ESounD output drivers.
*/
#include "SDL_config.h"
/* Allow access to an PulseAudio network stream mixing buffer */
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <pulse/pulseaudio.h>
#include <pulse/simple.h>
#include "SDL_timer.h"
#include "SDL_audio.h"
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
#include "../SDL_audiodev_c.h"
#include "../../../include/SDL_video.h" /* for SDL_WM_GetCaption(). */
#include "SDL_pulseaudio.h"
#ifdef SDL_AUDIO_DRIVER_PULSE_DYNAMIC
#include "SDL_name.h"
#include "SDL_loadso.h"
#else
#define SDL_NAME(X) X
#endif
/* The tag name used by the driver */
#define PULSE_DRIVER_NAME "pulse"
/* Audio driver functions */
static int PULSE_OpenAudio(_THIS, SDL_AudioSpec *spec);
static void PULSE_WaitAudio(_THIS);
static void PULSE_PlayAudio(_THIS);
static Uint8 *PULSE_GetAudioBuf(_THIS);
static void PULSE_CloseAudio(_THIS);
static void PULSE_WaitDone(_THIS);
static void PULSE_SetCaption(_THIS, const char *str);
#ifdef SDL_AUDIO_DRIVER_PULSE_DYNAMIC
static const char *pulse_library = SDL_AUDIO_DRIVER_PULSE_DYNAMIC;
static void *pulse_handle = NULL;
static int pulse_loaded = 0;
static pa_simple* (*SDL_NAME(pa_simple_new))(
const char *server,
const char *name,
pa_stream_direction_t dir,
const char *dev,
const char *stream_name,
const pa_sample_spec *ss,
const pa_channel_map *map,
const pa_buffer_attr *attr,
int *error
);
static void (*SDL_NAME(pa_simple_free))(pa_simple *s);
static pa_channel_map* (*SDL_NAME(pa_channel_map_init_auto))(
pa_channel_map *m,
unsigned channels,
pa_channel_map_def_t def
);
static pa_mainloop * (*SDL_NAME(pa_mainloop_new))(void);
static pa_mainloop_api * (*SDL_NAME(pa_mainloop_get_api))(pa_mainloop *m);
static int (*SDL_NAME(pa_mainloop_iterate))(pa_mainloop *m, int block, int *retval);
static void (*SDL_NAME(pa_mainloop_free))(pa_mainloop *m);
static pa_operation_state_t (*SDL_NAME(pa_operation_get_state))(pa_operation *o);
static void (*SDL_NAME(pa_operation_cancel))(pa_operation *o);
static void (*SDL_NAME(pa_operation_unref))(pa_operation *o);
static pa_context * (*SDL_NAME(pa_context_new))(
pa_mainloop_api *m, const char *name);
static int (*SDL_NAME(pa_context_connect))(
pa_context *c, const char *server,
pa_context_flags_t flags, const pa_spawn_api *api);
static pa_context_state_t (*SDL_NAME(pa_context_get_state))(pa_context *c);
static void (*SDL_NAME(pa_context_disconnect))(pa_context *c);
static void (*SDL_NAME(pa_context_unref))(pa_context *c);
static pa_stream * (*SDL_NAME(pa_stream_new))(pa_context *c,
const char *name, const pa_sample_spec *ss, const pa_channel_map *map);
static int (*SDL_NAME(pa_stream_connect_playback))(pa_stream *s, const char *dev,
const pa_buffer_attr *attr, pa_stream_flags_t flags,
pa_cvolume *volume, pa_stream *sync_stream);
static pa_stream_state_t (*SDL_NAME(pa_stream_get_state))(pa_stream *s);
static size_t (*SDL_NAME(pa_stream_writable_size))(pa_stream *s);
static int (*SDL_NAME(pa_stream_write))(pa_stream *s, const void *data, size_t nbytes,
pa_free_cb_t free_cb, int64_t offset, pa_seek_mode_t seek);
static pa_operation * (*SDL_NAME(pa_stream_drain))(pa_stream *s,
pa_stream_success_cb_t cb, void *userdata);
static int (*SDL_NAME(pa_stream_disconnect))(pa_stream *s);
static void (*SDL_NAME(pa_stream_unref))(pa_stream *s);
static pa_operation* (*SDL_NAME(pa_context_set_name))(pa_context *c,
const char *name, pa_context_success_cb_t cb, void *userdata);
static struct {
const char *name;
void **func;
} pulse_functions[] = {
{ "pa_simple_new",
(void **)&SDL_NAME(pa_simple_new) },
{ "pa_simple_free",
(void **)&SDL_NAME(pa_simple_free) },
{ "pa_channel_map_init_auto",
(void **)&SDL_NAME(pa_channel_map_init_auto) },
{ "pa_mainloop_new",
(void **)&SDL_NAME(pa_mainloop_new) },
{ "pa_mainloop_get_api",
(void **)&SDL_NAME(pa_mainloop_get_api) },
{ "pa_mainloop_iterate",
(void **)&SDL_NAME(pa_mainloop_iterate) },
{ "pa_mainloop_free",
(void **)&SDL_NAME(pa_mainloop_free) },
{ "pa_operation_get_state",
(void **)&SDL_NAME(pa_operation_get_state) },
{ "pa_operation_cancel",
(void **)&SDL_NAME(pa_operation_cancel) },
{ "pa_operation_unref",
(void **)&SDL_NAME(pa_operation_unref) },
{ "pa_context_new",
(void **)&SDL_NAME(pa_context_new) },
{ "pa_context_connect",
(void **)&SDL_NAME(pa_context_connect) },
{ "pa_context_get_state",
(void **)&SDL_NAME(pa_context_get_state) },
{ "pa_context_disconnect",
(void **)&SDL_NAME(pa_context_disconnect) },
{ "pa_context_unref",
(void **)&SDL_NAME(pa_context_unref) },
{ "pa_stream_new",
(void **)&SDL_NAME(pa_stream_new) },
{ "pa_stream_connect_playback",
(void **)&SDL_NAME(pa_stream_connect_playback) },
{ "pa_stream_get_state",
(void **)&SDL_NAME(pa_stream_get_state) },
{ "pa_stream_writable_size",
(void **)&SDL_NAME(pa_stream_writable_size) },
{ "pa_stream_write",
(void **)&SDL_NAME(pa_stream_write) },
{ "pa_stream_drain",
(void **)&SDL_NAME(pa_stream_drain) },
{ "pa_stream_disconnect",
(void **)&SDL_NAME(pa_stream_disconnect) },
{ "pa_stream_unref",
(void **)&SDL_NAME(pa_stream_unref) },
{ "pa_context_set_name",
(void **)&SDL_NAME(pa_context_set_name) },
};
static void UnloadPulseLibrary()
{
if ( pulse_loaded ) {
SDL_UnloadObject(pulse_handle);
pulse_handle = NULL;
pulse_loaded = 0;
}
}
static int LoadPulseLibrary(void)
{
int i, retval = -1;
pulse_handle = SDL_LoadObject(pulse_library);
if ( pulse_handle ) {
pulse_loaded = 1;
retval = 0;
for ( i=0; i<SDL_arraysize(pulse_functions); ++i ) {
*pulse_functions[i].func = SDL_LoadFunction(pulse_handle, pulse_functions[i].name);
if ( !*pulse_functions[i].func ) {
retval = -1;
UnloadPulseLibrary();
break;
}
}
}
return retval;
}
#else
static void UnloadPulseLibrary()
{
return;
}
static int LoadPulseLibrary(void)
{
return 0;
}
#endif /* SDL_AUDIO_DRIVER_PULSE_DYNAMIC */
/* Audio driver bootstrap functions */
static int Audio_Available(void)
{
pa_sample_spec paspec;
pa_simple *connection;
int available;
available = 0;
if ( LoadPulseLibrary() < 0 ) {
return available;
}
/* Connect with a dummy format. */
paspec.format = PA_SAMPLE_U8;
paspec.rate = 11025;
paspec.channels = 1;
connection = SDL_NAME(pa_simple_new)(
NULL, /* server */
"Test stream", /* application name */
PA_STREAM_PLAYBACK, /* playback mode */
NULL, /* device on the server */
"Simple DirectMedia Layer", /* stream description */
&paspec, /* sample format spec */
NULL, /* channel map */
NULL, /* buffering attributes */
NULL /* error code */
);
if ( connection != NULL ) {
available = 1;
SDL_NAME(pa_simple_free)(connection);
}
UnloadPulseLibrary();
return(available);
}
static void Audio_DeleteDevice(SDL_AudioDevice *device)
{
SDL_free(device->hidden->caption);
SDL_free(device->hidden);
SDL_free(device);
UnloadPulseLibrary();
}
static SDL_AudioDevice *Audio_CreateDevice(int devindex)
{
SDL_AudioDevice *this;
/* Initialize all variables that we clean on shutdown */
LoadPulseLibrary();
this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
if ( this ) {
SDL_memset(this, 0, (sizeof *this));
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
}
if ( (this == NULL) || (this->hidden == NULL) ) {
SDL_OutOfMemory();
if ( this ) {
SDL_free(this);
}
return(0);
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
/* Set the function pointers */
this->OpenAudio = PULSE_OpenAudio;
this->WaitAudio = PULSE_WaitAudio;
this->PlayAudio = PULSE_PlayAudio;
this->GetAudioBuf = PULSE_GetAudioBuf;
this->CloseAudio = PULSE_CloseAudio;
this->WaitDone = PULSE_WaitDone;
this->SetCaption = PULSE_SetCaption;
this->free = Audio_DeleteDevice;
return this;
}
AudioBootStrap PULSE_bootstrap = {
PULSE_DRIVER_NAME, "PulseAudio",
Audio_Available, Audio_CreateDevice
};
/* This function waits until it is possible to write a full sound buffer */
static void PULSE_WaitAudio(_THIS)
{
int size;
while(1) {
if (SDL_NAME(pa_context_get_state)(context) != PA_CONTEXT_READY ||
SDL_NAME(pa_stream_get_state)(stream) != PA_STREAM_READY ||
SDL_NAME(pa_mainloop_iterate)(mainloop, 1, NULL) < 0) {
this->enabled = 0;
return;
}
size = SDL_NAME(pa_stream_writable_size)(stream);
if (size >= mixlen)
return;
}
}
static void PULSE_PlayAudio(_THIS)
{
/* Write the audio data */
if (SDL_NAME(pa_stream_write)(stream, mixbuf, mixlen, NULL, 0LL, PA_SEEK_RELATIVE) < 0)
this->enabled = 0;
}
static Uint8 *PULSE_GetAudioBuf(_THIS)
{
return(mixbuf);
}
static void PULSE_CloseAudio(_THIS)
{
if ( mixbuf != NULL ) {
SDL_FreeAudioMem(mixbuf);
mixbuf = NULL;
}
if ( stream != NULL ) {
SDL_NAME(pa_stream_disconnect)(stream);
SDL_NAME(pa_stream_unref)(stream);
stream = NULL;
}
if (context != NULL) {
SDL_NAME(pa_context_disconnect)(context);
SDL_NAME(pa_context_unref)(context);
context = NULL;
}
if (mainloop != NULL) {
SDL_NAME(pa_mainloop_free)(mainloop);
mainloop = NULL;
}
}
/* Try to get the name of the program */
static char *get_progname(void)
{
#ifdef __LINUX__
char *progname = NULL;
FILE *fp;
static char temp[BUFSIZ];
SDL_snprintf(temp, SDL_arraysize(temp), "/proc/%d/cmdline", getpid());
fp = fopen(temp, "r");
if ( fp != NULL ) {
if ( fgets(temp, sizeof(temp)-1, fp) ) {
progname = SDL_strrchr(temp, '/');
if ( progname == NULL ) {
progname = temp;
} else {
progname = progname+1;
}
}
fclose(fp);
}
return(progname);
#elif defined(__NetBSD__)
return getprogname();
#else
return("unknown");
#endif
}
static void caption_set_complete(pa_context *c, int success, void *userdata)
{
/* no-op. */
}
static void PULSE_SetCaption(_THIS, const char *str)
{
SDL_free(this->hidden->caption);
if ((str == NULL) || (*str == '\0')) {
str = get_progname(); /* set a default so SOMETHING shows up. */
}
this->hidden->caption = SDL_strdup(str);
if (context != NULL) {
SDL_NAME(pa_context_set_name)(context, this->hidden->caption,
caption_set_complete, 0);
}
}
static void stream_drain_complete(pa_stream *s, int success, void *userdata)
{
/* no-op. */
}
static void PULSE_WaitDone(_THIS)
{
pa_operation *o;
o = SDL_NAME(pa_stream_drain)(stream, stream_drain_complete, NULL);
if (!o)
return;
while (SDL_NAME(pa_operation_get_state)(o) != PA_OPERATION_DONE) {
if (SDL_NAME(pa_context_get_state)(context) != PA_CONTEXT_READY ||
SDL_NAME(pa_stream_get_state)(stream) != PA_STREAM_READY ||
SDL_NAME(pa_mainloop_iterate)(mainloop, 1, NULL) < 0) {
SDL_NAME(pa_operation_cancel)(o);
break;
}
}
SDL_NAME(pa_operation_unref)(o);
}
static int PULSE_OpenAudio(_THIS, SDL_AudioSpec *spec)
{
int state;
Uint16 test_format;
pa_sample_spec paspec;
pa_buffer_attr paattr;
pa_channel_map pacmap;
pa_stream_flags_t flags = 0;
paspec.format = PA_SAMPLE_INVALID;
for ( test_format = SDL_FirstAudioFormat(spec->format); test_format; ) {
switch ( test_format ) {
case AUDIO_U8:
paspec.format = PA_SAMPLE_U8;
break;
case AUDIO_S16LSB:
paspec.format = PA_SAMPLE_S16LE;
break;
case AUDIO_S16MSB:
paspec.format = PA_SAMPLE_S16BE;
break;
}
if ( paspec.format != PA_SAMPLE_INVALID )
break;
test_format = SDL_NextAudioFormat();
}
if (paspec.format == PA_SAMPLE_INVALID ) {
SDL_SetError("Couldn't find any suitable audio formats");
return(-1);
}
spec->format = test_format;
paspec.channels = spec->channels;
paspec.rate = spec->freq;
/* Calculate the final parameters for this audio specification */
#ifdef PA_STREAM_ADJUST_LATENCY
spec->samples /= 2; /* Mix in smaller chunck to avoid underruns */
#endif
SDL_CalculateAudioSpec(spec);
/* Allocate mixing buffer */
mixlen = spec->size;
mixbuf = (Uint8 *)SDL_AllocAudioMem(mixlen);
if ( mixbuf == NULL ) {
return(-1);
}
SDL_memset(mixbuf, spec->silence, spec->size);
/* Reduced prebuffering compared to the defaults. */
#ifdef PA_STREAM_ADJUST_LATENCY
paattr.tlength = mixlen * 4; /* 2x original requested bufsize */
paattr.prebuf = -1;
paattr.maxlength = -1;
paattr.minreq = mixlen; /* -1 can lead to pa_stream_writable_size()
>= mixlen never becoming true */
flags = PA_STREAM_ADJUST_LATENCY;
#else
paattr.tlength = mixlen*2;
paattr.prebuf = mixlen*2;
paattr.maxlength = mixlen*2;
paattr.minreq = mixlen;
#endif
/* The SDL ALSA output hints us that we use Windows' channel mapping */
/* http://bugzilla.libsdl.org/show_bug.cgi?id=110 */
SDL_NAME(pa_channel_map_init_auto)(
&pacmap, spec->channels, PA_CHANNEL_MAP_WAVEEX);
/* Set up a new main loop */
if (!(mainloop = SDL_NAME(pa_mainloop_new)())) {
PULSE_CloseAudio(this);
SDL_SetError("pa_mainloop_new() failed");
return(-1);
}
if (this->hidden->caption == NULL) {
char *title = NULL;
SDL_WM_GetCaption(&title, NULL);
PULSE_SetCaption(this, title);
}
mainloop_api = SDL_NAME(pa_mainloop_get_api)(mainloop);
if (!(context = SDL_NAME(pa_context_new)(mainloop_api,
this->hidden->caption))) {
PULSE_CloseAudio(this);
SDL_SetError("pa_context_new() failed");
return(-1);
}
/* Connect to the PulseAudio server */
if (SDL_NAME(pa_context_connect)(context, NULL, 0, NULL) < 0) {
PULSE_CloseAudio(this);
SDL_SetError("Could not setup connection to PulseAudio");
return(-1);
}
do {
if (SDL_NAME(pa_mainloop_iterate)(mainloop, 1, NULL) < 0) {
PULSE_CloseAudio(this);
SDL_SetError("pa_mainloop_iterate() failed");
return(-1);
}
state = SDL_NAME(pa_context_get_state)(context);
if (!PA_CONTEXT_IS_GOOD(state)) {
PULSE_CloseAudio(this);
SDL_SetError("Could not connect to PulseAudio");
return(-1);
}
} while (state != PA_CONTEXT_READY);
stream = SDL_NAME(pa_stream_new)(
context,
"Simple DirectMedia Layer", /* stream description */
&paspec, /* sample format spec */
&pacmap /* channel map */
);
if ( stream == NULL ) {
PULSE_CloseAudio(this);
SDL_SetError("Could not setup PulseAudio stream");
return(-1);
}
if (SDL_NAME(pa_stream_connect_playback)(stream, NULL, &paattr, flags,
NULL, NULL) < 0) {
PULSE_CloseAudio(this);
SDL_SetError("Could not connect PulseAudio stream");
return(-1);
}
do {
if (SDL_NAME(pa_mainloop_iterate)(mainloop, 1, NULL) < 0) {
PULSE_CloseAudio(this);
SDL_SetError("pa_mainloop_iterate() failed");
return(-1);
}
state = SDL_NAME(pa_stream_get_state)(stream);
if (!PA_STREAM_IS_GOOD(state)) {
PULSE_CloseAudio(this);
SDL_SetError("Could not create to PulseAudio stream");
return(-1);
}
} while (state != PA_STREAM_READY);
return(0);
}

View file

@ -1,73 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Stéphan Kochen
stephan@kochen.nl
Based on parts of the ALSA and ESounD output drivers.
*/
#include "SDL_config.h"
#ifndef _SDL_pulseaudio_h
#define _SDL_pulseaudio_h
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the video functions */
#define _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData {
pa_mainloop *mainloop;
pa_mainloop_api *mainloop_api;
pa_context *context;
pa_stream *stream;
char *caption;
/* Raw mixing buffer */
Uint8 *mixbuf;
int mixlen;
};
#if (PA_API_VERSION < 12)
/** Return non-zero if the passed state is one of the connected states */
static inline int PA_CONTEXT_IS_GOOD(pa_context_state_t x) {
return
x == PA_CONTEXT_CONNECTING ||
x == PA_CONTEXT_AUTHORIZING ||
x == PA_CONTEXT_SETTING_NAME ||
x == PA_CONTEXT_READY;
}
/** Return non-zero if the passed state is one of the connected states */
static inline int PA_STREAM_IS_GOOD(pa_stream_state_t x) {
return
x == PA_STREAM_CREATING ||
x == PA_STREAM_READY;
}
#endif /* pulseaudio <= 0.9.10 */
/* Old variable names */
#define mainloop (this->hidden->mainloop)
#define mainloop_api (this->hidden->mainloop_api)
#define context (this->hidden->context)
#define stream (this->hidden->stream)
#define mixbuf (this->hidden->mixbuf)
#define mixlen (this->hidden->mixlen)
#endif /* _SDL_pulseaudio_h */

View file

@ -1,432 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
/* Allow access to a raw mixing buffer */
#include <fcntl.h>
#include <errno.h>
#ifdef __NETBSD__
#include <sys/ioctl.h>
#include <sys/audioio.h>
#endif
#ifdef __SVR4
#include <sys/audioio.h>
#else
#include <sys/time.h>
#include <sys/types.h>
#endif
#include <unistd.h>
#include "SDL_timer.h"
#include "SDL_audio.h"
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
#include "../SDL_audiodev_c.h"
#include "SDL_sunaudio.h"
/* Open the audio device for playback, and don't block if busy */
#define OPEN_FLAGS (O_WRONLY|O_NONBLOCK)
/* Audio driver functions */
static int DSP_OpenAudio(_THIS, SDL_AudioSpec *spec);
static void DSP_WaitAudio(_THIS);
static void DSP_PlayAudio(_THIS);
static Uint8 *DSP_GetAudioBuf(_THIS);
static void DSP_CloseAudio(_THIS);
static Uint8 snd2au(int sample);
/* Audio driver bootstrap functions */
static int Audio_Available(void)
{
int fd;
int available;
available = 0;
fd = SDL_OpenAudioPath(NULL, 0, OPEN_FLAGS, 1);
if ( fd >= 0 ) {
available = 1;
close(fd);
}
return(available);
}
static void Audio_DeleteDevice(SDL_AudioDevice *device)
{
SDL_free(device->hidden);
SDL_free(device);
}
static SDL_AudioDevice *Audio_CreateDevice(int devindex)
{
SDL_AudioDevice *this;
/* Initialize all variables that we clean on shutdown */
this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
if ( this ) {
SDL_memset(this, 0, (sizeof *this));
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
}
if ( (this == NULL) || (this->hidden == NULL) ) {
SDL_OutOfMemory();
if ( this ) {
SDL_free(this);
}
return(0);
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
audio_fd = -1;
/* Set the function pointers */
this->OpenAudio = DSP_OpenAudio;
this->WaitAudio = DSP_WaitAudio;
this->PlayAudio = DSP_PlayAudio;
this->GetAudioBuf = DSP_GetAudioBuf;
this->CloseAudio = DSP_CloseAudio;
this->free = Audio_DeleteDevice;
return this;
}
AudioBootStrap SUNAUDIO_bootstrap = {
"audio", "UNIX /dev/audio interface",
Audio_Available, Audio_CreateDevice
};
#ifdef DEBUG_AUDIO
void CheckUnderflow(_THIS)
{
#ifdef AUDIO_GETINFO
audio_info_t info;
int left;
ioctl(audio_fd, AUDIO_GETINFO, &info);
left = (written - info.play.samples);
if ( written && (left == 0) ) {
fprintf(stderr, "audio underflow!\n");
}
#endif
}
#endif
void DSP_WaitAudio(_THIS)
{
#ifdef AUDIO_GETINFO
#define SLEEP_FUDGE 10 /* 10 ms scheduling fudge factor */
audio_info_t info;
Sint32 left;
ioctl(audio_fd, AUDIO_GETINFO, &info);
left = (written - info.play.samples);
if ( left > fragsize ) {
Sint32 sleepy;
sleepy = ((left - fragsize)/frequency);
sleepy -= SLEEP_FUDGE;
if ( sleepy > 0 ) {
SDL_Delay(sleepy);
}
}
#else
fd_set fdset;
FD_ZERO(&fdset);
FD_SET(audio_fd, &fdset);
select(audio_fd+1, NULL, &fdset, NULL, NULL);
#endif
}
void DSP_PlayAudio(_THIS)
{
/* Write the audio data */
if ( ulaw_only ) {
/* Assuming that this->spec.freq >= 8000 Hz */
int accum, incr, pos;
Uint8 *aubuf;
accum = 0;
incr = this->spec.freq/8;
aubuf = ulaw_buf;
switch (audio_fmt & 0xFF) {
case 8: {
Uint8 *sndbuf;
sndbuf = mixbuf;
for ( pos=0; pos < fragsize; ++pos ) {
*aubuf = snd2au((0x80-*sndbuf)*64);
accum += incr;
while ( accum > 0 ) {
accum -= 1000;
sndbuf += 1;
}
aubuf += 1;
}
}
break;
case 16: {
Sint16 *sndbuf;
sndbuf = (Sint16 *)mixbuf;
for ( pos=0; pos < fragsize; ++pos ) {
*aubuf = snd2au(*sndbuf/4);
accum += incr;
while ( accum > 0 ) {
accum -= 1000;
sndbuf += 1;
}
aubuf += 1;
}
}
break;
}
#ifdef DEBUG_AUDIO
CheckUnderflow(this);
#endif
if ( write(audio_fd, ulaw_buf, fragsize) < 0 ) {
/* Assume fatal error, for now */
this->enabled = 0;
}
written += fragsize;
} else {
#ifdef DEBUG_AUDIO
CheckUnderflow(this);
#endif
if ( write(audio_fd, mixbuf, this->spec.size) < 0 ) {
/* Assume fatal error, for now */
this->enabled = 0;
}
written += fragsize;
}
}
Uint8 *DSP_GetAudioBuf(_THIS)
{
return(mixbuf);
}
void DSP_CloseAudio(_THIS)
{
if ( mixbuf != NULL ) {
SDL_FreeAudioMem(mixbuf);
mixbuf = NULL;
}
if ( ulaw_buf != NULL ) {
SDL_free(ulaw_buf);
ulaw_buf = NULL;
}
close(audio_fd);
}
int DSP_OpenAudio(_THIS, SDL_AudioSpec *spec)
{
char audiodev[1024];
#ifdef AUDIO_SETINFO
int enc;
#endif
int desired_freq = spec->freq;
/* Initialize our freeable variables, in case we fail*/
audio_fd = -1;
mixbuf = NULL;
ulaw_buf = NULL;
/* Determine the audio parameters from the AudioSpec */
switch ( spec->format & 0xFF ) {
case 8: { /* Unsigned 8 bit audio data */
spec->format = AUDIO_U8;
#ifdef AUDIO_SETINFO
enc = AUDIO_ENCODING_LINEAR8;
#endif
}
break;
case 16: { /* Signed 16 bit audio data */
spec->format = AUDIO_S16SYS;
#ifdef AUDIO_SETINFO
enc = AUDIO_ENCODING_LINEAR;
#endif
}
break;
default: {
SDL_SetError("Unsupported audio format");
return(-1);
}
}
audio_fmt = spec->format;
/* Open the audio device */
audio_fd = SDL_OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 1);
if ( audio_fd < 0 ) {
SDL_SetError("Couldn't open %s: %s", audiodev,
strerror(errno));
return(-1);
}
ulaw_only = 0; /* modern Suns do support linear audio */
#ifdef AUDIO_SETINFO
for(;;) {
audio_info_t info;
AUDIO_INITINFO(&info); /* init all fields to "no change" */
/* Try to set the requested settings */
info.play.sample_rate = spec->freq;
info.play.channels = spec->channels;
info.play.precision = (enc == AUDIO_ENCODING_ULAW)
? 8 : spec->format & 0xff;
info.play.encoding = enc;
if( ioctl(audio_fd, AUDIO_SETINFO, &info) == 0 ) {
/* Check to be sure we got what we wanted */
if(ioctl(audio_fd, AUDIO_GETINFO, &info) < 0) {
SDL_SetError("Error getting audio parameters: %s",
strerror(errno));
return -1;
}
if(info.play.encoding == enc
&& info.play.precision == (spec->format & 0xff)
&& info.play.channels == spec->channels) {
/* Yow! All seems to be well! */
spec->freq = info.play.sample_rate;
break;
}
}
switch(enc) {
case AUDIO_ENCODING_LINEAR8:
/* unsigned 8bit apparently not supported here */
enc = AUDIO_ENCODING_LINEAR;
spec->format = AUDIO_S16SYS;
break; /* try again */
case AUDIO_ENCODING_LINEAR:
/* linear 16bit didn't work either, resort to µ-law */
enc = AUDIO_ENCODING_ULAW;
spec->channels = 1;
spec->freq = 8000;
spec->format = AUDIO_U8;
ulaw_only = 1;
break;
default:
/* oh well... */
SDL_SetError("Error setting audio parameters: %s",
strerror(errno));
return -1;
}
}
#endif /* AUDIO_SETINFO */
written = 0;
/* We can actually convert on-the-fly to U-Law */
if ( ulaw_only ) {
spec->freq = desired_freq;
fragsize = (spec->samples*1000)/(spec->freq/8);
frequency = 8;
ulaw_buf = (Uint8 *)SDL_malloc(fragsize);
if ( ulaw_buf == NULL ) {
SDL_OutOfMemory();
return(-1);
}
spec->channels = 1;
} else {
fragsize = spec->samples;
frequency = spec->freq/1000;
}
#ifdef DEBUG_AUDIO
fprintf(stderr, "Audio device %s U-Law only\n",
ulaw_only ? "is" : "is not");
fprintf(stderr, "format=0x%x chan=%d freq=%d\n",
spec->format, spec->channels, spec->freq);
#endif
/* Update the fragment size as size in bytes */
SDL_CalculateAudioSpec(spec);
/* Allocate mixing buffer */
mixbuf = (Uint8 *)SDL_AllocAudioMem(spec->size);
if ( mixbuf == NULL ) {
SDL_OutOfMemory();
return(-1);
}
SDL_memset(mixbuf, spec->silence, spec->size);
/* We're ready to rock and roll. :-) */
return(0);
}
/************************************************************************/
/* This function (snd2au()) copyrighted: */
/************************************************************************/
/* Copyright 1989 by Rich Gopstein and Harris Corporation */
/* */
/* Permission to use, copy, modify, and distribute this software */
/* and its documentation for any purpose and without fee is */
/* hereby granted, provided that the above copyright notice */
/* appears in all copies and that both that copyright notice and */
/* this permission notice appear in supporting documentation, and */
/* that the name of Rich Gopstein and Harris Corporation not be */
/* used in advertising or publicity pertaining to distribution */
/* of the software without specific, written prior permission. */
/* Rich Gopstein and Harris Corporation make no representations */
/* about the suitability of this software for any purpose. It */
/* provided "as is" without express or implied warranty. */
/************************************************************************/
static Uint8 snd2au(int sample)
{
int mask;
if (sample < 0) {
sample = -sample;
mask = 0x7f;
} else {
mask = 0xff;
}
if (sample < 32) {
sample = 0xF0 | (15 - sample / 2);
} else if (sample < 96) {
sample = 0xE0 | (15 - (sample - 32) / 4);
} else if (sample < 224) {
sample = 0xD0 | (15 - (sample - 96) / 8);
} else if (sample < 480) {
sample = 0xC0 | (15 - (sample - 224) / 16);
} else if (sample < 992) {
sample = 0xB0 | (15 - (sample - 480) / 32);
} else if (sample < 2016) {
sample = 0xA0 | (15 - (sample - 992) / 64);
} else if (sample < 4064) {
sample = 0x90 | (15 - (sample - 2016) / 128);
} else if (sample < 8160) {
sample = 0x80 | (15 - (sample - 4064) / 256);
} else {
sample = 0x80;
}
return (mask & sample);
}

View file

@ -1,55 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
#ifndef _SDL_lowaudio_h
#define _SDL_lowaudio_h
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the video functions */
#define _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData {
/* The file descriptor for the audio device */
int audio_fd;
Uint16 audio_fmt; /* The app audio format */
Uint8 *mixbuf; /* The app mixing buffer */
int ulaw_only; /* Flag -- does hardware only output U-law? */
Uint8 *ulaw_buf; /* The U-law mixing buffer */
Sint32 written; /* The number of samples written */
int fragsize; /* The audio fragment size in samples */
int frequency; /* The audio frequency in KHz */
};
/* Old variable names */
#define audio_fd (this->hidden->audio_fd)
#define audio_fmt (this->hidden->audio_fmt)
#define mixbuf (this->hidden->mixbuf)
#define ulaw_only (this->hidden->ulaw_only)
#define ulaw_buf (this->hidden->ulaw_buf)
#define written (this->hidden->written)
#define fragsize (this->hidden->fragsize)
#define frequency (this->hidden->frequency)
#endif /* _SDL_lowaudio_h */

View file

@ -1,614 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
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 library 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
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@devolution.com
*/
/*
SDL_epocaudio.cpp
Epoc based SDL audio driver implementation
Markus Mertama
*/
#ifdef SAVE_RCSID
static char rcsid =
"@(#) $Id: SDL_epocaudio.c,v 0.0.0.0 2001/06/19 17:19:56 hercules Exp $";
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include "epoc_sdl.h"
#include <e32hal.h>
extern "C" {
#include "SDL_audio.h"
#include "SDL_error.h"
#include "SDL_audiomem.h"
#include "SDL_audio_c.h"
#include "SDL_timer.h"
#include "SDL_audiodev_c.h"
}
#include "SDL_epocaudio.h"
#include "streamplayer.h"
//#define DEBUG_AUDIO
/* Audio driver functions */
static int EPOC_OpenAudio(SDL_AudioDevice *thisdevice, SDL_AudioSpec *spec);
static void EPOC_WaitAudio(SDL_AudioDevice *thisdevice);
static void EPOC_PlayAudio(SDL_AudioDevice *thisdevice);
static Uint8 *EPOC_GetAudioBuf(SDL_AudioDevice *thisdevice);
static void EPOC_CloseAudio(SDL_AudioDevice *thisdevice);
static void EPOC_ThreadInit(SDL_AudioDevice *thisdevice);
static int Audio_Available(void);
static SDL_AudioDevice *Audio_CreateDevice(int devindex);
static void Audio_DeleteDevice(SDL_AudioDevice *device);
//void sos_adump(SDL_AudioDevice* thisdevice, void* data, int len);
#ifdef __WINS__
#define DODUMP
#endif
#ifdef DODUMP
NONSHARABLE_CLASS(TDump)
{
public:
TInt Open();
void Close();
void Dump(const TDesC8& aDes);
private:
RFile iFile;
RFs iFs;
};
TInt TDump::Open()
{
TInt err = iFs.Connect();
if(err == KErrNone)
{
#ifdef __WINS__
_LIT(target, "C:\\sdlau.raw");
#else
_LIT(target, "E:\\sdlau.raw");
#endif
err = iFile.Replace(iFs, target, EFileWrite);
}
return err;
}
void TDump::Close()
{
iFile.Close();
iFs.Close();
}
void TDump::Dump(const TDesC8& aDes)
{
iFile.Write(aDes);
}
#endif
NONSHARABLE_CLASS(CSimpleWait) : public CTimer
{
public:
void Wait(TTimeIntervalMicroSeconds32 aWait);
static CSimpleWait* NewL();
private:
CSimpleWait();
void RunL();
};
CSimpleWait* CSimpleWait::NewL()
{
CSimpleWait* wait = new (ELeave) CSimpleWait();
CleanupStack::PushL(wait);
wait->ConstructL();
CleanupStack::Pop();
return wait;
}
void CSimpleWait::Wait(TTimeIntervalMicroSeconds32 aWait)
{
After(aWait);
CActiveScheduler::Start();
}
CSimpleWait::CSimpleWait() : CTimer(CActive::EPriorityStandard)
{
CActiveScheduler::Add(this);
}
void CSimpleWait::RunL()
{
CActiveScheduler::Stop();
}
const TInt KAudioBuffers(2);
NONSHARABLE_CLASS(CEpocAudio) : public CBase, public MStreamObs, public MStreamProvider
{
public:
static void* NewL(TInt BufferSize, TInt aFill);
inline static CEpocAudio& Current(SDL_AudioDevice* thisdevice);
static void Free(SDL_AudioDevice* thisdevice);
void Wait();
void Play();
// void SetBuffer(const TDesC8& aBuffer);
void ThreadInitL(TAny* aDevice);
void Open(TInt iRate, TInt iChannels, TUint32 aType, TInt aBytes);
~CEpocAudio();
TUint8* Buffer();
TBool SetPause(TBool aPause);
#ifdef DODUMP
void Dump(const TDesC8& aBuf) {iDump.Dump(aBuf);}
#endif
private:
CEpocAudio(TInt aBufferSize);
void Complete(TInt aState, TInt aError);
TPtrC8 Data();
void ConstructL(TInt aFill);
private:
TInt iBufferSize;
CStreamPlayer* iPlayer;
TInt iBufferRate;
TInt iRate;
TInt iChannels;
TUint32 iType;
TInt iPosition;
TThreadId iTid;
TUint8* iAudioPtr;
TUint8* iBuffer;
// TTimeIntervalMicroSeconds iStart;
TTime iStart;
TInt iTune;
CSimpleWait* iWait;
#ifdef DODUMP
TDump iDump;
#endif
};
inline CEpocAudio& CEpocAudio::Current(SDL_AudioDevice* thisdevice)
{
return *static_cast<CEpocAudio*>((void*)thisdevice->hidden);
}
/*
TBool EndSc(TAny*)
{
CActiveScheduler::Stop();
}
LOCAL_C void CleanScL()
{
CIdle* d = CIdle::NewLC(CActive:::EPriorityIdle);
d->Start(TCallBack(EndSc));
CActiveScheduler::Start();
}
*/
void CEpocAudio::Free(SDL_AudioDevice* thisdevice)
{
CEpocAudio* ea = static_cast<CEpocAudio*>((void*)thisdevice->hidden);
if(ea)
{
ASSERT(ea->iTid == RThread().Id());
delete ea;
thisdevice->hidden = NULL;
CActiveScheduler* as = CActiveScheduler::Current();
ASSERT(as->StackDepth() == 0);
delete as;
CActiveScheduler::Install(NULL);
}
ASSERT(thisdevice->hidden == NULL);
}
CEpocAudio::CEpocAudio(TInt aBufferSize) : iBufferSize(aBufferSize), iPosition(-1)
{
}
void* CEpocAudio::NewL(TInt aBufferSize, TInt aFill)
{
CEpocAudio* eAudioLib = new (ELeave) CEpocAudio(aBufferSize);
CleanupStack::PushL(eAudioLib);
eAudioLib->ConstructL(aFill);
CleanupStack::Pop();
return eAudioLib;
}
void CEpocAudio::ConstructL(TInt aFill)
{
iBuffer = (TUint8*) User::AllocL(KAudioBuffers * iBufferSize);
memset(iBuffer, aFill, KAudioBuffers * iBufferSize);
iAudioPtr = iBuffer;
}
TBool CEpocAudio::SetPause(TBool aPause)
{
if(aPause && iPosition >= 0)
{
iPosition = -1;
if(iPlayer != NULL)
iPlayer->Stop();
}
if(!aPause && iPosition < 0)
{
iPosition = 0;
if(iPlayer != NULL)
iPlayer->Start();
}
return iPosition < 0;
}
void CEpocAudio::ThreadInitL(TAny* aDevice)
{
iTid = RThread().Id();
CActiveScheduler* as = new (ELeave) CActiveScheduler();
CActiveScheduler::Install(as);
EpocSdlEnv::AppendCleanupItem(TSdlCleanupItem((TSdlCleanupOperation)EPOC_CloseAudio, aDevice));
iWait = CSimpleWait::NewL();
iPlayer = new (ELeave) CStreamPlayer(*this, *this);
iPlayer->ConstructL();
iPlayer->OpenStream(iRate, iChannels, iType);
#ifdef DODUMP
User::LeaveIfError(iDump.Open());
#endif
}
TUint8* CEpocAudio::Buffer()
{
iStart.UniversalTime();
// iStart = iPlayer->Position();
return iAudioPtr;
}
CEpocAudio::~CEpocAudio()
{
if(iWait != NULL)
iWait->Cancel();
delete iWait;
if(iPlayer != NULL)
iPlayer->Close();
delete iPlayer;
delete iBuffer;
}
void CEpocAudio::Complete(TInt aState, TInt aError)
{
if(aState == MStreamObs::EClose)
{
}
if(iPlayer->Closed())
return;
switch(aError)
{
case KErrUnderflow:
case KErrInUse:
iPlayer->Start();
break;
case KErrAbort:
iPlayer->Open();
}
}
void sos_adump(SDL_AudioDevice* thisdevice, void* data, int len)
{
#ifdef DODUMP
const TPtrC8 buf((TUint8*)data, len);
CEpocAudio::Current(thisdevice).Dump(buf);
#endif
}
const TInt KClip(256);
TPtrC8 CEpocAudio::Data()
{
if(iPosition < 0)
return KNullDesC8();
TPtrC8 data(iAudioPtr + iPosition, KClip);
#ifdef DODUMP
iDump.Dump(data);
#endif
iPosition += KClip;
if(iPosition >= iBufferSize)
{
/* if(iAudioPtr == iBuffer)
iAudioPtr = iBuffer + iBufferSize;
else
iAudioPtr = iBuffer;
*/
iAudioPtr += iBufferSize;
if((iAudioPtr - iBuffer) >= KAudioBuffers * iBufferSize)
iAudioPtr = iBuffer;
iPosition = -1;
if(iWait->IsActive())
{
iWait->Cancel();
CActiveScheduler::Stop();
}
}
return data;
}
void CEpocAudio::Play()
{
iPosition = 0;
}
void CEpocAudio::Wait()
{
if(iPosition >= 0 /*&& iPlayer->Playing()*/)
{
const TInt64 bufMs = TInt64(iBufferSize - KClip) * TInt64(1000000);
const TInt64 specTime = bufMs / TInt64(iRate * iChannels * 2);
iWait->After(specTime);
CActiveScheduler::Start();
TTime end;
end.UniversalTime();
const TTimeIntervalMicroSeconds delta = end.MicroSecondsFrom(iStart);
// const TTimeIntervalMicroSeconds end = iPlayer->Position();
const TInt diff = specTime - delta.Int64();
if(diff > 0 && diff < 200000)
{
User::After(diff);
}
}
else
{
User::After(10000);
// iWait->Wait(10000); //just give some time...
}
}
void CEpocAudio::Open(TInt aRate, TInt aChannels, TUint32 aType, TInt aBytes)
{
iRate = aRate;
iChannels = aChannels;
iType = aType;
iBufferRate = iRate * iChannels * aBytes; //1/x
}
/* Audio driver bootstrap functions */
AudioBootStrap EPOCAudio_bootstrap = {
"epoc\0\0\0",
"EPOC streaming audio\0\0\0",
Audio_Available,
Audio_CreateDevice
};
static SDL_AudioDevice *Audio_CreateDevice(int /*devindex*/)
{
SDL_AudioDevice *thisdevice;
/* Initialize all variables that we clean on shutdown */
thisdevice = (SDL_AudioDevice *)malloc(sizeof(SDL_AudioDevice));
if ( thisdevice ) {
memset(thisdevice, 0, (sizeof *thisdevice));
thisdevice->hidden = NULL; /*(struct SDL_PrivateAudioData *)
malloc((sizeof thisdevice->hidden)); */
}
if ( (thisdevice == NULL) /*|| (thisdevice->hidden == NULL) */) {
SDL_OutOfMemory();
if ( thisdevice ) {
free(thisdevice);
}
return(0);
}
// memset(thisdevice->hidden, 0, (sizeof *thisdevice->hidden));
/* Set the function pointers */
thisdevice->OpenAudio = EPOC_OpenAudio;
thisdevice->WaitAudio = EPOC_WaitAudio;
thisdevice->PlayAudio = EPOC_PlayAudio;
thisdevice->GetAudioBuf = EPOC_GetAudioBuf;
thisdevice->CloseAudio = EPOC_CloseAudio;
thisdevice->ThreadInit = EPOC_ThreadInit;
thisdevice->free = Audio_DeleteDevice;
return thisdevice;
}
static void Audio_DeleteDevice(SDL_AudioDevice *device)
{
//free(device->hidden);
free(device);
}
static int Audio_Available(void)
{
return(1); // Audio stream modules should be always there!
}
static int EPOC_OpenAudio(SDL_AudioDevice *thisdevice, SDL_AudioSpec *spec)
{
SDL_TRACE("SDL:EPOC_OpenAudio");
TUint32 type = KMMFFourCCCodePCM16;
TInt bytes = 2;
switch(spec->format)
{
case AUDIO_U16LSB:
type = KMMFFourCCCodePCMU16;
break;
case AUDIO_S16LSB:
type = KMMFFourCCCodePCM16;
break;
case AUDIO_U16MSB:
type = KMMFFourCCCodePCMU16B;
break;
case AUDIO_S16MSB:
type = KMMFFourCCCodePCM16B;
break;
//8 bit not supported!
case AUDIO_U8:
case AUDIO_S8:
default:
spec->format = AUDIO_S16LSB;
};
if(spec->channels > 2)
spec->channels = 2;
spec->freq = CStreamPlayer::ClosestSupportedRate(spec->freq);
/* Allocate mixing buffer */
const TInt buflen = spec->size;// * bytes * spec->channels;
// audiobuf = NULL;
TRAPD(err, thisdevice->hidden = static_cast<SDL_PrivateAudioData*>(CEpocAudio::NewL(buflen, spec->silence)));
if(err != KErrNone)
return -1;
CEpocAudio::Current(thisdevice).Open(spec->freq, spec->channels, type, bytes);
CEpocAudio::Current(thisdevice).SetPause(ETrue);
// isSDLAudioPaused = 1;
thisdevice->enabled = 0; /* enable only after audio engine has been initialized!*/
/* We're ready to rock and roll. :-) */
return(0);
}
static void EPOC_CloseAudio(SDL_AudioDevice* thisdevice)
{
#ifdef DEBUG_AUDIO
SDL_TRACE("Close audio\n");
#endif
CEpocAudio::Free(thisdevice);
}
static void EPOC_ThreadInit(SDL_AudioDevice *thisdevice)
{
SDL_TRACE("SDL:EPOC_ThreadInit");
CEpocAudio::Current(thisdevice).ThreadInitL(thisdevice);
RThread().SetPriority(EPriorityMore);
thisdevice->enabled = 1;
}
/* This function waits until it is possible to write a full sound buffer */
static void EPOC_WaitAudio(SDL_AudioDevice* thisdevice)
{
#ifdef DEBUG_AUDIO
SDL_TRACE1("wait %d audio\n", CEpocAudio::AudioLib().StreamPlayer(KSfxChannel).SyncTime());
TInt tics = User::TickCount();
#endif
CEpocAudio::Current(thisdevice).Wait();
#ifdef DEBUG_AUDIO
TInt ntics = User::TickCount() - tics;
SDL_TRACE1("audio waited %d\n", ntics);
SDL_TRACE1("audio at %d\n", tics);
#endif
}
static void EPOC_PlayAudio(SDL_AudioDevice* thisdevice)
{
if(CEpocAudio::Current(thisdevice).SetPause(SDL_GetAudioStatus() == SDL_AUDIO_PAUSED))
SDL_Delay(500); //hold on the busy loop
else
CEpocAudio::Current(thisdevice).Play();
#ifdef DEBUG_AUDIO
SDL_TRACE("buffer has audio data\n");
#endif
#ifdef DEBUG_AUDIO
SDL_TRACE1("Wrote %d bytes of audio data\n", buflen);
#endif
}
static Uint8 *EPOC_GetAudioBuf(SDL_AudioDevice* thisdevice)
{
return CEpocAudio::Current(thisdevice).Buffer();
}

View file

@ -1,37 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
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 library 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
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@devolution.com
*/
#ifdef SAVE_RCSID
static char rcsid =
"@(#) $Id: SDL_epocaudio.h,v 1.1.2.2 2001/02/10 07:20:03 hercules Exp $";
#endif
#ifndef _SDL_EPOCAUDIO_H
#define _SDL_EPOCAUDIO_H
extern "C" {
#include "SDL_sysaudio.h"
}
#endif /* _SDL_EPOCAUDIO_H */

View file

@ -1,279 +0,0 @@
#include "streamplayer.h"
#include<mda/common/audio.h>
const TInt KMaxVolume(256);
LOCAL_C TInt GetSampleRate(TInt aRate)
{
switch(aRate)
{
case 8000: return TMdaAudioDataSettings::ESampleRate8000Hz;
case 11025: return TMdaAudioDataSettings::ESampleRate11025Hz;
case 12000: return TMdaAudioDataSettings::ESampleRate12000Hz;
case 16000: return TMdaAudioDataSettings::ESampleRate16000Hz;
case 22050: return TMdaAudioDataSettings::ESampleRate22050Hz;
case 24000: return TMdaAudioDataSettings::ESampleRate24000Hz;
case 32000: return TMdaAudioDataSettings::ESampleRate32000Hz;
case 44100: return TMdaAudioDataSettings::ESampleRate44100Hz;
case 48000: return TMdaAudioDataSettings::ESampleRate48000Hz;
case 96000: return TMdaAudioDataSettings::ESampleRate96000Hz;
case 64000: return TMdaAudioDataSettings::ESampleRate64000Hz;
}
return KErrNotFound;
}
LOCAL_C TInt GetChannels(TInt aChannels)
{
switch(aChannels)
{
case 1: return TMdaAudioDataSettings::EChannelsMono;
case 2: return TMdaAudioDataSettings::EChannelsStereo;
}
return KErrNotFound;
}
TInt CStreamPlayer::ClosestSupportedRate(TInt aRate)
{
if(aRate > 96000)
return 96000;
TInt rate = aRate;
while(GetSampleRate(rate) == KErrNotFound)
{
++rate;
}
return rate;
}
CStreamPlayer::CStreamPlayer(MStreamProvider& aProvider, MStreamObs& aObs) :
iProvider(aProvider), iObs(aObs), iVolume(KMaxVolume)
{
}
CStreamPlayer::~CStreamPlayer()
{
iState |= EDied;
if(iState & EInited)
Close();
User::After(100000); //wait buffer to be flushed
ASSERT(iPtr.Length() == 0);
delete iStream;
}
void CStreamPlayer::ConstructL()
{
iStream = CMdaAudioOutputStream::NewL(*this, EMdaPriorityMax);
iSilence.SetMax();
iSilence.FillZ();
}
TInt CStreamPlayer::OpenStream(TInt aRate, TInt aChannels, TUint32 aType)
{
Close();
iType = aType;
iRate = GetSampleRate(aRate);
if(iRate == KErrNotFound)
return KErrNotSupported;
iChannels = GetChannels(aChannels);
if(iChannels == KErrNotFound)
return KErrNotSupported;
Open();
return KErrNone;
}
TInt CStreamPlayer::MaxVolume() const
{
return KMaxVolume;
}
void CStreamPlayer::SetVolume(TInt aNew)
{
const TInt maxi = MaxVolume();
if(aNew > maxi)
return;
if(aNew < 0)
return;
iVolume = aNew;
iState |= EVolumeChange;
}
TInt CStreamPlayer::Volume() const
{
return iVolume;
}
void CStreamPlayer::Open()
{
TMdaAudioDataSettings audioSettings;
audioSettings.Query();
audioSettings.iCaps = TMdaAudioDataSettings::ERealTime |
TMdaAudioDataSettings::ESampleRateFixed;
audioSettings.iSampleRate = iRate;
audioSettings.iChannels = iChannels;
audioSettings.iFlags = TMdaAudioDataSettings::ENoNetworkRouting;
audioSettings.iVolume = 0;
iState &= ~EStopped;
iStream->Open(&audioSettings);
}
void CStreamPlayer::Stop()
{
if(iState & (EStarted | EInited))
{
Close();
iState |= EStopped;
}
}
void CStreamPlayer::Start()
{
if(iPtr.Length() == 0)
{
iState |= EStarted;
if(iState & EInited)
{
Request();
}
else if(iState & EStopped)
{
Open();
}
}
}
void CStreamPlayer::Close()
{
iState &= ~EInited;
iStream->Stop();
iState &= ~EStarted;
}
void CStreamPlayer::Request()
{
if(iState & EInited)
{
iPtr.Set(KNullDesC8);
if(iState & EVolumeChange)
{
const TReal newVol = iVolume;
const TReal newMax = MaxVolume();
const TInt maxVol = iStream->MaxVolume();
const TReal max = static_cast<TReal>(maxVol);
const TReal newvolume = (newVol * max) / newMax;
const TInt vol = static_cast<TReal>(newvolume);
iStream->SetVolume(vol);
iState &= ~EVolumeChange;
}
if(iState & EStarted)
{
iPtr.Set(iProvider.Data());
}
if(iPtr.Length() == 0)
{
iPtr.Set(iSilence);
}
TRAPD(err, iStream->WriteL(iPtr));
if(err != KErrNone)
{
iObs.Complete(MStreamObs::EWrite, err);
}
/* else
{
iProvider.Written(iPtr.Length());
}*/
}
}
void CStreamPlayer::SetCapsL()
{
iStream->SetDataTypeL(iType);
iStream->SetAudioPropertiesL(iRate, iChannels);
}
void CStreamPlayer::MaoscOpenComplete(TInt aError)
{
if(aError == KErrNone)
{
TRAPD(err, SetCapsL());
if(err == KErrNone)
{
iStream->SetPriority(EPriorityNormal, EMdaPriorityPreferenceTime);
iState |= EInited;
SetVolume(Volume());
if(iState & EStarted)
{
Request();
}
}
aError = err;
}
if(!(iState & EDied))
iObs.Complete(MStreamObs::EInit, aError);
}
void CStreamPlayer::MaoscBufferCopied(TInt aError, const TDesC8& /*aBuffer*/)
{
iPtr.Set(KNullDesC8);
if(aError == KErrNone)
{
if(iState & EInited)
Request();
else
iStream->Stop();
}
else if(!(iState & EDied))
iObs.Complete(MStreamObs::EPlay, aError);
}
void CStreamPlayer::MaoscPlayComplete(TInt aError)
{
iPtr.Set(KNullDesC8);
iState &= ~EStarted;
if(!(iState & EDied))
iObs.Complete(MStreamObs::EClose, aError);
}
TBool CStreamPlayer::Playing() const
{
return (iState & EInited) && (iState & EStarted);
}
TBool CStreamPlayer::Closed() const
{
return !(iState & EInited) && !(iState & EDied);
}
/*
void CStreamPlayer::Request()
{
SetActive();
TRequestStatus* s = &iStatus;
User::RequestComplete(s, KErrNone);
}
// iTimer.After(0);
*/

View file

@ -1,89 +0,0 @@
#ifndef STREAMPLAYER_H
#define STREAMPLAYER_H
#include<MdaAudioOutputStream.h>
const TInt KSilenceBuffer = 256;
class MStreamObs
{
public:
enum
{
EInit,
EPlay,
EWrite,
EClose,
};
virtual void Complete(TInt aState, TInt aError) = 0;
};
class MStreamProvider
{
public:
virtual TPtrC8 Data() = 0;
};
NONSHARABLE_CLASS(CStreamPlayer) : public CBase, public MMdaAudioOutputStreamCallback
{
public:
CStreamPlayer(MStreamProvider& aProvider, MStreamObs& aObs);
~CStreamPlayer();
void ConstructL();
static TInt ClosestSupportedRate(TInt aRate);
TInt OpenStream(TInt aRate, TInt aChannels, TUint32 aType = KMMFFourCCCodePCM16);
void SetVolume(TInt aNew);
TInt Volume() const;
TInt MaxVolume() const;
void Stop();
void Start();
void Open();
void Close();
TBool Playing() const;
TBool Closed() const;
private:
void MaoscOpenComplete(TInt aError) ;
void MaoscBufferCopied(TInt aError, const TDesC8& aBuffer);
void MaoscPlayComplete(TInt aError);
private:
void Request();
void SetCapsL();
private:
MStreamProvider& iProvider;
MStreamObs& iObs;
TInt iVolume;
CMdaAudioOutputStream* iStream;
TInt iRate;
TInt iChannels;
TUint32 iType;
enum
{
ENone = 0,
EInited = 0x1,
EStarted = 0x2,
EStopped = 0x4,
EVolumeChange = 0x8,
EDied = 0x10
};
TInt iState;
TBuf8<KSilenceBuffer> iSilence;
TPtrC8 iPtr;
};
#endif

View file

@ -1,547 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Carsten Griwodz
griff@kom.tu-darmstadt.de
based on linux/SDL_dspaudio.c by Sam Lantinga
*/
#include "SDL_config.h"
/* Allow access to a raw mixing buffer */
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include "SDL_audio.h"
#include "../SDL_audio_c.h"
#include "../SDL_audiodev_c.h"
#include "SDL_umsaudio.h"
/* The tag name used by UMS audio */
#define UMS_DRIVER_NAME "ums"
#define DEBUG_AUDIO 1
/* Audio driver functions */
static int UMS_OpenAudio(_THIS, SDL_AudioSpec *spec);
static void UMS_PlayAudio(_THIS);
static Uint8 *UMS_GetAudioBuf(_THIS);
static void UMS_CloseAudio(_THIS);
static UMSAudioDevice_ReturnCode UADOpen(_THIS, string device, string mode, long flags);
static UMSAudioDevice_ReturnCode UADClose(_THIS);
static UMSAudioDevice_ReturnCode UADGetBitsPerSample(_THIS, long* bits);
static UMSAudioDevice_ReturnCode UADSetBitsPerSample(_THIS, long bits);
static UMSAudioDevice_ReturnCode UADSetSampleRate(_THIS, long rate, long* set_rate);
static UMSAudioDevice_ReturnCode UADSetByteOrder(_THIS, string byte_order);
static UMSAudioDevice_ReturnCode UADSetAudioFormatType(_THIS, string fmt);
static UMSAudioDevice_ReturnCode UADSetNumberFormat(_THIS, string fmt);
static UMSAudioDevice_ReturnCode UADInitialize(_THIS);
static UMSAudioDevice_ReturnCode UADStart(_THIS);
static UMSAudioDevice_ReturnCode UADStop(_THIS);
static UMSAudioDevice_ReturnCode UADSetTimeFormat(_THIS, UMSAudioTypes_TimeFormat fmt );
static UMSAudioDevice_ReturnCode UADWriteBuffSize(_THIS, long* buff_size );
static UMSAudioDevice_ReturnCode UADWriteBuffRemain(_THIS, long* buff_size );
static UMSAudioDevice_ReturnCode UADWriteBuffUsed(_THIS, long* buff_size );
static UMSAudioDevice_ReturnCode UADSetDMABufferSize(_THIS, long bytes, long* bytes_ret );
static UMSAudioDevice_ReturnCode UADSetVolume(_THIS, long volume );
static UMSAudioDevice_ReturnCode UADSetBalance(_THIS, long balance );
static UMSAudioDevice_ReturnCode UADSetChannels(_THIS, long channels );
static UMSAudioDevice_ReturnCode UADPlayRemainingData(_THIS, boolean block );
static UMSAudioDevice_ReturnCode UADEnableOutput(_THIS, string output, long* left_gain, long* right_gain);
static UMSAudioDevice_ReturnCode UADWrite(_THIS, UMSAudioTypes_Buffer* buff, long samples, long* samples_written);
/* Audio driver bootstrap functions */
static int Audio_Available(void)
{
return 1;
}
static void Audio_DeleteDevice(_THIS)
{
if(this->hidden->playbuf._buffer) SDL_free(this->hidden->playbuf._buffer);
if(this->hidden->fillbuf._buffer) SDL_free(this->hidden->fillbuf._buffer);
_somFree( this->hidden->umsdev );
SDL_free(this->hidden);
SDL_free(this);
}
static SDL_AudioDevice *Audio_CreateDevice(int devindex)
{
SDL_AudioDevice *this;
/*
* Allocate and initialize management storage and private management
* storage for this SDL-using library.
*/
this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
if ( this ) {
SDL_memset(this, 0, (sizeof *this));
this->hidden = (struct SDL_PrivateAudioData *)SDL_malloc((sizeof *this->hidden));
}
if ( (this == NULL) || (this->hidden == NULL) ) {
SDL_OutOfMemory();
if ( this ) {
SDL_free(this);
}
return(0);
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
#ifdef DEBUG_AUDIO
fprintf(stderr, "Creating UMS Audio device\n");
#endif
/*
* Calls for UMS env initialization and audio object construction.
*/
this->hidden->ev = somGetGlobalEnvironment();
this->hidden->umsdev = UMSAudioDeviceNew();
/*
* Set the function pointers.
*/
this->OpenAudio = UMS_OpenAudio;
this->WaitAudio = NULL; /* we do blocking output */
this->PlayAudio = UMS_PlayAudio;
this->GetAudioBuf = UMS_GetAudioBuf;
this->CloseAudio = UMS_CloseAudio;
this->free = Audio_DeleteDevice;
#ifdef DEBUG_AUDIO
fprintf(stderr, "done\n");
#endif
return this;
}
AudioBootStrap UMS_bootstrap = {
UMS_DRIVER_NAME, "AIX UMS audio",
Audio_Available, Audio_CreateDevice
};
static Uint8 *UMS_GetAudioBuf(_THIS)
{
#ifdef DEBUG_AUDIO
fprintf(stderr, "enter UMS_GetAudioBuf\n");
#endif
return this->hidden->fillbuf._buffer;
/*
long bufSize;
UMSAudioDevice_ReturnCode rc;
rc = UADSetTimeFormat(this, UMSAudioTypes_Bytes );
rc = UADWriteBuffSize(this, bufSize );
*/
}
static void UMS_CloseAudio(_THIS)
{
UMSAudioDevice_ReturnCode rc;
#ifdef DEBUG_AUDIO
fprintf(stderr, "enter UMS_CloseAudio\n");
#endif
rc = UADPlayRemainingData(this, TRUE);
rc = UADStop(this);
rc = UADClose(this);
}
static void UMS_PlayAudio(_THIS)
{
UMSAudioDevice_ReturnCode rc;
long samplesToWrite;
long samplesWritten;
UMSAudioTypes_Buffer swpbuf;
#ifdef DEBUG_AUDIO
fprintf(stderr, "enter UMS_PlayAudio\n");
#endif
samplesToWrite = this->hidden->playbuf._length/this->hidden->bytesPerSample;
do
{
rc = UADWrite(this, &this->hidden->playbuf,
samplesToWrite,
&samplesWritten );
samplesToWrite -= samplesWritten;
/* rc values: UMSAudioDevice_Success
* UMSAudioDevice_Failure
* UMSAudioDevice_Preempted
* UMSAudioDevice_Interrupted
* UMSAudioDevice_DeviceError
*/
if ( rc == UMSAudioDevice_DeviceError ) {
#ifdef DEBUG_AUDIO
fprintf(stderr, "Returning from PlayAudio with devices error\n");
#endif
return;
}
}
while(samplesToWrite>0);
SDL_LockAudio();
SDL_memcpy( &swpbuf, &this->hidden->playbuf, sizeof(UMSAudioTypes_Buffer) );
SDL_memcpy( &this->hidden->playbuf, &this->hidden->fillbuf, sizeof(UMSAudioTypes_Buffer) );
SDL_memcpy( &this->hidden->fillbuf, &swpbuf, sizeof(UMSAudioTypes_Buffer) );
SDL_UnlockAudio();
#ifdef DEBUG_AUDIO
fprintf(stderr, "Wrote audio data and swapped buffer\n");
#endif
}
#if 0
// /* Set the DSP frequency */
// value = spec->freq;
// if ( ioctl(this->hidden->audio_fd, SOUND_PCM_WRITE_RATE, &value) < 0 ) {
// SDL_SetError("Couldn't set audio frequency");
// return(-1);
// }
// spec->freq = value;
#endif
static int UMS_OpenAudio(_THIS, SDL_AudioSpec *spec)
{
char* audiodev = "/dev/paud0";
long lgain;
long rgain;
long outRate;
long outBufSize;
long bitsPerSample;
long samplesPerSec;
long success;
Uint16 test_format;
int frag_spec;
UMSAudioDevice_ReturnCode rc;
#ifdef DEBUG_AUDIO
fprintf(stderr, "enter UMS_OpenAudio\n");
#endif
rc = UADOpen(this, audiodev,"PLAY", UMSAudioDevice_BlockingIO);
if ( rc != UMSAudioDevice_Success ) {
SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno));
return -1;
}
rc = UADSetAudioFormatType(this, "PCM");
success = 0;
test_format = SDL_FirstAudioFormat(spec->format);
do
{
#ifdef DEBUG_AUDIO
fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
#endif
switch ( test_format )
{
case AUDIO_U8:
/* from the mac code: better ? */
/* sample_bits = spec->size / spec->samples / spec->channels * 8; */
success = 1;
bitsPerSample = 8;
rc = UADSetSampleRate(this, spec->freq << 16, &outRate );
rc = UADSetByteOrder(this, "MSB"); /* irrelevant */
rc = UADSetNumberFormat(this, "UNSIGNED");
break;
case AUDIO_S8:
success = 1;
bitsPerSample = 8;
rc = UADSetSampleRate(this, spec->freq << 16, &outRate );
rc = UADSetByteOrder(this, "MSB"); /* irrelevant */
rc = UADSetNumberFormat(this, "SIGNED");
break;
case AUDIO_S16LSB:
success = 1;
bitsPerSample = 16;
rc = UADSetSampleRate(this, spec->freq << 16, &outRate );
rc = UADSetByteOrder(this, "LSB");
rc = UADSetNumberFormat(this, "SIGNED");
break;
case AUDIO_S16MSB:
success = 1;
bitsPerSample = 16;
rc = UADSetSampleRate(this, spec->freq << 16, &outRate );
rc = UADSetByteOrder(this, "MSB");
rc = UADSetNumberFormat(this, "SIGNED");
break;
case AUDIO_U16LSB:
success = 1;
bitsPerSample = 16;
rc = UADSetSampleRate(this, spec->freq << 16, &outRate );
rc = UADSetByteOrder(this, "LSB");
rc = UADSetNumberFormat(this, "UNSIGNED");
break;
case AUDIO_U16MSB:
success = 1;
bitsPerSample = 16;
rc = UADSetSampleRate(this, spec->freq << 16, &outRate );
rc = UADSetByteOrder(this, "MSB");
rc = UADSetNumberFormat(this, "UNSIGNED");
break;
default:
break;
}
if ( ! success ) {
test_format = SDL_NextAudioFormat();
}
}
while ( ! success && test_format );
if ( success == 0 ) {
SDL_SetError("Couldn't find any hardware audio formats");
return -1;
}
spec->format = test_format;
for ( frag_spec = 0; (0x01<<frag_spec) < spec->size; ++frag_spec );
if ( (0x01<<frag_spec) != spec->size ) {
SDL_SetError("Fragment size must be a power of two");
return -1;
}
if ( frag_spec > 2048 ) frag_spec = 2048;
this->hidden->bytesPerSample = (bitsPerSample / 8) * spec->channels;
samplesPerSec = this->hidden->bytesPerSample * outRate;
this->hidden->playbuf._length = 0;
this->hidden->playbuf._maximum = spec->size;
this->hidden->playbuf._buffer = (unsigned char*)SDL_malloc(spec->size);
this->hidden->fillbuf._length = 0;
this->hidden->fillbuf._maximum = spec->size;
this->hidden->fillbuf._buffer = (unsigned char*)SDL_malloc(spec->size);
rc = UADSetBitsPerSample(this, bitsPerSample );
rc = UADSetDMABufferSize(this, frag_spec, &outBufSize );
rc = UADSetChannels(this, spec->channels); /* functions reduces to mono or stereo */
lgain = 100; /*maximum left input gain*/
rgain = 100; /*maimum right input gain*/
rc = UADEnableOutput(this, "LINE_OUT",&lgain,&rgain);
rc = UADInitialize(this);
rc = UADStart(this);
rc = UADSetVolume(this, 100);
rc = UADSetBalance(this, 0);
/* We're ready to rock and roll. :-) */
return 0;
}
static UMSAudioDevice_ReturnCode UADGetBitsPerSample(_THIS, long* bits)
{
return UMSAudioDevice_get_bits_per_sample( this->hidden->umsdev,
this->hidden->ev,
bits );
}
static UMSAudioDevice_ReturnCode UADSetBitsPerSample(_THIS, long bits)
{
return UMSAudioDevice_set_bits_per_sample( this->hidden->umsdev,
this->hidden->ev,
bits );
}
static UMSAudioDevice_ReturnCode UADSetSampleRate(_THIS, long rate, long* set_rate)
{
/* from the mac code: sample rate = spec->freq << 16; */
return UMSAudioDevice_set_sample_rate( this->hidden->umsdev,
this->hidden->ev,
rate,
set_rate );
}
static UMSAudioDevice_ReturnCode UADSetByteOrder(_THIS, string byte_order)
{
return UMSAudioDevice_set_byte_order( this->hidden->umsdev,
this->hidden->ev,
byte_order );
}
static UMSAudioDevice_ReturnCode UADSetAudioFormatType(_THIS, string fmt)
{
/* possible PCM, A_LAW or MU_LAW */
return UMSAudioDevice_set_audio_format_type( this->hidden->umsdev,
this->hidden->ev,
fmt );
}
static UMSAudioDevice_ReturnCode UADSetNumberFormat(_THIS, string fmt)
{
/* possible SIGNED, UNSIGNED, or TWOS_COMPLEMENT */
return UMSAudioDevice_set_number_format( this->hidden->umsdev,
this->hidden->ev,
fmt );
}
static UMSAudioDevice_ReturnCode UADInitialize(_THIS)
{
return UMSAudioDevice_initialize( this->hidden->umsdev,
this->hidden->ev );
}
static UMSAudioDevice_ReturnCode UADStart(_THIS)
{
return UMSAudioDevice_start( this->hidden->umsdev,
this->hidden->ev );
}
static UMSAudioDevice_ReturnCode UADSetTimeFormat(_THIS, UMSAudioTypes_TimeFormat fmt )
{
/*
* Switches the time format to the new format, immediately.
* possible UMSAudioTypes_Msecs, UMSAudioTypes_Bytes or UMSAudioTypes_Samples
*/
return UMSAudioDevice_set_time_format( this->hidden->umsdev,
this->hidden->ev,
fmt );
}
static UMSAudioDevice_ReturnCode UADWriteBuffSize(_THIS, long* buff_size )
{
/*
* returns write buffer size in the current time format
*/
return UMSAudioDevice_write_buff_size( this->hidden->umsdev,
this->hidden->ev,
buff_size );
}
static UMSAudioDevice_ReturnCode UADWriteBuffRemain(_THIS, long* buff_size )
{
/*
* returns amount of available space in the write buffer
* in the current time format
*/
return UMSAudioDevice_write_buff_remain( this->hidden->umsdev,
this->hidden->ev,
buff_size );
}
static UMSAudioDevice_ReturnCode UADWriteBuffUsed(_THIS, long* buff_size )
{
/*
* returns amount of filled space in the write buffer
* in the current time format
*/
return UMSAudioDevice_write_buff_used( this->hidden->umsdev,
this->hidden->ev,
buff_size );
}
static UMSAudioDevice_ReturnCode UADSetDMABufferSize(_THIS, long bytes, long* bytes_ret )
{
/*
* Request a new DMA buffer size, maximum requested size 2048.
* Takes effect with next initialize() call.
* Devices may or may not support DMA.
*/
return UMSAudioDevice_set_DMA_buffer_size( this->hidden->umsdev,
this->hidden->ev,
bytes,
bytes_ret );
}
static UMSAudioDevice_ReturnCode UADSetVolume(_THIS, long volume )
{
/*
* Set the volume.
* Takes effect immediately.
*/
return UMSAudioDevice_set_volume( this->hidden->umsdev,
this->hidden->ev,
volume );
}
static UMSAudioDevice_ReturnCode UADSetBalance(_THIS, long balance )
{
/*
* Set the balance.
* Takes effect immediately.
*/
return UMSAudioDevice_set_balance( this->hidden->umsdev,
this->hidden->ev,
balance );
}
static UMSAudioDevice_ReturnCode UADSetChannels(_THIS, long channels )
{
/*
* Set mono or stereo.
* Takes effect with next initialize() call.
*/
if ( channels != 1 ) channels = 2;
return UMSAudioDevice_set_number_of_channels( this->hidden->umsdev,
this->hidden->ev,
channels );
}
static UMSAudioDevice_ReturnCode UADOpen(_THIS, string device, string mode, long flags)
{
return UMSAudioDevice_open( this->hidden->umsdev,
this->hidden->ev,
device,
mode,
flags );
}
static UMSAudioDevice_ReturnCode UADWrite(_THIS, UMSAudioTypes_Buffer* buff,
long samples,
long* samples_written)
{
return UMSAudioDevice_write( this->hidden->umsdev,
this->hidden->ev,
buff,
samples,
samples_written );
}
static UMSAudioDevice_ReturnCode UADPlayRemainingData(_THIS, boolean block )
{
return UMSAudioDevice_play_remaining_data( this->hidden->umsdev,
this->hidden->ev,
block);
}
static UMSAudioDevice_ReturnCode UADStop(_THIS)
{
return UMSAudioDevice_stop( this->hidden->umsdev,
this->hidden->ev );
}
static UMSAudioDevice_ReturnCode UADClose(_THIS)
{
return UMSAudioDevice_close( this->hidden->umsdev,
this->hidden->ev );
}
static UMSAudioDevice_ReturnCode UADEnableOutput(_THIS, string output, long* left_gain, long* right_gain)
{
return UMSAudioDevice_enable_output( this->hidden->umsdev,
this->hidden->ev,
output,
left_gain,
right_gain );
}

View file

@ -1,50 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Carsten Griwodz
griff@kom.tu-darmstadt.de
based on linux/SDL_dspaudio.h by Sam Lantinga
*/
#include "SDL_config.h"
#ifndef _SDL_UMSaudio_h
#define _SDL_UMSaudio_h
#include <UMS/UMSAudioDevice.h>
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the video functions */
#define _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData
{
/* Pointer to the (open) UMS audio device */
Environment* ev;
UMSAudioDevice umsdev;
/* Raw mixing buffer */
UMSAudioTypes_Buffer playbuf;
UMSAudioTypes_Buffer fillbuf;
long bytesPerSample;
};
#endif /* _SDL_UMSaudio_h */

View file

@ -1,322 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
/* Allow access to a raw mixing buffer */
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <mmsystem.h>
#include "SDL_timer.h"
#include "SDL_audio.h"
#include "../SDL_audio_c.h"
#include "SDL_dibaudio.h"
#if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
#include "win_ce_semaphore.h"
#endif
/* Audio driver functions */
static int DIB_OpenAudio(_THIS, SDL_AudioSpec *spec);
static void DIB_ThreadInit(_THIS);
static void DIB_WaitAudio(_THIS);
static Uint8 *DIB_GetAudioBuf(_THIS);
static void DIB_PlayAudio(_THIS);
static void DIB_WaitDone(_THIS);
static void DIB_CloseAudio(_THIS);
/* Audio driver bootstrap functions */
static int Audio_Available(void)
{
return(1);
}
static void Audio_DeleteDevice(SDL_AudioDevice *device)
{
SDL_free(device->hidden);
SDL_free(device);
}
static SDL_AudioDevice *Audio_CreateDevice(int devindex)
{
SDL_AudioDevice *this;
/* Initialize all variables that we clean on shutdown */
this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
if ( this ) {
SDL_memset(this, 0, (sizeof *this));
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
}
if ( (this == NULL) || (this->hidden == NULL) ) {
SDL_OutOfMemory();
if ( this ) {
SDL_free(this);
}
return(0);
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
/* Set the function pointers */
this->OpenAudio = DIB_OpenAudio;
this->ThreadInit = DIB_ThreadInit;
this->WaitAudio = DIB_WaitAudio;
this->PlayAudio = DIB_PlayAudio;
this->GetAudioBuf = DIB_GetAudioBuf;
this->WaitDone = DIB_WaitDone;
this->CloseAudio = DIB_CloseAudio;
this->free = Audio_DeleteDevice;
return this;
}
AudioBootStrap WAVEOUT_bootstrap = {
"waveout", "Win95/98/NT/2000 WaveOut",
Audio_Available, Audio_CreateDevice
};
/* The Win32 callback for filling the WAVE device */
static void CALLBACK FillSound(HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance,
DWORD dwParam1, DWORD dwParam2)
{
SDL_AudioDevice *this = (SDL_AudioDevice *)dwInstance;
/* Only service "buffer done playing" messages */
if ( uMsg != WOM_DONE )
return;
/* Signal that we are done playing a buffer */
#if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
ReleaseSemaphoreCE(audio_sem, 1, NULL);
#else
ReleaseSemaphore(audio_sem, 1, NULL);
#endif
}
static void SetMMerror(char *function, MMRESULT code)
{
size_t len;
char errbuf[MAXERRORLENGTH];
#ifdef _WIN32_WCE
wchar_t werrbuf[MAXERRORLENGTH];
#endif
SDL_snprintf(errbuf, SDL_arraysize(errbuf), "%s: ", function);
len = SDL_strlen(errbuf);
#ifdef _WIN32_WCE
/* UNICODE version */
waveOutGetErrorText(code, werrbuf, MAXERRORLENGTH-len);
WideCharToMultiByte(CP_ACP,0,werrbuf,-1,errbuf+len,MAXERRORLENGTH-len,NULL,NULL);
#else
waveOutGetErrorText(code, errbuf+len, (UINT)(MAXERRORLENGTH-len));
#endif
SDL_SetError("%s",errbuf);
}
/* Set high priority for the audio thread */
static void DIB_ThreadInit(_THIS)
{
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
}
void DIB_WaitAudio(_THIS)
{
/* Wait for an audio chunk to finish */
#if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
WaitForSemaphoreCE(audio_sem, INFINITE);
#else
WaitForSingleObject(audio_sem, INFINITE);
#endif
}
Uint8 *DIB_GetAudioBuf(_THIS)
{
Uint8 *retval;
retval = (Uint8 *)(wavebuf[next_buffer].lpData);
return retval;
}
void DIB_PlayAudio(_THIS)
{
/* Queue it up */
waveOutWrite(sound, &wavebuf[next_buffer], sizeof(wavebuf[0]));
next_buffer = (next_buffer+1)%NUM_BUFFERS;
}
void DIB_WaitDone(_THIS)
{
int i, left;
do {
left = NUM_BUFFERS;
for ( i=0; i<NUM_BUFFERS; ++i ) {
if ( wavebuf[i].dwFlags & WHDR_DONE ) {
--left;
}
}
if ( left > 0 ) {
SDL_Delay(100);
}
} while ( left > 0 );
}
void DIB_CloseAudio(_THIS)
{
int i;
/* Close up audio */
if ( audio_sem ) {
#if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
CloseSynchHandle(audio_sem);
#else
CloseHandle(audio_sem);
#endif
}
if ( sound ) {
waveOutClose(sound);
}
/* Clean up mixing buffers */
for ( i=0; i<NUM_BUFFERS; ++i ) {
if ( wavebuf[i].dwUser != 0xFFFF ) {
waveOutUnprepareHeader(sound, &wavebuf[i],
sizeof(wavebuf[i]));
wavebuf[i].dwUser = 0xFFFF;
}
}
/* Free raw mixing buffer */
if ( mixbuf != NULL ) {
SDL_free(mixbuf);
mixbuf = NULL;
}
}
int DIB_OpenAudio(_THIS, SDL_AudioSpec *spec)
{
MMRESULT result;
int i;
WAVEFORMATEX waveformat;
/* Initialize the wavebuf structures for closing */
sound = NULL;
audio_sem = NULL;
for ( i = 0; i < NUM_BUFFERS; ++i )
wavebuf[i].dwUser = 0xFFFF;
mixbuf = NULL;
/* Set basic WAVE format parameters */
SDL_memset(&waveformat, 0, sizeof(waveformat));
waveformat.wFormatTag = WAVE_FORMAT_PCM;
/* Determine the audio parameters from the AudioSpec */
switch ( spec->format & 0xFF ) {
case 8:
/* Unsigned 8 bit audio data */
spec->format = AUDIO_U8;
waveformat.wBitsPerSample = 8;
break;
case 16:
/* Signed 16 bit audio data */
spec->format = AUDIO_S16;
waveformat.wBitsPerSample = 16;
break;
default:
SDL_SetError("Unsupported audio format");
return(-1);
}
waveformat.nChannels = spec->channels;
waveformat.nSamplesPerSec = spec->freq;
waveformat.nBlockAlign =
waveformat.nChannels * (waveformat.wBitsPerSample/8);
waveformat.nAvgBytesPerSec =
waveformat.nSamplesPerSec * waveformat.nBlockAlign;
/* Check the buffer size -- minimum of 1/4 second (word aligned) */
if ( spec->samples < (spec->freq/4) )
spec->samples = ((spec->freq/4)+3)&~3;
/* Update the fragment size as size in bytes */
SDL_CalculateAudioSpec(spec);
/* Open the audio device */
result = waveOutOpen(&sound, WAVE_MAPPER, &waveformat,
(DWORD_PTR)FillSound, (DWORD_PTR)this, CALLBACK_FUNCTION);
if ( result != MMSYSERR_NOERROR ) {
SetMMerror("waveOutOpen()", result);
return(-1);
}
#ifdef SOUND_DEBUG
/* Check the sound device we retrieved */
{
WAVEOUTCAPS caps;
result = waveOutGetDevCaps((UINT)sound, &caps, sizeof(caps));
if ( result != MMSYSERR_NOERROR ) {
SetMMerror("waveOutGetDevCaps()", result);
return(-1);
}
printf("Audio device: %s\n", caps.szPname);
}
#endif
/* Create the audio buffer semaphore */
#if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
audio_sem = CreateSemaphoreCE(NULL, NUM_BUFFERS-1, NUM_BUFFERS, NULL);
#else
audio_sem = CreateSemaphore(NULL, NUM_BUFFERS-1, NUM_BUFFERS, NULL);
#endif
if ( audio_sem == NULL ) {
SDL_SetError("Couldn't create semaphore");
return(-1);
}
/* Create the sound buffers */
mixbuf = (Uint8 *)SDL_malloc(NUM_BUFFERS*spec->size);
if ( mixbuf == NULL ) {
SDL_SetError("Out of memory");
return(-1);
}
for ( i = 0; i < NUM_BUFFERS; ++i ) {
SDL_memset(&wavebuf[i], 0, sizeof(wavebuf[i]));
wavebuf[i].lpData = (LPSTR) &mixbuf[i*spec->size];
wavebuf[i].dwBufferLength = spec->size;
wavebuf[i].dwFlags = WHDR_DONE;
result = waveOutPrepareHeader(sound, &wavebuf[i],
sizeof(wavebuf[i]));
if ( result != MMSYSERR_NOERROR ) {
SetMMerror("waveOutPrepareHeader()", result);
return(-1);
}
}
/* Ready to go! */
next_buffer = 0;
return(0);
}

View file

@ -1,49 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
#ifndef _SDL_lowaudio_h
#define _SDL_lowaudio_h
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the video functions */
#define _THIS SDL_AudioDevice *this
#define NUM_BUFFERS 2 /* -- Don't lower this! */
struct SDL_PrivateAudioData {
HWAVEOUT sound;
HANDLE audio_sem;
Uint8 *mixbuf; /* The raw allocated mixing buffer */
WAVEHDR wavebuf[NUM_BUFFERS]; /* Wave audio fragments */
int next_buffer;
};
/* Old variable names */
#define sound (this->hidden->sound)
#define audio_sem (this->hidden->audio_sem)
#define mixbuf (this->hidden->mixbuf)
#define wavebuf (this->hidden->wavebuf)
#define next_buffer (this->hidden->next_buffer)
#endif /* _SDL_lowaudio_h */

View file

@ -1,705 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
/* Allow access to a raw mixing buffer */
#include "SDL_timer.h"
#include "SDL_audio.h"
#include "../SDL_audio_c.h"
#include "SDL_dx5audio.h"
/* Define this if you want to use DirectX 6 DirectSoundNotify interface */
//#define USE_POSITION_NOTIFY
/* DirectX function pointers for audio */
HRESULT (WINAPI *DSoundCreate)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN);
/* Audio driver functions */
static int DX5_OpenAudio(_THIS, SDL_AudioSpec *spec);
static void DX5_ThreadInit(_THIS);
static void DX5_WaitAudio_BusyWait(_THIS);
#ifdef USE_POSITION_NOTIFY
static void DX6_WaitAudio_EventWait(_THIS);
#endif
static void DX5_PlayAudio(_THIS);
static Uint8 *DX5_GetAudioBuf(_THIS);
static void DX5_WaitDone(_THIS);
static void DX5_CloseAudio(_THIS);
/* Audio driver bootstrap functions */
static int Audio_Available(void)
{
HINSTANCE DSoundDLL;
int dsound_ok;
/* Version check DSOUND.DLL (Is DirectX okay?) */
dsound_ok = 0;
DSoundDLL = LoadLibrary(TEXT("DSOUND.DLL"));
if ( DSoundDLL != NULL ) {
/* We just use basic DirectSound, we're okay */
/* Yay! */
/* Unfortunately, the sound drivers on NT have
higher latencies than the audio buffers used
by many SDL applications, so there are gaps
in the audio - it sounds terrible. Punt for now.
*/
OSVERSIONINFO ver;
ver.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
GetVersionEx(&ver);
switch (ver.dwPlatformId) {
case VER_PLATFORM_WIN32_NT:
if ( ver.dwMajorVersion > 4 ) {
/* Win2K */
dsound_ok = 1;
} else {
/* WinNT */
dsound_ok = 0;
}
break;
default:
/* Win95 or Win98 */
dsound_ok = 1;
break;
}
/* Now check for DirectX 5 or better - otherwise
* we will fail later in DX5_OpenAudio without a chance
* to fall back to the DIB driver. */
if (dsound_ok) {
/* DirectSoundCaptureCreate was added in DX5 */
if (!GetProcAddress(DSoundDLL, TEXT("DirectSoundCaptureCreate")))
dsound_ok = 0;
}
/* Clean up.. */
FreeLibrary(DSoundDLL);
}
return(dsound_ok);
}
/* Functions for loading the DirectX functions dynamically */
static HINSTANCE DSoundDLL = NULL;
static void DX5_Unload(void)
{
if ( DSoundDLL != NULL ) {
FreeLibrary(DSoundDLL);
DSoundCreate = NULL;
DSoundDLL = NULL;
}
}
static int DX5_Load(void)
{
int status;
DX5_Unload();
DSoundDLL = LoadLibrary(TEXT("DSOUND.DLL"));
if ( DSoundDLL != NULL ) {
DSoundCreate = (void *)GetProcAddress(DSoundDLL,
TEXT("DirectSoundCreate"));
}
if ( DSoundDLL && DSoundCreate ) {
status = 0;
} else {
DX5_Unload();
status = -1;
}
return status;
}
static void Audio_DeleteDevice(SDL_AudioDevice *device)
{
DX5_Unload();
SDL_free(device->hidden);
SDL_free(device);
}
static SDL_AudioDevice *Audio_CreateDevice(int devindex)
{
SDL_AudioDevice *this;
/* Load DirectX */
if ( DX5_Load() < 0 ) {
return(NULL);
}
/* Initialize all variables that we clean on shutdown */
this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
if ( this ) {
SDL_memset(this, 0, (sizeof *this));
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
}
if ( (this == NULL) || (this->hidden == NULL) ) {
SDL_OutOfMemory();
if ( this ) {
SDL_free(this);
}
return(0);
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
/* Set the function pointers */
this->OpenAudio = DX5_OpenAudio;
this->ThreadInit = DX5_ThreadInit;
this->WaitAudio = DX5_WaitAudio_BusyWait;
this->PlayAudio = DX5_PlayAudio;
this->GetAudioBuf = DX5_GetAudioBuf;
this->WaitDone = DX5_WaitDone;
this->CloseAudio = DX5_CloseAudio;
this->free = Audio_DeleteDevice;
return this;
}
AudioBootStrap DSOUND_bootstrap = {
"dsound", "Win95/98/2000 DirectSound",
Audio_Available, Audio_CreateDevice
};
static void SetDSerror(const char *function, int code)
{
static const char *error;
static char errbuf[1024];
errbuf[0] = 0;
switch (code) {
case E_NOINTERFACE:
error =
"Unsupported interface\n-- Is DirectX 5.0 or later installed?";
break;
case DSERR_ALLOCATED:
error = "Audio device in use";
break;
case DSERR_BADFORMAT:
error = "Unsupported audio format";
break;
case DSERR_BUFFERLOST:
error = "Mixing buffer was lost";
break;
case DSERR_CONTROLUNAVAIL:
error = "Control requested is not available";
break;
case DSERR_INVALIDCALL:
error = "Invalid call for the current state";
break;
case DSERR_INVALIDPARAM:
error = "Invalid parameter";
break;
case DSERR_NODRIVER:
error = "No audio device found";
break;
case DSERR_OUTOFMEMORY:
error = "Out of memory";
break;
case DSERR_PRIOLEVELNEEDED:
error = "Caller doesn't have priority";
break;
case DSERR_UNSUPPORTED:
error = "Function not supported";
break;
default:
SDL_snprintf(errbuf, SDL_arraysize(errbuf),
"%s: Unknown DirectSound error: 0x%x",
function, code);
break;
}
if ( ! errbuf[0] ) {
SDL_snprintf(errbuf, SDL_arraysize(errbuf), "%s: %s", function, error);
}
SDL_SetError("%s", errbuf);
return;
}
/* DirectSound needs to be associated with a window */
static HWND mainwin = NULL;
/* */
void DX5_SoundFocus(HWND hwnd)
{
mainwin = hwnd;
}
static void DX5_ThreadInit(_THIS)
{
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
}
static void DX5_WaitAudio_BusyWait(_THIS)
{
DWORD status;
DWORD cursor, junk;
HRESULT result;
/* Semi-busy wait, since we have no way of getting play notification
on a primary mixing buffer located in hardware (DirectX 5.0)
*/
result = IDirectSoundBuffer_GetCurrentPosition(mixbuf, &junk, &cursor);
if ( result != DS_OK ) {
if ( result == DSERR_BUFFERLOST ) {
IDirectSoundBuffer_Restore(mixbuf);
}
#ifdef DEBUG_SOUND
SetDSerror("DirectSound GetCurrentPosition", result);
#endif
return;
}
while ( (cursor/mixlen) == lastchunk ) {
/* FIXME: find out how much time is left and sleep that long */
SDL_Delay(1);
/* Try to restore a lost sound buffer */
IDirectSoundBuffer_GetStatus(mixbuf, &status);
if ( (status&DSBSTATUS_BUFFERLOST) ) {
IDirectSoundBuffer_Restore(mixbuf);
IDirectSoundBuffer_GetStatus(mixbuf, &status);
if ( (status&DSBSTATUS_BUFFERLOST) ) {
break;
}
}
if ( ! (status&DSBSTATUS_PLAYING) ) {
result = IDirectSoundBuffer_Play(mixbuf, 0, 0, DSBPLAY_LOOPING);
if ( result == DS_OK ) {
continue;
}
#ifdef DEBUG_SOUND
SetDSerror("DirectSound Play", result);
#endif
return;
}
/* Find out where we are playing */
result = IDirectSoundBuffer_GetCurrentPosition(mixbuf,
&junk, &cursor);
if ( result != DS_OK ) {
SetDSerror("DirectSound GetCurrentPosition", result);
return;
}
}
}
#ifdef USE_POSITION_NOTIFY
static void DX6_WaitAudio_EventWait(_THIS)
{
DWORD status;
HRESULT result;
/* Try to restore a lost sound buffer */
IDirectSoundBuffer_GetStatus(mixbuf, &status);
if ( (status&DSBSTATUS_BUFFERLOST) ) {
IDirectSoundBuffer_Restore(mixbuf);
IDirectSoundBuffer_GetStatus(mixbuf, &status);
if ( (status&DSBSTATUS_BUFFERLOST) ) {
return;
}
}
if ( ! (status&DSBSTATUS_PLAYING) ) {
result = IDirectSoundBuffer_Play(mixbuf, 0, 0, DSBPLAY_LOOPING);
if ( result != DS_OK ) {
#ifdef DEBUG_SOUND
SetDSerror("DirectSound Play", result);
#endif
return;
}
}
WaitForSingleObject(audio_event, INFINITE);
}
#endif /* USE_POSITION_NOTIFY */
static void DX5_PlayAudio(_THIS)
{
/* Unlock the buffer, allowing it to play */
if ( locked_buf ) {
IDirectSoundBuffer_Unlock(mixbuf, locked_buf, mixlen, NULL, 0);
}
}
static Uint8 *DX5_GetAudioBuf(_THIS)
{
DWORD cursor, junk;
HRESULT result;
DWORD rawlen;
/* Figure out which blocks to fill next */
locked_buf = NULL;
result = IDirectSoundBuffer_GetCurrentPosition(mixbuf, &junk, &cursor);
if ( result == DSERR_BUFFERLOST ) {
IDirectSoundBuffer_Restore(mixbuf);
result = IDirectSoundBuffer_GetCurrentPosition(mixbuf,
&junk, &cursor);
}
if ( result != DS_OK ) {
SetDSerror("DirectSound GetCurrentPosition", result);
return(NULL);
}
cursor /= mixlen;
#ifdef DEBUG_SOUND
/* Detect audio dropouts */
{ DWORD spot = cursor;
if ( spot < lastchunk ) {
spot += NUM_BUFFERS;
}
if ( spot > lastchunk+1 ) {
fprintf(stderr, "Audio dropout, missed %d fragments\n",
(spot - (lastchunk+1)));
}
}
#endif
lastchunk = cursor;
cursor = (cursor+1)%NUM_BUFFERS;
cursor *= mixlen;
/* Lock the audio buffer */
result = IDirectSoundBuffer_Lock(mixbuf, cursor, mixlen,
(LPVOID *)&locked_buf, &rawlen, NULL, &junk, 0);
if ( result == DSERR_BUFFERLOST ) {
IDirectSoundBuffer_Restore(mixbuf);
result = IDirectSoundBuffer_Lock(mixbuf, cursor, mixlen,
(LPVOID *)&locked_buf, &rawlen, NULL, &junk, 0);
}
if ( result != DS_OK ) {
SetDSerror("DirectSound Lock", result);
return(NULL);
}
return(locked_buf);
}
static void DX5_WaitDone(_THIS)
{
Uint8 *stream;
/* Wait for the playing chunk to finish */
stream = this->GetAudioBuf(this);
if ( stream != NULL ) {
SDL_memset(stream, silence, mixlen);
this->PlayAudio(this);
}
this->WaitAudio(this);
/* Stop the looping sound buffer */
IDirectSoundBuffer_Stop(mixbuf);
}
static void DX5_CloseAudio(_THIS)
{
if ( sound != NULL ) {
if ( mixbuf != NULL ) {
/* Clean up the audio buffer */
IDirectSoundBuffer_Release(mixbuf);
mixbuf = NULL;
}
if ( audio_event != NULL ) {
CloseHandle(audio_event);
audio_event = NULL;
}
IDirectSound_Release(sound);
sound = NULL;
}
}
#ifdef USE_PRIMARY_BUFFER
/* This function tries to create a primary audio buffer, and returns the
number of audio chunks available in the created buffer.
*/
static int CreatePrimary(LPDIRECTSOUND sndObj, HWND focus,
LPDIRECTSOUNDBUFFER *sndbuf, WAVEFORMATEX *wavefmt, Uint32 chunksize)
{
HRESULT result;
DSBUFFERDESC format;
DSBCAPS caps;
int numchunks;
/* Try to set primary mixing privileges */
result = IDirectSound_SetCooperativeLevel(sndObj, focus,
DSSCL_WRITEPRIMARY);
if ( result != DS_OK ) {
#ifdef DEBUG_SOUND
SetDSerror("DirectSound SetCooperativeLevel", result);
#endif
return(-1);
}
/* Try to create the primary buffer */
SDL_memset(&format, 0, sizeof(format));
format.dwSize = sizeof(format);
format.dwFlags=(DSBCAPS_PRIMARYBUFFER|DSBCAPS_GETCURRENTPOSITION2);
format.dwFlags |= DSBCAPS_STICKYFOCUS;
#ifdef USE_POSITION_NOTIFY
format.dwFlags |= DSBCAPS_CTRLPOSITIONNOTIFY;
#endif
result = IDirectSound_CreateSoundBuffer(sndObj, &format, sndbuf, NULL);
if ( result != DS_OK ) {
#ifdef DEBUG_SOUND
SetDSerror("DirectSound CreateSoundBuffer", result);
#endif
return(-1);
}
/* Check the size of the fragment buffer */
SDL_memset(&caps, 0, sizeof(caps));
caps.dwSize = sizeof(caps);
result = IDirectSoundBuffer_GetCaps(*sndbuf, &caps);
if ( result != DS_OK ) {
#ifdef DEBUG_SOUND
SetDSerror("DirectSound GetCaps", result);
#endif
IDirectSoundBuffer_Release(*sndbuf);
return(-1);
}
if ( (chunksize > caps.dwBufferBytes) ||
((caps.dwBufferBytes%chunksize) != 0) ) {
/* The primary buffer size is not a multiple of 'chunksize'
-- this hopefully doesn't happen when 'chunksize' is a
power of 2.
*/
IDirectSoundBuffer_Release(*sndbuf);
SDL_SetError(
"Primary buffer size is: %d, cannot break it into chunks of %d bytes\n",
caps.dwBufferBytes, chunksize);
return(-1);
}
numchunks = (caps.dwBufferBytes/chunksize);
/* Set the primary audio format */
result = IDirectSoundBuffer_SetFormat(*sndbuf, wavefmt);
if ( result != DS_OK ) {
#ifdef DEBUG_SOUND
SetDSerror("DirectSound SetFormat", result);
#endif
IDirectSoundBuffer_Release(*sndbuf);
return(-1);
}
return(numchunks);
}
#endif /* USE_PRIMARY_BUFFER */
/* This function tries to create a secondary audio buffer, and returns the
number of audio chunks available in the created buffer.
*/
static int CreateSecondary(LPDIRECTSOUND sndObj, HWND focus,
LPDIRECTSOUNDBUFFER *sndbuf, WAVEFORMATEX *wavefmt, Uint32 chunksize)
{
const int numchunks = 8;
HRESULT result;
DSBUFFERDESC format;
LPVOID pvAudioPtr1, pvAudioPtr2;
DWORD dwAudioBytes1, dwAudioBytes2;
/* Try to set primary mixing privileges */
if ( focus ) {
result = IDirectSound_SetCooperativeLevel(sndObj,
focus, DSSCL_PRIORITY);
} else {
result = IDirectSound_SetCooperativeLevel(sndObj,
GetDesktopWindow(), DSSCL_NORMAL);
}
if ( result != DS_OK ) {
#ifdef DEBUG_SOUND
SetDSerror("DirectSound SetCooperativeLevel", result);
#endif
return(-1);
}
/* Try to create the secondary buffer */
SDL_memset(&format, 0, sizeof(format));
format.dwSize = sizeof(format);
format.dwFlags = DSBCAPS_GETCURRENTPOSITION2;
#ifdef USE_POSITION_NOTIFY
format.dwFlags |= DSBCAPS_CTRLPOSITIONNOTIFY;
#endif
if ( ! focus ) {
format.dwFlags |= DSBCAPS_GLOBALFOCUS;
} else {
format.dwFlags |= DSBCAPS_STICKYFOCUS;
}
format.dwBufferBytes = numchunks*chunksize;
if ( (format.dwBufferBytes < DSBSIZE_MIN) ||
(format.dwBufferBytes > DSBSIZE_MAX) ) {
SDL_SetError("Sound buffer size must be between %d and %d",
DSBSIZE_MIN/numchunks, DSBSIZE_MAX/numchunks);
return(-1);
}
format.dwReserved = 0;
format.lpwfxFormat = wavefmt;
result = IDirectSound_CreateSoundBuffer(sndObj, &format, sndbuf, NULL);
if ( result != DS_OK ) {
SetDSerror("DirectSound CreateSoundBuffer", result);
return(-1);
}
IDirectSoundBuffer_SetFormat(*sndbuf, wavefmt);
/* Silence the initial audio buffer */
result = IDirectSoundBuffer_Lock(*sndbuf, 0, format.dwBufferBytes,
(LPVOID *)&pvAudioPtr1, &dwAudioBytes1,
(LPVOID *)&pvAudioPtr2, &dwAudioBytes2,
DSBLOCK_ENTIREBUFFER);
if ( result == DS_OK ) {
if ( wavefmt->wBitsPerSample == 8 ) {
SDL_memset(pvAudioPtr1, 0x80, dwAudioBytes1);
} else {
SDL_memset(pvAudioPtr1, 0x00, dwAudioBytes1);
}
IDirectSoundBuffer_Unlock(*sndbuf,
(LPVOID)pvAudioPtr1, dwAudioBytes1,
(LPVOID)pvAudioPtr2, dwAudioBytes2);
}
/* We're ready to go */
return(numchunks);
}
/* This function tries to set position notify events on the mixing buffer */
#ifdef USE_POSITION_NOTIFY
static int CreateAudioEvent(_THIS)
{
LPDIRECTSOUNDNOTIFY notify;
DSBPOSITIONNOTIFY *notify_positions;
int i, retval;
HRESULT result;
/* Default to fail on exit */
retval = -1;
notify = NULL;
/* Query for the interface */
result = IDirectSoundBuffer_QueryInterface(mixbuf,
&IID_IDirectSoundNotify, (void *)&notify);
if ( result != DS_OK ) {
goto done;
}
/* Allocate the notify structures */
notify_positions = (DSBPOSITIONNOTIFY *)SDL_malloc(NUM_BUFFERS*
sizeof(*notify_positions));
if ( notify_positions == NULL ) {
goto done;
}
/* Create the notify event */
audio_event = CreateEvent(NULL, FALSE, FALSE, NULL);
if ( audio_event == NULL ) {
goto done;
}
/* Set up the notify structures */
for ( i=0; i<NUM_BUFFERS; ++i ) {
notify_positions[i].dwOffset = i*mixlen;
notify_positions[i].hEventNotify = audio_event;
}
result = IDirectSoundNotify_SetNotificationPositions(notify,
NUM_BUFFERS, notify_positions);
if ( result == DS_OK ) {
retval = 0;
}
done:
if ( notify != NULL ) {
IDirectSoundNotify_Release(notify);
}
return(retval);
}
#endif /* USE_POSITION_NOTIFY */
static int DX5_OpenAudio(_THIS, SDL_AudioSpec *spec)
{
HRESULT result;
WAVEFORMATEX waveformat;
/* Set basic WAVE format parameters */
SDL_memset(&waveformat, 0, sizeof(waveformat));
waveformat.wFormatTag = WAVE_FORMAT_PCM;
/* Determine the audio parameters from the AudioSpec */
switch ( spec->format & 0xFF ) {
case 8:
/* Unsigned 8 bit audio data */
spec->format = AUDIO_U8;
silence = 0x80;
waveformat.wBitsPerSample = 8;
break;
case 16:
/* Signed 16 bit audio data */
spec->format = AUDIO_S16;
silence = 0x00;
waveformat.wBitsPerSample = 16;
break;
default:
SDL_SetError("Unsupported audio format");
return(-1);
}
waveformat.nChannels = spec->channels;
waveformat.nSamplesPerSec = spec->freq;
waveformat.nBlockAlign =
waveformat.nChannels * (waveformat.wBitsPerSample/8);
waveformat.nAvgBytesPerSec =
waveformat.nSamplesPerSec * waveformat.nBlockAlign;
/* Update the fragment size as size in bytes */
SDL_CalculateAudioSpec(spec);
/* Open the audio device */
result = DSoundCreate(NULL, &sound, NULL);
if ( result != DS_OK ) {
SetDSerror("DirectSoundCreate", result);
return(-1);
}
/* Create the audio buffer to which we write */
NUM_BUFFERS = -1;
#ifdef USE_PRIMARY_BUFFER
if ( mainwin ) {
NUM_BUFFERS = CreatePrimary(sound, mainwin, &mixbuf,
&waveformat, spec->size);
}
#endif /* USE_PRIMARY_BUFFER */
if ( NUM_BUFFERS < 0 ) {
NUM_BUFFERS = CreateSecondary(sound, mainwin, &mixbuf,
&waveformat, spec->size);
if ( NUM_BUFFERS < 0 ) {
return(-1);
}
#ifdef DEBUG_SOUND
fprintf(stderr, "Using secondary audio buffer\n");
#endif
}
#ifdef DEBUG_SOUND
else
fprintf(stderr, "Using primary audio buffer\n");
#endif
/* The buffer will auto-start playing in DX5_WaitAudio() */
lastchunk = 0;
mixlen = spec->size;
#ifdef USE_POSITION_NOTIFY
/* See if we can use DirectX 6 event notification */
if ( CreateAudioEvent(this) == 0 ) {
this->WaitAudio = DX6_WaitAudio_EventWait;
} else {
this->WaitAudio = DX5_WaitAudio_BusyWait;
}
#endif
return(0);
}

View file

@ -1,55 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
#ifndef _SDL_lowaudio_h
#define _SDL_lowaudio_h
#include "directx.h"
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the video functions */
#define _THIS SDL_AudioDevice *this
/* The DirectSound objects */
struct SDL_PrivateAudioData {
LPDIRECTSOUND sound;
LPDIRECTSOUNDBUFFER mixbuf;
int NUM_BUFFERS;
int mixlen, silence;
DWORD lastchunk;
Uint8 *locked_buf;
HANDLE audio_event;
};
/* Old variable names */
#define sound (this->hidden->sound)
#define mixbuf (this->hidden->mixbuf)
#define NUM_BUFFERS (this->hidden->NUM_BUFFERS)
#define mixlen (this->hidden->mixlen)
#define silence (this->hidden->silence)
#define lastchunk (this->hidden->lastchunk)
#define locked_buf (this->hidden->locked_buf)
#define audio_event (this->hidden->audio_event)
#endif /* _SDL_lowaudio_h */

View file

@ -1,81 +0,0 @@
#ifndef _directx_h
#define _directx_h
/* Include all of the DirectX 5.0 headers and adds any necessary tweaks */
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <mmsystem.h>
#ifndef WIN32
#define WIN32
#endif
#undef WINNT
/* Far pointers don't exist in 32-bit code */
#ifndef FAR
#define FAR
#endif
/* Error codes not yet included in Win32 API header files */
#ifndef MAKE_HRESULT
#define MAKE_HRESULT(sev,fac,code) \
((HRESULT)(((unsigned long)(sev)<<31) | ((unsigned long)(fac)<<16) | ((unsigned long)(code))))
#endif
#ifndef S_OK
#define S_OK (HRESULT)0x00000000L
#endif
#ifndef SUCCEEDED
#define SUCCEEDED(x) ((HRESULT)(x) >= 0)
#endif
#ifndef FAILED
#define FAILED(x) ((HRESULT)(x)<0)
#endif
#ifndef E_FAIL
#define E_FAIL (HRESULT)0x80000008L
#endif
#ifndef E_NOINTERFACE
#define E_NOINTERFACE (HRESULT)0x80004002L
#endif
#ifndef E_OUTOFMEMORY
#define E_OUTOFMEMORY (HRESULT)0x8007000EL
#endif
#ifndef E_INVALIDARG
#define E_INVALIDARG (HRESULT)0x80070057L
#endif
#ifndef E_NOTIMPL
#define E_NOTIMPL (HRESULT)0x80004001L
#endif
#ifndef REGDB_E_CLASSNOTREG
#define REGDB_E_CLASSNOTREG (HRESULT)0x80040154L
#endif
/* Severity codes */
#ifndef SEVERITY_ERROR
#define SEVERITY_ERROR 1
#endif
/* Error facility codes */
#ifndef FACILITY_WIN32
#define FACILITY_WIN32 7
#endif
#ifndef FIELD_OFFSET
#define FIELD_OFFSET(type, field) ((LONG)&(((type *)0)->field))
#endif
/* DirectX headers (if it isn't included, I haven't tested it yet)
*/
/* We need these defines to mark what version of DirectX API we use */
#define DIRECTDRAW_VERSION 0x0700
#define DIRECTSOUND_VERSION 0x0500
#define DIRECTINPUT_VERSION 0x0500
#include <ddraw.h>
#include <dsound.h>
#include <dinput.h>
#endif /* _directx_h */

View file

@ -1,660 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Carsten Griwodz
griff@kom.tu-darmstadt.de
based on linux/SDL_syscdrom.c by Sam Lantinga
*/
#include "SDL_config.h"
#ifdef SDL_CDROM_AIX
/* Functions for system-level CD-ROM audio control */
/*#define DEBUG_CDROM 1*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/devinfo.h>
#include <sys/mntctl.h>
#include <sys/statfs.h>
#include <sys/vmount.h>
#include <fstab.h>
#include <sys/scdisk.h>
#include "SDL_cdrom.h"
#include "../SDL_syscdrom.h"
/* The maximum number of CD-ROM drives we'll detect */
#define MAX_DRIVES 16
/* A list of available CD-ROM drives */
static char *SDL_cdlist[MAX_DRIVES];
static dev_t SDL_cdmode[MAX_DRIVES];
/* The system-dependent CD control functions */
static const char *SDL_SYS_CDName(int drive);
static int SDL_SYS_CDOpen(int drive);
static int SDL_SYS_CDGetTOC(SDL_CD *cdrom);
static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position);
static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length);
static int SDL_SYS_CDPause(SDL_CD *cdrom);
static int SDL_SYS_CDResume(SDL_CD *cdrom);
static int SDL_SYS_CDStop(SDL_CD *cdrom);
static int SDL_SYS_CDEject(SDL_CD *cdrom);
static void SDL_SYS_CDClose(SDL_CD *cdrom);
static int SDL_SYS_CDioctl(int id, int command, void *arg);
/* Check a drive to see if it is a CD-ROM */
static int CheckDrive(char *drive, struct stat *stbuf)
{
int is_cd;
int cdfd;
int ret;
struct devinfo info;
/* If it doesn't exist, return -1 */
if ( stat(drive, stbuf) < 0 ) {
return -1;
}
/* If it does exist, verify that it's an available CD-ROM */
is_cd = 0;
if ( S_ISCHR(stbuf->st_mode) || S_ISBLK(stbuf->st_mode) ) {
cdfd = open(drive, (O_RDONLY|O_EXCL|O_NONBLOCK), 0);
if ( cdfd >= 0 ) {
ret = SDL_SYS_CDioctl( cdfd, IOCINFO, &info );
if ( ret < 0 ) {
/* Some kind of error */
is_cd = 0;
} else {
if ( info.devtype == DD_CDROM ) {
is_cd = 1;
} else {
is_cd = 0;
}
}
close(cdfd);
}
#ifdef DEBUG_CDROM
else
{
fprintf(stderr, "Could not open drive %s (%s)\n", drive, strerror(errno));
}
#endif
}
return is_cd;
}
/* Add a CD-ROM drive to our list of valid drives */
static void AddDrive(char *drive, struct stat *stbuf)
{
int i;
if ( SDL_numcds < MAX_DRIVES ) {
/* Check to make sure it's not already in our list.
This can happen when we see a drive via symbolic link.
*/
for ( i=0; i<SDL_numcds; ++i ) {
if ( stbuf->st_rdev == SDL_cdmode[i] ) {
#ifdef DEBUG_CDROM
fprintf(stderr, "Duplicate drive detected: %s == %s\n", drive, SDL_cdlist[i]);
#endif
return;
}
}
/* Add this drive to our list */
i = SDL_numcds;
SDL_cdlist[i] = SDL_strdup(drive);
if ( SDL_cdlist[i] == NULL ) {
SDL_OutOfMemory();
return;
}
SDL_cdmode[i] = stbuf->st_rdev;
++SDL_numcds;
#ifdef DEBUG_CDROM
fprintf(stderr, "Added CD-ROM drive: %s\n", drive);
#endif
}
}
static void CheckMounts()
{
char* buffer;
int bufsz;
struct vmount* ptr;
int ret;
buffer = (char*)SDL_malloc(10);
bufsz = 10;
if ( buffer==NULL )
{
fprintf(stderr, "Could not allocate 10 bytes in aix/SDL_syscdrom.c:CheckMounts\n" );
exit ( -10 );
}
do
{
/* mntctrl() returns an array of all mounted filesystems */
ret = mntctl ( MCTL_QUERY, bufsz, buffer );
if ( ret == 0 )
{
/* Buffer was too small, realloc. */
bufsz = *(int*)buffer; /* Required size is in first word. */
/* (whatever a word is in AIX 4.3.3) */
/* int seems to be OK in 32bit mode. */
SDL_free(buffer);
buffer = (char*)SDL_malloc(bufsz);
if ( buffer==NULL )
{
fprintf(stderr,
"Could not allocate %d bytes in aix/SDL_syscdrom.c:CheckMounts\n",
bufsz );
exit ( -10 );
}
}
else if ( ret < 0 )
{
#ifdef DEBUG_CDROM
fprintf(stderr, "Error reading vmount structures\n");
#endif
return;
}
}
while ( ret == 0 );
#ifdef DEBUG_CDROM
fprintf ( stderr, "Read %d vmount structures\n",ret );
#endif
ptr = (struct vmount*)buffer;
do
{
switch(ptr->vmt_gfstype)
{
case MNT_CDROM :
{
struct stat stbuf;
char* text;
text = (char*)ptr + ptr->vmt_data[VMT_OBJECT].vmt_off;
#ifdef DEBUG_CDROM
fprintf(stderr, "Checking mount path: %s mounted on %s\n",
text, (char*)ptr + ptr->vmt_data[VMT_STUB].vmt_off );
#endif
if ( CheckDrive( text, &stbuf) > 0)
{
AddDrive( text, &stbuf);
}
}
break;
default :
break;
}
ptr = (struct vmount*)((char*)ptr + ptr->vmt_length);
ret--;
}
while ( ret > 0 );
free ( buffer );
}
static int CheckNonmounts()
{
#ifdef _THREAD_SAFE
AFILE_t fsFile = NULL;
int passNo = 0;
int ret;
struct fstab entry;
struct stat stbuf;
ret = setfsent_r( &fsFile, &passNo );
if ( ret != 0 ) return -1;
do
{
ret = getfsent_r ( &entry, &fsFile, &passNo );
if ( ret == 0 ) {
char* l = SDL_strrchr(entry.fs_spec,'/');
if ( l != NULL ) {
if ( !SDL_strncmp("cd",++l,2) ) {
#ifdef DEBUG_CDROM
fprintf(stderr,
"Found unmounted CD ROM drive with device name %s\n",
entry.fs_spec);
#endif
if ( CheckDrive( entry.fs_spec, &stbuf) > 0)
{
AddDrive( entry.fs_spec, &stbuf);
}
}
}
}
}
while ( ret == 0 );
ret = endfsent_r ( &fsFile );
if ( ret != 0 ) return -1;
return 0;
#else
struct fstab* entry;
struct stat stbuf;
setfsent();
do
{
entry = getfsent();
if ( entry != NULL ) {
char* l = SDL_strrchr(entry->fs_spec,'/');
if ( l != NULL ) {
if ( !SDL_strncmp("cd",++l,2) ) {
#ifdef DEBUG_CDROM
fprintf(stderr,"Found unmounted CD ROM drive with device name %s", entry->fs_spec);
#endif
if ( CheckDrive( entry->fs_spec, &stbuf) > 0)
{
AddDrive( entry->fs_spec, &stbuf);
}
}
}
}
}
while ( entry != NULL );
endfsent();
#endif
}
int SDL_SYS_CDInit(void)
{
char *SDLcdrom;
struct stat stbuf;
/* Fill in our driver capabilities */
SDL_CDcaps.Name = SDL_SYS_CDName;
SDL_CDcaps.Open = SDL_SYS_CDOpen;
SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC;
SDL_CDcaps.Status = SDL_SYS_CDStatus;
SDL_CDcaps.Play = SDL_SYS_CDPlay;
SDL_CDcaps.Pause = SDL_SYS_CDPause;
SDL_CDcaps.Resume = SDL_SYS_CDResume;
SDL_CDcaps.Stop = SDL_SYS_CDStop;
SDL_CDcaps.Eject = SDL_SYS_CDEject;
SDL_CDcaps.Close = SDL_SYS_CDClose;
/* Look in the environment for our CD-ROM drive list */
SDLcdrom = SDL_getenv("SDL_CDROM"); /* ':' separated list of devices */
if ( SDLcdrom != NULL ) {
char *cdpath, *delim;
size_t len = SDL_strlen(SDLcdrom)+1;
cdpath = SDL_stack_alloc(char, len);
if ( cdpath != NULL ) {
SDL_strlcpy(cdpath, SDLcdrom, len);
SDLcdrom = cdpath;
do {
delim = SDL_strchr(SDLcdrom, ':');
if ( delim ) {
*delim++ = '\0';
}
#ifdef DEBUG_CDROM
fprintf(stderr, "Checking CD-ROM drive from SDL_CDROM: %s\n", SDLcdrom);
#endif
if ( CheckDrive(SDLcdrom, &stbuf) > 0 ) {
AddDrive(SDLcdrom, &stbuf);
}
if ( delim ) {
SDLcdrom = delim;
} else {
SDLcdrom = NULL;
}
} while ( SDLcdrom );
SDL_stack_free(cdpath);
}
/* If we found our drives, there's nothing left to do */
if ( SDL_numcds > 0 ) {
return(0);
}
}
CheckMounts();
CheckNonmounts();
return 0;
}
/* General ioctl() CD-ROM command function */
static int SDL_SYS_CDioctl(int id, int command, void *arg)
{
int retval;
retval = ioctl(id, command, arg);
if ( retval < 0 ) {
SDL_SetError("ioctl() error: %s", strerror(errno));
}
return retval;
}
static const char *SDL_SYS_CDName(int drive)
{
return(SDL_cdlist[drive]);
}
static int SDL_SYS_CDOpen(int drive)
{
int fd;
char* lastsl;
char* cdromname;
size_t len;
/*
* We found /dev/cd? drives and that is in our list. But we can
* open only the /dev/rcd? versions of those devices for Audio CD.
*/
len = SDL_strlen(SDL_cdlist[drive])+2;
cdromname = (char*)SDL_malloc(len);
SDL_strlcpy(cdromname,SDL_cdlist[drive],len);
lastsl = SDL_strrchr(cdromname,'/');
if (lastsl) {
*lastsl = 0;
SDL_strlcat(cdromname,"/r",len);
lastsl = SDL_strrchr(SDL_cdlist[drive],'/');
if (lastsl) {
lastsl++;
SDL_strlcat(cdromname,lastsl,len);
}
}
#ifdef DEBUG_CDROM
fprintf(stderr, "Should open drive %s, opening %s\n", SDL_cdlist[drive], cdromname);
#endif
/*
* Use exclusive access. Don't use SC_DIAGNOSTICS as xmcd does because they
* require root priviledges, and we don't want that. SC_SINGLE provides
* exclusive access with less trouble.
*/
fd = openx(cdromname, O_RDONLY, NULL, SC_SINGLE);
if ( fd < 0 )
{
#ifdef DEBUG_CDROM
fprintf(stderr, "Could not open drive %s (%s)\n", cdromname, strerror(errno));
#endif
}
else
{
struct mode_form_op cdMode;
int ret;
#ifdef DEBUG_CDROM
cdMode.action = CD_GET_MODE;
ret = SDL_SYS_CDioctl(fd, DK_CD_MODE, &cdMode);
if ( ret < 0 ) {
fprintf(stderr,
"Could not get drive mode for %s (%s)\n",
cdromname, strerror(errno));
} else {
switch(cdMode.cd_mode_form) {
case CD_MODE1 :
fprintf(stderr,
"Drive mode for %s is %s\n",
cdromname, "CD-ROM Data Mode 1");
break;
case CD_MODE2_FORM1 :
fprintf(stderr,
"Drive mode for %s is %s\n",
cdromname, "CD-ROM XA Data Mode 2 Form 1");
break;
case CD_MODE2_FORM2 :
fprintf(stderr,
"Drive mode for %s is %s\n",
cdromname, "CD-ROM XA Data Mode 2 Form 2");
break;
case CD_DA :
fprintf(stderr,
"Drive mode for %s is %s\n",
cdromname, "CD-DA");
break;
default :
fprintf(stderr,
"Drive mode for %s is %s\n",
cdromname, "unknown");
break;
}
}
#endif
cdMode.action = CD_CHG_MODE;
cdMode.cd_mode_form = CD_DA;
ret = SDL_SYS_CDioctl(fd, DK_CD_MODE, &cdMode);
if ( ret < 0 ) {
#ifdef DEBUG_CDROM
fprintf(stderr,
"Could not set drive mode for %s (%s)\n",
cdromname, strerror(errno));
#endif
SDL_SetError("ioctl() error: Could not set CD drive mode, %s",
strerror(errno));
} else {
#ifdef DEBUG_CDROM
fprintf(stderr,
"Drive mode for %s set to CD_DA\n",
cdromname);
#endif
}
}
SDL_free(cdromname);
return fd;
}
static int SDL_SYS_CDGetTOC(SDL_CD *cdrom)
{
struct cd_audio_cmd cmd;
struct cd_audio_cmd entry;
int i;
int okay;
cmd.audio_cmds = CD_TRK_INFO_AUDIO;
cmd.msf_flag = FALSE;
if ( SDL_SYS_CDioctl(cdrom->id, DKAUDIO, &cmd) < 0 ) {
return -1;
}
okay = 0;
cdrom->numtracks = cmd.indexing.track_index.last_track
- cmd.indexing.track_index.first_track+1;
if ( cdrom->numtracks > SDL_MAX_TRACKS ) {
cdrom->numtracks = SDL_MAX_TRACKS;
}
/* Read all the track TOC entries */
for ( i=0; i<=cdrom->numtracks; ++i ) {
if ( i == cdrom->numtracks ) {
cdrom->track[i].id = 0xAA;;
} else {
cdrom->track[i].id = cmd.indexing.track_index.first_track+i;
}
entry.audio_cmds = CD_GET_TRK_MSF;
entry.indexing.track_msf.track = cdrom->track[i].id;
if ( SDL_SYS_CDioctl(cdrom->id, DKAUDIO, &entry) < 0 ) {
break;
} else {
cdrom->track[i].type = 0; /* don't know how to detect 0x04 data track */
cdrom->track[i].offset = MSF_TO_FRAMES(
entry.indexing.track_msf.mins,
entry.indexing.track_msf.secs,
entry.indexing.track_msf.frames);
cdrom->track[i].length = 0;
if ( i > 0 ) {
cdrom->track[i-1].length = cdrom->track[i].offset
- cdrom->track[i-1].offset;
}
}
}
if ( i == (cdrom->numtracks+1) ) {
okay = 1;
}
return(okay ? 0 : -1);
}
/* Get CD-ROM status */
static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position)
{
CDstatus status;
struct cd_audio_cmd cmd;
cmd.audio_cmds = CD_INFO_AUDIO;
if ( SDL_SYS_CDioctl(cdrom->id, DKAUDIO, &cmd) < 0 ) {
#ifdef DEBUG_CDROM
fprintf(stderr, "ioctl failed in SDL_SYS_CDStatus (%s)\n", SDL_GetError());
#endif
status = CD_ERROR;
} else {
switch (cmd.status) {
case CD_NO_AUDIO:
case CD_COMPLETED:
status = CD_STOPPED;
break;
case CD_PLAY_AUDIO:
status = CD_PLAYING;
break;
case CD_PAUSE_AUDIO:
status = CD_PAUSED;
break;
case CD_NOT_VALID:
#ifdef DEBUG_CDROM
fprintf(stderr, "cdStatus failed with CD_NOT_VALID\n");
#endif
status = CD_ERROR;
break;
case CD_STATUS_ERROR:
#ifdef DEBUG_CDROM
fprintf(stderr, "cdStatus failed with CD_STATUS_ERROR\n");
#endif
status = CD_ERROR;
break;
default:
#ifdef DEBUG_CDROM
fprintf(stderr, "cdStatus failed with unknown error\n");
#endif
status = CD_ERROR;
break;
}
}
if ( position ) {
if ( status == CD_PLAYING || (status == CD_PAUSED) ) {
*position = MSF_TO_FRAMES( cmd.indexing.info_audio.current_mins,
cmd.indexing.info_audio.current_secs,
cmd.indexing.info_audio.current_frames);
} else {
*position = 0;
}
}
return status;
}
/* Start play */
static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length)
{
struct cd_audio_cmd cmd;
/*
* My CD Rom is muted by default. I think I read that this is new with
* AIX 4.3. SDL does not change the volume, so I need a kludge. Maybe
* its better to do this elsewhere?
*/
cmd.audio_cmds = CD_PLAY_AUDIO | CD_SET_VOLUME;
cmd.msf_flag = TRUE;
FRAMES_TO_MSF(start,
&cmd.indexing.msf.first_mins,
&cmd.indexing.msf.first_secs,
&cmd.indexing.msf.first_frames);
FRAMES_TO_MSF(start+length,
&cmd.indexing.msf.last_mins,
&cmd.indexing.msf.last_secs,
&cmd.indexing.msf.last_frames);
cmd.volume_type = CD_VOLUME_ALL;
cmd.all_channel_vol = 255; /* This is a uchar. What is a good value? No docu! */
cmd.out_port_0_sel = CD_AUDIO_CHNL_0;
cmd.out_port_1_sel = CD_AUDIO_CHNL_1;
cmd.out_port_2_sel = CD_AUDIO_CHNL_2;
cmd.out_port_3_sel = CD_AUDIO_CHNL_3;
#ifdef DEBUG_CDROM
fprintf(stderr, "Trying to play from %d:%d:%d to %d:%d:%d\n",
cmd.indexing.msf.first_mins,
cmd.indexing.msf.first_secs,
cmd.indexing.msf.first_frames,
cmd.indexing.msf.last_mins,
cmd.indexing.msf.last_secs,
cmd.indexing.msf.last_frames);
#endif
return(SDL_SYS_CDioctl(cdrom->id, DKAUDIO, &cmd));
}
/* Pause play */
static int SDL_SYS_CDPause(SDL_CD *cdrom)
{
struct cd_audio_cmd cmd;
cmd.audio_cmds = CD_PAUSE_AUDIO;
return(SDL_SYS_CDioctl(cdrom->id, DKAUDIO, &cmd));
}
/* Resume play */
static int SDL_SYS_CDResume(SDL_CD *cdrom)
{
struct cd_audio_cmd cmd;
cmd.audio_cmds = CD_RESUME_AUDIO;
return(SDL_SYS_CDioctl(cdrom->id, DKAUDIO, &cmd));
}
/* Stop play */
static int SDL_SYS_CDStop(SDL_CD *cdrom)
{
struct cd_audio_cmd cmd;
cmd.audio_cmds = CD_STOP_AUDIO;
return(SDL_SYS_CDioctl(cdrom->id, DKAUDIO, &cmd));
}
/* Eject the CD-ROM */
static int SDL_SYS_CDEject(SDL_CD *cdrom)
{
return(SDL_SYS_CDioctl(cdrom->id, DKEJECT, 0));
}
/* Close the CD-ROM handle */
static void SDL_SYS_CDClose(SDL_CD *cdrom)
{
close(cdrom->id);
}
void SDL_SYS_CDQuit(void)
{
int i;
if ( SDL_numcds > 0 ) {
for ( i=0; i<SDL_numcds; ++i ) {
SDL_free(SDL_cdlist[i]);
}
SDL_numcds = 0;
}
}
#endif /* SDL_CDROM_AIX */

View file

@ -1,410 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
#ifdef SDL_CDROM_BEOS
/* Functions for system-level CD-ROM audio control on BeOS
(not completely implemented yet)
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <scsi.h>
#include <Directory.h>
#include <Entry.h>
#include <Path.h>
#include "SDL_cdrom.h"
extern "C" {
#include "../SDL_syscdrom.h"
}
/* Constants to help us get at the SCSI table-of-contents info */
#define CD_NUMTRACKS(toc) toc.toc_data[3]
#define CD_TRACK(toc, track) (&toc.toc_data[6+(track)*8])
#define CD_TRACK_N(toc, track) CD_TRACK(toc, track)[0]
#define CD_TRACK_M(toc, track) CD_TRACK(toc, track)[3]
#define CD_TRACK_S(toc, track) CD_TRACK(toc, track)[4]
#define CD_TRACK_F(toc, track) CD_TRACK(toc, track)[5]
/* Constants to help us get at the SCSI position info */
#define POS_TRACK(pos) pos.position[6]
#define POS_ABS_M(pos) pos.position[9]
#define POS_ABS_S(pos) pos.position[10]
#define POS_ABS_F(pos) pos.position[11]
#define POS_REL_M(pos) pos.position[13]
#define POS_REL_S(pos) pos.position[14]
#define POS_REL_F(pos) pos.position[15]
/* The maximum number of CD-ROM drives we'll detect */
#define MAX_DRIVES 16
/* A list of available CD-ROM drives */
static char *SDL_cdlist[MAX_DRIVES];
/* The system-dependent CD control functions */
static const char *SDL_SYS_CDName(int drive);
static int SDL_SYS_CDOpen(int drive);
static int SDL_SYS_CDGetTOC(SDL_CD *cdrom);
static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position);
static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length);
static int SDL_SYS_CDPause(SDL_CD *cdrom);
static int SDL_SYS_CDResume(SDL_CD *cdrom);
static int SDL_SYS_CDStop(SDL_CD *cdrom);
static int SDL_SYS_CDEject(SDL_CD *cdrom);
static void SDL_SYS_CDClose(SDL_CD *cdrom);
int try_dir(const char *directory);
/* Check a drive to see if it is a CD-ROM */
static int CheckDrive(char *drive)
{
struct stat stbuf;
int is_cd, cdfd;
device_geometry info;
/* If it doesn't exist, return -1 */
if ( stat(drive, &stbuf) < 0 ) {
return(-1);
}
/* If it does exist, verify that it's an available CD-ROM */
is_cd = 0;
cdfd = open(drive, 0);
if ( cdfd >= 0 ) {
if ( ioctl(cdfd, B_GET_GEOMETRY, &info) == B_NO_ERROR ) {
if ( info.device_type == B_CD ) {
is_cd = 1;
}
}
close(cdfd);
} else {
/* This can happen when the drive is open .. (?) */;
is_cd = 1;
}
return(is_cd);
}
/* Add a CD-ROM drive to our list of valid drives */
static void AddDrive(char *drive)
{
int i;
size_t len;
if ( SDL_numcds < MAX_DRIVES ) {
/* Add this drive to our list */
i = SDL_numcds;
len = SDL_strlen(drive)+1;
SDL_cdlist[i] = (char *)SDL_malloc(len);
if ( SDL_cdlist[i] == NULL ) {
SDL_OutOfMemory();
return;
}
SDL_strlcpy(SDL_cdlist[i], drive, len);
++SDL_numcds;
#ifdef CDROM_DEBUG
fprintf(stderr, "Added CD-ROM drive: %s\n", drive);
#endif
}
}
/* IDE bus scanning magic */
enum {
IDE_GET_DEVICES_INFO = B_DEVICE_OP_CODES_END + 50,
};
struct ide_ctrl_info {
bool ide_0_present;
bool ide_0_master_present;
bool ide_0_slave_present;
int ide_0_master_type;
int ide_0_slave_type;
bool ide_1_present;
bool ide_1_master_present;
bool ide_1_slave_present;
int ide_1_master_type;
int ide_1_slave_type;
};
int SDL_SYS_CDInit(void)
{
char *SDLcdrom;
/* Fill in our driver capabilities */
SDL_CDcaps.Name = SDL_SYS_CDName;
SDL_CDcaps.Open = SDL_SYS_CDOpen;
SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC;
SDL_CDcaps.Status = SDL_SYS_CDStatus;
SDL_CDcaps.Play = SDL_SYS_CDPlay;
SDL_CDcaps.Pause = SDL_SYS_CDPause;
SDL_CDcaps.Resume = SDL_SYS_CDResume;
SDL_CDcaps.Stop = SDL_SYS_CDStop;
SDL_CDcaps.Eject = SDL_SYS_CDEject;
SDL_CDcaps.Close = SDL_SYS_CDClose;
/* Look in the environment for our CD-ROM drive list */
SDLcdrom = SDL_getenv("SDL_CDROM"); /* ':' separated list of devices */
if ( SDLcdrom != NULL ) {
char *cdpath, *delim;
size_t len = SDL_strlen(SDLcdrom)+1;
cdpath = SDL_stack_alloc(char, len);
if ( cdpath != NULL ) {
SDL_strlcpy(cdpath, SDLcdrom, len);
SDLcdrom = cdpath;
do {
delim = SDL_strchr(SDLcdrom, ':');
if ( delim ) {
*delim++ = '\0';
}
if ( CheckDrive(SDLcdrom) > 0 ) {
AddDrive(SDLcdrom);
}
if ( delim ) {
SDLcdrom = delim;
} else {
SDLcdrom = NULL;
}
} while ( SDLcdrom );
SDL_stack_free(cdpath);
}
/* If we found our drives, there's nothing left to do */
if ( SDL_numcds > 0 ) {
return(0);
}
}
/* Scan the system for CD-ROM drives */
try_dir("/dev/disk");
return 0;
}
int try_dir(const char *directory)
{
BDirectory dir;
dir.SetTo(directory);
if(dir.InitCheck() != B_NO_ERROR) {
return false;
}
dir.Rewind();
BEntry entry;
while(dir.GetNextEntry(&entry) >= 0) {
BPath path;
const char *name;
entry_ref e;
if(entry.GetPath(&path) != B_NO_ERROR)
continue;
name = path.Path();
if(entry.GetRef(&e) != B_NO_ERROR)
continue;
if(entry.IsDirectory()) {
if(SDL_strcmp(e.name, "floppy") == 0)
continue; /* ignore floppy (it is not silent) */
int devfd = try_dir(name);
if(devfd >= 0)
return devfd;
}
else {
int devfd;
device_geometry g;
if(SDL_strcmp(e.name, "raw") != 0)
continue; /* ignore partitions */
devfd = open(name, O_RDONLY);
if(devfd < 0)
continue;
if(ioctl(devfd, B_GET_GEOMETRY, &g, sizeof(g)) >= 0) {
if(g.device_type == B_CD)
{
AddDrive(strdup(name));
}
}
close(devfd);
}
}
return B_ERROR;
}
/* General ioctl() CD-ROM command function */
static int SDL_SYS_CDioctl(int index, int command, void *arg)
{
int okay;
int fd;
okay = 0;
fd = open(SDL_cdlist[index], 0);
if ( fd >= 0 ) {
if ( ioctl(fd, command, arg) == B_NO_ERROR ) {
okay = 1;
}
close(fd);
}
return(okay ? 0 : -1);
}
static const char *SDL_SYS_CDName(int drive)
{
return(SDL_cdlist[drive]);
}
static int SDL_SYS_CDOpen(int drive)
{
return(drive);
}
static int SDL_SYS_CDGetTOC(SDL_CD *cdrom)
{
int i;
scsi_toc toc;
if ( SDL_SYS_CDioctl(cdrom->id, B_SCSI_GET_TOC, &toc) == 0 ) {
cdrom->numtracks = CD_NUMTRACKS(toc);
if ( cdrom->numtracks > SDL_MAX_TRACKS ) {
cdrom->numtracks = SDL_MAX_TRACKS;
}
for ( i=0; i<=cdrom->numtracks; ++i ) {
cdrom->track[i].id = CD_TRACK_N(toc, i);
/* FIXME: How do we tell on BeOS? */
cdrom->track[i].type = SDL_AUDIO_TRACK;
cdrom->track[i].offset = MSF_TO_FRAMES(
CD_TRACK_M(toc, i),
CD_TRACK_S(toc, i),
CD_TRACK_F(toc, i));
cdrom->track[i].length = 0;
if ( i > 0 ) {
cdrom->track[i-1].length =
cdrom->track[i].offset-
cdrom->track[i-1].offset;
}
}
return(0);
} else {
return(-1);
}
}
/* Get CD-ROM status */
static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position)
{
CDstatus status;
int fd;
int cur_frame;
scsi_position pos;
fd = open(SDL_cdlist[cdrom->id], 0);
cur_frame = 0;
if ( fd >= 0 ) {
if ( ioctl(fd, B_SCSI_GET_POSITION, &pos) == B_NO_ERROR ) {
cur_frame = MSF_TO_FRAMES(
POS_ABS_M(pos), POS_ABS_S(pos), POS_ABS_F(pos));
}
if ( ! pos.position[1] || (pos.position[1] >= 0x13) ||
((pos.position[1] == 0x12) && (!pos.position[6])) ) {
status = CD_STOPPED;
} else
if ( pos.position[1] == 0x11 ) {
status = CD_PLAYING;
} else {
status = CD_PAUSED;
}
close(fd);
} else {
status = CD_TRAYEMPTY;
}
if ( position ) {
*position = cur_frame;
}
return(status);
}
/* Start play */
static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length)
{
int okay;
int fd;
scsi_play_position pos;
okay = 0;
fd = open(SDL_cdlist[cdrom->id], 0);
if ( fd >= 0 ) {
FRAMES_TO_MSF(start, &pos.start_m, &pos.start_s, &pos.start_f);
FRAMES_TO_MSF(start+length, &pos.end_m, &pos.end_s, &pos.end_f);
if ( ioctl(fd, B_SCSI_PLAY_POSITION, &pos) == B_NO_ERROR ) {
okay = 1;
}
close(fd);
}
return(okay ? 0 : -1);
}
/* Pause play */
static int SDL_SYS_CDPause(SDL_CD *cdrom)
{
return(SDL_SYS_CDioctl(cdrom->id, B_SCSI_PAUSE_AUDIO, 0));
}
/* Resume play */
static int SDL_SYS_CDResume(SDL_CD *cdrom)
{
return(SDL_SYS_CDioctl(cdrom->id, B_SCSI_RESUME_AUDIO, 0));
}
/* Stop play */
static int SDL_SYS_CDStop(SDL_CD *cdrom)
{
return(SDL_SYS_CDioctl(cdrom->id, B_SCSI_STOP_AUDIO, 0));
}
/* Eject the CD-ROM */
static int SDL_SYS_CDEject(SDL_CD *cdrom)
{
return(SDL_SYS_CDioctl(cdrom->id, B_SCSI_EJECT, 0));
}
/* Close the CD-ROM handle */
static void SDL_SYS_CDClose(SDL_CD *cdrom)
{
close(cdrom->id);
}
void SDL_SYS_CDQuit(void)
{
int i;
if ( SDL_numcds > 0 ) {
for ( i=0; i<SDL_numcds; ++i ) {
SDL_free(SDL_cdlist[i]);
}
SDL_numcds = 0;
}
}
#endif /* SDL_CDROM_BEOS */

View file

@ -1,542 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
#ifdef SDL_CDROM_BSDI
/*
* Functions for system-level CD-ROM audio control for BSD/OS 4.x
* This started life out as a copy of the freebsd/SDL_cdrom.c file but was
* heavily modified. Works for standard (MMC) SCSI and ATAPI CDrom drives.
*
* Steven Schultz - sms@to.gd-es.com
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <err.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include </sys/dev/scsi/scsi.h>
#include </sys/dev/scsi/scsi_ioctl.h>
#include "SDL_cdrom.h"
#include "../SDL_syscdrom.h"
/*
* The msf_to_frame and frame_to_msf were yanked from libcdrom and inlined
* here so that -lcdrom doesn't have to be dragged in for something so simple.
*/
#define FRAMES_PER_SECOND 75
#define FRAMES_PER_MINUTE (FRAMES_PER_SECOND * 60)
int
msf_to_frame(int minute, int second, int frame)
{
return(minute * FRAMES_PER_MINUTE + second * FRAMES_PER_SECOND + frame);
}
void
frame_to_msf(int frame, int *minp, int *secp, int *framep)
{
*minp = frame / FRAMES_PER_MINUTE;
*secp = (frame % FRAMES_PER_MINUTE) / FRAMES_PER_SECOND;
*framep = frame % FRAMES_PER_SECOND;
}
/* The maximum number of CD-ROM drives we'll detect */
#define MAX_DRIVES 16
/* A list of available CD-ROM drives */
static char *SDL_cdlist[MAX_DRIVES];
static dev_t SDL_cdmode[MAX_DRIVES];
/* The system-dependent CD control functions */
static const char *SDL_SYS_CDName(int drive);
static int SDL_SYS_CDOpen(int drive);
static int SDL_SYS_CDGetTOC(SDL_CD *cdrom);
static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position);
static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length);
static int SDL_SYS_CDPause(SDL_CD *cdrom);
static int SDL_SYS_CDResume(SDL_CD *cdrom);
static int SDL_SYS_CDStop(SDL_CD *cdrom);
static int SDL_SYS_CDEject(SDL_CD *cdrom);
static void SDL_SYS_CDClose(SDL_CD *cdrom);
typedef struct scsi_cdb cdb_t;
static int scsi_cmd(int fd,
struct scsi_cdb *cdb,
int cdblen,
int rw,
caddr_t data,
int datalen,
struct scsi_user_cdb *sus)
{
int scsistatus;
unsigned char *cp;
struct scsi_user_cdb suc;
/* safety checks */
if (!cdb) return(-1);
if (rw != SUC_READ && rw != SUC_WRITE) return(-1);
suc.suc_flags = rw;
suc.suc_cdblen = cdblen;
bcopy(cdb, suc.suc_cdb, cdblen);
suc.suc_datalen = datalen;
suc.suc_data = data;
suc.suc_timeout = 10; /* 10 secs max for TUR or SENSE */
if (ioctl(fd, SCSIRAWCDB, &suc) == -1)
return(-11);
scsistatus = suc.suc_sus.sus_status;
cp = suc.suc_sus.sus_sense;
/*
* If a place to copy the sense data back to has been provided then the
* caller is responsible for checking the errors and printing any information
* out if the status was not successful.
*/
if (scsistatus != 0 && !sus)
{
fprintf(stderr,"scsistatus = %x cmd = %x\n",
scsistatus, cdb[0]);
fprintf(stderr, "sense %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x\n",
cp[0], cp[1], cp[2], cp[3], cp[4], cp[5],
cp[6], cp[7], cp[8], cp[9], cp[10], cp[11],
cp[12], cp[13], cp[14], cp[15]);
return(1);
}
if (sus)
bcopy(&suc, sus, sizeof (struct scsi_user_cdb));
if (scsistatus)
return(1); /* Return non-zero for unsuccessful status */
return(0);
}
/* request vendor brand and model */
unsigned char *Inquiry(int fd)
{
static struct scsi_cdb6 cdb =
{
0x12,
0, 0, 0,
56,
0
};
static unsigned char Inqbuffer[56];
if (scsi_cmd(fd, (cdb_t *)&cdb, 6, SUC_READ, Inqbuffer,
sizeof(Inqbuffer), 0))
return("\377");
return(Inqbuffer);
}
#define ADD_SENSECODE 12
#define ADD_SC_QUALIFIER 13
int TestForMedium(int fd)
{
int sts, asc, ascq;
struct scsi_user_cdb sus;
static struct scsi_cdb6 cdb =
{
CMD_TEST_UNIT_READY, /* command */
0, /* reserved */
0, /* reserved */
0, /* reserved */
0, /* reserved */
0 /* reserved */
};
again: sts = scsi_cmd(fd, (cdb_t *)&cdb, 6, SUC_READ, 0, 0, &sus);
asc = sus.suc_sus.sus_sense[ADD_SENSECODE];
ascq = sus.suc_sus.sus_sense[ADD_SC_QUALIFIER];
if (asc == 0x3a && ascq == 0x0) /* no medium */
return(0);
if (asc == 0x28 && ascq == 0x0) /* medium changed */
goto again;
if (asc == 0x4 && ascq == 0x1 ) /* coming ready */
{
sleep(2);
goto again;
}
return(1);
}
/* Check a drive to see if it is a CD-ROM */
static int CheckDrive(char *drive, struct stat *stbuf)
{
int is_cd = 0, cdfd;
char *p;
/* If it doesn't exist, return -1 */
if ( stat(drive, stbuf) < 0 ) {
return(-1);
}
/* If it does exist, verify that it's an available CD-ROM */
cdfd = open(drive, (O_RDONLY|O_EXCL|O_NONBLOCK), 0);
if ( cdfd >= 0 ) {
p = Inquiry(cdfd);
if (*p == TYPE_ROM)
is_cd = 1;
close(cdfd);
}
return(is_cd);
}
/* Add a CD-ROM drive to our list of valid drives */
static void AddDrive(char *drive, struct stat *stbuf)
{
int i;
if ( SDL_numcds < MAX_DRIVES ) {
/* Check to make sure it's not already in our list.
This can happen when we see a drive via symbolic link.
*/
for ( i=0; i<SDL_numcds; ++i ) {
if ( stbuf->st_rdev == SDL_cdmode[i] ) {
#ifdef DEBUG_CDROM
fprintf(stderr, "Duplicate drive detected: %s == %s\n", drive, SDL_cdlist[i]);
#endif
return;
}
}
/* Add this drive to our list */
i = SDL_numcds;
SDL_cdlist[i] = SDL_strdup(drive);
if ( SDL_cdlist[i] == NULL ) {
SDL_OutOfMemory();
return;
}
SDL_cdmode[i] = stbuf->st_rdev;
++SDL_numcds;
#ifdef DEBUG_CDROM
fprintf(stderr, "Added CD-ROM drive: %s\n", drive);
#endif
}
}
int SDL_SYS_CDInit(void)
{
/* checklist: /dev/rsr?c */
static char *checklist[] = {
"?0 rsr?", NULL
};
char *SDLcdrom;
int i, j, exists;
char drive[32];
struct stat stbuf;
/* Fill in our driver capabilities */
SDL_CDcaps.Name = SDL_SYS_CDName;
SDL_CDcaps.Open = SDL_SYS_CDOpen;
SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC;
SDL_CDcaps.Status = SDL_SYS_CDStatus;
SDL_CDcaps.Play = SDL_SYS_CDPlay;
SDL_CDcaps.Pause = SDL_SYS_CDPause;
SDL_CDcaps.Resume = SDL_SYS_CDResume;
SDL_CDcaps.Stop = SDL_SYS_CDStop;
SDL_CDcaps.Eject = SDL_SYS_CDEject;
SDL_CDcaps.Close = SDL_SYS_CDClose;
/* Look in the environment for our CD-ROM drive list */
SDLcdrom = SDL_getenv("SDL_CDROM"); /* ':' separated list of devices */
if ( SDLcdrom != NULL ) {
char *cdpath, *delim;
size_t len = SDL_strlen(SDLcdrom)+1;
cdpath = SDL_stack_alloc(char, len);
if ( cdpath != NULL ) {
SDL_strlcpy(cdpath, SDLcdrom, len);
SDLcdrom = cdpath;
do {
delim = SDL_strchr(SDLcdrom, ':');
if ( delim ) {
*delim++ = '\0';
}
if ( CheckDrive(SDLcdrom, &stbuf) > 0 ) {
AddDrive(SDLcdrom, &stbuf);
}
if ( delim ) {
SDLcdrom = delim;
} else {
SDLcdrom = NULL;
}
} while ( SDLcdrom );
SDL_stack_free(cdpath);
}
/* If we found our drives, there's nothing left to do */
if ( SDL_numcds > 0 ) {
return(0);
}
}
/* Scan the system for CD-ROM drives */
for ( i=0; checklist[i]; ++i ) {
if ( checklist[i][0] == '?' ) {
char *insert;
exists = 1;
for ( j=checklist[i][1]; exists; ++j ) {
SDL_snprintf(drive, SDL_arraysize(drive), "/dev/%sc", &checklist[i][3]);
insert = SDL_strchr(drive, '?');
if ( insert != NULL ) {
*insert = j;
}
switch (CheckDrive(drive, &stbuf)) {
/* Drive exists and is a CD-ROM */
case 1:
AddDrive(drive, &stbuf);
break;
/* Drive exists, but isn't a CD-ROM */
case 0:
break;
/* Drive doesn't exist */
case -1:
exists = 0;
break;
}
}
} else {
SDL_snprintf(drive, SDL_arraysize(drive), "/dev/%s", checklist[i]);
if ( CheckDrive(drive, &stbuf) > 0 ) {
AddDrive(drive, &stbuf);
}
}
}
return(0);
}
static const char *SDL_SYS_CDName(int drive)
{
return(SDL_cdlist[drive]);
}
static int SDL_SYS_CDOpen(int drive)
{
return(open(SDL_cdlist[drive], O_RDONLY | O_NONBLOCK | O_EXCL, 0));
}
static int SDL_SYS_CDGetTOC(SDL_CD *cdrom)
{
u_char cdb[10], buf[4], *p, *toc;
struct scsi_user_cdb sus;
int i, sts, first_track, last_track, ntracks, toc_size;
bzero(cdb, sizeof (cdb));
cdb[0] = 0x43; /* Read TOC */
cdb[1] = 0x2; /* MSF */
cdb[8] = 4; /* size TOC header */
sts = scsi_cmd(cdrom->id, (cdb_t *)cdb, 10, SUC_READ, buf, 4, &sus);
if (sts < 0)
return(-1);
first_track = buf[2];
last_track = buf[3];
ntracks = last_track - first_track + 1;
cdrom->numtracks = ntracks;
toc_size = 4 + (ntracks + 1) * 8;
toc = (u_char *)SDL_malloc(toc_size);
if (toc == NULL)
return(-1);
bzero(cdb, sizeof (cdb));
cdb[0] = 0x43;
cdb[1] = 0x2;
cdb[6] = first_track;
cdb[7] = toc_size >> 8;
cdb[8] = toc_size & 0xff;
sts = scsi_cmd(cdrom->id, (cdb_t *)cdb, 10, SUC_READ, toc, toc_size,
&sus);
if (sts < 0)
{
SDL_free(toc);
return(-1);
}
for (i = 0, p = toc+4; i <= ntracks; i++, p+= 8)
{
if (i == ntracks)
cdrom->track[i].id = 0xAA; /* Leadout */
else
cdrom->track[i].id = first_track + i;
if (p[1] & 0x20)
cdrom->track[i].type = SDL_DATA_TRACK;
else
cdrom->track[i].type = SDL_AUDIO_TRACK;
cdrom->track[i].offset = msf_to_frame(p[5], p[6], p[7]);
cdrom->track[i].length = 0;
if (i > 0)
cdrom->track[i-1].length = cdrom->track[i].offset -
cdrom->track[i-1].offset;
}
SDL_free(toc);
return(0);
}
/* Get CD-ROM status */
static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position)
{
CDstatus status;
u_char cdb[10], buf[16];
int sts;
struct scsi_user_cdb sus;
bzero(cdb, sizeof (cdb));
cdb[0] = 0x42; /* read subq */
cdb[1] = 0x2; /* MSF */
cdb[2] = 0x40; /* q channel */
cdb[3] = 1; /* current pos */
cdb[7] = sizeof (buf) >> 8;
cdb[8] = sizeof (buf) & 0xff;
sts = scsi_cmd(cdrom->id, (cdb_t *)cdb, 10, SUC_READ, buf, sizeof (buf),
&sus);
if (sts < 0)
return(-1);
if (sts)
{
if (TestForMedium(cdrom->id) == 0)
status = CD_TRAYEMPTY;
else
status = CD_ERROR;
}
else
{
switch (buf[1])
{
case 0x11:
status = CD_PLAYING;
break;
case 0x12:
status = CD_PAUSED;
break;
case 0x13:
case 0x14:
case 0x15:
status = CD_STOPPED;
break;
default:
status = CD_ERROR;
break;
}
}
if (position)
{
if ( status == CD_PLAYING || (status == CD_PAUSED) )
*position = msf_to_frame(buf[9], buf[10], buf[11]);
else
*position = 0;
}
return(status);
}
/* Start play */
static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length)
{
u_char cdb[10];
int sts, minute, second, frame, eminute, esecond, eframe;
struct scsi_user_cdb sus;
bzero(cdb, sizeof(cdb));
cdb[0] = 0x47; /* Play */
frame_to_msf(start, &minute, &second, &frame);
frame_to_msf(start + length, &eminute, &esecond, &eframe);
cdb[3] = minute;
cdb[4] = second;
cdb[5] = frame;
cdb[6] = eminute;
cdb[7] = esecond;
cdb[8] = eframe;
sts = scsi_cmd(cdrom->id, (cdb_t *)cdb, 10, SUC_READ, 0, 0, &sus);
return(sts);
}
static int
pauseresume(SDL_CD *cdrom, int flag)
{
u_char cdb[10];
struct scsi_user_cdb sus;
bzero(cdb, sizeof (cdb));
cdb[0] = 0x4b;
cdb[8] = flag & 0x1;
return(scsi_cmd(cdrom->id, (cdb_t *)cdb, 10, SUC_READ, 0, 0, &sus));
}
/* Pause play */
static int SDL_SYS_CDPause(SDL_CD *cdrom)
{
return(pauseresume(cdrom, 0));
}
/* Resume play */
static int SDL_SYS_CDResume(SDL_CD *cdrom)
{
return(pauseresume(cdrom, 1));
}
/* Stop play */
static int SDL_SYS_CDStop(SDL_CD *cdrom)
{
u_char cdb[6];
struct scsi_user_cdb sus;
bzero(cdb, sizeof (cdb));
cdb[0] = 0x1b; /* stop */
cdb[1] = 1; /* immediate */
return(scsi_cmd(cdrom->id, (cdb_t *)cdb, 6, SUC_READ, 0, 0, &sus));
}
/* Eject the CD-ROM */
static int SDL_SYS_CDEject(SDL_CD *cdrom)
{
u_char cdb[6];
struct scsi_user_cdb sus;
bzero(cdb, sizeof (cdb));
cdb[0] = 0x1b; /* stop */
cdb[1] = 1; /* immediate */
cdb[4] = 2; /* eject */
return(scsi_cmd(cdrom->id, (cdb_t *)cdb, 6, SUC_READ, 0, 0, &sus));
}
/* Close the CD-ROM handle */
static void SDL_SYS_CDClose(SDL_CD *cdrom)
{
close(cdrom->id);
}
void SDL_SYS_CDQuit(void)
{
int i;
if ( SDL_numcds > 0 ) {
for ( i=0; i<SDL_numcds; ++i ) {
SDL_free(SDL_cdlist[i]);
}
}
SDL_numcds = 0;
}
#endif /* SDL_CDROM_BSDI */

View file

@ -1,167 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
#ifdef SDL_CDROM_DC
/* Functions for system-level CD-ROM audio control */
#include <dc/cdrom.h>
#include <dc/spu.h>
#include "SDL_cdrom.h"
#include "../SDL_syscdrom.h"
/* The system-dependent CD control functions */
static const char *SDL_SYS_CDName(int drive);
static int SDL_SYS_CDOpen(int drive);
static int SDL_SYS_CDGetTOC(SDL_CD *cdrom);
static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position);
static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length);
static int SDL_SYS_CDPause(SDL_CD *cdrom);
static int SDL_SYS_CDResume(SDL_CD *cdrom);
static int SDL_SYS_CDStop(SDL_CD *cdrom);
static int SDL_SYS_CDEject(SDL_CD *cdrom);
static void SDL_SYS_CDClose(SDL_CD *cdrom);
int SDL_SYS_CDInit(void)
{
/* Fill in our driver capabilities */
SDL_CDcaps.Name = SDL_SYS_CDName;
SDL_CDcaps.Open = SDL_SYS_CDOpen;
SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC;
SDL_CDcaps.Status = SDL_SYS_CDStatus;
SDL_CDcaps.Play = SDL_SYS_CDPlay;
SDL_CDcaps.Pause = SDL_SYS_CDPause;
SDL_CDcaps.Resume = SDL_SYS_CDResume;
SDL_CDcaps.Stop = SDL_SYS_CDStop;
SDL_CDcaps.Eject = SDL_SYS_CDEject;
SDL_CDcaps.Close = SDL_SYS_CDClose;
return(0);
}
static const char *SDL_SYS_CDName(int drive)
{
return "/cd";
}
static int SDL_SYS_CDOpen(int drive)
{
return(drive);
}
#define TRACK_CDDA 0
static int SDL_SYS_CDGetTOC(SDL_CD *cdrom)
{
CDROM_TOC toc;
int ret,i;
ret = cdrom_read_toc(&toc,0);
if (ret!=ERR_OK) {
return -1;
}
cdrom->numtracks = TOC_TRACK(toc.last)-TOC_TRACK(toc.first)+1;
for(i=0;i<cdrom->numtracks;i++) {
unsigned long entry = toc.entry[i];
cdrom->track[i].id = i+1;
cdrom->track[i].type = (TOC_CTRL(toc.entry[i])==TRACK_CDDA)?SDL_AUDIO_TRACK:SDL_DATA_TRACK;
cdrom->track[i].offset = TOC_LBA(entry)-150;
cdrom->track[i].length = TOC_LBA((i+1<toc.last)?toc.entry[i+1]:toc.leadout_sector)-TOC_LBA(entry);
}
return 0;
}
/* Get CD-ROM status */
static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position)
{
int ret,dc_status,disc_type;
ret = cdrom_get_status(&dc_status,&disc_type);
if (ret!=ERR_OK) return CD_ERROR;
switch(dc_status) {
// case CD_STATUS_BUSY:
case CD_STATUS_PAUSED:
return CD_PAUSED;
case CD_STATUS_STANDBY:
return CD_STOPPED;
case CD_STATUS_PLAYING:
return CD_PLAYING;
// case CD_STATUS_SEEKING:
// case CD_STATUS_SCANING:
case CD_STATUS_OPEN:
case CD_STATUS_NO_DISC:
return CD_TRAYEMPTY;
default:
return CD_ERROR;
}
}
/* Start play */
static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length)
{
int ret = cdrom_cdda_play(start-150,start-150+length,1,CDDA_SECTORS);
return ret==ERR_OK?0:-1;
}
/* Pause play */
static int SDL_SYS_CDPause(SDL_CD *cdrom)
{
int ret=cdrom_cdda_pause();
return ret==ERR_OK?0:-1;
}
/* Resume play */
static int SDL_SYS_CDResume(SDL_CD *cdrom)
{
int ret=cdrom_cdda_resume();
return ret==ERR_OK?0:-1;
}
/* Stop play */
static int SDL_SYS_CDStop(SDL_CD *cdrom)
{
int ret=cdrom_spin_down();
return ret==ERR_OK?0:-1;
}
/* Eject the CD-ROM */
static int SDL_SYS_CDEject(SDL_CD *cdrom)
{
return -1;
}
/* Close the CD-ROM handle */
static void SDL_SYS_CDClose(SDL_CD *cdrom)
{
}
void SDL_SYS_CDQuit(void)
{
}
#endif /* SDL_CDROM_DC */

View file

@ -1,406 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
#ifdef SDL_CDROM_FREEBSD
/* Functions for system-level CD-ROM audio control */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <sys/cdio.h>
#include "SDL_cdrom.h"
#include "../SDL_syscdrom.h"
/* The maximum number of CD-ROM drives we'll detect */
#define MAX_DRIVES 16
/* A list of available CD-ROM drives */
static char *SDL_cdlist[MAX_DRIVES];
static dev_t SDL_cdmode[MAX_DRIVES];
/* The system-dependent CD control functions */
static const char *SDL_SYS_CDName(int drive);
static int SDL_SYS_CDOpen(int drive);
static int SDL_SYS_CDGetTOC(SDL_CD *cdrom);
static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position);
static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length);
static int SDL_SYS_CDPause(SDL_CD *cdrom);
static int SDL_SYS_CDResume(SDL_CD *cdrom);
static int SDL_SYS_CDStop(SDL_CD *cdrom);
static int SDL_SYS_CDEject(SDL_CD *cdrom);
static void SDL_SYS_CDClose(SDL_CD *cdrom);
/* Some ioctl() errno values which occur when the tray is empty */
#define ERRNO_TRAYEMPTY(errno) \
((errno == EIO) || (errno == ENOENT) || (errno == EINVAL))
/* Check a drive to see if it is a CD-ROM */
static int CheckDrive(char *drive, struct stat *stbuf)
{
int is_cd, cdfd;
struct ioc_read_subchannel info;
/* If it doesn't exist, return -1 */
if ( stat(drive, stbuf) < 0 ) {
return(-1);
}
/* If it does exist, verify that it's an available CD-ROM */
is_cd = 0;
if ( S_ISCHR(stbuf->st_mode) || S_ISBLK(stbuf->st_mode) ) {
cdfd = open(drive, (O_RDONLY|O_EXCL|O_NONBLOCK), 0);
if ( cdfd >= 0 ) {
info.address_format = CD_MSF_FORMAT;
info.data_format = CD_CURRENT_POSITION;
info.data_len = 0;
info.data = NULL;
/* Under Linux, EIO occurs when a disk is not present.
This isn't 100% reliable, so we use the USE_MNTENT
code above instead.
*/
if ( (ioctl(cdfd, CDIOCREADSUBCHANNEL, &info) == 0) ||
ERRNO_TRAYEMPTY(errno) ) {
is_cd = 1;
}
close(cdfd);
}
}
return(is_cd);
}
/* Add a CD-ROM drive to our list of valid drives */
static void AddDrive(char *drive, struct stat *stbuf)
{
int i;
if ( SDL_numcds < MAX_DRIVES ) {
/* Check to make sure it's not already in our list.
This can happen when we see a drive via symbolic link.
*/
for ( i=0; i<SDL_numcds; ++i ) {
if ( stbuf->st_rdev == SDL_cdmode[i] ) {
#ifdef DEBUG_CDROM
fprintf(stderr, "Duplicate drive detected: %s == %s\n", drive, SDL_cdlist[i]);
#endif
return;
}
}
/* Add this drive to our list */
i = SDL_numcds;
SDL_cdlist[i] = SDL_strdup(drive);
if ( SDL_cdlist[i] == NULL ) {
SDL_OutOfMemory();
return;
}
SDL_cdmode[i] = stbuf->st_rdev;
++SDL_numcds;
#ifdef DEBUG_CDROM
fprintf(stderr, "Added CD-ROM drive: %s\n", drive);
#endif
}
}
int SDL_SYS_CDInit(void)
{
/* checklist: /dev/cdrom,/dev/cd?c /dev/acd?c
/dev/matcd?c /dev/mcd?c /dev/scd?c */
static char *checklist[] = {
"cdrom", "?0 cd?", "?0 acd?", "?0 matcd?", "?0 mcd?", "?0 scd?",NULL
};
char *SDLcdrom;
int i, j, exists;
char drive[32];
struct stat stbuf;
/* Fill in our driver capabilities */
SDL_CDcaps.Name = SDL_SYS_CDName;
SDL_CDcaps.Open = SDL_SYS_CDOpen;
SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC;
SDL_CDcaps.Status = SDL_SYS_CDStatus;
SDL_CDcaps.Play = SDL_SYS_CDPlay;
SDL_CDcaps.Pause = SDL_SYS_CDPause;
SDL_CDcaps.Resume = SDL_SYS_CDResume;
SDL_CDcaps.Stop = SDL_SYS_CDStop;
SDL_CDcaps.Eject = SDL_SYS_CDEject;
SDL_CDcaps.Close = SDL_SYS_CDClose;
/* Look in the environment for our CD-ROM drive list */
SDLcdrom = SDL_getenv("SDL_CDROM"); /* ':' separated list of devices */
if ( SDLcdrom != NULL ) {
char *cdpath, *delim;
size_t len = SDL_strlen(SDLcdrom)+1;
cdpath = SDL_stack_alloc(char, len);
if ( cdpath != NULL ) {
SDL_strlcpy(cdpath, SDLcdrom, len);
SDLcdrom = cdpath;
do {
delim = SDL_strchr(SDLcdrom, ':');
if ( delim ) {
*delim++ = '\0';
}
if ( CheckDrive(SDLcdrom, &stbuf) > 0 ) {
AddDrive(SDLcdrom, &stbuf);
}
if ( delim ) {
SDLcdrom = delim;
} else {
SDLcdrom = NULL;
}
} while ( SDLcdrom );
SDL_stack_free(cdpath);
}
/* If we found our drives, there's nothing left to do */
if ( SDL_numcds > 0 ) {
return(0);
}
}
/* Scan the system for CD-ROM drives */
for ( i=0; checklist[i]; ++i ) {
if ( checklist[i][0] == '?' ) {
char *insert;
exists = 1;
for ( j=checklist[i][1]; exists; ++j ) {
SDL_snprintf(drive, SDL_arraysize(drive), "/dev/%sc", &checklist[i][3]);
insert = SDL_strchr(drive, '?');
if ( insert != NULL ) {
*insert = j;
}
switch (CheckDrive(drive, &stbuf)) {
/* Drive exists and is a CD-ROM */
case 1:
AddDrive(drive, &stbuf);
break;
/* Drive exists, but isn't a CD-ROM */
case 0:
break;
/* Drive doesn't exist */
case -1:
exists = 0;
break;
}
}
} else {
SDL_snprintf(drive, SDL_arraysize(drive), "/dev/%s", checklist[i]);
if ( CheckDrive(drive, &stbuf) > 0 ) {
AddDrive(drive, &stbuf);
}
}
}
return(0);
}
/* General ioctl() CD-ROM command function */
static int SDL_SYS_CDioctl(int id, int command, void *arg)
{
int retval;
retval = ioctl(id, command, arg);
if ( retval < 0 ) {
SDL_SetError("ioctl() error: %s", strerror(errno));
}
return(retval);
}
static const char *SDL_SYS_CDName(int drive)
{
return(SDL_cdlist[drive]);
}
static int SDL_SYS_CDOpen(int drive)
{
return(open(SDL_cdlist[drive], (O_RDONLY|O_EXCL|O_NONBLOCK), 0));
}
static int SDL_SYS_CDGetTOC(SDL_CD *cdrom)
{
struct ioc_toc_header toc;
int i, okay;
struct ioc_read_toc_entry entry;
struct cd_toc_entry data;
okay = 0;
if ( SDL_SYS_CDioctl(cdrom->id, CDIOREADTOCHEADER, &toc) == 0 ) {
cdrom->numtracks = toc.ending_track-toc.starting_track+1;
if ( cdrom->numtracks > SDL_MAX_TRACKS ) {
cdrom->numtracks = SDL_MAX_TRACKS;
}
/* Read all the track TOC entries */
for ( i=0; i<=cdrom->numtracks; ++i ) {
if ( i == cdrom->numtracks ) {
cdrom->track[i].id = 0xAA; /* CDROM_LEADOUT */
} else {
cdrom->track[i].id = toc.starting_track+i;
}
entry.starting_track = cdrom->track[i].id;
entry.address_format = CD_MSF_FORMAT;
entry.data_len = sizeof(data);
entry.data = &data;
if ( SDL_SYS_CDioctl(cdrom->id, CDIOREADTOCENTRYS,
&entry) < 0 ) {
break;
} else {
cdrom->track[i].type = data.control;
cdrom->track[i].offset = MSF_TO_FRAMES(
data.addr.msf.minute,
data.addr.msf.second,
data.addr.msf.frame);
cdrom->track[i].length = 0;
if ( i > 0 ) {
cdrom->track[i-1].length =
cdrom->track[i].offset-
cdrom->track[i-1].offset;
}
}
}
if ( i == (cdrom->numtracks+1) ) {
okay = 1;
}
}
return(okay ? 0 : -1);
}
/* Get CD-ROM status */
static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position)
{
CDstatus status;
struct ioc_toc_header toc;
struct ioc_read_subchannel info;
struct cd_sub_channel_info data;
info.address_format = CD_MSF_FORMAT;
info.data_format = CD_CURRENT_POSITION;
info.track = 0;
info.data_len = sizeof(data);
info.data = &data;
if ( ioctl(cdrom->id, CDIOCREADSUBCHANNEL, &info) < 0 ) {
if ( ERRNO_TRAYEMPTY(errno) ) {
status = CD_TRAYEMPTY;
} else {
status = CD_ERROR;
}
} else {
switch (data.header.audio_status) {
case CD_AS_AUDIO_INVALID:
case CD_AS_NO_STATUS:
/* Try to determine if there's a CD available */
if (ioctl(cdrom->id,CDIOREADTOCHEADER,&toc)==0)
status = CD_STOPPED;
else
status = CD_TRAYEMPTY;
break;
case CD_AS_PLAY_COMPLETED:
status = CD_STOPPED;
break;
case CD_AS_PLAY_IN_PROGRESS:
status = CD_PLAYING;
break;
case CD_AS_PLAY_PAUSED:
status = CD_PAUSED;
break;
default:
status = CD_ERROR;
break;
}
}
if ( position ) {
if ( status == CD_PLAYING || (status == CD_PAUSED) ) {
*position = MSF_TO_FRAMES(
data.what.position.absaddr.msf.minute,
data.what.position.absaddr.msf.second,
data.what.position.absaddr.msf.frame);
} else {
*position = 0;
}
}
return(status);
}
/* Start play */
static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length)
{
struct ioc_play_msf playtime;
FRAMES_TO_MSF(start,
&playtime.start_m, &playtime.start_s, &playtime.start_f);
FRAMES_TO_MSF(start+length,
&playtime.end_m, &playtime.end_s, &playtime.end_f);
#ifdef DEBUG_CDROM
fprintf(stderr, "Trying to play from %d:%d:%d to %d:%d:%d\n",
playtime.cdmsf_min0, playtime.cdmsf_sec0, playtime.cdmsf_frame0,
playtime.cdmsf_min1, playtime.cdmsf_sec1, playtime.cdmsf_frame1);
#endif
ioctl(cdrom->id, CDIOCSTART, 0);
return(SDL_SYS_CDioctl(cdrom->id, CDIOCPLAYMSF, &playtime));
}
/* Pause play */
static int SDL_SYS_CDPause(SDL_CD *cdrom)
{
return(SDL_SYS_CDioctl(cdrom->id, CDIOCPAUSE, 0));
}
/* Resume play */
static int SDL_SYS_CDResume(SDL_CD *cdrom)
{
return(SDL_SYS_CDioctl(cdrom->id, CDIOCRESUME, 0));
}
/* Stop play */
static int SDL_SYS_CDStop(SDL_CD *cdrom)
{
return(SDL_SYS_CDioctl(cdrom->id, CDIOCSTOP, 0));
}
/* Eject the CD-ROM */
static int SDL_SYS_CDEject(SDL_CD *cdrom)
{
return(SDL_SYS_CDioctl(cdrom->id, CDIOCEJECT, 0));
}
/* Close the CD-ROM handle */
static void SDL_SYS_CDClose(SDL_CD *cdrom)
{
close(cdrom->id);
}
void SDL_SYS_CDQuit(void)
{
int i;
if ( SDL_numcds > 0 ) {
for ( i=0; i<SDL_numcds; ++i ) {
SDL_free(SDL_cdlist[i]);
}
SDL_numcds = 0;
}
}
#endif /* SDL_CDROM_FREEBSD */

View file

@ -1,564 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
#ifdef SDL_CDROM_LINUX
/* Functions for system-level CD-ROM audio control */
#include <string.h> /* For strerror() */
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#ifdef __LINUX__
#ifdef HAVE_LINUX_VERSION_H
/* linux 2.6.9 workaround */
#include <linux/version.h>
#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,9)
#include <asm/types.h>
#define __le64 __u64
#define __le32 __u32
#define __le16 __u16
#define __be64 __u64
#define __be32 __u32
#define __be16 __u16
#endif /* linux 2.6.9 workaround */
#endif /* HAVE_LINUX_VERSION_H */
#include <linux/cdrom.h>
#endif
#ifdef __SVR4
#include <sys/cdio.h>
#endif
/* Define this to use the alternative getmntent() code */
#ifndef __SVR4
#define USE_MNTENT
#endif
#ifdef USE_MNTENT
#if defined(__USLC__)
#include <sys/mntent.h>
#else
#include <mntent.h>
#endif
#ifndef _PATH_MNTTAB
#ifdef MNTTAB
#define _PATH_MNTTAB MNTTAB
#else
#define _PATH_MNTTAB "/etc/fstab"
#endif
#endif /* !_PATH_MNTTAB */
#ifndef _PATH_MOUNTED
#define _PATH_MOUNTED "/etc/mtab"
#endif /* !_PATH_MOUNTED */
#ifndef MNTTYPE_CDROM
#define MNTTYPE_CDROM "iso9660"
#endif
#ifndef MNTTYPE_SUPER
#define MNTTYPE_SUPER "supermount"
#endif
#endif /* USE_MNTENT */
#include "SDL_cdrom.h"
#include "../SDL_syscdrom.h"
/* The maximum number of CD-ROM drives we'll detect */
#define MAX_DRIVES 16
/* A list of available CD-ROM drives */
static char *SDL_cdlist[MAX_DRIVES];
static dev_t SDL_cdmode[MAX_DRIVES];
/* The system-dependent CD control functions */
static const char *SDL_SYS_CDName(int drive);
static int SDL_SYS_CDOpen(int drive);
static int SDL_SYS_CDGetTOC(SDL_CD *cdrom);
static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position);
static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length);
static int SDL_SYS_CDPause(SDL_CD *cdrom);
static int SDL_SYS_CDResume(SDL_CD *cdrom);
static int SDL_SYS_CDStop(SDL_CD *cdrom);
static int SDL_SYS_CDEject(SDL_CD *cdrom);
static void SDL_SYS_CDClose(SDL_CD *cdrom);
/* Some ioctl() errno values which occur when the tray is empty */
#ifndef ENOMEDIUM
#define ENOMEDIUM ENOENT
#endif
#define ERRNO_TRAYEMPTY(errno) \
((errno == EIO) || (errno == ENOENT) || \
(errno == EINVAL) || (errno == ENOMEDIUM))
/* Check a drive to see if it is a CD-ROM */
static int CheckDrive(char *drive, char *mnttype, struct stat *stbuf)
{
int is_cd, cdfd;
struct cdrom_subchnl info;
/* If it doesn't exist, return -1 */
if ( stat(drive, stbuf) < 0 ) {
return(-1);
}
/* If it does exist, verify that it's an available CD-ROM */
is_cd = 0;
if ( S_ISCHR(stbuf->st_mode) || S_ISBLK(stbuf->st_mode) ) {
cdfd = open(drive, (O_RDONLY|O_NONBLOCK), 0);
if ( cdfd >= 0 ) {
info.cdsc_format = CDROM_MSF;
/* Under Linux, EIO occurs when a disk is not present.
*/
if ( (ioctl(cdfd, CDROMSUBCHNL, &info) == 0) ||
ERRNO_TRAYEMPTY(errno) ) {
is_cd = 1;
}
close(cdfd);
}
#ifdef USE_MNTENT
/* Even if we can't read it, it might be mounted */
else if ( mnttype && (SDL_strcmp(mnttype, MNTTYPE_CDROM) == 0) ) {
is_cd = 1;
}
#endif
}
return(is_cd);
}
/* Add a CD-ROM drive to our list of valid drives */
static void AddDrive(char *drive, struct stat *stbuf)
{
int i;
if ( SDL_numcds < MAX_DRIVES ) {
/* Check to make sure it's not already in our list.
This can happen when we see a drive via symbolic link.
*/
for ( i=0; i<SDL_numcds; ++i ) {
if ( stbuf->st_rdev == SDL_cdmode[i] ) {
#ifdef DEBUG_CDROM
fprintf(stderr, "Duplicate drive detected: %s == %s\n", drive, SDL_cdlist[i]);
#endif
return;
}
}
/* Add this drive to our list */
i = SDL_numcds;
SDL_cdlist[i] = SDL_strdup(drive);
if ( SDL_cdlist[i] == NULL ) {
SDL_OutOfMemory();
return;
}
SDL_cdmode[i] = stbuf->st_rdev;
++SDL_numcds;
#ifdef DEBUG_CDROM
fprintf(stderr, "Added CD-ROM drive: %s\n", drive);
#endif
}
}
#ifdef USE_MNTENT
static void CheckMounts(const char *mtab)
{
FILE *mntfp;
struct mntent *mntent;
struct stat stbuf;
mntfp = setmntent(mtab, "r");
if ( mntfp != NULL ) {
char *tmp;
char *mnt_type;
size_t mnt_type_len;
char *mnt_dev;
size_t mnt_dev_len;
while ( (mntent=getmntent(mntfp)) != NULL ) {
mnt_type_len = SDL_strlen(mntent->mnt_type) + 1;
mnt_type = SDL_stack_alloc(char, mnt_type_len);
if (mnt_type == NULL)
continue; /* maybe you'll get lucky next time. */
mnt_dev_len = SDL_strlen(mntent->mnt_fsname) + 1;
mnt_dev = SDL_stack_alloc(char, mnt_dev_len);
if (mnt_dev == NULL) {
SDL_stack_free(mnt_type);
continue;
}
SDL_strlcpy(mnt_type, mntent->mnt_type, mnt_type_len);
SDL_strlcpy(mnt_dev, mntent->mnt_fsname, mnt_dev_len);
/* Handle "supermount" filesystem mounts */
if ( SDL_strcmp(mnt_type, MNTTYPE_SUPER) == 0 ) {
tmp = SDL_strstr(mntent->mnt_opts, "fs=");
if ( tmp ) {
SDL_stack_free(mnt_type);
mnt_type = SDL_strdup(tmp + SDL_strlen("fs="));
if ( mnt_type ) {
tmp = SDL_strchr(mnt_type, ',');
if ( tmp ) {
*tmp = '\0';
}
}
}
tmp = SDL_strstr(mntent->mnt_opts, "dev=");
if ( tmp ) {
SDL_stack_free(mnt_dev);
mnt_dev = SDL_strdup(tmp + SDL_strlen("dev="));
if ( mnt_dev ) {
tmp = SDL_strchr(mnt_dev, ',');
if ( tmp ) {
*tmp = '\0';
}
}
}
}
if ( SDL_strcmp(mnt_type, MNTTYPE_CDROM) == 0 ) {
#ifdef DEBUG_CDROM
fprintf(stderr, "Checking mount path from %s: %s mounted on %s of %s\n",
mtab, mnt_dev, mntent->mnt_dir, mnt_type);
#endif
if (CheckDrive(mnt_dev, mnt_type, &stbuf) > 0) {
AddDrive(mnt_dev, &stbuf);
}
}
SDL_stack_free(mnt_dev);
SDL_stack_free(mnt_type);
}
endmntent(mntfp);
}
}
#endif /* USE_MNTENT */
int SDL_SYS_CDInit(void)
{
/* checklist: /dev/cdrom, /dev/hd?, /dev/scd? /dev/sr? */
static char *checklist[] = {
"cdrom", "?a hd?", "?0 scd?", "?0 sr?", NULL
};
char *SDLcdrom;
int i, j, exists;
char drive[32];
struct stat stbuf;
/* Fill in our driver capabilities */
SDL_CDcaps.Name = SDL_SYS_CDName;
SDL_CDcaps.Open = SDL_SYS_CDOpen;
SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC;
SDL_CDcaps.Status = SDL_SYS_CDStatus;
SDL_CDcaps.Play = SDL_SYS_CDPlay;
SDL_CDcaps.Pause = SDL_SYS_CDPause;
SDL_CDcaps.Resume = SDL_SYS_CDResume;
SDL_CDcaps.Stop = SDL_SYS_CDStop;
SDL_CDcaps.Eject = SDL_SYS_CDEject;
SDL_CDcaps.Close = SDL_SYS_CDClose;
/* Look in the environment for our CD-ROM drive list */
SDLcdrom = SDL_getenv("SDL_CDROM"); /* ':' separated list of devices */
if ( SDLcdrom != NULL ) {
char *cdpath, *delim;
size_t len = SDL_strlen(SDLcdrom)+1;
cdpath = SDL_stack_alloc(char, len);
if ( cdpath != NULL ) {
SDL_strlcpy(cdpath, SDLcdrom, len);
SDLcdrom = cdpath;
do {
delim = SDL_strchr(SDLcdrom, ':');
if ( delim ) {
*delim++ = '\0';
}
#ifdef DEBUG_CDROM
fprintf(stderr, "Checking CD-ROM drive from SDL_CDROM: %s\n", SDLcdrom);
#endif
if ( CheckDrive(SDLcdrom, NULL, &stbuf) > 0 ) {
AddDrive(SDLcdrom, &stbuf);
}
if ( delim ) {
SDLcdrom = delim;
} else {
SDLcdrom = NULL;
}
} while ( SDLcdrom );
SDL_stack_free(cdpath);
}
/* If we found our drives, there's nothing left to do */
if ( SDL_numcds > 0 ) {
return(0);
}
}
#ifdef USE_MNTENT
/* Check /dev/cdrom first :-) */
if (CheckDrive("/dev/cdrom", NULL, &stbuf) > 0) {
AddDrive("/dev/cdrom", &stbuf);
}
/* Now check the currently mounted CD drives */
CheckMounts(_PATH_MOUNTED);
/* Finally check possible mountable drives in /etc/fstab */
CheckMounts(_PATH_MNTTAB);
/* If we found our drives, there's nothing left to do */
if ( SDL_numcds > 0 ) {
return(0);
}
#endif /* USE_MNTENT */
/* Scan the system for CD-ROM drives.
Not always 100% reliable, so use the USE_MNTENT code above first.
*/
for ( i=0; checklist[i]; ++i ) {
if ( checklist[i][0] == '?' ) {
char *insert;
exists = 1;
for ( j=checklist[i][1]; exists; ++j ) {
SDL_snprintf(drive, SDL_arraysize(drive), "/dev/%s", &checklist[i][3]);
insert = SDL_strchr(drive, '?');
if ( insert != NULL ) {
*insert = j;
}
#ifdef DEBUG_CDROM
fprintf(stderr, "Checking possible CD-ROM drive: %s\n", drive);
#endif
switch (CheckDrive(drive, NULL, &stbuf)) {
/* Drive exists and is a CD-ROM */
case 1:
AddDrive(drive, &stbuf);
break;
/* Drive exists, but isn't a CD-ROM */
case 0:
break;
/* Drive doesn't exist */
case -1:
exists = 0;
break;
}
}
} else {
SDL_snprintf(drive, SDL_arraysize(drive), "/dev/%s", checklist[i]);
#ifdef DEBUG_CDROM
fprintf(stderr, "Checking possible CD-ROM drive: %s\n", drive);
#endif
if ( CheckDrive(drive, NULL, &stbuf) > 0 ) {
AddDrive(drive, &stbuf);
}
}
}
return(0);
}
/* General ioctl() CD-ROM command function */
static int SDL_SYS_CDioctl(int id, int command, void *arg)
{
int retval;
retval = ioctl(id, command, arg);
if ( retval < 0 ) {
SDL_SetError("ioctl() error: %s", strerror(errno));
}
return(retval);
}
static const char *SDL_SYS_CDName(int drive)
{
return(SDL_cdlist[drive]);
}
static int SDL_SYS_CDOpen(int drive)
{
return(open(SDL_cdlist[drive], (O_RDONLY|O_NONBLOCK), 0));
}
static int SDL_SYS_CDGetTOC(SDL_CD *cdrom)
{
struct cdrom_tochdr toc;
int i, okay;
struct cdrom_tocentry entry;
okay = 0;
if ( SDL_SYS_CDioctl(cdrom->id, CDROMREADTOCHDR, &toc) == 0 ) {
cdrom->numtracks = toc.cdth_trk1-toc.cdth_trk0+1;
if ( cdrom->numtracks > SDL_MAX_TRACKS ) {
cdrom->numtracks = SDL_MAX_TRACKS;
}
/* Read all the track TOC entries */
for ( i=0; i<=cdrom->numtracks; ++i ) {
if ( i == cdrom->numtracks ) {
cdrom->track[i].id = CDROM_LEADOUT;
} else {
cdrom->track[i].id = toc.cdth_trk0+i;
}
entry.cdte_track = cdrom->track[i].id;
entry.cdte_format = CDROM_MSF;
if ( SDL_SYS_CDioctl(cdrom->id, CDROMREADTOCENTRY,
&entry) < 0 ) {
break;
} else {
if ( entry.cdte_ctrl & CDROM_DATA_TRACK ) {
cdrom->track[i].type = SDL_DATA_TRACK;
} else {
cdrom->track[i].type = SDL_AUDIO_TRACK;
}
cdrom->track[i].offset = MSF_TO_FRAMES(
entry.cdte_addr.msf.minute,
entry.cdte_addr.msf.second,
entry.cdte_addr.msf.frame);
cdrom->track[i].length = 0;
if ( i > 0 ) {
cdrom->track[i-1].length =
cdrom->track[i].offset-
cdrom->track[i-1].offset;
}
}
}
if ( i == (cdrom->numtracks+1) ) {
okay = 1;
}
}
return(okay ? 0 : -1);
}
/* Get CD-ROM status */
static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position)
{
CDstatus status;
struct cdrom_tochdr toc;
struct cdrom_subchnl info;
info.cdsc_format = CDROM_MSF;
if ( ioctl(cdrom->id, CDROMSUBCHNL, &info) < 0 ) {
if ( ERRNO_TRAYEMPTY(errno) ) {
status = CD_TRAYEMPTY;
} else {
status = CD_ERROR;
}
} else {
switch (info.cdsc_audiostatus) {
case CDROM_AUDIO_INVALID:
case CDROM_AUDIO_NO_STATUS:
/* Try to determine if there's a CD available */
if (ioctl(cdrom->id, CDROMREADTOCHDR, &toc)==0)
status = CD_STOPPED;
else
status = CD_TRAYEMPTY;
break;
case CDROM_AUDIO_COMPLETED:
status = CD_STOPPED;
break;
case CDROM_AUDIO_PLAY:
status = CD_PLAYING;
break;
case CDROM_AUDIO_PAUSED:
/* Workaround buggy CD-ROM drive */
if ( info.cdsc_trk == CDROM_LEADOUT ) {
status = CD_STOPPED;
} else {
status = CD_PAUSED;
}
break;
default:
status = CD_ERROR;
break;
}
}
if ( position ) {
if ( status == CD_PLAYING || (status == CD_PAUSED) ) {
*position = MSF_TO_FRAMES(
info.cdsc_absaddr.msf.minute,
info.cdsc_absaddr.msf.second,
info.cdsc_absaddr.msf.frame);
} else {
*position = 0;
}
}
return(status);
}
/* Start play */
static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length)
{
struct cdrom_msf playtime;
FRAMES_TO_MSF(start,
&playtime.cdmsf_min0, &playtime.cdmsf_sec0, &playtime.cdmsf_frame0);
FRAMES_TO_MSF(start+length,
&playtime.cdmsf_min1, &playtime.cdmsf_sec1, &playtime.cdmsf_frame1);
#ifdef DEBUG_CDROM
fprintf(stderr, "Trying to play from %d:%d:%d to %d:%d:%d\n",
playtime.cdmsf_min0, playtime.cdmsf_sec0, playtime.cdmsf_frame0,
playtime.cdmsf_min1, playtime.cdmsf_sec1, playtime.cdmsf_frame1);
#endif
return(SDL_SYS_CDioctl(cdrom->id, CDROMPLAYMSF, &playtime));
}
/* Pause play */
static int SDL_SYS_CDPause(SDL_CD *cdrom)
{
return(SDL_SYS_CDioctl(cdrom->id, CDROMPAUSE, 0));
}
/* Resume play */
static int SDL_SYS_CDResume(SDL_CD *cdrom)
{
return(SDL_SYS_CDioctl(cdrom->id, CDROMRESUME, 0));
}
/* Stop play */
static int SDL_SYS_CDStop(SDL_CD *cdrom)
{
return(SDL_SYS_CDioctl(cdrom->id, CDROMSTOP, 0));
}
/* Eject the CD-ROM */
static int SDL_SYS_CDEject(SDL_CD *cdrom)
{
return(SDL_SYS_CDioctl(cdrom->id, CDROMEJECT, 0));
}
/* Close the CD-ROM handle */
static void SDL_SYS_CDClose(SDL_CD *cdrom)
{
close(cdrom->id);
}
void SDL_SYS_CDQuit(void)
{
int i;
if ( SDL_numcds > 0 ) {
for ( i=0; i<SDL_numcds; ++i ) {
SDL_free(SDL_cdlist[i]);
}
SDL_numcds = 0;
}
}
#endif /* SDL_CDROM_LINUX */

View file

@ -1,525 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
#ifdef SDL_CDROM_MACOS
/* MacOS functions for system-level CD-ROM audio control */
#include <Devices.h>
#include <Files.h>
#include <LowMem.h> /* Use entry table macros, not functions in InterfaceLib */
#include "SDL_cdrom.h"
#include "../SDL_syscdrom.h"
#include "SDL_syscdrom_c.h"
/* Added by Matt Slot */
#if !defined(LMGetUnitTableEntryCount)
#define LMGetUnitTableEntryCount() *(short *)0x01D2
#endif
/* The maximum number of CD-ROM drives we'll detect */
#define MAX_DRIVES 26
/* A list of available CD-ROM drives */
static long SDL_cdversion = 0;
static struct {
short dRefNum;
short driveNum;
long frames;
char name[256];
Boolean hasAudio;
} SDL_cdlist[MAX_DRIVES];
static StringPtr gDriverName = "\p.AppleCD";
/* The system-dependent CD control functions */
static const char *SDL_SYS_CDName(int drive);
static int SDL_SYS_CDOpen(int drive);
static int SDL_SYS_CDGetTOC(SDL_CD *cdrom);
static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position);
static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length);
static int SDL_SYS_CDPause(SDL_CD *cdrom);
static int SDL_SYS_CDResume(SDL_CD *cdrom);
static int SDL_SYS_CDStop(SDL_CD *cdrom);
static int SDL_SYS_CDEject(SDL_CD *cdrom);
static void SDL_SYS_CDClose(SDL_CD *cdrom);
static short SDL_SYS_ShortToBCD(short value)
{
return((value % 10) + (value / 10) * 0x10); /* Convert value to BCD */
}
static short SDL_SYS_BCDToShort(short value)
{
return((value % 0x10) + (value / 0x10) * 10); /* Convert value from BCD */
}
int SDL_SYS_CDInit(void)
{
SInt16 dRefNum = 0;
SInt16 first, last;
SDL_numcds = 0;
/* Check that the software is available */
if (Gestalt(kGestaltAudioCDSelector, &SDL_cdversion) ||
!SDL_cdversion) return(0);
/* Fill in our driver capabilities */
SDL_CDcaps.Name = SDL_SYS_CDName;
SDL_CDcaps.Open = SDL_SYS_CDOpen;
SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC;
SDL_CDcaps.Status = SDL_SYS_CDStatus;
SDL_CDcaps.Play = SDL_SYS_CDPlay;
SDL_CDcaps.Pause = SDL_SYS_CDPause;
SDL_CDcaps.Resume = SDL_SYS_CDResume;
SDL_CDcaps.Stop = SDL_SYS_CDStop;
SDL_CDcaps.Eject = SDL_SYS_CDEject;
SDL_CDcaps.Close = SDL_SYS_CDClose;
/* Walk the list, count each AudioCD driver, and save the refnums */
first = -1;
last = 0 - LMGetUnitTableEntryCount();
for(dRefNum = first; dRefNum >= last; dRefNum--) {
Str255 driverName;
StringPtr namePtr;
DCtlHandle deviceEntry;
deviceEntry = GetDCtlEntry(dRefNum);
if (! deviceEntry) continue;
/* Is this an .AppleCD ? */
namePtr = (*deviceEntry)->dCtlFlags & (1L << dRAMBased) ?
((StringPtr) ((DCtlPtr) deviceEntry)->dCtlDriver + 18) :
((StringPtr) (*deviceEntry)->dCtlDriver + 18);
BlockMoveData(namePtr, driverName, namePtr[0]+1);
if (driverName[0] > gDriverName[0]) driverName[0] = gDriverName[0];
if (! EqualString(driverName, gDriverName, false, false)) continue;
/* Record the basic info for each drive */
SDL_cdlist[SDL_numcds].dRefNum = dRefNum;
BlockMoveData(namePtr + 1, SDL_cdlist[SDL_numcds].name, namePtr[0]);
SDL_cdlist[SDL_numcds].name[namePtr[0]] = 0;
SDL_cdlist[SDL_numcds].hasAudio = false;
SDL_numcds++;
}
return(0);
}
static const char *SDL_SYS_CDName(int drive)
{
return(SDL_cdlist[drive].name);
}
static int get_drivenum(int drive)
{
QHdr *driveQ = GetDrvQHdr();
DrvQEl *driveElem;
/* Update the drive number */
SDL_cdlist[drive].driveNum = 0;
if ( driveQ->qTail ) {
driveQ->qTail->qLink = 0;
}
for ( driveElem=(DrvQEl *)driveQ->qHead; driveElem;
driveElem = (DrvQEl *)driveElem->qLink ) {
if ( driveElem->dQRefNum == SDL_cdlist[drive].dRefNum ) {
SDL_cdlist[drive].driveNum = driveElem->dQDrive;
break;
}
}
return(SDL_cdlist[drive].driveNum);
}
static int SDL_SYS_CDOpen(int drive)
{
return(drive);
}
static int SDL_SYS_CDGetTOC(SDL_CD *cdrom)
{
CDCntrlParam cdpb;
CDTrackData tracks[SDL_MAX_TRACKS];
long i, leadout;
/* Get the number of tracks on the CD by examining the TOC */
SDL_memset(&cdpb, 0, sizeof(cdpb));
cdpb.ioVRefNum = SDL_cdlist[cdrom->id].driveNum;
cdpb.ioCRefNum = SDL_cdlist[cdrom->id].dRefNum;
cdpb.csCode = kReadTOC;
cdpb.csParam.words[0] = kGetTrackRange;
if ( PBControlSync((ParmBlkPtr)&cdpb) != noErr ) {
SDL_SetError("PBControlSync() failed");
return(-1);
}
cdrom->numtracks =
SDL_SYS_BCDToShort(cdpb.csParam.bytes[1]) -
SDL_SYS_BCDToShort(cdpb.csParam.bytes[0]) + 1;
if ( cdrom->numtracks > SDL_MAX_TRACKS )
cdrom->numtracks = SDL_MAX_TRACKS;
cdrom->status = CD_STOPPED;
cdrom->cur_track = 0; /* Apparently these are set elsewhere */
cdrom->cur_frame = 0; /* Apparently these are set elsewhere */
/* Get the lead out area of the CD by examining the TOC */
SDL_memset(&cdpb, 0, sizeof(cdpb));
cdpb.ioVRefNum = SDL_cdlist[cdrom->id].driveNum;
cdpb.ioCRefNum = SDL_cdlist[cdrom->id].dRefNum;
cdpb.csCode = kReadTOC;
cdpb.csParam.words[0] = kGetLeadOutArea;
if ( PBControlSync((ParmBlkPtr)&cdpb) != noErr ) {
SDL_SetError("PBControlSync() failed");
return(-1);
}
leadout = MSF_TO_FRAMES(
SDL_SYS_BCDToShort(cdpb.csParam.bytes[0]),
SDL_SYS_BCDToShort(cdpb.csParam.bytes[1]),
SDL_SYS_BCDToShort(cdpb.csParam.bytes[2]));
/* Get an array of track locations by examining the TOC */
SDL_memset(tracks, 0, sizeof(tracks));
SDL_memset(&cdpb, 0, sizeof(cdpb));
cdpb.ioVRefNum = SDL_cdlist[cdrom->id].driveNum;
cdpb.ioCRefNum = SDL_cdlist[cdrom->id].dRefNum;
cdpb.csCode = kReadTOC;
cdpb.csParam.words[0] = kGetTrackEntries; /* Type of Query */
* ((long *) (cdpb.csParam.words+1)) = (long) tracks;
cdpb.csParam.words[3] = cdrom->numtracks * sizeof(tracks[0]);
* ((char *) (cdpb.csParam.words+4)) = 1; /* First track */
if ( PBControlSync((ParmBlkPtr)&cdpb) != noErr ) {
SDL_SetError("PBControlSync() failed");
return(-1);
}
/* Read all the track TOC entries */
SDL_cdlist[cdrom->id].hasAudio = false;
for ( i=0; i<cdrom->numtracks; ++i )
{
cdrom->track[i].id = i+1;
if (tracks[i].entry.control & kDataTrackMask)
cdrom->track[i].type = SDL_DATA_TRACK;
else
{
cdrom->track[i].type = SDL_AUDIO_TRACK;
SDL_cdlist[SDL_numcds].hasAudio = true;
}
cdrom->track[i].offset = MSF_TO_FRAMES(
SDL_SYS_BCDToShort(tracks[i].entry.min),
SDL_SYS_BCDToShort(tracks[i].entry.min),
SDL_SYS_BCDToShort(tracks[i].entry.frame));
cdrom->track[i].length = MSF_TO_FRAMES(
SDL_SYS_BCDToShort(tracks[i+1].entry.min),
SDL_SYS_BCDToShort(tracks[i+1].entry.min),
SDL_SYS_BCDToShort(tracks[i+1].entry.frame)) -
cdrom->track[i].offset;
}
/* Apparently SDL wants a fake last entry */
cdrom->track[i].offset = leadout;
cdrom->track[i].length = 0;
return(0);
}
/* Get CD-ROM status */
static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position)
{
CDCntrlParam cdpb;
CDstatus status = CD_ERROR;
Boolean spinning = false;
if (position) *position = 0;
/* Get the number of tracks on the CD by examining the TOC */
if ( ! get_drivenum(cdrom->id) ) {
return(CD_TRAYEMPTY);
}
SDL_memset(&cdpb, 0, sizeof(cdpb));
cdpb.ioVRefNum = SDL_cdlist[cdrom->id].driveNum;
cdpb.ioCRefNum = SDL_cdlist[cdrom->id].dRefNum;
cdpb.csCode = kReadTOC;
cdpb.csParam.words[0] = kGetTrackRange;
if ( PBControlSync((ParmBlkPtr)&cdpb) != noErr ) {
SDL_SetError("PBControlSync() failed");
return(CD_ERROR);
}
cdrom->numtracks =
SDL_SYS_BCDToShort(cdpb.csParam.bytes[1]) -
SDL_SYS_BCDToShort(cdpb.csParam.bytes[0]) + 1;
if ( cdrom->numtracks > SDL_MAX_TRACKS )
cdrom->numtracks = SDL_MAX_TRACKS;
cdrom->cur_track = 0; /* Apparently these are set elsewhere */
cdrom->cur_frame = 0; /* Apparently these are set elsewhere */
if (1 || SDL_cdlist[cdrom->id].hasAudio) {
/* Get the current playback status */
SDL_memset(&cdpb, 0, sizeof(cdpb));
cdpb.ioVRefNum = SDL_cdlist[cdrom->id].driveNum;
cdpb.ioCRefNum = SDL_cdlist[cdrom->id].dRefNum;
cdpb.csCode = kAudioStatus;
if ( PBControlSync((ParmBlkPtr)&cdpb) != noErr ) {
SDL_SetError("PBControlSync() failed");
return(-1);
}
switch(cdpb.csParam.cd.status) {
case kStatusPlaying:
status = CD_PLAYING;
spinning = true;
break;
case kStatusPaused:
status = CD_PAUSED;
spinning = true;
break;
case kStatusMuted:
status = CD_PLAYING; /* What should I do here? */
spinning = true;
break;
case kStatusDone:
status = CD_STOPPED;
spinning = true;
break;
case kStatusStopped:
status = CD_STOPPED;
spinning = false;
break;
case kStatusError:
default:
status = CD_ERROR;
spinning = false;
break;
}
if (spinning && position) *position = MSF_TO_FRAMES(
SDL_SYS_BCDToShort(cdpb.csParam.cd.minute),
SDL_SYS_BCDToShort(cdpb.csParam.cd.second),
SDL_SYS_BCDToShort(cdpb.csParam.cd.frame));
}
else
status = CD_ERROR; /* What should I do here? */
return(status);
}
/* Start play */
static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length)
{
CDCntrlParam cdpb;
/* Pause the current audio playback to avoid audible artifacts */
if ( SDL_SYS_CDPause(cdrom) < 0 ) {
return(-1);
}
/* Specify the AudioCD playback mode */
SDL_memset(&cdpb, 0, sizeof(cdpb));
cdpb.ioVRefNum = SDL_cdlist[cdrom->id].driveNum;
cdpb.ioCRefNum = SDL_cdlist[cdrom->id].dRefNum;
cdpb.csCode = kSetPlayMode;
cdpb.csParam.bytes[0] = false; /* Repeat? */
cdpb.csParam.bytes[1] = kPlayModeSequential; /* Play mode */
/* ¥¥¥ÊTreat as soft error, NEC Drive doesnt support this call ¥¥¥ */
PBControlSync((ParmBlkPtr) &cdpb);
#if 1
/* Specify the end of audio playback */
SDL_memset(&cdpb, 0, sizeof(cdpb));
cdpb.ioVRefNum = SDL_cdlist[cdrom->id].driveNum;
cdpb.ioCRefNum = SDL_cdlist[cdrom->id].dRefNum;
cdpb.csCode = kAudioStop;
cdpb.csParam.words[0] = kBlockPosition; /* Position Mode */
*(long *) (cdpb.csParam.words + 1) = start+length-1; /* Search Address */
if ( PBControlSync((ParmBlkPtr)&cdpb) != noErr ) {
SDL_SetError("PBControlSync() failed");
return(-1);
}
/* Specify the start of audio playback, and start it */
SDL_memset(&cdpb, 0, sizeof(cdpb));
cdpb.ioVRefNum = SDL_cdlist[cdrom->id].driveNum;
cdpb.ioCRefNum = SDL_cdlist[cdrom->id].dRefNum;
cdpb.csCode = kAudioPlay;
cdpb.csParam.words[0] = kBlockPosition; /* Position Mode */
*(long *) (cdpb.csParam.words + 1) = start+1; /* Search Address */
cdpb.csParam.words[3] = false; /* Stop address? */
cdpb.csParam.words[4] = kStereoPlayMode; /* Audio Play Mode */
if ( PBControlSync((ParmBlkPtr)&cdpb) != noErr ) {
SDL_SetError("PBControlSync() failed");
return(-1);
}
#else
/* Specify the end of audio playback */
FRAMES_TO_MSF(start+length, &m, &s, &f);
SDL_memset(&cdpb, 0, sizeof(cdpb));
cdpb.ioVRefNum = SDL_cdlist[cdrom->id].driveNum;
cdpb.ioCRefNum = SDL_cdlist[cdrom->id].dRefNum;
cdpb.csCode = kAudioStop;
cdpb.csParam.words[0] = kTrackPosition; /* Position Mode */
cdpb.csParam.words[1] = 0; /* Search Address (hiword)*/
cdpb.csParam.words[2] = /* Search Address (loword)*/
SDL_SYS_ShortToBCD(cdrom->numtracks);
if ( PBControlSync((ParmBlkPtr)&cdpb) != noErr ) {
SDL_SetError("PBControlSync() failed");
return(-1);
}
/* Specify the start of audio playback, and start it */
FRAMES_TO_MSF(start, &m, &s, &f);
SDL_memset(&cdpb, 0, sizeof(cdpb));
cdpb.ioVRefNum = SDL_cdlist[cdrom->id].driveNum;
cdpb.ioCRefNum = SDL_cdlist[cdrom->id].dRefNum;
cdpb.csCode = kAudioPlay;
cdpb.csParam.words[0] = kTrackPosition; /* Position Mode */
cdpb.csParam.words[1] = 0; /* Search Address (hiword)*/
cdpb.csParam.words[2] = SDL_SYS_ShortToBCD(1); /* Search Address (loword)*/
cdpb.csParam.words[3] = false; /* Stop address? */
cdpb.csParam.words[4] = kStereoPlayMode; /* Audio Play Mode */
if ( PBControlSync((ParmBlkPtr)&cdpb) != noErr ) {
SDL_SetError("PBControlSync() failed");
return(-1);
}
#endif
return(0);
}
/* Pause play */
static int SDL_SYS_CDPause(SDL_CD *cdrom)
{
CDCntrlParam cdpb;
SDL_memset(&cdpb, 0, sizeof(cdpb));
cdpb.ioVRefNum = SDL_cdlist[cdrom->id].driveNum;
cdpb.ioCRefNum = SDL_cdlist[cdrom->id].dRefNum;
cdpb.csCode = kAudioPause;
cdpb.csParam.words[0] = 0; /* Pause/Continue Flag (hiword) */
cdpb.csParam.words[1] = 1; /* Pause/Continue Flag (loword) */
if ( PBControlSync((ParmBlkPtr)&cdpb) != noErr ) {
SDL_SetError("PBControlSync() failed");
return(-1);
}
return(0);
}
/* Resume play */
static int SDL_SYS_CDResume(SDL_CD *cdrom)
{
CDCntrlParam cdpb;
SDL_memset(&cdpb, 0, sizeof(cdpb));
cdpb.ioVRefNum = SDL_cdlist[cdrom->id].driveNum;
cdpb.ioCRefNum = SDL_cdlist[cdrom->id].dRefNum;
cdpb.csCode = kAudioPause;
cdpb.csParam.words[0] = 0; /* Pause/Continue Flag (hiword) */
cdpb.csParam.words[1] = 0; /* Pause/Continue Flag (loword) */
if ( PBControlSync((ParmBlkPtr)&cdpb) != noErr ) {
SDL_SetError("PBControlSync() failed");
return(-1);
}
return(0);
}
/* Stop play */
static int SDL_SYS_CDStop(SDL_CD *cdrom)
{
CDCntrlParam cdpb;
SDL_memset(&cdpb, 0, sizeof(cdpb));
cdpb.ioVRefNum = SDL_cdlist[cdrom->id].driveNum;
cdpb.ioCRefNum = SDL_cdlist[cdrom->id].dRefNum;
cdpb.csCode = kAudioStop;
cdpb.csParam.words[0] = 0; /* Position Mode */
cdpb.csParam.words[1] = 0; /* Search Address (hiword) */
cdpb.csParam.words[2] = 0; /* Search Address (loword) */
if ( PBControlSync((ParmBlkPtr)&cdpb) != noErr ) {
SDL_SetError("PBControlSync() failed");
return(-1);
}
return(0);
}
/* Eject the CD-ROM */
static int SDL_SYS_CDEject(SDL_CD *cdrom)
{
Boolean disk = false;
QHdr *driveQ = GetDrvQHdr();
DrvQEl *driveElem;
HParamBlockRec hpb;
ParamBlockRec cpb;
for ( driveElem = (DrvQEl *) driveQ->qHead; driveElem; driveElem =
(driveElem) ? ((DrvQEl *) driveElem->qLink) :
((DrvQEl *) driveQ->qHead) ) {
if ( driveQ->qTail ) {
driveQ->qTail->qLink = 0;
}
if ( driveElem->dQRefNum != SDL_cdlist[cdrom->id].dRefNum ) {
continue;
}
/* Does drive contain mounted volume? If not, skip */
SDL_memset(&hpb, 0, sizeof(hpb));
hpb.volumeParam.ioVRefNum = driveElem->dQDrive;
if ( PBHGetVInfoSync(&hpb) != noErr ) {
continue;
}
if ( (UnmountVol(0, driveElem->dQDrive) == noErr) &&
(Eject(0, driveElem->dQDrive) == noErr) ) {
driveElem = 0; /* Clear pointer to reset our loop */
disk = true;
}
}
/* If no disk is present, just eject the tray */
if (! disk) {
SDL_memset(&cpb, 0, sizeof(cpb));
cpb.cntrlParam.ioVRefNum = 0; /* No Drive */
cpb.cntrlParam.ioCRefNum = SDL_cdlist[cdrom->id].dRefNum;
cpb.cntrlParam.csCode = kEjectTheDisc;
if ( PBControlSync((ParmBlkPtr)&cpb) != noErr ) {
SDL_SetError("PBControlSync() failed");
return(-1);
}
}
return(0);
}
/* Close the CD-ROM handle */
static void SDL_SYS_CDClose(SDL_CD *cdrom)
{
return;
}
void SDL_SYS_CDQuit(void)
{
while(SDL_numcds--)
SDL_memset(SDL_cdlist + SDL_numcds, 0, sizeof(SDL_cdlist[0]));
}
#endif /* SDL_CDROM_MACOS */

View file

@ -1,140 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
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 library 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
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
/* This is the MacOS specific header for the SDL CD-ROM API
Contributed by Matt Slot
*/
/* AppleCD Control calls */
#define kVerifyTheDisc 5 /* Returns noErr if there is disc inserted */
#define kEjectTheDisc 7 /* Eject disc from drive */
#define kUserEject 80 /* Enable/disable the CD-ROM eject button */
#define kReadTOC 100 /* Extract various TOC information from the disc */
#define kReadQ 101 /* Extract Q subcode info for the current track */
#define kAudioTrackSearch 103 /* Start playback from the indicated position */
#define kAudioPlay 104 /* Start playback from the indicated position */
#define kAudioPause 105 /* Pause/continue the playback */
#define kAudioStop 106 /* Stop playback at the indicated position */
#define kAudioStatus 107 /* Return audio play status */
#define kAudioControl 109 /* Set the output volume for the audio channels */
#define kReadAudioVolume 112 /* Get the output volume for the audio channels */
#define kSetTrackList 122 /* Set the track program for the audio CD to play */
#define kGetTrackList 123 /* Get the track program the audio CD is playing */
#define kGetTrackIndex 124 /* Get the track index the audio CD is playing */
#define kSetPlayMode 125 /* Set the audio tracks play mode */
#define kGetPlayMode 126 /* Get the audio tracks play mode */
/* AppleCD Status calls */
#define kGetDriveType 96 /* Get the type of the physical CD-ROM drive */
#define kWhoIsThere 97 /* Get a bitmap of SCSI IDs the driver controls */
#define kGetBlockSize 98 /* Get current block size of the CD-ROM drive */
/* AppleCD other constants */
#define kBlockPosition 0 /* Position at the specified logical block number */
#define kAbsMSFPosition 1 /* Position at the specified Min/Sec/Frame (in BCD) */
#define kTrackPosition 2 /* Position at the specified track number (in BCD) */
#define kIndexPosition 3 /* Position at the nth track in program (in BCD) */
#define kMutedPlayMode 0 /* Play the audio track with no output */
#define kStereoPlayMode 9 /* Play the audio track in normal stereo */
#define kControlFieldMask 0x0D /* Bits 3,2,0 in the nibble */
#define kDataTrackMask 0x04 /* Indicates Data Track */
#define kGetTrackRange 1 /* Query TOC for track numbers */
#define kGetLeadOutArea 2 /* Query TOC for "Lead Out" end of audio data */
#define kGetTrackEntries 3 /* Query TOC for track starts and data types */
#define kStatusPlaying 0 /* Audio Play operation in progress */
#define kStatusPaused 1 /* CD-ROM device in Hold Track ("Pause") state */
#define kStatusMuted 2 /* MUTING-ON operation in progress */
#define kStatusDone 3 /* Audio Play completed */
#define kStatusError 4 /* Error occurred during audio play operation */
#define kStatusStopped 5 /* Audio play operation not requested */
#define kPlayModeSequential 0 /* Play tracks in order */
#define kPlayModeShuffled 1 /* Play tracks randomly */
#define kPlayModeProgrammed 2 /* Use custom playlist */
/* AppleCD Gestalt selectors */
#define kGestaltAudioCDSelector 'aucd'
#define kDriverVersion52 0x00000520
#define kDriverVersion51 0x00000510
#define kDriverVersion50 0x00000500
/* Drive type constants */
#define kDriveAppleCD_SC 1
#define kDriveAppleCD_SCPlus_or_150 2
#define kDriveAppleCD_300_or_300Plus 3
/* Misc constants */
#define kFirstSCSIDevice -33
#define kLastSCSIDevice -40
#if PRAGMA_STRUCT_ALIGN
#pragma options align=mac68k
#endif
/* AppleCD driver parameter block */
typedef struct CDCntrlParam {
QElemPtr qLink;
short qType;
short ioTrap;
Ptr ioCmdAddr;
IOCompletionUPP ioCompletion;
OSErr ioResult;
StringPtr ioNamePtr;
short ioVRefNum;
short ioCRefNum;
short csCode;
union {
long longs[6];
short words[11];
unsigned char bytes[22];
struct {
unsigned char status;
unsigned char play;
unsigned char control;
unsigned char minute;
unsigned char second;
unsigned char frame;
} cd;
} csParam;
} CDCntrlParam, *CDCntrlParamPtr;
typedef union CDTrackData {
long value; /* Treat as a longword value */
struct {
unsigned char reserved : 4; /* Unused by AppleCD driver */
unsigned char control : 4; /* Track flags (data track?) */
unsigned char min; /* Start of track (BCD) */
unsigned char sec; /* Start of track (BCD) */
unsigned char frame; /* Start of track (BCD) */
} entry; /* Broken into fields */
} CDTrackData, *CDTrackPtr;
#if PRAGMA_STRUCT_ALIGN
#pragma options align=reset
#endif

View file

@ -1,360 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
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 library 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
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
This file based on Apple sample code. We haven't changed the file name,
so if you want to see the original search for it on apple.com/developer
*/
#include "SDL_config.h"
#include "SDL_endian.h"
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
AudioFilePlayer.cpp
*/
#include "AudioFilePlayer.h"
/*
void ThrowResult (OSStatus result, const char* str)
{
SDL_SetError ("Error: %s %d", str, result);
throw result;
}
*/
#if DEBUG
static void PrintStreamDesc (AudioStreamBasicDescription *inDesc)
{
if (!inDesc) {
printf ("Can't print a NULL desc!\n");
return;
}
printf ("- - - - - - - - - - - - - - - - - - - -\n");
printf (" Sample Rate:%f\n", inDesc->mSampleRate);
printf (" Format ID:%s\n", (char*)&inDesc->mFormatID);
printf (" Format Flags:%lX\n", inDesc->mFormatFlags);
printf (" Bytes per Packet:%ld\n", inDesc->mBytesPerPacket);
printf (" Frames per Packet:%ld\n", inDesc->mFramesPerPacket);
printf (" Bytes per Frame:%ld\n", inDesc->mBytesPerFrame);
printf (" Channels per Frame:%ld\n", inDesc->mChannelsPerFrame);
printf (" Bits per Channel:%ld\n", inDesc->mBitsPerChannel);
printf ("- - - - - - - - - - - - - - - - - - - -\n");
}
#endif
static int AudioFilePlayer_SetDestination (AudioFilePlayer *afp, AudioUnit *inDestUnit)
{
/*if (afp->mConnected) throw static_cast<OSStatus>(-1);*/ /* can't set dest if already engaged */
if (afp->mConnected)
return 0 ;
SDL_memcpy(&afp->mPlayUnit, inDestUnit, sizeof (afp->mPlayUnit));
OSStatus result = noErr;
/* we can "down" cast a component instance to a component */
ComponentDescription desc;
result = GetComponentInfo ((Component)*inDestUnit, &desc, 0, 0, 0);
if (result) return 0; /*THROW_RESULT("GetComponentInfo")*/
/* we're going to use this to know which convert routine to call
a v1 audio unit will have a type of 'aunt'
a v2 audio unit will have one of several different types. */
if (desc.componentType != kAudioUnitType_Output) {
result = badComponentInstance;
/*THROW_RESULT("BAD COMPONENT")*/
if (result) return 0;
}
/* Set the input format of the audio unit. */
result = AudioUnitSetProperty (*inDestUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
0,
&afp->mFileDescription,
sizeof (afp->mFileDescription));
/*THROW_RESULT("AudioUnitSetProperty")*/
if (result) return 0;
return 1;
}
static void AudioFilePlayer_SetNotifier(AudioFilePlayer *afp, AudioFilePlayNotifier inNotifier, void *inRefCon)
{
afp->mNotifier = inNotifier;
afp->mRefCon = inRefCon;
}
static int AudioFilePlayer_IsConnected(AudioFilePlayer *afp)
{
return afp->mConnected;
}
static AudioUnit AudioFilePlayer_GetDestUnit(AudioFilePlayer *afp)
{
return afp->mPlayUnit;
}
static void AudioFilePlayer_Print(AudioFilePlayer *afp)
{
#if DEBUG
printf ("Is Connected:%s\n", (IsConnected() ? "true" : "false"));
printf ("- - - - - - - - - - - - - - \n");
#endif
}
static void AudioFilePlayer_SetStartFrame (AudioFilePlayer *afp, int frame)
{
SInt64 position = frame * 2352;
afp->mStartFrame = frame;
afp->mAudioFileManager->SetPosition (afp->mAudioFileManager, position);
}
static int AudioFilePlayer_GetCurrentFrame (AudioFilePlayer *afp)
{
return afp->mStartFrame + (afp->mAudioFileManager->GetByteCounter(afp->mAudioFileManager) / 2352);
}
static void AudioFilePlayer_SetStopFrame (AudioFilePlayer *afp, int frame)
{
SInt64 position = frame * 2352;
afp->mAudioFileManager->SetEndOfFile (afp->mAudioFileManager, position);
}
void delete_AudioFilePlayer(AudioFilePlayer *afp)
{
if (afp != NULL)
{
afp->Disconnect(afp);
if (afp->mAudioFileManager) {
delete_AudioFileManager(afp->mAudioFileManager);
afp->mAudioFileManager = 0;
}
if (afp->mForkRefNum) {
FSCloseFork (afp->mForkRefNum);
afp->mForkRefNum = 0;
}
SDL_free(afp);
}
}
static int AudioFilePlayer_Connect(AudioFilePlayer *afp)
{
#if DEBUG
printf ("Connect:%x, engaged=%d\n", (int)afp->mPlayUnit, (afp->mConnected ? 1 : 0));
#endif
if (!afp->mConnected)
{
if (!afp->mAudioFileManager->DoConnect(afp->mAudioFileManager))
return 0;
/* set the render callback for the file data to be supplied to the sound converter AU */
afp->mInputCallback.inputProc = afp->mAudioFileManager->FileInputProc;
afp->mInputCallback.inputProcRefCon = afp->mAudioFileManager;
OSStatus result = AudioUnitSetProperty (afp->mPlayUnit,
kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Input,
0,
&afp->mInputCallback,
sizeof(afp->mInputCallback));
if (result) return 0; /*THROW_RESULT("AudioUnitSetProperty")*/
afp->mConnected = 1;
}
return 1;
}
/* warning noted, now please go away ;-) */
/* #warning This should redirect the calling of notification code to some other thread */
static void AudioFilePlayer_DoNotification (AudioFilePlayer *afp, OSStatus inStatus)
{
if (afp->mNotifier) {
(*afp->mNotifier) (afp->mRefCon, inStatus);
} else {
SDL_SetError ("Notification posted with no notifier in place");
if (inStatus == kAudioFilePlay_FileIsFinished)
afp->Disconnect(afp);
else if (inStatus != kAudioFilePlayErr_FilePlayUnderrun)
afp->Disconnect(afp);
}
}
static void AudioFilePlayer_Disconnect (AudioFilePlayer *afp)
{
#if DEBUG
printf ("Disconnect:%x,%ld, engaged=%d\n", (int)afp->mPlayUnit, 0, (afp->mConnected ? 1 : 0));
#endif
if (afp->mConnected)
{
afp->mConnected = 0;
afp->mInputCallback.inputProc = 0;
afp->mInputCallback.inputProcRefCon = 0;
OSStatus result = AudioUnitSetProperty (afp->mPlayUnit,
kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Input,
0,
&afp->mInputCallback,
sizeof(afp->mInputCallback));
if (result)
SDL_SetError ("AudioUnitSetProperty:RemoveInputCallback:%ld", result);
afp->mAudioFileManager->Disconnect(afp->mAudioFileManager);
}
}
typedef struct {
UInt32 offset;
UInt32 blockSize;
} SSNDData;
static int AudioFilePlayer_OpenFile (AudioFilePlayer *afp, const FSRef *inRef, SInt64 *outFileDataSize)
{
ContainerChunk chunkHeader;
ChunkHeader chunk;
SSNDData ssndData;
OSErr result;
HFSUniStr255 dfName;
ByteCount actual;
SInt64 offset;
/* Open the data fork of the input file */
result = FSGetDataForkName(&dfName);
if (result) return 0; /*THROW_RESULT("AudioFilePlayer::OpenFile(): FSGetDataForkName")*/
result = FSOpenFork(inRef, dfName.length, dfName.unicode, fsRdPerm, &afp->mForkRefNum);
if (result) return 0; /*THROW_RESULT("AudioFilePlayer::OpenFile(): FSOpenFork")*/
/* Read the file header, and check if it's indeed an AIFC file */
result = FSReadFork(afp->mForkRefNum, fsAtMark, 0, sizeof(chunkHeader), &chunkHeader, &actual);
if (result) return 0; /*THROW_RESULT("AudioFilePlayer::OpenFile(): FSReadFork")*/
if (SDL_SwapBE32(chunkHeader.ckID) != 'FORM') {
result = -1;
if (result) return 0; /*THROW_RESULT("AudioFilePlayer::OpenFile(): chunk id is not 'FORM'");*/
}
if (SDL_SwapBE32(chunkHeader.formType) != 'AIFC') {
result = -1;
if (result) return 0; /*THROW_RESULT("AudioFilePlayer::OpenFile(): file format is not 'AIFC'");*/
}
/* Search for the SSND chunk. We ignore all compression etc. information
in other chunks. Of course that is kind of evil, but for now we are lazy
and rely on the cdfs to always give us the same fixed format.
TODO: Parse the COMM chunk we currently skip to fill in mFileDescription.
*/
offset = 0;
do {
result = FSReadFork(afp->mForkRefNum, fsFromMark, offset, sizeof(chunk), &chunk, &actual);
if (result) return 0; /*THROW_RESULT("AudioFilePlayer::OpenFile(): FSReadFork")*/
chunk.ckID = SDL_SwapBE32(chunk.ckID);
chunk.ckSize = SDL_SwapBE32(chunk.ckSize);
/* Skip the chunk data */
offset = chunk.ckSize;
} while (chunk.ckID != 'SSND');
/* Read the header of the SSND chunk. After this, we are positioned right
at the start of the audio data. */
result = FSReadFork(afp->mForkRefNum, fsAtMark, 0, sizeof(ssndData), &ssndData, &actual);
if (result) return 0; /*THROW_RESULT("AudioFilePlayer::OpenFile(): FSReadFork")*/
ssndData.offset = SDL_SwapBE32(ssndData.offset);
result = FSSetForkPosition(afp->mForkRefNum, fsFromMark, ssndData.offset);
if (result) return 0; /*THROW_RESULT("AudioFilePlayer::OpenFile(): FSSetForkPosition")*/
/* Data size */
*outFileDataSize = chunk.ckSize - ssndData.offset - 8;
/* File format */
afp->mFileDescription.mSampleRate = 44100;
afp->mFileDescription.mFormatID = kAudioFormatLinearPCM;
afp->mFileDescription.mFormatFlags = kLinearPCMFormatFlagIsPacked | kLinearPCMFormatFlagIsSignedInteger;
afp->mFileDescription.mBytesPerPacket = 4;
afp->mFileDescription.mFramesPerPacket = 1;
afp->mFileDescription.mBytesPerFrame = 4;
afp->mFileDescription.mChannelsPerFrame = 2;
afp->mFileDescription.mBitsPerChannel = 16;
return 1;
}
AudioFilePlayer *new_AudioFilePlayer (const FSRef *inFileRef)
{
SInt64 fileDataSize = 0;
AudioFilePlayer *afp = (AudioFilePlayer *) SDL_malloc(sizeof (AudioFilePlayer));
if (afp == NULL)
return NULL;
SDL_memset(afp, '\0', sizeof (*afp));
#define SET_AUDIOFILEPLAYER_METHOD(m) afp->m = AudioFilePlayer_##m
SET_AUDIOFILEPLAYER_METHOD(SetDestination);
SET_AUDIOFILEPLAYER_METHOD(SetNotifier);
SET_AUDIOFILEPLAYER_METHOD(SetStartFrame);
SET_AUDIOFILEPLAYER_METHOD(GetCurrentFrame);
SET_AUDIOFILEPLAYER_METHOD(SetStopFrame);
SET_AUDIOFILEPLAYER_METHOD(Connect);
SET_AUDIOFILEPLAYER_METHOD(Disconnect);
SET_AUDIOFILEPLAYER_METHOD(DoNotification);
SET_AUDIOFILEPLAYER_METHOD(IsConnected);
SET_AUDIOFILEPLAYER_METHOD(GetDestUnit);
SET_AUDIOFILEPLAYER_METHOD(Print);
SET_AUDIOFILEPLAYER_METHOD(OpenFile);
#undef SET_AUDIOFILEPLAYER_METHOD
if (!afp->OpenFile (afp, inFileRef, &fileDataSize))
{
SDL_free(afp);
return NULL;
}
/* we want about 4 seconds worth of data for the buffer */
int bytesPerSecond = (UInt32) (4 * afp->mFileDescription.mSampleRate * afp->mFileDescription.mBytesPerFrame);
#if DEBUG
printf("File format:\n");
PrintStreamDesc (&afp->mFileDescription);
#endif
afp->mAudioFileManager = new_AudioFileManager(afp, afp->mForkRefNum,
fileDataSize,
bytesPerSecond);
if (afp->mAudioFileManager == NULL)
{
delete_AudioFilePlayer(afp);
return NULL;
}
return afp;
}

View file

@ -1,178 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
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 library 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
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
This file based on Apple sample code. We haven't changed the file name,
so if you want to see the original search for it on apple.com/developer
*/
#include "SDL_config.h"
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
AudioFilePlayer.h
*/
#ifndef __AudioFilePlayer_H__
#define __AudioFilePlayer_H__
#include <CoreServices/CoreServices.h>
#include <AudioUnit/AudioUnit.h>
#if MAC_OS_X_VERSION_MAX_ALLOWED <= 1050
#include <AudioUnit/AUNTComponent.h>
#endif
#if (MAC_OS_X_VERSION_MAX_ALLOWED < 1050)
typedef SInt16 FSIORefNum;
#endif
#include "SDL_error.h"
const char* AudioFilePlayerErrorStr (OSStatus error);
/*
void ThrowResult (OSStatus result, const char *str);
#define THROW_RESULT(str) \
if (result) { \
ThrowResult (result, str); \
}
*/
typedef void (*AudioFilePlayNotifier)(void *inRefCon,
OSStatus inStatus);
enum {
kAudioFilePlayErr_FilePlayUnderrun = -10000,
kAudioFilePlay_FileIsFinished = -10001,
kAudioFilePlay_PlayerIsUninitialized = -10002
};
struct S_AudioFileManager;
#pragma mark __________ AudioFilePlayer
typedef struct S_AudioFilePlayer
{
/*public:*/
int (*SetDestination)(struct S_AudioFilePlayer *afp, AudioUnit *inDestUnit);
void (*SetNotifier)(struct S_AudioFilePlayer *afp, AudioFilePlayNotifier inNotifier, void *inRefCon);
void (*SetStartFrame)(struct S_AudioFilePlayer *afp, int frame); /* seek in the file */
int (*GetCurrentFrame)(struct S_AudioFilePlayer *afp); /* get the current frame position */
void (*SetStopFrame)(struct S_AudioFilePlayer *afp, int frame); /* set limit in the file */
int (*Connect)(struct S_AudioFilePlayer *afp);
void (*Disconnect)(struct S_AudioFilePlayer *afp);
void (*DoNotification)(struct S_AudioFilePlayer *afp, OSStatus inError);
int (*IsConnected)(struct S_AudioFilePlayer *afp);
AudioUnit (*GetDestUnit)(struct S_AudioFilePlayer *afp);
void (*Print)(struct S_AudioFilePlayer *afp);
/*private:*/
AudioUnit mPlayUnit;
FSIORefNum mForkRefNum;
AURenderCallbackStruct mInputCallback;
AudioStreamBasicDescription mFileDescription;
int mConnected;
struct S_AudioFileManager* mAudioFileManager;
AudioFilePlayNotifier mNotifier;
void* mRefCon;
int mStartFrame;
#pragma mark __________ Private_Methods
int (*OpenFile)(struct S_AudioFilePlayer *afp, const FSRef *inRef, SInt64 *outFileSize);
} AudioFilePlayer;
AudioFilePlayer *new_AudioFilePlayer(const FSRef *inFileRef);
void delete_AudioFilePlayer(AudioFilePlayer *afp);
#pragma mark __________ AudioFileManager
typedef struct S_AudioFileManager
{
/*public:*/
/* this method should NOT be called by an object of this class
as it is called by the parent's Disconnect() method */
void (*Disconnect)(struct S_AudioFileManager *afm);
int (*DoConnect)(struct S_AudioFileManager *afm);
OSStatus (*Read)(struct S_AudioFileManager *afm, char *buffer, ByteCount *len);
const char* (*GetFileBuffer)(struct S_AudioFileManager *afm);
const AudioFilePlayer *(*GetParent)(struct S_AudioFileManager *afm);
void (*SetPosition)(struct S_AudioFileManager *afm, SInt64 pos); /* seek/rewind in the file */
int (*GetByteCounter)(struct S_AudioFileManager *afm); /* return actual bytes streamed to audio hardware */
void (*SetEndOfFile)(struct S_AudioFileManager *afm, SInt64 pos); /* set the "EOF" (will behave just like it reached eof) */
/*protected:*/
AudioFilePlayer* mParent;
SInt16 mForkRefNum;
SInt64 mAudioDataOffset;
char* mFileBuffer;
int mByteCounter;
int mReadFromFirstBuffer;
int mLockUnsuccessful;
int mIsEngaged;
int mNumTimesAskedSinceFinished;
void* mTmpBuffer;
UInt32 mBufferSize;
UInt32 mBufferOffset;
/*public:*/
UInt32 mChunkSize;
SInt64 mFileLength;
SInt64 mReadFilePosition;
int mWriteToFirstBuffer;
int mFinishedReadingData;
/*protected:*/
OSStatus (*Render)(struct S_AudioFileManager *afm, AudioBufferList *ioData);
OSStatus (*GetFileData)(struct S_AudioFileManager *afm, void** inOutData, UInt32 *inOutDataSize);
void (*AfterRender)(struct S_AudioFileManager *afm);
/*public:*/
/*static*/
OSStatus (*FileInputProc)(void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList *ioData);
} AudioFileManager;
AudioFileManager *new_AudioFileManager (AudioFilePlayer *inParent,
SInt16 inForkRefNum,
SInt64 inFileLength,
UInt32 inChunkSize);
void delete_AudioFileManager(AudioFileManager *afm);
#endif

View file

@ -1,610 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
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 library 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
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
This file based on Apple sample code. We haven't changed the file name,
so if you want to see the original search for it on apple.com/developer
*/
#include "SDL_config.h"
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
AudioFileManager.cpp
*/
#include "AudioFilePlayer.h"
#include <mach/mach.h> /* used for setting policy of thread */
#include "SDLOSXCAGuard.h"
#include <pthread.h>
/*#include <list>*/
/*typedef void *FileData;*/
typedef struct S_FileData
{
AudioFileManager *obj;
struct S_FileData *next;
} FileData;
typedef struct S_FileReaderThread {
/*public:*/
SDLOSXCAGuard* (*GetGuard)(struct S_FileReaderThread *frt);
void (*AddReader)(struct S_FileReaderThread *frt);
void (*RemoveReader)(struct S_FileReaderThread *frt, AudioFileManager* inItem);
int (*TryNextRead)(struct S_FileReaderThread *frt, AudioFileManager* inItem);
int mThreadShouldDie;
/*private:*/
/*typedef std::list<AudioFileManager*> FileData;*/
SDLOSXCAGuard *mGuard;
UInt32 mThreadPriority;
int mNumReaders;
FileData *mFileData;
void (*ReadNextChunk)(struct S_FileReaderThread *frt);
int (*StartFixedPriorityThread)(struct S_FileReaderThread *frt);
/*static*/
UInt32 (*GetThreadBasePriority)(pthread_t inThread);
/*static*/
void* (*DiskReaderEntry)(void *inRefCon);
} FileReaderThread;
static SDLOSXCAGuard* FileReaderThread_GetGuard(FileReaderThread *frt)
{
return frt->mGuard;
}
/* returns 1 if succeeded */
static int FileReaderThread_TryNextRead (FileReaderThread *frt, AudioFileManager* inItem)
{
int didLock = 0;
int succeeded = 0;
if (frt->mGuard->Try(frt->mGuard, &didLock))
{
/*frt->mFileData.push_back (inItem);*/
/* !!! FIXME: this could be faster with a "tail" member. --ryan. */
FileData *i = frt->mFileData;
FileData *prev = NULL;
FileData *newfd = (FileData *) SDL_malloc(sizeof (FileData));
newfd->obj = inItem;
newfd->next = NULL;
while (i != NULL) { prev = i; i = i->next; }
if (prev == NULL)
frt->mFileData = newfd;
else
prev->next = newfd;
frt->mGuard->Notify(frt->mGuard);
succeeded = 1;
if (didLock)
frt->mGuard->Unlock(frt->mGuard);
}
return succeeded;
}
static void FileReaderThread_AddReader(FileReaderThread *frt)
{
if (frt->mNumReaders == 0)
{
frt->mThreadShouldDie = 0;
frt->StartFixedPriorityThread (frt);
}
frt->mNumReaders++;
}
static void FileReaderThread_RemoveReader (FileReaderThread *frt, AudioFileManager* inItem)
{
if (frt->mNumReaders > 0)
{
int bNeedsRelease = frt->mGuard->Lock(frt->mGuard);
/*frt->mFileData.remove (inItem);*/
FileData *i = frt->mFileData;
FileData *prev = NULL;
while (i != NULL)
{
FileData *next = i->next;
if (i->obj != inItem)
prev = i;
else
{
if (prev == NULL)
frt->mFileData = next;
else
prev->next = next;
SDL_free(i);
}
i = next;
}
if (--frt->mNumReaders == 0) {
frt->mThreadShouldDie = 1;
frt->mGuard->Notify(frt->mGuard); /* wake up thread so it will quit */
frt->mGuard->Wait(frt->mGuard); /* wait for thread to die */
}
if (bNeedsRelease) frt->mGuard->Unlock(frt->mGuard);
}
}
static int FileReaderThread_StartFixedPriorityThread (FileReaderThread *frt)
{
pthread_attr_t theThreadAttrs;
pthread_t pThread;
OSStatus result = pthread_attr_init(&theThreadAttrs);
if (result) return 0; /*THROW_RESULT("pthread_attr_init - Thread attributes could not be created.")*/
result = pthread_attr_setdetachstate(&theThreadAttrs, PTHREAD_CREATE_DETACHED);
if (result) return 0; /*THROW_RESULT("pthread_attr_setdetachstate - Thread attributes could not be detached.")*/
result = pthread_create (&pThread, &theThreadAttrs, frt->DiskReaderEntry, frt);
if (result) return 0; /*THROW_RESULT("pthread_create - Create and start the thread.")*/
pthread_attr_destroy(&theThreadAttrs);
/* we've now created the thread and started it
we'll now set the priority of the thread to the nominated priority
and we'll also make the thread fixed */
thread_extended_policy_data_t theFixedPolicy;
thread_precedence_policy_data_t thePrecedencePolicy;
SInt32 relativePriority;
/* make thread fixed */
theFixedPolicy.timeshare = 0; /* set to 1 for a non-fixed thread */
result = thread_policy_set (pthread_mach_thread_np(pThread), THREAD_EXTENDED_POLICY, (thread_policy_t)&theFixedPolicy, THREAD_EXTENDED_POLICY_COUNT);
if (result) return 0; /*THROW_RESULT("thread_policy - Couldn't set thread as fixed priority.")*/
/* set priority */
/* precedency policy's "importance" value is relative to spawning thread's priority */
relativePriority = frt->mThreadPriority - frt->GetThreadBasePriority(pthread_self());
thePrecedencePolicy.importance = relativePriority;
result = thread_policy_set (pthread_mach_thread_np(pThread), THREAD_PRECEDENCE_POLICY, (thread_policy_t)&thePrecedencePolicy, THREAD_PRECEDENCE_POLICY_COUNT);
if (result) return 0; /*THROW_RESULT("thread_policy - Couldn't set thread priority.")*/
return 1;
}
static UInt32 FileReaderThread_GetThreadBasePriority (pthread_t inThread)
{
thread_basic_info_data_t threadInfo;
policy_info_data_t thePolicyInfo;
unsigned int count;
/* get basic info */
count = THREAD_BASIC_INFO_COUNT;
thread_info (pthread_mach_thread_np (inThread), THREAD_BASIC_INFO, (integer_t*)&threadInfo, &count);
switch (threadInfo.policy) {
case POLICY_TIMESHARE:
count = POLICY_TIMESHARE_INFO_COUNT;
thread_info(pthread_mach_thread_np (inThread), THREAD_SCHED_TIMESHARE_INFO, (integer_t*)&(thePolicyInfo.ts), &count);
return thePolicyInfo.ts.base_priority;
break;
case POLICY_FIFO:
count = POLICY_FIFO_INFO_COUNT;
thread_info(pthread_mach_thread_np (inThread), THREAD_SCHED_FIFO_INFO, (integer_t*)&(thePolicyInfo.fifo), &count);
if (thePolicyInfo.fifo.depressed) {
return thePolicyInfo.fifo.depress_priority;
} else {
return thePolicyInfo.fifo.base_priority;
}
break;
case POLICY_RR:
count = POLICY_RR_INFO_COUNT;
thread_info(pthread_mach_thread_np (inThread), THREAD_SCHED_RR_INFO, (integer_t*)&(thePolicyInfo.rr), &count);
if (thePolicyInfo.rr.depressed) {
return thePolicyInfo.rr.depress_priority;
} else {
return thePolicyInfo.rr.base_priority;
}
break;
}
return 0;
}
static void *FileReaderThread_DiskReaderEntry (void *inRefCon)
{
FileReaderThread *frt = (FileReaderThread *)inRefCon;
frt->ReadNextChunk(frt);
#if DEBUG
printf ("finished with reading file\n");
#endif
return 0;
}
static void FileReaderThread_ReadNextChunk (FileReaderThread *frt)
{
OSStatus result;
ByteCount dataChunkSize;
AudioFileManager* theItem = 0;
for (;;)
{
{ /* this is a scoped based lock */
int bNeedsRelease = frt->mGuard->Lock(frt->mGuard);
if (frt->mThreadShouldDie) {
frt->mGuard->Notify(frt->mGuard);
if (bNeedsRelease) frt->mGuard->Unlock(frt->mGuard);
return;
}
/*if (frt->mFileData.empty())*/
if (frt->mFileData == NULL)
{
frt->mGuard->Wait(frt->mGuard);
}
/* kill thread */
if (frt->mThreadShouldDie) {
frt->mGuard->Notify(frt->mGuard);
if (bNeedsRelease) frt->mGuard->Unlock(frt->mGuard);
return;
}
/*theItem = frt->mFileData.front();*/
/*frt->mFileData.pop_front();*/
theItem = NULL;
if (frt->mFileData != NULL)
{
FileData *next = frt->mFileData->next;
theItem = frt->mFileData->obj;
SDL_free(frt->mFileData);
frt->mFileData = next;
}
if (bNeedsRelease) frt->mGuard->Unlock(frt->mGuard);
}
if ((theItem->mFileLength - theItem->mReadFilePosition) < theItem->mChunkSize)
dataChunkSize = theItem->mFileLength - theItem->mReadFilePosition;
else
dataChunkSize = theItem->mChunkSize;
/* this is the exit condition for the thread */
if (dataChunkSize <= 0) {
theItem->mFinishedReadingData = 1;
continue;
}
/* construct pointer */
char* writePtr = (char *) (theItem->GetFileBuffer(theItem) +
(theItem->mWriteToFirstBuffer ? 0 : theItem->mChunkSize));
/* read data */
result = theItem->Read(theItem, writePtr, &dataChunkSize);
if (result != noErr && result != eofErr) {
AudioFilePlayer *afp = (AudioFilePlayer *) theItem->GetParent(theItem);
afp->DoNotification(afp, result);
continue;
}
if (dataChunkSize != theItem->mChunkSize)
{
writePtr += dataChunkSize;
/* can't exit yet.. we still have to pass the partial buffer back */
SDL_memset(writePtr, 0, (theItem->mChunkSize - dataChunkSize));
}
theItem->mWriteToFirstBuffer = !theItem->mWriteToFirstBuffer; /* switch buffers */
if (result == eofErr)
theItem->mReadFilePosition = theItem->mFileLength;
else
theItem->mReadFilePosition += dataChunkSize; /* increment count */
}
}
void delete_FileReaderThread(FileReaderThread *frt)
{
if (frt != NULL)
{
delete_SDLOSXCAGuard(frt->mGuard);
SDL_free(frt);
}
}
FileReaderThread *new_FileReaderThread ()
{
FileReaderThread *frt = (FileReaderThread *) SDL_malloc(sizeof (FileReaderThread));
if (frt == NULL)
return NULL;
SDL_memset(frt, '\0', sizeof (*frt));
frt->mGuard = new_SDLOSXCAGuard();
if (frt->mGuard == NULL)
{
SDL_free(frt);
return NULL;
}
#define SET_FILEREADERTHREAD_METHOD(m) frt->m = FileReaderThread_##m
SET_FILEREADERTHREAD_METHOD(GetGuard);
SET_FILEREADERTHREAD_METHOD(AddReader);
SET_FILEREADERTHREAD_METHOD(RemoveReader);
SET_FILEREADERTHREAD_METHOD(TryNextRead);
SET_FILEREADERTHREAD_METHOD(ReadNextChunk);
SET_FILEREADERTHREAD_METHOD(StartFixedPriorityThread);
SET_FILEREADERTHREAD_METHOD(GetThreadBasePriority);
SET_FILEREADERTHREAD_METHOD(DiskReaderEntry);
#undef SET_FILEREADERTHREAD_METHOD
frt->mThreadPriority = 62;
return frt;
}
static FileReaderThread *sReaderThread;
static int AudioFileManager_DoConnect (AudioFileManager *afm)
{
if (!afm->mIsEngaged)
{
OSStatus result;
/*afm->mReadFilePosition = 0;*/
afm->mFinishedReadingData = 0;
afm->mNumTimesAskedSinceFinished = 0;
afm->mLockUnsuccessful = 0;
ByteCount dataChunkSize;
if ((afm->mFileLength - afm->mReadFilePosition) < afm->mChunkSize)
dataChunkSize = afm->mFileLength - afm->mReadFilePosition;
else
dataChunkSize = afm->mChunkSize;
result = afm->Read(afm, afm->mFileBuffer, &dataChunkSize);
if (result) return 0; /*THROW_RESULT("AudioFileManager::DoConnect(): Read")*/
afm->mReadFilePosition += dataChunkSize;
afm->mWriteToFirstBuffer = 0;
afm->mReadFromFirstBuffer = 1;
sReaderThread->AddReader(sReaderThread);
afm->mIsEngaged = 1;
}
/*
else
throw static_cast<OSStatus>(-1); */ /* thread has already been started */
return 1;
}
static void AudioFileManager_Disconnect (AudioFileManager *afm)
{
if (afm->mIsEngaged)
{
sReaderThread->RemoveReader (sReaderThread, afm);
afm->mIsEngaged = 0;
}
}
static OSStatus AudioFileManager_Read(AudioFileManager *afm, char *buffer, ByteCount *len)
{
return FSReadFork (afm->mForkRefNum,
fsFromStart,
afm->mReadFilePosition + afm->mAudioDataOffset,
*len,
buffer,
len);
}
static OSStatus AudioFileManager_GetFileData (AudioFileManager *afm, void** inOutData, UInt32 *inOutDataSize)
{
if (afm->mFinishedReadingData)
{
++afm->mNumTimesAskedSinceFinished;
*inOutDataSize = 0;
*inOutData = 0;
return noErr;
}
if (afm->mReadFromFirstBuffer == afm->mWriteToFirstBuffer) {
#if DEBUG
printf ("* * * * * * * Can't keep up with reading file\n");
#endif
afm->mParent->DoNotification (afm->mParent, kAudioFilePlayErr_FilePlayUnderrun);
*inOutDataSize = 0;
*inOutData = 0;
} else {
*inOutDataSize = afm->mChunkSize;
*inOutData = afm->mReadFromFirstBuffer ? afm->mFileBuffer : (afm->mFileBuffer + afm->mChunkSize);
}
afm->mLockUnsuccessful = !sReaderThread->TryNextRead (sReaderThread, afm);
afm->mReadFromFirstBuffer = !afm->mReadFromFirstBuffer;
return noErr;
}
static void AudioFileManager_AfterRender (AudioFileManager *afm)
{
if (afm->mNumTimesAskedSinceFinished > 0)
{
int didLock = 0;
SDLOSXCAGuard *guard = sReaderThread->GetGuard(sReaderThread);
if (guard->Try(guard, &didLock)) {
afm->mParent->DoNotification (afm->mParent, kAudioFilePlay_FileIsFinished);
if (didLock)
guard->Unlock(guard);
}
}
if (afm->mLockUnsuccessful)
afm->mLockUnsuccessful = !sReaderThread->TryNextRead (sReaderThread, afm);
}
static void AudioFileManager_SetPosition (AudioFileManager *afm, SInt64 pos)
{
if (pos < 0 || pos >= afm->mFileLength) {
SDL_SetError ("AudioFileManager::SetPosition - position invalid: %d filelen=%d\n",
(unsigned int)pos, (unsigned int)afm->mFileLength);
pos = 0;
}
afm->mReadFilePosition = pos;
}
static void AudioFileManager_SetEndOfFile (AudioFileManager *afm, SInt64 pos)
{
if (pos <= 0 || pos > afm->mFileLength) {
SDL_SetError ("AudioFileManager::SetEndOfFile - position beyond actual eof\n");
pos = afm->mFileLength;
}
afm->mFileLength = pos;
}
static const char *AudioFileManager_GetFileBuffer(AudioFileManager *afm)
{
return afm->mFileBuffer;
}
const AudioFilePlayer *AudioFileManager_GetParent(AudioFileManager *afm)
{
return afm->mParent;
}
static int AudioFileManager_GetByteCounter(AudioFileManager *afm)
{
return afm->mByteCounter;
}
static OSStatus AudioFileManager_FileInputProc (void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList *ioData)
{
AudioFileManager* afm = (AudioFileManager*)inRefCon;
return afm->Render(afm, ioData);
}
static OSStatus AudioFileManager_Render (AudioFileManager *afm, AudioBufferList *ioData)
{
OSStatus result = noErr;
AudioBuffer *abuf;
UInt32 i;
for (i = 0; i < ioData->mNumberBuffers; i++) {
abuf = &ioData->mBuffers[i];
if (afm->mBufferOffset >= afm->mBufferSize) {
result = afm->GetFileData(afm, &afm->mTmpBuffer, &afm->mBufferSize);
if (result) {
SDL_SetError ("AudioConverterFillBuffer:%ld\n", result);
afm->mParent->DoNotification(afm->mParent, result);
return result;
}
afm->mBufferOffset = 0;
}
if (abuf->mDataByteSize > afm->mBufferSize - afm->mBufferOffset)
abuf->mDataByteSize = afm->mBufferSize - afm->mBufferOffset;
abuf->mData = (char *)afm->mTmpBuffer + afm->mBufferOffset;
afm->mBufferOffset += abuf->mDataByteSize;
afm->mByteCounter += abuf->mDataByteSize;
afm->AfterRender(afm);
}
return result;
}
void delete_AudioFileManager (AudioFileManager *afm)
{
if (afm != NULL) {
if (afm->mFileBuffer) {
free(afm->mFileBuffer);
}
SDL_free(afm);
}
}
AudioFileManager *new_AudioFileManager(AudioFilePlayer *inParent,
SInt16 inForkRefNum,
SInt64 inFileLength,
UInt32 inChunkSize)
{
AudioFileManager *afm;
if (sReaderThread == NULL)
{
sReaderThread = new_FileReaderThread();
if (sReaderThread == NULL)
return NULL;
}
afm = (AudioFileManager *) SDL_malloc(sizeof (AudioFileManager));
if (afm == NULL)
return NULL;
SDL_memset(afm, '\0', sizeof (*afm));
#define SET_AUDIOFILEMANAGER_METHOD(m) afm->m = AudioFileManager_##m
SET_AUDIOFILEMANAGER_METHOD(Disconnect);
SET_AUDIOFILEMANAGER_METHOD(DoConnect);
SET_AUDIOFILEMANAGER_METHOD(Read);
SET_AUDIOFILEMANAGER_METHOD(GetFileBuffer);
SET_AUDIOFILEMANAGER_METHOD(GetParent);
SET_AUDIOFILEMANAGER_METHOD(SetPosition);
SET_AUDIOFILEMANAGER_METHOD(GetByteCounter);
SET_AUDIOFILEMANAGER_METHOD(SetEndOfFile);
SET_AUDIOFILEMANAGER_METHOD(Render);
SET_AUDIOFILEMANAGER_METHOD(GetFileData);
SET_AUDIOFILEMANAGER_METHOD(AfterRender);
SET_AUDIOFILEMANAGER_METHOD(FileInputProc);
#undef SET_AUDIOFILEMANAGER_METHOD
afm->mParent = inParent;
afm->mForkRefNum = inForkRefNum;
afm->mBufferSize = inChunkSize;
afm->mBufferOffset = inChunkSize;
afm->mChunkSize = inChunkSize;
afm->mFileLength = inFileLength;
afm->mFileBuffer = (char*) SDL_malloc(afm->mChunkSize * 2);
FSGetForkPosition(afm->mForkRefNum, &afm->mAudioDataOffset);
assert (afm->mFileBuffer != NULL);
return afm;
}

View file

@ -1,636 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
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 library 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
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
#include "CDPlayer.h"
#include "AudioFilePlayer.h"
#include "SDLOSXCAGuard.h"
/* we're exporting these functions into C land for SDL_syscdrom.c */
/*extern "C" {*/
/*///////////////////////////////////////////////////////////////////////////
Constants
//////////////////////////////////////////////////////////////////////////*/
#define kAudioCDFilesystemID (UInt16)(('J' << 8) | 'H') /* 'JH'; this avoids compiler warning */
/* XML PList keys */
#define kRawTOCDataString "Format 0x02 TOC Data"
#define kSessionsString "Sessions"
#define kSessionTypeString "Session Type"
#define kTrackArrayString "Track Array"
#define kFirstTrackInSessionString "First Track"
#define kLastTrackInSessionString "Last Track"
#define kLeadoutBlockString "Leadout Block"
#define kDataKeyString "Data"
#define kPointKeyString "Point"
#define kSessionNumberKeyString "Session Number"
#define kStartBlockKeyString "Start Block"
/*///////////////////////////////////////////////////////////////////////////
Globals
//////////////////////////////////////////////////////////////////////////*/
#pragma mark -- Globals --
static int playBackWasInit = 0;
static AudioUnit theUnit;
static AudioFilePlayer* thePlayer = NULL;
static CDPlayerCompletionProc completionProc = NULL;
static SDL_mutex *apiMutex = NULL;
static SDL_sem *callbackSem;
static SDL_CD* theCDROM;
/*///////////////////////////////////////////////////////////////////////////
Prototypes
//////////////////////////////////////////////////////////////////////////*/
#pragma mark -- Prototypes --
static OSStatus CheckInit ();
static void FilePlayNotificationHandler (void* inRefCon, OSStatus inStatus);
static int RunCallBackThread (void* inRefCon);
#pragma mark -- Public Functions --
void Lock ()
{
if (!apiMutex) {
apiMutex = SDL_CreateMutex();
}
SDL_mutexP(apiMutex);
}
void Unlock ()
{
SDL_mutexV(apiMutex);
}
int DetectAudioCDVolumes(FSVolumeRefNum *volumes, int numVolumes)
{
int volumeIndex;
int cdVolumeCount = 0;
OSStatus result = noErr;
for (volumeIndex = 1; result == noErr || result != nsvErr; volumeIndex++)
{
FSVolumeRefNum actualVolume;
FSVolumeInfo volumeInfo;
memset (&volumeInfo, 0, sizeof(volumeInfo));
result = FSGetVolumeInfo (kFSInvalidVolumeRefNum,
volumeIndex,
&actualVolume,
kFSVolInfoFSInfo,
&volumeInfo,
NULL,
NULL);
if (result == noErr)
{
if (volumeInfo.filesystemID == kAudioCDFilesystemID) /* It's an audio CD */
{
if (volumes != NULL && cdVolumeCount < numVolumes)
volumes[cdVolumeCount] = actualVolume;
cdVolumeCount++;
}
}
else
{
/* I'm commenting this out because it seems to be harmless */
/*SDL_SetError ("DetectAudioCDVolumes: FSGetVolumeInfo returned %d", result);*/
}
}
return cdVolumeCount;
}
int ReadTOCData (FSVolumeRefNum theVolume, SDL_CD *theCD)
{
HFSUniStr255 dataForkName;
OSStatus theErr;
FSIORefNum forkRefNum;
SInt64 forkSize;
Ptr forkData = 0;
ByteCount actualRead;
CFDataRef dataRef = 0;
CFPropertyListRef propertyListRef = 0;
FSRefParam fsRefPB;
FSRef tocPlistFSRef;
FSRef rootRef;
const char* error = "Unspecified Error";
const UniChar uniName[] = { '.','T','O','C','.','p','l','i','s','t' };
theErr = FSGetVolumeInfo(theVolume, 0, 0, kFSVolInfoNone, 0, 0, &rootRef);
if(theErr != noErr) {
error = "FSGetVolumeInfo";
goto bail;
}
SDL_memset(&fsRefPB, '\0', sizeof (fsRefPB));
/* get stuff from .TOC.plist */
fsRefPB.ref = &rootRef;
fsRefPB.newRef = &tocPlistFSRef;
fsRefPB.nameLength = sizeof (uniName) / sizeof (uniName[0]);
fsRefPB.name = uniName;
fsRefPB.textEncodingHint = kTextEncodingUnknown;
theErr = PBMakeFSRefUnicodeSync (&fsRefPB);
if(theErr != noErr) {
error = "PBMakeFSRefUnicodeSync";
goto bail;
}
/* Load and parse the TOC XML data */
theErr = FSGetDataForkName (&dataForkName);
if (theErr != noErr) {
error = "FSGetDataForkName";
goto bail;
}
theErr = FSOpenFork (&tocPlistFSRef, dataForkName.length, dataForkName.unicode, fsRdPerm, &forkRefNum);
if (theErr != noErr) {
error = "FSOpenFork";
goto bail;
}
theErr = FSGetForkSize (forkRefNum, &forkSize);
if (theErr != noErr) {
error = "FSGetForkSize";
goto bail;
}
/* Allocate some memory for the XML data */
forkData = NewPtr (forkSize);
if(forkData == NULL) {
error = "NewPtr";
goto bail;
}
theErr = FSReadFork (forkRefNum, fsFromStart, 0 /* offset location */, forkSize, forkData, &actualRead);
if(theErr != noErr) {
error = "FSReadFork";
goto bail;
}
dataRef = CFDataCreate (kCFAllocatorDefault, (UInt8 *)forkData, forkSize);
if(dataRef == 0) {
error = "CFDataCreate";
goto bail;
}
propertyListRef = CFPropertyListCreateFromXMLData (kCFAllocatorDefault,
dataRef,
kCFPropertyListImmutable,
NULL);
if (propertyListRef == NULL) {
error = "CFPropertyListCreateFromXMLData";
goto bail;
}
/* Now we got the Property List in memory. Parse it. */
/* First, make sure the root item is a CFDictionary. If not, release and bail. */
if(CFGetTypeID(propertyListRef)== CFDictionaryGetTypeID())
{
CFDictionaryRef dictRef = (CFDictionaryRef)propertyListRef;
CFDataRef theRawTOCDataRef;
CFArrayRef theSessionArrayRef;
CFIndex numSessions;
CFIndex index;
/* This is how we get the Raw TOC Data */
theRawTOCDataRef = (CFDataRef)CFDictionaryGetValue (dictRef, CFSTR(kRawTOCDataString));
/* Get the session array info. */
theSessionArrayRef = (CFArrayRef)CFDictionaryGetValue (dictRef, CFSTR(kSessionsString));
/* Find out how many sessions there are. */
numSessions = CFArrayGetCount (theSessionArrayRef);
/* Initialize the total number of tracks to 0 */
theCD->numtracks = 0;
/* Iterate over all sessions, collecting the track data */
for(index = 0; index < numSessions; index++)
{
CFDictionaryRef theSessionDict;
CFNumberRef leadoutBlock;
CFArrayRef trackArray;
CFIndex numTracks;
CFIndex trackIndex;
UInt32 value = 0;
theSessionDict = (CFDictionaryRef) CFArrayGetValueAtIndex (theSessionArrayRef, index);
leadoutBlock = (CFNumberRef) CFDictionaryGetValue (theSessionDict, CFSTR(kLeadoutBlockString));
trackArray = (CFArrayRef)CFDictionaryGetValue (theSessionDict, CFSTR(kTrackArrayString));
numTracks = CFArrayGetCount (trackArray);
for(trackIndex = 0; trackIndex < numTracks; trackIndex++) {
CFDictionaryRef theTrackDict;
CFNumberRef trackNumber;
CFNumberRef sessionNumber;
CFNumberRef startBlock;
CFBooleanRef isDataTrack;
UInt32 value;
theTrackDict = (CFDictionaryRef) CFArrayGetValueAtIndex (trackArray, trackIndex);
trackNumber = (CFNumberRef) CFDictionaryGetValue (theTrackDict, CFSTR(kPointKeyString));
sessionNumber = (CFNumberRef) CFDictionaryGetValue (theTrackDict, CFSTR(kSessionNumberKeyString));
startBlock = (CFNumberRef) CFDictionaryGetValue (theTrackDict, CFSTR(kStartBlockKeyString));
isDataTrack = (CFBooleanRef) CFDictionaryGetValue (theTrackDict, CFSTR(kDataKeyString));
/* Fill in the SDL_CD struct */
int idx = theCD->numtracks++;
CFNumberGetValue (trackNumber, kCFNumberSInt32Type, &value);
theCD->track[idx].id = value;
CFNumberGetValue (startBlock, kCFNumberSInt32Type, &value);
theCD->track[idx].offset = value;
theCD->track[idx].type = (isDataTrack == kCFBooleanTrue) ? SDL_DATA_TRACK : SDL_AUDIO_TRACK;
/* Since the track lengths are not stored in .TOC.plist we compute them. */
if (trackIndex > 0) {
theCD->track[idx-1].length = theCD->track[idx].offset - theCD->track[idx-1].offset;
}
}
/* Compute the length of the last track */
CFNumberGetValue (leadoutBlock, kCFNumberSInt32Type, &value);
theCD->track[theCD->numtracks-1].length =
value - theCD->track[theCD->numtracks-1].offset;
/* Set offset to leadout track */
theCD->track[theCD->numtracks].offset = value;
}
}
theErr = 0;
goto cleanup;
bail:
SDL_SetError ("ReadTOCData: %s returned %d", error, theErr);
theErr = -1;
cleanup:
if (propertyListRef != NULL)
CFRelease(propertyListRef);
if (dataRef != NULL)
CFRelease(dataRef);
if (forkData != NULL)
DisposePtr(forkData);
FSCloseFork (forkRefNum);
return theErr;
}
int ListTrackFiles (FSVolumeRefNum theVolume, FSRef *trackFiles, int numTracks)
{
OSStatus result = -1;
FSIterator iterator;
ItemCount actualObjects;
FSRef rootDirectory;
FSRef ref;
HFSUniStr255 nameStr;
result = FSGetVolumeInfo (theVolume,
0,
NULL,
kFSVolInfoFSInfo,
NULL,
NULL,
&rootDirectory);
if (result != noErr) {
SDL_SetError ("ListTrackFiles: FSGetVolumeInfo returned %d", result);
return result;
}
result = FSOpenIterator (&rootDirectory, kFSIterateFlat, &iterator);
if (result == noErr) {
do
{
result = FSGetCatalogInfoBulk (iterator, 1, &actualObjects,
NULL, kFSCatInfoNone, NULL, &ref, NULL, &nameStr);
if (result == noErr) {
CFStringRef name;
name = CFStringCreateWithCharacters (NULL, nameStr.unicode, nameStr.length);
/* Look for .aiff extension */
if (CFStringHasSuffix (name, CFSTR(".aiff")) ||
CFStringHasSuffix (name, CFSTR(".cdda"))) {
/* Extract the track id from the filename */
int trackID = 0, i = 0;
while (i < nameStr.length && !isdigit(nameStr.unicode[i])) {
++i;
}
while (i < nameStr.length && isdigit(nameStr.unicode[i])) {
trackID = 10 * trackID +(nameStr.unicode[i] - '0');
++i;
}
#if DEBUG_CDROM
printf("Found AIFF for track %d: '%s'\n", trackID,
CFStringGetCStringPtr (name, CFStringGetSystemEncoding()));
#endif
/* Track ID's start at 1, but we want to start at 0 */
trackID--;
assert(0 <= trackID && trackID <= SDL_MAX_TRACKS);
if (trackID < numTracks)
memcpy (&trackFiles[trackID], &ref, sizeof(FSRef));
}
CFRelease (name);
}
} while(noErr == result);
FSCloseIterator (iterator);
}
return 0;
}
int LoadFile (const FSRef *ref, int startFrame, int stopFrame)
{
int error = -1;
if (CheckInit () < 0)
goto bail;
/* release any currently playing file */
if (ReleaseFile () < 0)
goto bail;
#if DEBUG_CDROM
printf ("LoadFile: %d %d\n", startFrame, stopFrame);
#endif
/*try {*/
/* create a new player, and attach to the audio unit */
thePlayer = new_AudioFilePlayer(ref);
if (thePlayer == NULL) {
SDL_SetError ("LoadFile: Could not create player");
return -3; /*throw (-3);*/
}
if (!thePlayer->SetDestination(thePlayer, &theUnit))
goto bail;
if (startFrame >= 0)
thePlayer->SetStartFrame (thePlayer, startFrame);
if (stopFrame >= 0 && stopFrame > startFrame)
thePlayer->SetStopFrame (thePlayer, stopFrame);
/* we set the notifier later */
/*thePlayer->SetNotifier(thePlayer, FilePlayNotificationHandler, NULL);*/
if (!thePlayer->Connect(thePlayer))
goto bail;
#if DEBUG_CDROM
thePlayer->Print(thePlayer);
fflush (stdout);
#endif
/*}
catch (...)
{
goto bail;
}*/
error = 0;
bail:
return error;
}
int ReleaseFile ()
{
int error = -1;
/* (Don't see any way that the original C++ code could throw here.) --ryan. */
/*try {*/
if (thePlayer != NULL) {
thePlayer->Disconnect(thePlayer);
delete_AudioFilePlayer(thePlayer);
thePlayer = NULL;
}
/*}
catch (...)
{
goto bail;
}*/
error = 0;
/* bail: */
return error;
}
int PlayFile ()
{
OSStatus result = -1;
if (CheckInit () < 0)
goto bail;
/*try {*/
// start processing of the audio unit
result = AudioOutputUnitStart (theUnit);
if (result) goto bail; //THROW_RESULT("PlayFile: AudioOutputUnitStart")
/*}
catch (...)
{
goto bail;
}*/
result = 0;
bail:
return result;
}
int PauseFile ()
{
OSStatus result = -1;
if (CheckInit () < 0)
goto bail;
/*try {*/
/* stop processing the audio unit */
result = AudioOutputUnitStop (theUnit);
if (result) goto bail; /*THROW_RESULT("PauseFile: AudioOutputUnitStop")*/
/*}
catch (...)
{
goto bail;
}*/
result = 0;
bail:
return result;
}
void SetCompletionProc (CDPlayerCompletionProc proc, SDL_CD *cdrom)
{
assert(thePlayer != NULL);
theCDROM = cdrom;
completionProc = proc;
thePlayer->SetNotifier (thePlayer, FilePlayNotificationHandler, cdrom);
}
int GetCurrentFrame ()
{
int frame;
if (thePlayer == NULL)
frame = 0;
else
frame = thePlayer->GetCurrentFrame (thePlayer);
return frame;
}
#pragma mark -- Private Functions --
static OSStatus CheckInit ()
{
if (playBackWasInit)
return 0;
OSStatus result = noErr;
/* Create the callback semaphore */
callbackSem = SDL_CreateSemaphore(0);
/* Start callback thread */
SDL_CreateThread(RunCallBackThread, NULL);
{ /*try {*/
ComponentDescription desc;
desc.componentType = kAudioUnitType_Output;
desc.componentSubType = kAudioUnitSubType_DefaultOutput;
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
desc.componentFlags = 0;
desc.componentFlagsMask = 0;
Component comp = FindNextComponent (NULL, &desc);
if (comp == NULL) {
SDL_SetError ("CheckInit: FindNextComponent returned NULL");
if (result) return -1; //throw(internalComponentErr);
}
result = OpenAComponent (comp, &theUnit);
if (result) return -1; //THROW_RESULT("CheckInit: OpenAComponent")
// you need to initialize the output unit before you set it as a destination
result = AudioUnitInitialize (theUnit);
if (result) return -1; //THROW_RESULT("CheckInit: AudioUnitInitialize")
playBackWasInit = true;
}
/*catch (...)
{
return -1;
}*/
return 0;
}
static void FilePlayNotificationHandler(void * inRefCon, OSStatus inStatus)
{
if (inStatus == kAudioFilePlay_FileIsFinished) {
/* notify non-CA thread to perform the callback */
SDL_SemPost(callbackSem);
} else if (inStatus == kAudioFilePlayErr_FilePlayUnderrun) {
SDL_SetError ("CDPlayer Notification: buffer underrun");
} else if (inStatus == kAudioFilePlay_PlayerIsUninitialized) {
SDL_SetError ("CDPlayer Notification: player is uninitialized");
} else {
SDL_SetError ("CDPlayer Notification: unknown error %ld", inStatus);
}
}
static int RunCallBackThread (void *param)
{
for (;;) {
SDL_SemWait(callbackSem);
if (completionProc && theCDROM) {
#if DEBUG_CDROM
printf ("callback!\n");
#endif
(*completionProc)(theCDROM);
} else {
#if DEBUG_CDROM
printf ("callback?\n");
#endif
}
}
#if DEBUG_CDROM
printf ("thread dying now...\n");
#endif
return 0;
}
/*}; // extern "C" */

View file

@ -1,69 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
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 library 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
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
#ifndef __CDPlayer__H__
#define __CDPlayer__H__ 1
#include <string.h>
#include <Carbon/Carbon.h>
#include <CoreFoundation/CoreFoundation.h>
#include <AudioUnit/AudioUnit.h>
#include "SDL.h"
#include "SDL_thread.h"
#include "SDL_mutex.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef void (*CDPlayerCompletionProc)(SDL_CD *cdrom) ;
void Lock ();
void Unlock();
int LoadFile (const FSRef *ref, int startFrame, int endFrame); /* pass -1 to do nothing */
int ReleaseFile ();
int PlayFile ();
int PauseFile ();
void SetCompletionProc (CDPlayerCompletionProc proc, SDL_CD *cdrom);
int ReadTOCData (FSVolumeRefNum theVolume, SDL_CD *theCD);
int ListTrackFiles (FSVolumeRefNum theVolume, FSRef *trackFiles, int numTracks);
int DetectAudioCDVolumes (FSVolumeRefNum *volumes, int numVolumes);
int GetCurrentFrame ();
#ifdef __cplusplus
};
#endif
#endif /* __CD_Player__H__ */

View file

@ -1,199 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
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 library 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
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
/*
Note: This file hasn't been modified so technically we have to keep the disclaimer :-(
Copyright: © Copyright 2002 Apple Computer, Inc. All rights reserved.
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
("Apple") in consideration of your agreement to the following terms, and your
use, installation, modification or redistribution of this Apple software
constitutes acceptance of these terms. If you do not agree with these terms,
please do not use, install, modify or redistribute this Apple software.
In consideration of your agreement to abide by the following terms, and subject
to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs
copyrights in this original Apple software (the "Apple Software"), to use,
reproduce, modify and redistribute the Apple Software, with or without
modifications, in source and/or binary forms; provided that if you redistribute
the Apple Software in its entirety and without modifications, you must retain
this notice and the following text and disclaimers in all such redistributions of
the Apple Software. Neither the name, trademarks, service marks or logos of
Apple Computer, Inc. may be used to endorse or promote products derived from the
Apple Software without specific prior written permission from Apple. Except as
expressly stated in this notice, no other rights or licenses, express or implied,
are granted by Apple herein, including but not limited to any patent rights that
may be infringed by your derivative works or by other works in which the Apple
Software may be incorporated.
The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
COMBINATION WITH YOUR PRODUCTS.
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
(INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*=============================================================================
CAGuard.cp
=============================================================================*/
/*=============================================================================
Includes
=============================================================================*/
/*
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
*/
#include "SDL_stdinc.h"
/*#define NDEBUG 1*/
/*
#include <assert.h>
*/
#define assert(X)
#include "SDLOSXCAGuard.h"
/*#warning Need a try-based Locker too*/
/*=============================================================================
SDLOSXCAGuard
=============================================================================*/
static int SDLOSXCAGuard_Lock(SDLOSXCAGuard *cag)
{
int theAnswer = 0;
if(pthread_self() != cag->mOwner)
{
OSStatus theError = pthread_mutex_lock(&cag->mMutex);
(void)theError;
assert(theError == 0);
cag->mOwner = pthread_self();
theAnswer = 1;
}
return theAnswer;
}
static void SDLOSXCAGuard_Unlock(SDLOSXCAGuard *cag)
{
OSStatus theError;
assert(pthread_self() == cag->mOwner);
cag->mOwner = 0;
theError = pthread_mutex_unlock(&cag->mMutex);
(void)theError;
assert(theError == 0);
}
static int SDLOSXCAGuard_Try (SDLOSXCAGuard *cag, int *outWasLocked)
{
int theAnswer = 0;
*outWasLocked = 0;
if (pthread_self() == cag->mOwner) {
theAnswer = 1;
*outWasLocked = 0;
} else {
OSStatus theError = pthread_mutex_trylock(&cag->mMutex);
if (theError == 0) {
cag->mOwner = pthread_self();
theAnswer = 1;
*outWasLocked = 1;
}
}
return theAnswer;
}
static void SDLOSXCAGuard_Wait(SDLOSXCAGuard *cag)
{
OSStatus theError;
assert(pthread_self() == cag->mOwner);
cag->mOwner = 0;
theError = pthread_cond_wait(&cag->mCondVar, &cag->mMutex);
(void)theError;
assert(theError == 0);
cag->mOwner = pthread_self();
}
static void SDLOSXCAGuard_Notify(SDLOSXCAGuard *cag)
{
OSStatus theError = pthread_cond_signal(&cag->mCondVar);
(void)theError;
assert(theError == 0);
}
SDLOSXCAGuard *new_SDLOSXCAGuard(void)
{
OSStatus theError;
SDLOSXCAGuard *cag = (SDLOSXCAGuard *) SDL_malloc(sizeof (SDLOSXCAGuard));
if (cag == NULL)
return NULL;
SDL_memset(cag, '\0', sizeof (*cag));
#define SET_SDLOSXCAGUARD_METHOD(m) cag->m = SDLOSXCAGuard_##m
SET_SDLOSXCAGUARD_METHOD(Lock);
SET_SDLOSXCAGUARD_METHOD(Unlock);
SET_SDLOSXCAGUARD_METHOD(Try);
SET_SDLOSXCAGUARD_METHOD(Wait);
SET_SDLOSXCAGUARD_METHOD(Notify);
#undef SET_SDLOSXCAGUARD_METHOD
theError = pthread_mutex_init(&cag->mMutex, NULL);
(void)theError;
assert(theError == 0);
theError = pthread_cond_init(&cag->mCondVar, NULL);
(void)theError;
assert(theError == 0);
cag->mOwner = 0;
return cag;
}
void delete_SDLOSXCAGuard(SDLOSXCAGuard *cag)
{
if (cag != NULL)
{
pthread_mutex_destroy(&cag->mMutex);
pthread_cond_destroy(&cag->mCondVar);
SDL_free(cag);
}
}

View file

@ -1,116 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
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 library 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
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
/*
Note: This file hasn't been modified so technically we have to keep the disclaimer :-(
Copyright: © Copyright 2002 Apple Computer, Inc. All rights reserved.
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
("Apple") in consideration of your agreement to the following terms, and your
use, installation, modification or redistribution of this Apple software
constitutes acceptance of these terms. If you do not agree with these terms,
please do not use, install, modify or redistribute this Apple software.
In consideration of your agreement to abide by the following terms, and subject
to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs
copyrights in this original Apple software (the "Apple Software"), to use,
reproduce, modify and redistribute the Apple Software, with or without
modifications, in source and/or binary forms; provided that if you redistribute
the Apple Software in its entirety and without modifications, you must retain
this notice and the following text and disclaimers in all such redistributions of
the Apple Software. Neither the name, trademarks, service marks or logos of
Apple Computer, Inc. may be used to endorse or promote products derived from the
Apple Software without specific prior written permission from Apple. Except as
expressly stated in this notice, no other rights or licenses, express or implied,
are granted by Apple herein, including but not limited to any patent rights that
may be infringed by your derivative works or by other works in which the Apple
Software may be incorporated.
The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
COMBINATION WITH YOUR PRODUCTS.
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
(INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*=============================================================================
CAGuard.h
=============================================================================*/
#if !defined(__CAGuard_h__)
#define __CAGuard_h__
/*=============================================================================
Includes
=============================================================================*/
#include <CoreAudio/CoreAudioTypes.h>
#include <pthread.h>
/*=============================================================================
CAGuard
This is your typical mutex with signalling implemented via pthreads.
Lock() will return true if and only if the guard is locked on that call.
A thread that already has the guard will receive 'false' if it locks it
again. Use of the stack-based CAGuard::Locker class is highly recommended
to properly manage the recursive nesting. The Wait calls with timeouts
will return true if and only if the timeout period expired. They will
return false if they receive notification any other way.
=============================================================================*/
typedef struct S_SDLOSXCAGuard
{
/* Construction/Destruction */
/*public:*/
/* Actions */
/*public:*/
int (*Lock)(struct S_SDLOSXCAGuard *cag);
void (*Unlock)(struct S_SDLOSXCAGuard *cag);
int (*Try)(struct S_SDLOSXCAGuard *cag, int *outWasLocked); /* returns true if lock is free, false if not */
void (*Wait)(struct S_SDLOSXCAGuard *cag);
void (*Notify)(struct S_SDLOSXCAGuard *cag);
/* Implementation */
/*protected:*/
pthread_mutex_t mMutex;
pthread_cond_t mCondVar;
pthread_t mOwner;
} SDLOSXCAGuard;
SDLOSXCAGuard *new_SDLOSXCAGuard(void);
void delete_SDLOSXCAGuard(SDLOSXCAGuard *cag);
#endif

View file

@ -1,514 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
#ifdef SDL_CDROM_MACOSX
#include "SDL_syscdrom_c.h"
#pragma mark -- Globals --
static FSRef** tracks;
static FSVolumeRefNum* volumes;
static CDstatus status;
static int nextTrackFrame;
static int nextTrackFramesRemaining;
static int fakeCD;
static int currentTrack;
static int didReadTOC;
static int cacheTOCNumTracks;
static int currentDrive; /* Only allow 1 drive in use at a time */
#pragma mark -- Prototypes --
static const char *SDL_SYS_CDName (int drive);
static int SDL_SYS_CDOpen (int drive);
static int SDL_SYS_CDGetTOC (SDL_CD *cdrom);
static CDstatus SDL_SYS_CDStatus (SDL_CD *cdrom, int *position);
static int SDL_SYS_CDPlay (SDL_CD *cdrom, int start, int length);
static int SDL_SYS_CDPause (SDL_CD *cdrom);
static int SDL_SYS_CDResume (SDL_CD *cdrom);
static int SDL_SYS_CDStop (SDL_CD *cdrom);
static int SDL_SYS_CDEject (SDL_CD *cdrom);
static void SDL_SYS_CDClose (SDL_CD *cdrom);
#pragma mark -- Helper Functions --
/* Read a list of tracks from the volume */
static int LoadTracks (SDL_CD *cdrom)
{
/* Check if tracks are already loaded */
if ( tracks[cdrom->id] != NULL )
return 0;
/* Allocate memory for tracks */
tracks[cdrom->id] = (FSRef*) SDL_calloc (1, sizeof(**tracks) * cdrom->numtracks);
if (tracks[cdrom->id] == NULL) {
SDL_OutOfMemory ();
return -1;
}
/* Load tracks */
if (ListTrackFiles (volumes[cdrom->id], tracks[cdrom->id], cdrom->numtracks) < 0)
return -1;
return 0;
}
/* Find a file for a given start frame and length */
static FSRef* GetFileForOffset (SDL_CD *cdrom, int start, int length, int *outStartFrame, int *outStopFrame)
{
int i;
for (i = 0; i < cdrom->numtracks; i++) {
if (cdrom->track[i].offset <= start &&
start < (cdrom->track[i].offset + cdrom->track[i].length))
break;
}
if (i == cdrom->numtracks)
return NULL;
currentTrack = i;
*outStartFrame = start - cdrom->track[i].offset;
if ((*outStartFrame + length) < cdrom->track[i].length) {
*outStopFrame = *outStartFrame + length;
length = 0;
nextTrackFrame = -1;
nextTrackFramesRemaining = -1;
}
else {
*outStopFrame = -1;
length -= cdrom->track[i].length - *outStartFrame;
nextTrackFrame = cdrom->track[i+1].offset;
nextTrackFramesRemaining = length;
}
return &tracks[cdrom->id][i];
}
/* Setup another file for playback, or stop playback (called from another thread) */
static void CompletionProc (SDL_CD *cdrom)
{
Lock ();
if (nextTrackFrame > 0 && nextTrackFramesRemaining > 0) {
/* Load the next file to play */
int startFrame, stopFrame;
FSRef *file;
PauseFile ();
ReleaseFile ();
file = GetFileForOffset (cdrom, nextTrackFrame,
nextTrackFramesRemaining, &startFrame, &stopFrame);
if (file == NULL) {
status = CD_STOPPED;
Unlock ();
return;
}
LoadFile (file, startFrame, stopFrame);
SetCompletionProc (CompletionProc, cdrom);
PlayFile ();
}
else {
/* Release the current file */
PauseFile ();
ReleaseFile ();
status = CD_STOPPED;
}
Unlock ();
}
#pragma mark -- Driver Functions --
/* Initialize */
int SDL_SYS_CDInit (void)
{
/* Initialize globals */
volumes = NULL;
tracks = NULL;
status = CD_STOPPED;
nextTrackFrame = -1;
nextTrackFramesRemaining = -1;
fakeCD = SDL_FALSE;
currentTrack = -1;
didReadTOC = SDL_FALSE;
cacheTOCNumTracks = -1;
currentDrive = -1;
/* Fill in function pointers */
SDL_CDcaps.Name = SDL_SYS_CDName;
SDL_CDcaps.Open = SDL_SYS_CDOpen;
SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC;
SDL_CDcaps.Status = SDL_SYS_CDStatus;
SDL_CDcaps.Play = SDL_SYS_CDPlay;
SDL_CDcaps.Pause = SDL_SYS_CDPause;
SDL_CDcaps.Resume = SDL_SYS_CDResume;
SDL_CDcaps.Stop = SDL_SYS_CDStop;
SDL_CDcaps.Eject = SDL_SYS_CDEject;
SDL_CDcaps.Close = SDL_SYS_CDClose;
/*
Read the list of "drives"
This is currently a hack that infers drives from
mounted audio CD volumes, rather than
actual CD-ROM devices - which means it may not
act as expected sometimes.
*/
/* Find out how many cd volumes are mounted */
SDL_numcds = DetectAudioCDVolumes (NULL, 0);
/*
If there are no volumes, fake a cd device
so tray empty can be reported.
*/
if (SDL_numcds == 0) {
fakeCD = SDL_TRUE;
SDL_numcds = 1;
status = CD_TRAYEMPTY;
return 0;
}
/* Allocate space for volumes */
volumes = (FSVolumeRefNum*) SDL_calloc (1, sizeof(*volumes) * SDL_numcds);
if (volumes == NULL) {
SDL_OutOfMemory ();
return -1;
}
/* Allocate space for tracks */
tracks = (FSRef**) SDL_calloc (1, sizeof(*tracks) * (SDL_numcds + 1));
if (tracks == NULL) {
SDL_OutOfMemory ();
return -1;
}
/* Mark the end of the tracks array */
tracks[ SDL_numcds ] = (FSRef*)-1;
/*
Redetect, now save all volumes for later
Update SDL_numcds just in case it changed
*/
{
int numVolumes = SDL_numcds;
SDL_numcds = DetectAudioCDVolumes (volumes, numVolumes);
/* If more cds suddenly show up, ignore them */
if (SDL_numcds > numVolumes) {
SDL_SetError ("Some CD's were added but they will be ignored");
SDL_numcds = numVolumes;
}
}
return 0;
}
/* Shutdown and cleanup */
void SDL_SYS_CDQuit(void)
{
ReleaseFile();
if (volumes != NULL)
free (volumes);
if (tracks != NULL) {
FSRef **ptr;
for (ptr = tracks; *ptr != (FSRef*)-1; ptr++)
if (*ptr != NULL)
free (*ptr);
free (tracks);
}
}
/* Get the Unix disk name of the volume */
static const char *SDL_SYS_CDName (int drive)
{
/*
* !!! FIXME: PBHGetVolParmsSync() is gone in 10.6,
* !!! FIXME: replaced with FSGetVolumeParms(), which
* !!! FIXME: isn't available before 10.5. :/
*/
return "Mac OS X CD-ROM Device";
#if 0
OSStatus err = noErr;
HParamBlockRec pb;
GetVolParmsInfoBuffer volParmsInfo;
if (fakeCD)
return "Fake CD-ROM Device";
pb.ioParam.ioNamePtr = NULL;
pb.ioParam.ioVRefNum = volumes[drive];
pb.ioParam.ioBuffer = (Ptr)&volParmsInfo;
pb.ioParam.ioReqCount = (SInt32)sizeof(volParmsInfo);
err = PBHGetVolParmsSync(&pb);
if (err != noErr) {
SDL_SetError ("PBHGetVolParmsSync returned %d", err);
return NULL;
}
return volParmsInfo.vMDeviceID;
#endif
}
/* Open the "device" */
static int SDL_SYS_CDOpen (int drive)
{
/* Only allow 1 device to be open */
if (currentDrive >= 0) {
SDL_SetError ("Only one cdrom is supported");
return -1;
}
else
currentDrive = drive;
return drive;
}
/* Get the table of contents */
static int SDL_SYS_CDGetTOC (SDL_CD *cdrom)
{
if (fakeCD) {
SDL_SetError (kErrorFakeDevice);
return -1;
}
if (didReadTOC) {
cdrom->numtracks = cacheTOCNumTracks;
return 0;
}
ReadTOCData (volumes[cdrom->id], cdrom);
didReadTOC = SDL_TRUE;
cacheTOCNumTracks = cdrom->numtracks;
return 0;
}
/* Get CD-ROM status */
static CDstatus SDL_SYS_CDStatus (SDL_CD *cdrom, int *position)
{
if (position) {
int trackFrame;
Lock ();
trackFrame = GetCurrentFrame ();
Unlock ();
*position = cdrom->track[currentTrack].offset + trackFrame;
}
return status;
}
/* Start playback */
static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length)
{
int startFrame, stopFrame;
FSRef *ref;
if (fakeCD) {
SDL_SetError (kErrorFakeDevice);
return -1;
}
Lock();
if (LoadTracks (cdrom) < 0)
return -2;
if (PauseFile () < 0)
return -3;
if (ReleaseFile () < 0)
return -4;
ref = GetFileForOffset (cdrom, start, length, &startFrame, &stopFrame);
if (ref == NULL) {
SDL_SetError ("SDL_SYS_CDPlay: No file for start=%d, length=%d", start, length);
return -5;
}
if (LoadFile (ref, startFrame, stopFrame) < 0)
return -6;
SetCompletionProc (CompletionProc, cdrom);
if (PlayFile () < 0)
return -7;
status = CD_PLAYING;
Unlock();
return 0;
}
/* Pause playback */
static int SDL_SYS_CDPause(SDL_CD *cdrom)
{
if (fakeCD) {
SDL_SetError (kErrorFakeDevice);
return -1;
}
Lock ();
if (PauseFile () < 0) {
Unlock ();
return -2;
}
status = CD_PAUSED;
Unlock ();
return 0;
}
/* Resume playback */
static int SDL_SYS_CDResume(SDL_CD *cdrom)
{
if (fakeCD) {
SDL_SetError (kErrorFakeDevice);
return -1;
}
Lock ();
if (PlayFile () < 0) {
Unlock ();
return -2;
}
status = CD_PLAYING;
Unlock ();
return 0;
}
/* Stop playback */
static int SDL_SYS_CDStop(SDL_CD *cdrom)
{
if (fakeCD) {
SDL_SetError (kErrorFakeDevice);
return -1;
}
Lock ();
if (PauseFile () < 0) {
Unlock ();
return -2;
}
if (ReleaseFile () < 0) {
Unlock ();
return -3;
}
status = CD_STOPPED;
Unlock ();
return 0;
}
/* Eject the CD-ROM (Unmount the volume) */
static int SDL_SYS_CDEject(SDL_CD *cdrom)
{
OSStatus err;
pid_t dissenter;
if (fakeCD) {
SDL_SetError (kErrorFakeDevice);
return -1;
}
Lock ();
if (PauseFile () < 0) {
Unlock ();
return -2;
}
if (ReleaseFile () < 0) {
Unlock ();
return -3;
}
status = CD_STOPPED;
/* Eject the volume */
err = FSEjectVolumeSync(volumes[cdrom->id], kNilOptions, &dissenter);
if (err != noErr) {
Unlock ();
SDL_SetError ("PBUnmountVol returned %d", err);
return -4;
}
status = CD_TRAYEMPTY;
/* Invalidate volume and track info */
volumes[cdrom->id] = 0;
free (tracks[cdrom->id]);
tracks[cdrom->id] = NULL;
Unlock ();
return 0;
}
/* Close the CD-ROM */
static void SDL_SYS_CDClose(SDL_CD *cdrom)
{
currentDrive = -1;
return;
}
#endif /* SDL_CDROM_MACOSX */

View file

@ -1,136 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
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 library 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
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
/* This is the Mac OS X / CoreAudio specific header for the SDL CD-ROM API
Contributed by Darrell Walisser and Max Horn
*/
/***********************************************************************************
Implementation Notes
*********************
This code has several limitations currently (all of which are proabaly fixable):
1. A CD-ROM device is inferred from a mounted cdfs volume, so device 0 is
not necessarily the first CD-ROM device on the system. (Somewhat easy to fix
by useing the device name from the volume id's to reorder the volumes)
2. You can only open and control 1 CD-ROM device at a time. (Challenging to fix,
due to extensive code restructuring)
3. The status reported by SDL_CDStatus only changes to from CD_PLAYING to CD_STOPPED in
1-second intervals (because the audio is buffered in 1-second chunks) If
the audio data is less than 1 second, the remainder is filled with silence.
If you need to play sequences back-to-back that are less that 1 second long,
use the frame position to determine when to play the next sequence, instead
of SDL_CDStatus.
This may be possible to fix with a clever usage of the AudioUnit API.
4. When new volumes are inserted, our volume information is not updated. The only way
to refresh this information is to reinit the CD-ROM subsystem of SDL. To fix this,
one would probably have to fix point 1 above first, then figure out how to register
for a notification when new media is mounted in order to perform an automatic
rescan for cdfs volumes.
So, here comes a description of how this all works.
< Initializing >
To get things rolling, we have to locate mounted volumes that contain
audio (since nearly all Macs don't have analog audio-in on the sound card).
That's easy, since these volumes have a flag that indicates this special
filesystem. See DetectAudioCDVolumes() in CDPlayer.cpp for this code.
Next, we parse the invisible .TOC.plist in the root of the volume, which gets us
the track information (number, offset, length, leadout, etc). See ReadTOCData() in
CDPlayer.cpp for the skinny on this.
< The Playback Loop >
Now come the tricky parts. Let's start with basic audio playback. When a frame
range to play is requested, we must first find the .aiff files on the volume,
hopefully in the right order. Since these files all begin with a number "1 Audio Track",
etc, this is used to determine the correct track order.
Once all files are determined, we have to find what file corresponds to the start
and length parameter to SDL_SYS_CDPlay(). Again, this is quite simple by walking the
cdrom's track list. At this point, we also save the offset to the next track and frames
remaining, if we're going to have to play another file after the first one. See
GetFileForOffset() for this code.
At this point we have all info needed to start playback, so we hand off to the LoadFile()
function, which proceeds to do its magic and plays back the file.
When the file is finished playing, CompletionProc() is invoked, at which time we can
play the next file if the previously saved next track and frames remaining
indicates that we should.
< Magic >
OK, so it's not really magic, but since I don't fully understand all the hidden details it
seems like it to me ;-) The API's involved are the AudioUnit and AudioFile API's. These
appear to be an extension of CoreAudio for creating modular playback and f/x entities.
The important thing is that CPU usage is very low and reliability is very high. You'd
be hard-pressed to find a way to stutter the playback with other CPU-intensive tasks.
One part of this magic is that it uses multiple threads, which carries the usual potential
for disaster if not handled carefully. Playback currently requires 4 additional threads:
1. The coreaudio runloop thread
2. The coreaudio device i/o thread
3. The file streaming thread
4. The notification/callback thread
The first 2 threads are necessary evil - CoreAudio creates this no matter what the situation
is (even the SDL sound implementation creates theses suckers). The last two are are created
by us.
The file is streamed from disk using a threaded double-buffer approach.
This way, the high latency operation of reading from disk can be performed without interrupting
the real-time device thread (which amounts to avoiding dropouts). The device thread grabs the
buffer that isn't being read and sends it to the CoreAudio mixer where it eventually gets
to the sound card.
The device thread posts a notification when the file streaming thread is out of data. This
notification must be handled in a separate thread to avoid potential deadlock in the
device thread. That's where the notification thread comes in. This thread is signaled
whenever a notification needs to be processed, so another file can be played back if need be.
The API in CDPlayer.cpp contains synchronization because otherwise both the notification thread
and main thread (or another other thread using the SDL CD api) can potentially call it at the same time.
************************************************************************************/
#include "SDL_cdrom.h"
#include "../SDL_syscdrom.h"
#include "CDPlayer.h"
#define kErrorFakeDevice "Error: Cannot proceed since we're faking a CD-ROM device. Reinit the CD-ROM subsystem to scan for new volumes."

View file

@ -1,317 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
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 library 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
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
#ifdef SDL_CDROM_MINT
/*
Atari MetaDOS CD-ROM functions
Patrice Mandin
*/
#include <errno.h>
#include <mint/cdromio.h>
#include <mint/metados.h>
#include "SDL_cdrom.h"
#include "../SDL_syscdrom.h"
/* Some ioctl() errno values which occur when the tray is empty */
#ifndef ENOMEDIUM
#define ENOMEDIUM ENOENT
#endif
#define ERRNO_TRAYEMPTY(errno) \
((errno == EIO) || (errno == ENOENT) || \
(errno == EINVAL) || (errno == ENOMEDIUM))
/* The maximum number of CD-ROM drives we'll detect */
#define MAX_DRIVES 32
typedef struct {
char device[3]; /* Physical device letter + ':' + '\0' */
metaopen_t metaopen; /* Infos on opened drive */
} metados_drive_t;
static metados_drive_t metados_drives[MAX_DRIVES];
/* The system-dependent CD control functions */
static const char *SDL_SYS_CDName(int drive);
static int SDL_SYS_CDOpen(int drive);
static void SDL_SYS_CDClose(SDL_CD *cdrom);
static int SDL_SYS_CDioctl(int id, int command, void *arg);
static int SDL_SYS_CDGetTOC(SDL_CD *cdrom);
static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position);
static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length);
static int SDL_SYS_CDPause(SDL_CD *cdrom);
static int SDL_SYS_CDResume(SDL_CD *cdrom);
static int SDL_SYS_CDStop(SDL_CD *cdrom);
static int SDL_SYS_CDEject(SDL_CD *cdrom);
int SDL_SYS_CDInit(void)
{
metainit_t metainit={0,0,0,0};
metaopen_t metaopen;
int i, handle;
struct cdrom_subchnl info;
Metainit(&metainit);
if (metainit.version == NULL) {
#ifdef DEBUG_CDROM
fprintf(stderr, "MetaDOS not installed\n");
#endif
return -1;
}
if (metainit.drives_map == 0) {
#ifdef DEBUG_CDROM
fprintf(stderr, "No MetaDOS devices present\n");
#endif
return -1;
}
SDL_numcds = 0;
for (i='A'; i<='Z'; i++) {
metados_drives[SDL_numcds].device[0] = 0;
metados_drives[SDL_numcds].device[1] = ':';
metados_drives[SDL_numcds].device[2] = 0;
if (metainit.drives_map & (1<<(i-'A'))) {
handle = Metaopen(i, &metaopen);
if (handle == 0) {
info.cdsc_format = CDROM_MSF;
if ( (Metaioctl(i, METADOS_IOCTL_MAGIC, CDROMSUBCHNL, &info) == 0) || ERRNO_TRAYEMPTY(errno) ) {
metados_drives[SDL_numcds].device[0] = i;
++SDL_numcds;
}
Metaclose(i);
}
}
}
/* Fill in our driver capabilities */
SDL_CDcaps.Name = SDL_SYS_CDName;
SDL_CDcaps.Open = SDL_SYS_CDOpen;
SDL_CDcaps.Close = SDL_SYS_CDClose;
SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC;
SDL_CDcaps.Status = SDL_SYS_CDStatus;
SDL_CDcaps.Play = SDL_SYS_CDPlay;
SDL_CDcaps.Pause = SDL_SYS_CDPause;
SDL_CDcaps.Resume = SDL_SYS_CDResume;
SDL_CDcaps.Stop = SDL_SYS_CDStop;
SDL_CDcaps.Eject = SDL_SYS_CDEject;
return 0;
}
void SDL_SYS_CDQuit(void)
{
SDL_numcds = 0;
}
static const char *SDL_SYS_CDName(int drive)
{
return(metados_drives[drive].device);
}
static int SDL_SYS_CDOpen(int drive)
{
int handle;
handle = Metaopen(metados_drives[drive].device[0], &(metados_drives[drive].metaopen));
if (handle == 0) {
return drive;
}
return -1;
}
static void SDL_SYS_CDClose(SDL_CD *cdrom)
{
Metaclose(metados_drives[cdrom->id].device[0]);
}
static int SDL_SYS_CDioctl(int id, int command, void *arg)
{
int retval;
retval = Metaioctl(metados_drives[id].device[0], METADOS_IOCTL_MAGIC, command, arg);
if ( retval < 0 ) {
SDL_SetError("ioctl() error: %s", strerror(errno));
}
return(retval);
}
static int SDL_SYS_CDGetTOC(SDL_CD *cdrom)
{
int i,okay;
struct cdrom_tochdr toc;
struct cdrom_tocentry entry;
/* Use standard ioctl() */
if (SDL_SYS_CDioctl(cdrom->id, CDROMREADTOCHDR, &toc)<0) {
return -1;
}
cdrom->numtracks = toc.cdth_trk1-toc.cdth_trk0+1;
if ( cdrom->numtracks > SDL_MAX_TRACKS ) {
cdrom->numtracks = SDL_MAX_TRACKS;
}
/* Read all the track TOC entries */
okay=1;
for ( i=0; i<=cdrom->numtracks; ++i ) {
if ( i == cdrom->numtracks ) {
cdrom->track[i].id = CDROM_LEADOUT;
} else {
cdrom->track[i].id = toc.cdth_trk0+i;
}
entry.cdte_track = cdrom->track[i].id;
entry.cdte_format = CDROM_MSF;
if ( SDL_SYS_CDioctl(cdrom->id, CDROMREADTOCENTRY, &entry) < 0 ) {
okay=0;
break;
} else {
if ( entry.cdte_ctrl & CDROM_DATA_TRACK ) {
cdrom->track[i].type = SDL_DATA_TRACK;
} else {
cdrom->track[i].type = SDL_AUDIO_TRACK;
}
cdrom->track[i].offset = MSF_TO_FRAMES(
entry.cdte_addr.msf.minute,
entry.cdte_addr.msf.second,
entry.cdte_addr.msf.frame);
cdrom->track[i].length = 0;
if ( i > 0 ) {
cdrom->track[i-1].length = cdrom->track[i].offset-cdrom->track[i-1].offset;
}
}
}
return(okay ? 0 : -1);
}
/* Get CD-ROM status */
static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position)
{
CDstatus status;
struct cdrom_tochdr toc;
struct cdrom_subchnl info;
info.cdsc_format = CDROM_MSF;
if ( SDL_SYS_CDioctl(cdrom->id, CDROMSUBCHNL, &info) < 0 ) {
if ( ERRNO_TRAYEMPTY(errno) ) {
status = CD_TRAYEMPTY;
} else {
status = CD_ERROR;
}
} else {
switch (info.cdsc_audiostatus) {
case CDROM_AUDIO_INVALID:
case CDROM_AUDIO_NO_STATUS:
/* Try to determine if there's a CD available */
if (SDL_SYS_CDioctl(cdrom->id, CDROMREADTOCHDR, &toc)==0) {
status = CD_STOPPED;
} else {
status = CD_TRAYEMPTY;
}
break;
case CDROM_AUDIO_COMPLETED:
status = CD_STOPPED;
break;
case CDROM_AUDIO_PLAY:
status = CD_PLAYING;
break;
case CDROM_AUDIO_PAUSED:
/* Workaround buggy CD-ROM drive */
if ( info.cdsc_trk == CDROM_LEADOUT ) {
status = CD_STOPPED;
} else {
status = CD_PAUSED;
}
break;
default:
status = CD_ERROR;
break;
}
}
if ( position ) {
if ( status == CD_PLAYING || (status == CD_PAUSED) ) {
*position = MSF_TO_FRAMES(
info.cdsc_absaddr.msf.minute,
info.cdsc_absaddr.msf.second,
info.cdsc_absaddr.msf.frame);
} else {
*position = 0;
}
}
return(status);
}
/* Start play */
static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length)
{
struct cdrom_msf playtime;
FRAMES_TO_MSF(start,
&playtime.cdmsf_min0, &playtime.cdmsf_sec0, &playtime.cdmsf_frame0);
FRAMES_TO_MSF(start+length,
&playtime.cdmsf_min1, &playtime.cdmsf_sec1, &playtime.cdmsf_frame1);
#ifdef DEBUG_CDROM
fprintf(stderr, "Trying to play from %d:%d:%d to %d:%d:%d\n",
playtime.cdmsf_min0, playtime.cdmsf_sec0, playtime.cdmsf_frame0,
playtime.cdmsf_min1, playtime.cdmsf_sec1, playtime.cdmsf_frame1);
#endif
return SDL_SYS_CDioctl(cdrom->id, CDROMPLAYMSF, &playtime);
}
/* Pause play */
static int SDL_SYS_CDPause(SDL_CD *cdrom)
{
return SDL_SYS_CDioctl(cdrom->id, CDROMPAUSE, 0);
}
/* Resume play */
static int SDL_SYS_CDResume(SDL_CD *cdrom)
{
return SDL_SYS_CDioctl(cdrom->id, CDROMRESUME, 0);
}
/* Stop play */
static int SDL_SYS_CDStop(SDL_CD *cdrom)
{
return SDL_SYS_CDioctl(cdrom->id, CDROMSTOP, 0);
}
/* Eject the CD-ROM */
static int SDL_SYS_CDEject(SDL_CD *cdrom)
{
return SDL_SYS_CDioctl(cdrom->id, CDROMEJECT, 0);
}
#endif /* SDL_CDROM_MINT */

View file

@ -1,416 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
#ifdef SDL_CDROM_OPENBSD
/* Functions for system-level CD-ROM audio control */
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/cdio.h>
#include "SDL_cdrom.h"
#include "../SDL_syscdrom.h"
/* The maximum number of CD-ROM drives we'll detect */
#define MAX_DRIVES 16
/* A list of available CD-ROM drives */
static char *SDL_cdlist[MAX_DRIVES];
static dev_t SDL_cdmode[MAX_DRIVES];
/* The system-dependent CD control functions */
static const char *SDL_SYS_CDName(int drive);
static int SDL_SYS_CDOpen(int drive);
static int SDL_SYS_CDGetTOC(SDL_CD *cdrom);
static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position);
static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length);
static int SDL_SYS_CDPause(SDL_CD *cdrom);
static int SDL_SYS_CDResume(SDL_CD *cdrom);
static int SDL_SYS_CDStop(SDL_CD *cdrom);
static int SDL_SYS_CDEject(SDL_CD *cdrom);
static void SDL_SYS_CDClose(SDL_CD *cdrom);
/* Some ioctl() errno values which occur when the tray is empty */
#define ERRNO_TRAYEMPTY(errno) \
((errno == EIO) || (errno == ENOENT) || (errno == EINVAL) || \
(errno == ENODEV))
/* Check a drive to see if it is a CD-ROM */
static int CheckDrive(char *drive, struct stat *stbuf)
{
int is_cd, cdfd;
struct ioc_read_subchannel info;
/* If it doesn't exist, return -1 */
if ( stat(drive, stbuf) < 0 ) {
return(-1);
}
/* If it does exist, verify that it's an available CD-ROM */
is_cd = 0;
if ( S_ISCHR(stbuf->st_mode) || S_ISBLK(stbuf->st_mode) ) {
cdfd = open(drive, (O_RDONLY|O_EXCL|O_NONBLOCK), 0);
if ( cdfd >= 0 ) {
info.address_format = CD_MSF_FORMAT;
info.data_format = CD_CURRENT_POSITION;
info.data_len = 0;
info.data = NULL;
/* Under Linux, EIO occurs when a disk is not present.
This isn't 100% reliable, so we use the USE_MNTENT
code above instead.
*/
if ( (ioctl(cdfd, CDIOCREADSUBCHANNEL, &info) == 0) ||
ERRNO_TRAYEMPTY(errno) ) {
is_cd = 1;
}
close(cdfd);
}
else if (ERRNO_TRAYEMPTY(errno))
is_cd = 1;
}
return(is_cd);
}
/* Add a CD-ROM drive to our list of valid drives */
static void AddDrive(char *drive, struct stat *stbuf)
{
int i;
if ( SDL_numcds < MAX_DRIVES ) {
/* Check to make sure it's not already in our list.
This can happen when we see a drive via symbolic link.
*/
for ( i=0; i<SDL_numcds; ++i ) {
if ( stbuf->st_rdev == SDL_cdmode[i] ) {
#ifdef DEBUG_CDROM
fprintf(stderr, "Duplicate drive detected: %s == %s\n", drive, SDL_cdlist[i]);
#endif
return;
}
}
/* Add this drive to our list */
i = SDL_numcds;
SDL_cdlist[i] = SDL_strdup(drive);
if ( SDL_cdlist[i] == NULL ) {
SDL_OutOfMemory();
return;
}
SDL_cdmode[i] = stbuf->st_rdev;
++SDL_numcds;
#ifdef DEBUG_CDROM
fprintf(stderr, "Added CD-ROM drive: %s\n", drive);
#endif
}
}
int SDL_SYS_CDInit(void)
{
static char *checklist[] = {
#if defined(__OPENBSD__)
"?0 cd?c", "cdrom", NULL
#elif defined(__NETBSD__)
"?0 cd?d", "?0 cd?c", "cdrom", NULL
#else
"?0 cd?c", "?0 acd?c", "cdrom", NULL
#endif
};
char *SDLcdrom;
int i, j, exists;
char drive[32];
struct stat stbuf;
/* Fill in our driver capabilities */
SDL_CDcaps.Name = SDL_SYS_CDName;
SDL_CDcaps.Open = SDL_SYS_CDOpen;
SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC;
SDL_CDcaps.Status = SDL_SYS_CDStatus;
SDL_CDcaps.Play = SDL_SYS_CDPlay;
SDL_CDcaps.Pause = SDL_SYS_CDPause;
SDL_CDcaps.Resume = SDL_SYS_CDResume;
SDL_CDcaps.Stop = SDL_SYS_CDStop;
SDL_CDcaps.Eject = SDL_SYS_CDEject;
SDL_CDcaps.Close = SDL_SYS_CDClose;
/* Look in the environment for our CD-ROM drive list */
SDLcdrom = SDL_getenv("SDL_CDROM"); /* ':' separated list of devices */
if ( SDLcdrom != NULL ) {
char *cdpath, *delim;
size_t len = SDL_strlen(SDLcdrom)+1;
cdpath = SDL_stack_alloc(char, len);
if ( cdpath != NULL ) {
SDL_strlcpy(cdpath, SDLcdrom, len);
SDLcdrom = cdpath;
do {
delim = SDL_strchr(SDLcdrom, ':');
if ( delim ) {
*delim++ = '\0';
}
if ( CheckDrive(SDLcdrom, &stbuf) > 0 ) {
AddDrive(SDLcdrom, &stbuf);
}
if ( delim ) {
SDLcdrom = delim;
} else {
SDLcdrom = NULL;
}
} while ( SDLcdrom );
SDL_stack_free(cdpath);
}
/* If we found our drives, there's nothing left to do */
if ( SDL_numcds > 0 ) {
return(0);
}
}
/* Scan the system for CD-ROM drives */
for ( i=0; checklist[i]; ++i ) {
if ( checklist[i][0] == '?' ) {
char *insert;
exists = 1;
for ( j=checklist[i][1]; exists; ++j ) {
SDL_snprintf(drive, SDL_arraysize(drive), "/dev/%s", &checklist[i][3]);
insert = SDL_strchr(drive, '?');
if ( insert != NULL ) {
*insert = j;
}
switch (CheckDrive(drive, &stbuf)) {
/* Drive exists and is a CD-ROM */
case 1:
AddDrive(drive, &stbuf);
break;
/* Drive exists, but isn't a CD-ROM */
case 0:
break;
/* Drive doesn't exist */
case -1:
exists = 0;
break;
}
}
} else {
SDL_snprintf(drive, SDL_arraysize(drive), "/dev/%s", checklist[i]);
if ( CheckDrive(drive, &stbuf) > 0 ) {
AddDrive(drive, &stbuf);
}
}
}
return(0);
}
/* General ioctl() CD-ROM command function */
static int SDL_SYS_CDioctl(int id, int command, void *arg)
{
int retval;
retval = ioctl(id, command, arg);
if ( retval < 0 ) {
SDL_SetError("ioctl() error: %s", strerror(errno));
}
return(retval);
}
static const char *SDL_SYS_CDName(int drive)
{
return(SDL_cdlist[drive]);
}
static int SDL_SYS_CDOpen(int drive)
{
return(open(SDL_cdlist[drive], (O_RDONLY|O_EXCL|O_NONBLOCK), 0));
}
static int SDL_SYS_CDGetTOC(SDL_CD *cdrom)
{
struct ioc_toc_header toc;
int i, okay;
struct ioc_read_toc_entry entry;
struct cd_toc_entry data;
okay = 0;
if ( SDL_SYS_CDioctl(cdrom->id, CDIOREADTOCHEADER, &toc) == 0 ) {
cdrom->numtracks = toc.ending_track-toc.starting_track+1;
if ( cdrom->numtracks > SDL_MAX_TRACKS ) {
cdrom->numtracks = SDL_MAX_TRACKS;
}
/* Read all the track TOC entries */
for ( i=0; i<=cdrom->numtracks; ++i ) {
if ( i == cdrom->numtracks ) {
cdrom->track[i].id = 0xAA; /* CDROM_LEADOUT */
} else {
cdrom->track[i].id = toc.starting_track+i;
}
entry.starting_track = cdrom->track[i].id;
entry.address_format = CD_MSF_FORMAT;
entry.data_len = sizeof(data);
entry.data = &data;
if ( SDL_SYS_CDioctl(cdrom->id, CDIOREADTOCENTRYS,
&entry) < 0 ) {
break;
} else {
cdrom->track[i].type = data.control;
cdrom->track[i].offset = MSF_TO_FRAMES(
data.addr.msf.minute,
data.addr.msf.second,
data.addr.msf.frame);
cdrom->track[i].length = 0;
if ( i > 0 ) {
cdrom->track[i-1].length =
cdrom->track[i].offset-
cdrom->track[i-1].offset;
}
}
}
if ( i == (cdrom->numtracks+1) ) {
okay = 1;
}
}
return(okay ? 0 : -1);
}
/* Get CD-ROM status */
static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position)
{
CDstatus status;
struct ioc_toc_header toc;
struct ioc_read_subchannel info;
struct cd_sub_channel_info data;
info.address_format = CD_MSF_FORMAT;
info.data_format = CD_CURRENT_POSITION;
info.track = 0;
info.data_len = sizeof(data);
info.data = &data;
if ( ioctl(cdrom->id, CDIOCREADSUBCHANNEL, &info) < 0 ) {
if ( ERRNO_TRAYEMPTY(errno) ) {
status = CD_TRAYEMPTY;
} else {
status = CD_ERROR;
}
} else {
switch (data.header.audio_status) {
case CD_AS_AUDIO_INVALID:
case CD_AS_NO_STATUS:
/* Try to determine if there's a CD available */
if (ioctl(cdrom->id,CDIOREADTOCHEADER,&toc)==0)
status = CD_STOPPED;
else
status = CD_TRAYEMPTY;
break;
case CD_AS_PLAY_COMPLETED:
status = CD_STOPPED;
break;
case CD_AS_PLAY_IN_PROGRESS:
status = CD_PLAYING;
break;
case CD_AS_PLAY_PAUSED:
status = CD_PAUSED;
break;
default:
status = CD_ERROR;
break;
}
}
if ( position ) {
if ( status == CD_PLAYING || (status == CD_PAUSED) ) {
*position = MSF_TO_FRAMES(
data.what.position.absaddr.msf.minute,
data.what.position.absaddr.msf.second,
data.what.position.absaddr.msf.frame);
} else {
*position = 0;
}
}
return(status);
}
/* Start play */
static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length)
{
struct ioc_play_msf playtime;
FRAMES_TO_MSF(start,
&playtime.start_m, &playtime.start_s, &playtime.start_f);
FRAMES_TO_MSF(start+length,
&playtime.end_m, &playtime.end_s, &playtime.end_f);
#ifdef DEBUG_CDROM
fprintf(stderr, "Trying to play from %d:%d:%d to %d:%d:%d\n",
playtime.start_m, playtime.start_s, playtime.start_f,
playtime.end_m, playtime.end_s, playtime.end_f);
#endif
ioctl(cdrom->id, CDIOCSTART, 0);
return(SDL_SYS_CDioctl(cdrom->id, CDIOCPLAYMSF, &playtime));
}
/* Pause play */
static int SDL_SYS_CDPause(SDL_CD *cdrom)
{
return(SDL_SYS_CDioctl(cdrom->id, CDIOCPAUSE, 0));
}
/* Resume play */
static int SDL_SYS_CDResume(SDL_CD *cdrom)
{
return(SDL_SYS_CDioctl(cdrom->id, CDIOCRESUME, 0));
}
/* Stop play */
static int SDL_SYS_CDStop(SDL_CD *cdrom)
{
return(SDL_SYS_CDioctl(cdrom->id, CDIOCSTOP, 0));
}
/* Eject the CD-ROM */
static int SDL_SYS_CDEject(SDL_CD *cdrom)
{
SDL_SYS_CDioctl(cdrom->id, CDIOCALLOW, 0);
return(SDL_SYS_CDioctl(cdrom->id, CDIOCEJECT, 0));
}
/* Close the CD-ROM handle */
static void SDL_SYS_CDClose(SDL_CD *cdrom)
{
close(cdrom->id);
}
void SDL_SYS_CDQuit(void)
{
int i;
if ( SDL_numcds > 0 ) {
for ( i=0; i<SDL_numcds; ++i ) {
SDL_free(SDL_cdlist[i]);
}
SDL_numcds = 0;
}
}
#endif /* SDL_CDROM_OPENBSD */

View file

@ -1,393 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
#ifdef SDL_CDROM_OS2
/* Functions for system-level CD-ROM audio control */
#define INCL_MCIOS2
#include <os2.h>
#include <os2me.h>
#include "SDL_cdrom.h"
#include "../SDL_syscdrom.h"
/* Size of MCI result buffer (in bytes) */
#define MCI_CMDRETBUFSIZE 128
/* The maximum number of CD-ROM drives we'll detect */
#define MAX_DRIVES 16
/* A list of available CD-ROM drives */
static char *SDL_cdlist[MAX_DRIVES];
//static dev_t SDL_cdmode[MAX_DRIVES];
/* The system-dependent CD control functions */
static const char *SDL_SYS_CDName(int drive);
static int SDL_SYS_CDOpen(int drive);
static int SDL_SYS_CDGetTOC(SDL_CD *cdrom);
static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position);
static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length);
static int SDL_SYS_CDPause(SDL_CD *cdrom);
static int SDL_SYS_CDResume(SDL_CD *cdrom);
static int SDL_SYS_CDStop(SDL_CD *cdrom);
static int SDL_SYS_CDEject(SDL_CD *cdrom);
static void SDL_SYS_CDClose(SDL_CD *cdrom);
/* MCI Timing Functions */
#define MCI_MMTIMEPERSECOND 3000
#define FRAMESFROMMM(mmtime) (((mmtime)*CD_FPS)/MCI_MMTIMEPERSECOND)
/* Ready for MCI CDAudio Devices */
int SDL_SYS_CDInit(void)
{
int i; /* generig counter */
MCI_SYSINFO_PARMS msp; /* Structure to MCI SysInfo parameters */
CHAR SysInfoRet[MCI_CMDRETBUFSIZE]; /* Buffer for MCI Command result */
/* Fill in our driver capabilities */
SDL_CDcaps.Name = SDL_SYS_CDName;
SDL_CDcaps.Open = SDL_SYS_CDOpen;
SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC;
SDL_CDcaps.Status = SDL_SYS_CDStatus;
SDL_CDcaps.Play = SDL_SYS_CDPlay;
SDL_CDcaps.Pause = SDL_SYS_CDPause;
SDL_CDcaps.Resume = SDL_SYS_CDResume;
SDL_CDcaps.Stop = SDL_SYS_CDStop;
SDL_CDcaps.Eject = SDL_SYS_CDEject;
SDL_CDcaps.Close = SDL_SYS_CDClose;
/* Get the number of CD ROMs in the System */
/* Clean SysInfo structure */
SDL_memset(&msp, 0x00, sizeof(MCI_SYSINFO_PARMS));
/* Prepare structure to Ask Numer of Audio CDs */
msp.usDeviceType = MCI_DEVTYPE_CD_AUDIO; /* CD Audio Type */
msp.pszReturn = (PSZ)&SysInfoRet; /* Return Structure */
msp.ulRetSize = MCI_CMDRETBUFSIZE; /* Size of ret struct */
if (LOUSHORT(mciSendCommand(0,MCI_SYSINFO, MCI_SYSINFO_QUANTITY | MCI_WAIT, (PVOID)&msp, 0)) != MCIERR_SUCCESS) return(CD_ERROR);
SDL_numcds = atoi(SysInfoRet);
if (SDL_numcds > MAX_DRIVES) SDL_numcds = MAX_DRIVES; /* Limit maximum CD number */
/* Get and Add their system name to the SDL_cdlist */
msp.pszReturn = (PSZ)&SysInfoRet; /* Return Structure */
msp.ulRetSize = MCI_CMDRETBUFSIZE; /* Size of ret struct */
msp.usDeviceType = MCI_DEVTYPE_CD_AUDIO; /* CD Audio Type */
for (i=0; i<SDL_numcds; i++)
{
msp.ulNumber = i+1;
mciSendCommand(0,MCI_SYSINFO, MCI_SYSINFO_NAME | MCI_WAIT,&msp, 0);
SDL_cdlist[i] = SDL_strdup(SysInfoRet);
if ( SDL_cdlist[i] == NULL )
{
SDL_OutOfMemory();
return(-1);
}
}
return(0);
}
/* Return CDAudio System Dependent Device Name - Ready for MCI*/
static const char *SDL_SYS_CDName(int drive)
{
return(SDL_cdlist[drive]);
}
/* Open CDAudio Device - Ready for MCI */
static int SDL_SYS_CDOpen(int drive)
{
MCI_OPEN_PARMS mop;
MCI_SET_PARMS msp;
MCI_GENERIC_PARMS mgp;
/* Open the device */
mop.hwndCallback = (HWND)NULL; // None
mop.usDeviceID = (USHORT)NULL; // Will be returned.
mop.pszDeviceType = (PSZ)SDL_cdlist[drive]; // CDAudio Device
if (LOUSHORT(mciSendCommand(0,MCI_OPEN,MCI_WAIT,&mop, 0)) != MCIERR_SUCCESS) return(CD_ERROR);
/* Set time format */
msp.hwndCallback = (HWND)NULL; // None
msp.ulTimeFormat = MCI_FORMAT_MSF; // Minute : Second : Frame structure
msp.ulSpeedFormat = (ULONG)NULL; // No change
msp.ulAudio = (ULONG)NULL; // No Channel
msp.ulLevel = (ULONG)NULL; // No Volume
msp.ulOver = (ULONG)NULL; // No Delay
msp.ulItem = (ULONG)NULL; // No item
msp.ulValue = (ULONG)NULL; // No value for item flag
if (LOUSHORT(mciSendCommand(mop.usDeviceID,MCI_SET,MCI_WAIT | MCI_SET_TIME_FORMAT,&msp, 0)) == MCIERR_SUCCESS) return (mop.usDeviceID);
/* Error setting time format? - Close opened device */
mgp.hwndCallback = (HWND)NULL; // None
mciSendCommand(mop.usDeviceID,MCI_CLOSE,MCI_WAIT,&mgp, 0);
return(CD_ERROR);
}
/* Get CD Table Of Contents - Ready for MCI */
static int SDL_SYS_CDGetTOC(SDL_CD *cdrom)
{
MCI_TOC_PARMS mtp;
MCI_STATUS_PARMS msp;
MCI_TOC_REC * mtr;
INT i;
/* Correction because MCI cannot read TOC while CD is playing (it'll stop!) */
if (cdrom->status == CD_PLAYING || cdrom->status == CD_PAUSED) return 0;
/* Get Number of Tracks */
msp.hwndCallback = (HWND)NULL; /* None */
msp.ulReturn = (ULONG)NULL; /* We want this information */
msp.ulItem = MCI_STATUS_NUMBER_OF_TRACKS;
msp.ulValue = (ULONG)NULL; /* No additional information */
if (LOUSHORT(mciSendCommand(cdrom->id,MCI_STATUS,MCI_WAIT | MCI_STATUS_ITEM,&msp, 0)) != MCIERR_SUCCESS) return(CD_ERROR);
cdrom->numtracks = msp.ulReturn;
if ( cdrom->numtracks > SDL_MAX_TRACKS )
{
cdrom->numtracks = SDL_MAX_TRACKS;
}
/* Alocate space for TOC data */
mtr = (MCI_TOC_REC *)SDL_malloc(cdrom->numtracks*sizeof(MCI_TOC_REC));
if ( mtr == NULL )
{
SDL_OutOfMemory();
return(-1);
}
/* Get TOC from CD */
mtp.pBuf = mtr;
mtp.ulBufSize = cdrom->numtracks*sizeof(MCI_TOC_REC);
if (LOUSHORT(mciSendCommand(cdrom->id,MCI_GETTOC,MCI_WAIT,&mtp, 0)) != MCIERR_SUCCESS)
{
SDL_OutOfMemory();
SDL_free(mtr);
return(CD_ERROR);
}
/* Fill SDL Tracks Structure */
for (i=0; i<cdrom->numtracks; i++)
{
/* Set Track ID */
cdrom->track[i].id = (mtr+i)->TrackNum;
/* Set Track Type */
msp.hwndCallback = (HWND)NULL; /* None */
msp.ulReturn = (ULONG)NULL; /* We want this information */
msp.ulItem = MCI_CD_STATUS_TRACK_TYPE;
msp.ulValue = (ULONG)((mtr+i)->TrackNum); /* Track Number? */
if (LOUSHORT(mciSendCommand(cdrom->id,MCI_STATUS,MCI_WAIT | MCI_TRACK | MCI_STATUS_ITEM,&msp, 0)) != MCIERR_SUCCESS)
{
SDL_free(mtr);
return (CD_ERROR);
}
if (msp.ulReturn==MCI_CD_TRACK_AUDIO) cdrom->track[i].type = SDL_AUDIO_TRACK;
else cdrom->track[i].type = SDL_DATA_TRACK;
/* Set Track Length - values from MCI are in MMTIMEs - 3000 MMTIME = 1 second */
cdrom->track[i].length = FRAMESFROMMM((mtr+i)->ulEndAddr - (mtr+i)->ulStartAddr);
/* Set Track Offset */
cdrom->track[i].offset = FRAMESFROMMM((mtr+i)->ulStartAddr);
}
SDL_free(mtr);
return(0);
}
/* Get CD-ROM status - Ready for MCI */
static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position)
{
CDstatus status;
MCI_STATUS_PARMS msp;
/* Get Status from MCI */
msp.hwndCallback = (HWND)NULL; /* None */
msp.ulReturn = (ULONG)NULL; /* We want this information */
msp.ulItem = MCI_STATUS_MODE;
msp.ulValue = (ULONG)NULL; /* No additional information */
if (LOUSHORT(mciSendCommand(cdrom->id,MCI_STATUS,MCI_WAIT | MCI_STATUS_ITEM,&msp, 0)) != MCIERR_SUCCESS) status = CD_ERROR;
else
{
switch(msp.ulReturn)
{
case MCI_MODE_NOT_READY:
status = CD_TRAYEMPTY;
break;
case MCI_MODE_PAUSE:
status = CD_PAUSED;
break;
case MCI_MODE_PLAY:
status = CD_PLAYING;
break;
case MCI_MODE_STOP:
status = CD_STOPPED;
break;
/* These cases should not occour */
case MCI_MODE_RECORD:
case MCI_MODE_SEEK:
default:
status = CD_ERROR;
break;
}
}
/* Determine position */
if (position != NULL) /* The SDL $&$&%# CDROM call sends NULL pointer here! */
{
if ((status == CD_PLAYING) || (status == CD_PAUSED))
{
/* Get Position */
msp.hwndCallback = (HWND)NULL; /* None */
msp.ulReturn = (ULONG)NULL; /* We want this information */
msp.ulItem = MCI_STATUS_POSITION;
msp.ulValue = (ULONG)NULL; /* No additiona info */
if (LOUSHORT(mciSendCommand(cdrom->id,MCI_STATUS,MCI_WAIT | MCI_STATUS_ITEM,&msp, 0)) != MCIERR_SUCCESS) return (CD_ERROR);
/* Convert from MSF (format selected in the Open process) to Frames (format that will be returned) */
*position = MSF_TO_FRAMES(MSF_MINUTE(msp.ulReturn),MSF_SECOND(msp.ulReturn),MSF_FRAME(msp.ulReturn));
}
else *position = 0;
}
return(status);
}
/* Start play - Ready for MCI */
static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length)
{
MCI_GENERIC_PARMS mgp;
MCI_STATUS_PARMS msp;
MCI_PLAY_PARMS mpp;
ULONG min,sec,frm;
/* Start MSF */
FRAMES_TO_MSF(start, &min, &sec, &frm);
MSF_MINUTE(mpp.ulFrom) = min;
MSF_SECOND(mpp.ulFrom) = sec;
MSF_FRAME(mpp.ulFrom) = frm;
/* End MSF */
FRAMES_TO_MSF(start+length, &min, &sec, &frm);
MSF_MINUTE(mpp.ulTo) = min;
MSF_SECOND(mpp.ulTo) = sec;
MSF_FRAME(mpp.ulTo) = frm;
#ifdef DEBUG_CDROM
fprintf(stderr, "Trying to play from %d:%d:%d to %d:%d:%d\n",
playtime.cdmsf_min0, playtime.cdmsf_sec0, playtime.cdmsf_frame0,
playtime.cdmsf_min1, playtime.cdmsf_sec1, playtime.cdmsf_frame1);
#endif
/* Verifies if it is paused first... and if it is, unpause before stopping it. */
msp.hwndCallback = (HWND)NULL; /* None */
msp.ulReturn = (ULONG)NULL; /* We want this information */
msp.ulItem = MCI_STATUS_MODE;
msp.ulValue = (ULONG)NULL; /* No additional information */
if (LOUSHORT(mciSendCommand(cdrom->id,MCI_STATUS,MCI_WAIT | MCI_STATUS_ITEM,&msp, 0)) == MCIERR_SUCCESS)
{
if (msp.ulReturn == MCI_MODE_PAUSE)
{
mgp.hwndCallback = (HWND)NULL; // None
mciSendCommand(cdrom->id,MCI_RESUME,0,&mgp, 0);
}
}
/* Now play it. */
mpp.hwndCallback = (HWND)NULL; // We do not want the info. temp
if (LOUSHORT(mciSendCommand(cdrom->id,MCI_PLAY,MCI_FROM | MCI_TO,&mpp, 0)) == MCIERR_SUCCESS) return 0;
return (CD_ERROR);
}
/* Pause play - Ready for MCI */
static int SDL_SYS_CDPause(SDL_CD *cdrom)
{
MCI_GENERIC_PARMS mgp;
mgp.hwndCallback = (HWND)NULL; // None
if (LOUSHORT(mciSendCommand(cdrom->id,MCI_PAUSE,MCI_WAIT,&mgp, 0)) == MCIERR_SUCCESS) return 0;
return(CD_ERROR);
}
/* Resume play - Ready for MCI */
static int SDL_SYS_CDResume(SDL_CD *cdrom)
{
MCI_GENERIC_PARMS mgp;
mgp.hwndCallback = (HWND)NULL; // None
if (LOUSHORT(mciSendCommand(cdrom->id,MCI_RESUME,MCI_WAIT,&mgp, 0)) == MCIERR_SUCCESS) return 0;
return(CD_ERROR);
}
/* Stop play - Ready for MCI */
static int SDL_SYS_CDStop(SDL_CD *cdrom)
{
MCI_GENERIC_PARMS mgp;
MCI_STATUS_PARMS msp;
/* Verifies if it is paused first... and if it is, unpause before stopping it. */
msp.hwndCallback = (HWND)NULL; /* None */
msp.ulReturn = (ULONG)NULL; /* We want this information */
msp.ulItem = MCI_STATUS_MODE;
msp.ulValue = (ULONG)NULL; /* No additional information */
if (LOUSHORT(mciSendCommand(cdrom->id,MCI_STATUS,MCI_WAIT | MCI_STATUS_ITEM,&msp, 0)) == MCIERR_SUCCESS)
{
if (msp.ulReturn == MCI_MODE_PAUSE)
{
mgp.hwndCallback = (HWND)NULL; // None
mciSendCommand(cdrom->id,MCI_RESUME,0,&mgp, 0);
}
}
/* Now stops the media */
mgp.hwndCallback = (HWND)NULL; // None
if (LOUSHORT(mciSendCommand(cdrom->id,MCI_STOP,MCI_WAIT,&mgp, 0)) == MCIERR_SUCCESS) return 0;
return(CD_ERROR);
}
/* Eject the CD-ROM - Ready for MCI */
static int SDL_SYS_CDEject(SDL_CD *cdrom)
{
MCI_SET_PARMS msp;
msp.hwndCallback = (HWND)NULL; // None
msp.ulTimeFormat = (ULONG)NULL; // No change
msp.ulSpeedFormat = (ULONG)NULL; // No change
msp.ulAudio = (ULONG)NULL; // No Channel
msp.ulLevel = (ULONG)NULL; // No Volume
msp.ulOver = (ULONG)NULL; // No Delay
msp.ulItem = (ULONG)NULL; // No item
msp.ulValue = (ULONG)NULL; // No value for item flag
if (LOUSHORT(mciSendCommand(cdrom->id,MCI_SET,MCI_WAIT | MCI_SET_DOOR_OPEN,&msp, 0)) == MCIERR_SUCCESS) return 0;
return(CD_ERROR);
}
/* Close the CD-ROM handle - Ready for MCI */
static void SDL_SYS_CDClose(SDL_CD *cdrom)
{
MCI_GENERIC_PARMS mgp;
mgp.hwndCallback = (HWND)NULL; // None
mciSendCommand(cdrom->id,MCI_CLOSE,MCI_WAIT,&mgp, 0);
}
/* Finalize CDROM Subsystem - Ready for MCI */
void SDL_SYS_CDQuit(void)
{
int i;
if ( SDL_numcds > 0 )
{
for ( i=0; i<SDL_numcds; ++i )
{
SDL_free(SDL_cdlist[i]);
}
SDL_numcds = 0;
}
}
#endif /* SDL_CDROM_OS2 */

View file

@ -1,444 +0,0 @@
/*
Tru64 audio module for SDL (Simple DirectMedia Layer)
Copyright (C) 2003
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 library 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
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "SDL_config.h"
#ifdef SDL_CDROM_OSF
/* Functions for system-level CD-ROM audio control */
/* #define DEBUG_CDROM 1 */
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <io/cam/cdrom.h>
#include <io/cam/rzdisk.h>
#include <io/common/devgetinfo.h>
#include "SDL_cdrom.h"
#include "../SDL_syscdrom.h"
/* The maximum number of CD-ROM drives we'll detect */
#define MAX_DRIVES 16
/* A list of available CD-ROM drives */
static char *SDL_cdlist[MAX_DRIVES];
static dev_t SDL_cdmode[MAX_DRIVES];
/* The system-dependent CD control functions */
static const char *SDL_SYS_CDName(int drive);
static int SDL_SYS_CDOpen(int drive);
static int SDL_SYS_CDGetTOC(SDL_CD *cdrom);
static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position);
static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length);
static int SDL_SYS_CDPause(SDL_CD *cdrom);
static int SDL_SYS_CDResume(SDL_CD *cdrom);
static int SDL_SYS_CDStop(SDL_CD *cdrom);
static int SDL_SYS_CDEject(SDL_CD *cdrom);
static void SDL_SYS_CDClose(SDL_CD *cdrom);
/* Check a drive to see if it is a CD-ROM */
/* Caution!! Not tested. */
static int CheckDrive(char *drive, struct stat *stbuf)
{
int cdfd, is_cd = 0;
struct mode_sel_sns_params msp;
struct inquiry_info inq;
#ifdef DEBUG_CDROM
char *devtype[] = {"Disk", "Tape", "Printer", "Processor", "WORM",
"CD-ROM", "Scanner", "Optical", "Changer", "Comm", "Unknown"};
#endif
bzero(&msp, sizeof(msp));
bzero(&inq, sizeof(inq));
/* If it doesn't exist, return -1 */
if ( stat(drive, stbuf) < 0 ) {
return(-1);
}
if ( (cdfd = open(drive, (O_RDWR|O_NDELAY), 0)) >= 0 ) {
msp.msp_addr = (caddr_t) &inq;
msp.msp_pgcode = 0;
msp.msp_pgctrl = 0;
msp.msp_length = sizeof(inq);
msp.msp_setps = 0;
if ( ioctl(cdfd, SCSI_GET_INQUIRY_DATA, &msp) )
return (0);
#ifdef DEBUG_CDROM
fprintf(stderr, "Device Type: %s\n", devtype[inq.perfdt]);
fprintf(stderr, "Vendor: %.8s\n", inq.vndrid);
fprintf(stderr, "Product: %.8s\n", inq.prodid);
fprintf(stderr, "Revision: %.8s\n", inq.revlvl);
#endif
if ( inq.perfdt == DTYPE_RODIRECT )
is_cd = 1;
}
return(is_cd);
}
/* Add a CD-ROM drive to our list of valid drives */
static void AddDrive(char *drive, struct stat *stbuf)
{
int i;
if ( SDL_numcds < MAX_DRIVES ) {
/* Check to make sure it's not already in our list.
* This can happen when we see a drive via symbolic link.
*
*/
for ( i=0; i<SDL_numcds; ++i ) {
if ( stbuf->st_rdev == SDL_cdmode[i] ) {
#ifdef DEBUG_CDROM
fprintf(stderr, "Duplicate drive detected: %s == %s\n", drive, SDL_cdlist[i]);
#endif
return;
}
}
/* Add this drive to our list */
i = SDL_numcds;
SDL_cdlist[i] = SDL_strdup(drive);
if ( SDL_cdlist[i] == NULL ) {
SDL_OutOfMemory();
return;
}
SDL_cdmode[i] = stbuf->st_rdev;
++SDL_numcds;
#ifdef DEBUG_CDROM
fprintf(stderr, "Added CD-ROM drive: %s\n", drive);
#endif
}
}
int SDL_SYS_CDInit(void)
{
/* checklist:
*
* Tru64 5.X (/dev/rdisk/cdrom?c)
* dir: /dev/rdisk, name: cdrom
*
* Digital UNIX 4.0X (/dev/rrz?c)
* dir: /dev, name: rrz
*
*/
struct {
char *dir;
char *name;
} checklist[] = {
{"/dev/rdisk", "cdrom"},
{"/dev", "rrz"},
{NULL, NULL}};
char drive[32];
char *SDLcdrom;
int i, j, exists;
struct stat stbuf;
/* Fill in our driver capabilities */
SDL_CDcaps.Name = SDL_SYS_CDName;
SDL_CDcaps.Open = SDL_SYS_CDOpen;
SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC;
SDL_CDcaps.Status = SDL_SYS_CDStatus;
SDL_CDcaps.Play = SDL_SYS_CDPlay;
SDL_CDcaps.Pause = SDL_SYS_CDPause;
SDL_CDcaps.Resume = SDL_SYS_CDResume;
SDL_CDcaps.Stop = SDL_SYS_CDStop;
SDL_CDcaps.Eject = SDL_SYS_CDEject;
SDL_CDcaps.Close = SDL_SYS_CDClose;
/* Look in the environment for our CD-ROM drive list */
SDLcdrom = SDL_getenv("SDL_CDROM"); /* ':' separated list of devices */
if ( SDLcdrom != NULL ) {
char *cdpath, *delim;
size_t len = SDL_strlen(SDLcdrom)+1;
cdpath = SDL_stack_alloc(char, len);
if ( cdpath != NULL ) {
SDL_strlcpy(cdpath, SDLcdrom, len);
SDLcdrom = cdpath;
do {
delim = SDL_strchr(SDLcdrom, ':');
if ( delim ) {
*delim++ = '\0';
}
if ( CheckDrive(SDLcdrom, &stbuf) > 0 ) {
AddDrive(SDLcdrom, &stbuf);
}
if ( delim ) {
SDLcdrom = delim;
} else {
SDLcdrom = NULL;
}
} while ( SDLcdrom );
SDL_stack_free(cdpath);
}
/* If we found our drives, there's nothing left to do */
if ( SDL_numcds > 0 ) {
return(0);
}
}
/* Scan the system for CD-ROM drives */
for ( i = 0; checklist[i].dir; ++i) {
DIR *devdir;
struct dirent *devent;
int name_len;
devdir = opendir(checklist[i].dir);
if (devdir) {
name_len = SDL_strlen(checklist[i].name);
while (devent = readdir(devdir))
if (SDL_memcmp(checklist[i].name, devent->d_name, name_len) == 0)
if (devent->d_name[devent->d_namlen-1] == 'c') {
SDL_snprintf(drive, SDL_arraysize(drive), "%s/%s", checklist[i].dir, devent->d_name);
#ifdef DEBUG_CDROM
fprintf(stderr, "Try to add drive: %s\n", drive);
#endif
if ( CheckDrive(drive, &stbuf) > 0 )
AddDrive(drive, &stbuf);
}
closedir(devdir);
} else {
#ifdef DEBUG_CDROM
fprintf(stderr, "cannot open dir: %s\n", checklist[i].dir);
#endif
}
}
return (0);
}
static const char *SDL_SYS_CDName(int drive)
{
return(SDL_cdlist[drive]);
}
static int SDL_SYS_CDOpen(int drive)
{
/* O_RDWR: To use ioctl(fd, SCSI_STOP_UNIT) */
return(open(SDL_cdlist[drive], (O_RDWR|O_NDELAY), 0));
}
static int SDL_SYS_CDGetTOC(SDL_CD *cdrom)
{
struct cd_toc toc;
struct cd_toc_header hdr;
struct cd_toc_entry *cdte;
int i;
int okay = 0;
if ( ioctl(cdrom->id, CDROM_TOC_HEADER, &hdr) ) {
fprintf(stderr,"ioctl error CDROM_TOC_HEADER\n");
return -1;
}
cdrom->numtracks = hdr.th_ending_track - hdr.th_starting_track + 1;
if ( cdrom->numtracks > SDL_MAX_TRACKS ) {
cdrom->numtracks = SDL_MAX_TRACKS;
}
#ifdef DEBUG_CDROM
fprintf(stderr,"hdr.th_data_len1 = %d\n", hdr.th_data_len1);
fprintf(stderr,"hdr.th_data_len0 = %d\n", hdr.th_data_len0);
fprintf(stderr,"hdr.th_starting_track = %d\n", hdr.th_starting_track);
fprintf(stderr,"hdr.th_ending_track = %d\n", hdr.th_ending_track);
fprintf(stderr,"cdrom->numtracks = %d\n", cdrom->numtracks);
#endif
toc.toc_address_format = CDROM_LBA_FORMAT;
toc.toc_starting_track = 0;
toc.toc_alloc_length = (hdr.th_data_len1 << 8) +
hdr.th_data_len0 + sizeof(hdr);
if ( (toc.toc_buffer = alloca(toc.toc_alloc_length)) == NULL) {
fprintf(stderr,"cannot allocate toc.toc_buffer\n");
return -1;
}
bzero (toc.toc_buffer, toc.toc_alloc_length);
if (ioctl(cdrom->id, CDROM_TOC_ENTRYS, &toc)) {
fprintf(stderr,"ioctl error CDROM_TOC_ENTRYS\n");
return -1;
}
cdte =(struct cd_toc_entry *) ((char *) toc.toc_buffer + sizeof(hdr));
for (i=0; i <= cdrom->numtracks; ++i) {
if (i == cdrom->numtracks ) {
cdrom->track[i].id = 0xAA;;
} else {
cdrom->track[i].id = hdr.th_starting_track + i;
}
cdrom->track[i].type =
cdte[i].te_control & CDROM_DATA_TRACK;
cdrom->track[i].offset =
cdte[i].te_absaddr.lba.addr3 << 24 |
cdte[i].te_absaddr.lba.addr2 << 16 |
cdte[i].te_absaddr.lba.addr1 << 8 |
cdte[i].te_absaddr.lba.addr0;
cdrom->track[i].length = 0;
if ( i > 0 ) {
cdrom->track[i - 1].length =
cdrom->track[i].offset -
cdrom->track[i - 1].offset;
}
}
#ifdef DEBUG_CDROM
for (i = 0; i <= cdrom->numtracks; i++) {
fprintf(stderr,"toc_entry[%d].te_track_number = %d\n",
i,cdte[i].te_track_number);
fprintf(stderr,"cdrom->track[%d].id = %d\n", i,cdrom->track[i].id);
fprintf(stderr,"cdrom->track[%d].type = %x\n", i,cdrom->track[i].type);
fprintf(stderr,"cdrom->track[%d].offset = %d\n", i,cdrom->track[i].offset);
fprintf(stderr,"cdrom->track[%d].length = %d\n", i,cdrom->track[i].length);
}
#endif
if ( i == (cdrom->numtracks+1) ) {
okay = 1;
}
return(okay ? 0 : -1);
}
/* Get CD-ROM status */
static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position)
{
CDstatus status;
struct cd_sub_channel sc;
struct cd_subc_channel_data scd;
sc.sch_address_format = CDROM_LBA_FORMAT;
sc.sch_data_format = CDROM_CURRENT_POSITION;
sc.sch_track_number = 0;
sc.sch_alloc_length = sizeof(scd);
sc.sch_buffer = (caddr_t)&scd;
if ( ioctl(cdrom->id, CDROM_READ_SUBCHANNEL, &sc) ) {
status = CD_ERROR;
fprintf(stderr,"ioctl error CDROM_READ_SUBCHANNEL \n");
} else {
switch (scd.scd_header.sh_audio_status) {
case AS_AUDIO_INVALID:
status = CD_STOPPED;
break;
case AS_PLAY_IN_PROGRESS:
status = CD_PLAYING;
break;
case AS_PLAY_PAUSED:
status = CD_PAUSED;
break;
case AS_PLAY_COMPLETED:
status = CD_STOPPED;
break;
case AS_PLAY_ERROR:
status = CD_ERROR;
break;
case AS_NO_STATUS:
status = CD_STOPPED;
break;
default:
status = CD_ERROR;
break;
}
#ifdef DEBUG_CDROM
fprintf(stderr,"scd.scd_header.sh_audio_status = %x\n",
scd.scd_header.sh_audio_status);
#endif
}
if (position) {
if (status == CD_PLAYING || (status == CD_PAUSED) ) {
*position =
scd.scd_position_data.scp_absaddr.lba.addr3 << 24 |
scd.scd_position_data.scp_absaddr.lba.addr2 << 16 |
scd.scd_position_data.scp_absaddr.lba.addr1 << 8 |
scd.scd_position_data.scp_absaddr.lba.addr0;
} else {
*position = 0;
}
}
return status;
}
/* Start play */
static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length)
{
/*
* Play MSF
*/
struct cd_play_audio_msf msf;
int end;
bzero(&msf, sizeof(msf));
end = start +length;
FRAMES_TO_MSF(start + 150, /* LBA = 4500*M + 75*S + F - 150 */
&msf.msf_starting_M_unit,
&msf.msf_starting_S_unit,
&msf.msf_starting_F_unit);
FRAMES_TO_MSF(end + 150, /* LBA = 4500*M + 75*S + F - 150 */
&msf.msf_ending_M_unit,
&msf.msf_ending_S_unit,
&msf.msf_ending_F_unit);
return(ioctl(cdrom->id, CDROM_PLAY_AUDIO_MSF, &msf));
}
/* Pause play */
static int SDL_SYS_CDPause(SDL_CD *cdrom)
{
return(ioctl(cdrom->id, CDROM_PAUSE_PLAY));
}
/* Resume play */
static int SDL_SYS_CDResume(SDL_CD *cdrom)
{
return(ioctl(cdrom->id, CDROM_RESUME_PLAY));
}
/* Stop play */
static int SDL_SYS_CDStop(SDL_CD *cdrom)
{
return(ioctl(cdrom->id, SCSI_STOP_UNIT));
}
/* Eject the CD-ROM */
static int SDL_SYS_CDEject(SDL_CD *cdrom)
{
return(ioctl(cdrom->id, CDROM_EJECT_CADDY));
}
/* Close the CD-ROM handle */
static void SDL_SYS_CDClose(SDL_CD *cdrom)
{
close(cdrom->id);
}
void SDL_SYS_CDQuit(void)
{
int i;
if ( SDL_numcds > 0 ) {
for ( i=0; i<SDL_numcds; ++i ) {
SDL_free(SDL_cdlist[i]);
}
SDL_numcds = 0;
}
}
#endif /* SDL_CDROM_OSF */

View file

@ -1,551 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
#ifdef SDL_CDROM_QNX
/* Functions for system-level CD-ROM audio control */
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <sys/cdrom.h>
#include <sys/dcmd_cam.h>
#include "SDL_timer.h"
#include "SDL_cdrom.h"
#include "../SDL_syscdrom.h"
/* The maximum number of CD-ROM drives we'll detect */
#define MAX_DRIVES 16
#define QNX_CD_OPENMODE O_RDONLY | O_EXCL
/* A list of available CD-ROM drives */
static char *SDL_cdlist[MAX_DRIVES];
static dev_t SDL_cdmode[MAX_DRIVES];
static int SDL_cdopen[MAX_DRIVES];
/* The system-dependent CD control functions */
static const char *SDL_SYS_CDName(int drive);
static int SDL_SYS_CDOpen(int drive);
static int SDL_SYS_CDGetTOC(SDL_CD *cdrom);
static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position);
static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length);
static int SDL_SYS_CDPause(SDL_CD *cdrom);
static int SDL_SYS_CDResume(SDL_CD *cdrom);
static int SDL_SYS_CDStop(SDL_CD *cdrom);
static int SDL_SYS_CDEject(SDL_CD *cdrom);
static void SDL_SYS_CDClose(SDL_CD *cdrom);
/* Check a drive to see if it is a CD-ROM */
static int CheckDrive(char *drive, struct stat *stbuf)
{
int is_cd, cdfd;
cam_devinfo_t dinfo;
int devctlret=0;
int atapi;
int removable;
int cdb10;
/* If it doesn't exist, return -1 */
if (stat(drive, stbuf) < 0)
{
return(-1);
}
/* If it does exist, verify that it's an available CD-ROM */
is_cd = 0;
if (S_ISCHR(stbuf->st_mode) || S_ISBLK(stbuf->st_mode))
{
cdfd = open(drive, QNX_CD_OPENMODE);
if ( cdfd >= 0 )
{
devctlret=devctl(cdfd, DCMD_CAM_DEVINFO, &dinfo, sizeof(cam_devinfo_t), NULL);
if (devctlret==EOK)
{
atapi=dinfo.flags & DEV_ATAPI;
removable=dinfo.flags & DEV_REMOVABLE;
cdb10=dinfo.flags & DEV_CDB_10; /* I'm not sure about that flag */
/* in the near future need to add more checks for splitting cdroms from other devices */
if ((atapi)&&(removable))
{
is_cd = 1;
}
}
close(cdfd);
}
}
return(is_cd);
}
/* Add a CD-ROM drive to our list of valid drives */
static void AddDrive(char *drive, struct stat *stbuf)
{
int i;
if (SDL_numcds < MAX_DRIVES)
{
/* Check to make sure it's not already in our list.
This can happen when we see a drive via symbolic link. */
for (i=0; i<SDL_numcds; ++i)
{
if (stbuf->st_rdev == SDL_cdmode[i])
{
return;
}
}
/* Add this drive to our list */
i = SDL_numcds;
SDL_cdlist[i] = SDL_strdup(drive);
if (SDL_cdlist[i] == NULL)
{
SDL_OutOfMemory();
return;
}
SDL_cdmode[i] = stbuf->st_rdev;
++SDL_numcds;
}
}
int SDL_SYS_CDInit(void)
{
/* checklist: /dev/cdrom, /dev/cd?, /dev/scd? */
static char *checklist[]={"cdrom", "?0 cd?", "?1 cd?", "?0 scd?", NULL};
char *SDLcdrom;
int i, j, exists;
char drive[32];
struct stat stbuf;
/* Fill in our driver capabilities */
SDL_CDcaps.Name = SDL_SYS_CDName;
SDL_CDcaps.Open = SDL_SYS_CDOpen;
SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC;
SDL_CDcaps.Status = SDL_SYS_CDStatus;
SDL_CDcaps.Play = SDL_SYS_CDPlay;
SDL_CDcaps.Pause = SDL_SYS_CDPause;
SDL_CDcaps.Resume = SDL_SYS_CDResume;
SDL_CDcaps.Stop = SDL_SYS_CDStop;
SDL_CDcaps.Eject = SDL_SYS_CDEject;
SDL_CDcaps.Close = SDL_SYS_CDClose;
/* clearing device open status */
for (i=0; i<MAX_DRIVES; i++)
{
SDL_cdopen[i]=0;
}
/* Look in the environment for our CD-ROM drive list */
SDLcdrom = SDL_getenv("SDL_CDROM"); /* ':' separated list of devices */
if ( SDLcdrom != NULL )
{
char *cdpath, *delim;
size_t len = SDL_strlen(SDLcdrom)+1;
cdpath = SDL_stack_alloc(char, len);
if (cdpath != NULL)
{
SDL_strlcpy(cdpath, SDLcdrom, len);
SDLcdrom = cdpath;
do {
delim = SDL_strchr(SDLcdrom, ':');
if (delim)
{
*delim++ = '\0';
}
if (CheckDrive(SDLcdrom, &stbuf) > 0)
{
AddDrive(SDLcdrom, &stbuf);
}
if (delim)
{
SDLcdrom = delim;
}
else
{
SDLcdrom = NULL;
}
} while (SDLcdrom);
SDL_stack_free(cdpath);
}
/* If we found our drives, there's nothing left to do */
if (SDL_numcds > 0)
{
return(0);
}
}
/* Scan the system for CD-ROM drives */
for ( i=0; checklist[i]; ++i )
{
if (checklist[i][0] == '?')
{
char* insert;
exists = 1;
for ( j=checklist[i][1]; exists; ++j )
{
SDL_snprintf(drive, SDL_arraysize(drive), "/dev/%s", &checklist[i][3]);
insert = SDL_strchr(drive, '?');
if (insert != NULL)
{
*insert = j;
}
switch (CheckDrive(drive, &stbuf))
{
/* Drive exists and is a CD-ROM */
case 1:
AddDrive(drive, &stbuf);
break;
/* Drive exists, but isn't a CD-ROM */
case 0:
break;
/* Drive doesn't exist */
case -1:
exists = 0;
break;
}
}
}
else
{
SDL_snprintf(drive, SDL_arraysize(drive), "/dev/%s", checklist[i]);
if (CheckDrive(drive, &stbuf) > 0)
{
AddDrive(drive, &stbuf);
}
}
}
return(0);
}
static const char *SDL_SYS_CDName(int drive)
{
return(SDL_cdlist[drive]);
}
static int SDL_SYS_CDOpen(int drive)
{
int handle;
handle=open(SDL_cdlist[drive], QNX_CD_OPENMODE);
if (handle>0)
{
SDL_cdopen[drive]=handle;
}
return (handle);
}
static int SDL_SYS_CDGetTOC(SDL_CD *cdrom)
{
cdrom_read_toc_t toc;
int i, okay;
okay = 0;
if (devctl(cdrom->id, DCMD_CAM_CDROMREADTOC, &toc, sizeof(toc), NULL) == 0)
{
cdrom->numtracks = toc.last_track - toc.first_track + 1;
if (cdrom->numtracks > SDL_MAX_TRACKS)
{
cdrom->numtracks = SDL_MAX_TRACKS;
}
/* Read all the track TOC entries */
for (i=0; i<=cdrom->numtracks; ++i)
{
if (i == cdrom->numtracks)
{
cdrom->track[i].id = CDROM_LEADOUT;
}
else
{
cdrom->track[i].id = toc.first_track+i;
}
cdrom->track[i].type = toc.toc_entry[i].control_adr & 0x0F;
cdrom->track[i].offset = toc.toc_entry[i].addr.lba;
cdrom->track[i].length = 0;
if (i > 0)
{
cdrom->track[i-1].length = cdrom->track[i].offset-cdrom->track[i-1].offset;
}
}
if (i == (cdrom->numtracks+1))
{
okay = 1;
}
}
return (okay ? 0 : -1);
}
/* Get CD-ROM status */
static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position)
{
CDstatus status;
cdrom_read_toc_t toc;
cdrom_subch_data_t info;
cam_devinfo_t dinfo;
int devctlret=0;
int drive=-1;
int i;
int eagaincnt=0;
/* check media presence before read subchannel call, some cdroms can lockups */
/* if no media, while calling read subchannel functions. */
devctlret=devctl(cdrom->id, DCMD_CAM_DEVINFO, &dinfo, sizeof(cam_devinfo_t), NULL);
if (devctlret==EOK)
{
if ((dinfo.flags & DEV_NO_MEDIA)!=0)
{
status = CD_TRAYEMPTY;
if (position)
{
*position = 0;
}
return (status);
}
}
/* if media exists, then do other stuff */
SDL_memset(&info, 0x00, sizeof(info));
info.subch_command.data_format = CDROM_SUBCH_CURRENT_POSITION;
do {
devctlret=devctl(cdrom->id, DCMD_CAM_CDROMSUBCHNL, &info, sizeof(info), NULL);
if (devctlret==EIO)
{
/* big workaround for media change, handle is unusable after that,
that bug was found in QNX 6.2, 6.2.1 is not released yet. */
for (i=0; i<MAX_DRIVES; i++)
{
if (SDL_cdopen[i]==cdrom->id)
{
drive=i;
break;
}
}
if (drive==-1)
{
/* that cannot happen, but ... */
break;
}
close(cdrom->id);
cdrom->id=open(SDL_cdlist[drive], QNX_CD_OPENMODE);
devctlret=EAGAIN;
}
if (devctlret==EAGAIN)
{
eagaincnt++;
}
if (eagaincnt==2)
{
/* workaround for broken cdroms, which can return always EAGAIN when its not ready, */
/* that mean errornous media or just no media avail */
devctlret=ENXIO;
break;
}
} while ((devctlret==EAGAIN)||(devctlret==ESTALE));
if (devctlret != 0)
{
if (devctlret==ENXIO)
{
status = CD_TRAYEMPTY;
}
else
{
status = CD_ERROR;
}
}
else
{
switch (info.current_position.header.audio_status)
{
case CDROM_AUDIO_INVALID:
case CDROM_AUDIO_NO_STATUS:
/* Try to determine if there's a CD available */
if (devctl(cdrom->id, DCMD_CAM_CDROMREADTOC, &toc, sizeof(toc), NULL)==0)
status = CD_STOPPED;
else
status = CD_TRAYEMPTY;
break;
case CDROM_AUDIO_COMPLETED:
status = CD_STOPPED;
break;
case CDROM_AUDIO_PLAY:
status = CD_PLAYING;
break;
case CDROM_AUDIO_PAUSED:
/* Workaround buggy CD-ROM drive */
if (info.current_position.data_format == CDROM_LEADOUT)
{
status = CD_STOPPED;
}
else
{
status = CD_PAUSED;
}
break;
default:
status = CD_ERROR;
break;
}
}
if (position)
{
if (status==CD_PLAYING || (status==CD_PAUSED))
{
*position = MSF_TO_FRAMES(info.current_position.addr.msf.minute,
info.current_position.addr.msf.second,
info.current_position.addr.msf.frame);
}
else
{
*position = 0;
}
}
return (status);
}
/* Start play */
static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length)
{
cdrom_playmsf_t playtime;
FRAMES_TO_MSF(start, &playtime.start_minute, &playtime.start_second, &playtime.start_frame);
FRAMES_TO_MSF(start+length, &playtime.end_minute, &playtime.end_second, &playtime.end_frame);
if (devctl(cdrom->id, DCMD_CAM_CDROMPLAYMSF, &playtime, sizeof(playtime), NULL) != 0)
{
return -1;
}
else
{
return 0;
}
}
/* Pause play */
static int SDL_SYS_CDPause(SDL_CD *cdrom)
{
if (devctl(cdrom->id, DCMD_CAM_CDROMPAUSE, NULL, 0, NULL)!=0)
{
return -1;
}
else
{
return 0;
}
}
/* Resume play */
static int SDL_SYS_CDResume(SDL_CD *cdrom)
{
if (devctl(cdrom->id, DCMD_CAM_CDROMRESUME, NULL, 0, NULL)!=0)
{
return -1;
}
else
{
return 0;
}
}
/* Stop play */
static int SDL_SYS_CDStop(SDL_CD *cdrom)
{
if (devctl(cdrom->id, DCMD_CAM_CDROMSTOP, NULL, 0, NULL)!=0)
{
return -1;
}
else
{
return 0;
}
}
/* Eject the CD-ROM */
static int SDL_SYS_CDEject(SDL_CD *cdrom)
{
if (devctl(cdrom->id, DCMD_CAM_EJECT_MEDIA, NULL, 0, NULL)!=0)
{
return -1;
}
else
{
return 0;
}
}
/* Close the CD-ROM handle */
static void SDL_SYS_CDClose(SDL_CD *cdrom)
{
int i;
for (i=0; i<MAX_DRIVES; i++)
{
if (SDL_cdopen[i]==cdrom->id)
{
SDL_cdopen[i]=0;
break;
}
}
close(cdrom->id);
}
void SDL_SYS_CDQuit(void)
{
int i;
if (SDL_numcds > 0)
{
for (i=0; i<SDL_numcds; ++i)
{
SDL_free(SDL_cdlist[i]);
}
SDL_numcds = 0;
}
}
#endif /* SDL_CDROM_QNX */

View file

@ -1,386 +0,0 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2012 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
#ifdef SDL_CDROM_WIN32
/* Functions for system-level CD-ROM audio control */
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <mmsystem.h>
#include "SDL_cdrom.h"
#include "../SDL_syscdrom.h"
/* This really broken?? */
#define BROKEN_MCI_PAUSE /* Pausing actually stops play -- Doh! */
/* The maximum number of CD-ROM drives we'll detect (Don't change!) */
#define MAX_DRIVES 26
/* A list of available CD-ROM drives */
static char *SDL_cdlist[MAX_DRIVES];
static MCIDEVICEID SDL_mciID[MAX_DRIVES];
#ifdef BROKEN_MCI_PAUSE
static int SDL_paused[MAX_DRIVES];
#endif
static int SDL_CD_end_position;
/* The system-dependent CD control functions */
static const char *SDL_SYS_CDName(int drive);
static int SDL_SYS_CDOpen(int drive);
static int SDL_SYS_CDGetTOC(SDL_CD *cdrom);
static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position);
static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length);
static int SDL_SYS_CDPause(SDL_CD *cdrom);
static int SDL_SYS_CDResume(SDL_CD *cdrom);
static int SDL_SYS_CDStop(SDL_CD *cdrom);
static int SDL_SYS_CDEject(SDL_CD *cdrom);
static void SDL_SYS_CDClose(SDL_CD *cdrom);
/* Add a CD-ROM drive to our list of valid drives */
static void AddDrive(char *drive)
{
int i;
if ( SDL_numcds < MAX_DRIVES ) {
/* Add this drive to our list */
i = SDL_numcds;
SDL_cdlist[i] = SDL_strdup(drive);
if ( SDL_cdlist[i] == NULL ) {
SDL_OutOfMemory();
return;
}
++SDL_numcds;
#ifdef CDROM_DEBUG
fprintf(stderr, "Added CD-ROM drive: %s\n", drive);
#endif
}
}
int SDL_SYS_CDInit(void)
{
/* checklist: Drive 'A' - 'Z' */
int i;
char drive[4];
/* Fill in our driver capabilities */
SDL_CDcaps.Name = SDL_SYS_CDName;
SDL_CDcaps.Open = SDL_SYS_CDOpen;
SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC;
SDL_CDcaps.Status = SDL_SYS_CDStatus;
SDL_CDcaps.Play = SDL_SYS_CDPlay;
SDL_CDcaps.Pause = SDL_SYS_CDPause;
SDL_CDcaps.Resume = SDL_SYS_CDResume;
SDL_CDcaps.Stop = SDL_SYS_CDStop;
SDL_CDcaps.Eject = SDL_SYS_CDEject;
SDL_CDcaps.Close = SDL_SYS_CDClose;
/* Scan the system for CD-ROM drives */
for ( i='A'; i<='Z'; ++i ) {
SDL_snprintf(drive, SDL_arraysize(drive), "%c:\\", i);
if ( GetDriveType(drive) == DRIVE_CDROM ) {
AddDrive(drive);
}
}
SDL_memset(SDL_mciID, 0, sizeof(SDL_mciID));
return(0);
}
/* General ioctl() CD-ROM command function */
static int SDL_SYS_CDioctl(int id, UINT msg, DWORD flags, void *arg)
{
MCIERROR mci_error;
mci_error = mciSendCommand(SDL_mciID[id], msg, flags, (DWORD_PTR)arg);
if ( mci_error ) {
char error[256];
mciGetErrorString(mci_error, error, 256);
SDL_SetError("mciSendCommand() error: %s", error);
}
return(!mci_error ? 0 : -1);
}
static const char *SDL_SYS_CDName(int drive)
{
return(SDL_cdlist[drive]);
}
static int SDL_SYS_CDOpen(int drive)
{
MCI_OPEN_PARMS mci_open;
MCI_SET_PARMS mci_set;
char device[3];
DWORD flags;
/* Open the requested device */
mci_open.lpstrDeviceType = (LPCSTR) MCI_DEVTYPE_CD_AUDIO;
device[0] = *SDL_cdlist[drive];
device[1] = ':';
device[2] = '\0';
mci_open.lpstrElementName = device;
flags =
(MCI_OPEN_TYPE|MCI_OPEN_SHAREABLE|MCI_OPEN_TYPE_ID|MCI_OPEN_ELEMENT);
if ( SDL_SYS_CDioctl(0, MCI_OPEN, flags, &mci_open) < 0 ) {
flags &= ~MCI_OPEN_SHAREABLE;
if ( SDL_SYS_CDioctl(0, MCI_OPEN, flags, &mci_open) < 0 ) {
return(-1);
}
}
SDL_mciID[drive] = mci_open.wDeviceID;
/* Set the minute-second-frame time format */
mci_set.dwTimeFormat = MCI_FORMAT_MSF;
SDL_SYS_CDioctl(drive, MCI_SET, MCI_SET_TIME_FORMAT, &mci_set);
#ifdef BROKEN_MCI_PAUSE
SDL_paused[drive] = 0;
#endif
return(drive);
}
static int SDL_SYS_CDGetTOC(SDL_CD *cdrom)
{
MCI_STATUS_PARMS mci_status;
int i, okay;
DWORD flags;
okay = 0;
mci_status.dwItem = MCI_STATUS_NUMBER_OF_TRACKS;
flags = MCI_STATUS_ITEM | MCI_WAIT;
if ( SDL_SYS_CDioctl(cdrom->id, MCI_STATUS, flags, &mci_status) == 0 ) {
cdrom->numtracks = mci_status.dwReturn;
if ( cdrom->numtracks > SDL_MAX_TRACKS ) {
cdrom->numtracks = SDL_MAX_TRACKS;
}
/* Read all the track TOC entries */
flags = MCI_STATUS_ITEM | MCI_TRACK | MCI_WAIT;
for ( i=0; i<cdrom->numtracks; ++i ) {
cdrom->track[i].id = i+1;
mci_status.dwTrack = cdrom->track[i].id;
#ifdef MCI_CDA_STATUS_TYPE_TRACK
mci_status.dwItem = MCI_CDA_STATUS_TYPE_TRACK;
if ( SDL_SYS_CDioctl(cdrom->id, MCI_STATUS, flags,
&mci_status) < 0 ) {
break;
}
if ( mci_status.dwReturn == MCI_CDA_TRACK_AUDIO ) {
cdrom->track[i].type = SDL_AUDIO_TRACK;
} else {
cdrom->track[i].type = SDL_DATA_TRACK;
}
#else
cdrom->track[i].type = SDL_AUDIO_TRACK;
#endif
mci_status.dwItem = MCI_STATUS_POSITION;
if ( SDL_SYS_CDioctl(cdrom->id, MCI_STATUS, flags,
&mci_status) < 0 ) {
break;
}
cdrom->track[i].offset = MSF_TO_FRAMES(
MCI_MSF_MINUTE(mci_status.dwReturn),
MCI_MSF_SECOND(mci_status.dwReturn),
MCI_MSF_FRAME(mci_status.dwReturn));
cdrom->track[i].length = 0;
if ( i > 0 ) {
cdrom->track[i-1].length =
cdrom->track[i].offset-
cdrom->track[i-1].offset;
}
}
if ( i == cdrom->numtracks ) {
mci_status.dwTrack = cdrom->track[i - 1].id;
mci_status.dwItem = MCI_STATUS_LENGTH;
if ( SDL_SYS_CDioctl(cdrom->id, MCI_STATUS, flags,
&mci_status) == 0 ) {
cdrom->track[i - 1].length = MSF_TO_FRAMES(
MCI_MSF_MINUTE(mci_status.dwReturn),
MCI_MSF_SECOND(mci_status.dwReturn),
MCI_MSF_FRAME(mci_status.dwReturn));
/* compute lead-out offset */
cdrom->track[i].offset = cdrom->track[i - 1].offset +
cdrom->track[i - 1].length;
cdrom->track[i].length = 0;
okay = 1;
}
}
}
return(okay ? 0 : -1);
}
/* Get CD-ROM status */
static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position)
{
CDstatus status;
MCI_STATUS_PARMS mci_status;
DWORD flags;
flags = MCI_STATUS_ITEM | MCI_WAIT;
mci_status.dwItem = MCI_STATUS_MODE;
if ( SDL_SYS_CDioctl(cdrom->id, MCI_STATUS, flags, &mci_status) < 0 ) {
status = CD_ERROR;
} else {
switch (mci_status.dwReturn) {
case MCI_MODE_NOT_READY:
case MCI_MODE_OPEN:
status = CD_TRAYEMPTY;
break;
case MCI_MODE_STOP:
#ifdef BROKEN_MCI_PAUSE
if ( SDL_paused[cdrom->id] ) {
status = CD_PAUSED;
} else {
status = CD_STOPPED;
}
#else
status = CD_STOPPED;
#endif /* BROKEN_MCI_PAUSE */
break;
case MCI_MODE_PLAY:
#ifdef BROKEN_MCI_PAUSE
if ( SDL_paused[cdrom->id] ) {
status = CD_PAUSED;
} else {
status = CD_PLAYING;
}
#else
status = CD_PLAYING;
#endif /* BROKEN_MCI_PAUSE */
break;
case MCI_MODE_PAUSE:
status = CD_PAUSED;
break;
default:
status = CD_ERROR;
break;
}
}
if ( position ) {
if ( status == CD_PLAYING || (status == CD_PAUSED) ) {
mci_status.dwItem = MCI_STATUS_POSITION;
if ( SDL_SYS_CDioctl(cdrom->id, MCI_STATUS, flags,
&mci_status) == 0 ) {
*position = MSF_TO_FRAMES(
MCI_MSF_MINUTE(mci_status.dwReturn),
MCI_MSF_SECOND(mci_status.dwReturn),
MCI_MSF_FRAME(mci_status.dwReturn));
} else {
*position = 0;
}
} else {
*position = 0;
}
}
return(status);
}
/* Start play */
static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length)
{
MCI_PLAY_PARMS mci_play;
int m, s, f;
DWORD flags;
flags = MCI_FROM | MCI_TO | MCI_NOTIFY;
mci_play.dwCallback = 0;
FRAMES_TO_MSF(start, &m, &s, &f);
mci_play.dwFrom = MCI_MAKE_MSF(m, s, f);
FRAMES_TO_MSF(start+length, &m, &s, &f);
mci_play.dwTo = MCI_MAKE_MSF(m, s, f);
SDL_CD_end_position = mci_play.dwTo;
return(SDL_SYS_CDioctl(cdrom->id, MCI_PLAY, flags, &mci_play));
}
/* Pause play */
static int SDL_SYS_CDPause(SDL_CD *cdrom)
{
#ifdef BROKEN_MCI_PAUSE
SDL_paused[cdrom->id] = 1;
#endif
return(SDL_SYS_CDioctl(cdrom->id, MCI_PAUSE, MCI_WAIT, NULL));
}
/* Resume play */
static int SDL_SYS_CDResume(SDL_CD *cdrom)
{
#ifdef BROKEN_MCI_PAUSE
MCI_STATUS_PARMS mci_status;
int okay;
int flags;
okay = 0;
/* Play from the current play position to the end position set earlier */
flags = MCI_STATUS_ITEM | MCI_WAIT;
mci_status.dwItem = MCI_STATUS_POSITION;
if ( SDL_SYS_CDioctl(cdrom->id, MCI_STATUS, flags, &mci_status) == 0 ) {
MCI_PLAY_PARMS mci_play;
flags = MCI_FROM | MCI_TO | MCI_NOTIFY;
mci_play.dwCallback = 0;
mci_play.dwFrom = mci_status.dwReturn;
mci_play.dwTo = SDL_CD_end_position;
if (SDL_SYS_CDioctl(cdrom->id,MCI_PLAY,flags,&mci_play) == 0) {
okay = 1;
SDL_paused[cdrom->id] = 0;
}
}
return(okay ? 0 : -1);
#else
return(SDL_SYS_CDioctl(cdrom->id, MCI_RESUME, MCI_WAIT, NULL));
#endif /* BROKEN_MCI_PAUSE */
}
/* Stop play */
static int SDL_SYS_CDStop(SDL_CD *cdrom)
{
return(SDL_SYS_CDioctl(cdrom->id, MCI_STOP, MCI_WAIT, NULL));
}
/* Eject the CD-ROM */
static int SDL_SYS_CDEject(SDL_CD *cdrom)
{
return(SDL_SYS_CDioctl(cdrom->id, MCI_SET, MCI_SET_DOOR_OPEN, NULL));
}
/* Close the CD-ROM handle */
static void SDL_SYS_CDClose(SDL_CD *cdrom)
{
SDL_SYS_CDioctl(cdrom->id, MCI_CLOSE, MCI_WAIT, NULL);
}
void SDL_SYS_CDQuit(void)
{
int i;
if ( SDL_numcds > 0 ) {
for ( i=0; i<SDL_numcds; ++i ) {
SDL_free(SDL_cdlist[i]);
SDL_cdlist[i] = NULL;
}
SDL_numcds = 0;
}
}
#endif /* SDL_CDROM_WIN32 */

View file

@ -1,438 +0,0 @@
GNU LIBRARY GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the library GPL. It is
numbered 2 because it goes with version 2 of the ordinary GPL.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Library General Public License, applies to some
specially designated Free Software Foundation software, and to any
other libraries whose authors decide to use it. You can use it for
your libraries, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if
you distribute copies of the library, or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link a program with the library, you must provide
complete object files to the recipients so that they can relink them
with the library, after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
Our method of protecting your rights has two steps: (1) copyright
the library, and (2) offer you this license which gives you legal
permission to copy, distribute and/or modify the library.
Also, for each distributor's protection, we want to make certain
that everyone understands that there is no warranty for this free
library. If the library is modified by someone else and passed on, we
want its recipients to know that what they have is not the original
version, so that any problems introduced by others will not reflect on
the original authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that companies distributing free
software will individually obtain patent licenses, thus in effect
transforming the program into proprietary software. To prevent this,
we have made it clear that any patent must be licensed for everyone's
free use or not licensed at all.
Most GNU software, including some libraries, is covered by the ordinary
GNU General Public License, which was designed for utility programs. This
license, the GNU Library General Public License, applies to certain
designated libraries. This license is quite different from the ordinary
one; be sure to read it in full, and don't assume that anything in it is
the same as in the ordinary license.
The reason we have a separate public license for some libraries is that
they blur the distinction we usually make between modifying or adding to a
program and simply using it. Linking a program with a library, without
changing the library, is in some sense simply using the library, and is
analogous to running a utility program or application program. However, in
a textual and legal sense, the linked executable is a combined work, a
derivative of the original library, and the ordinary General Public License
treats it as such.
Because of this blurred distinction, using the ordinary General
Public License for libraries did not effectively promote software
sharing, because most developers did not use the libraries. We
concluded that weaker conditions might promote sharing better.
However, unrestricted linking of non-free programs would deprive the
users of those programs of all benefit from the free status of the
libraries themselves. This Library General Public License is intended to
permit developers of non-free programs to use free libraries, while
preserving your freedom as a user of such programs to change the free
libraries that are incorporated in them. (We have not seen how to achieve
this as regards changes in header files, but we have achieved it as regards
changes in the actual functions of the Library.) The hope is that this
will lead to faster development of free libraries.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, while the latter only
works together with the library.
Note that it is possible for a library to be covered by the ordinary
General Public License rather than by this special one.
GNU LIBRARY GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library which
contains a notice placed by the copyright holder or other authorized
party saying it may be distributed under the terms of this Library
General Public License (also called "this License"). Each licensee is
addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also compile or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
c) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
d) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the source code distributed need not include anything that is normally
distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Library General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS

View file

@ -1,100 +0,0 @@
/*
Header definitions for the MMX routines for the HERMES library
Copyright (c) 1998 Christian Nentwich (c.nentwich@cs.ucl.ac.uk)
This source code is licensed under the GNU LGPL
Please refer to the file COPYING.LIB contained in the distribution for
licensing conditions
*/
#include "SDL_config.h"
#ifndef __HERMES_HEAD_MMX__
#define __HERMES_HEAD_MMX__
/* If you cannot stand ifdefs, then please do not look into this file, it's
going to end your life :) */
#ifdef X86_ASSEMBLER
#ifdef __cplusplus
extern "C" {
#endif
void STACKCALL ConvertMMX(HermesConverterInterface *);
void STACKCALL ClearMMX_32(HermesClearInterface *);
void STACKCALL ClearMMX_24(HermesClearInterface *);
void STACKCALL ClearMMX_16(HermesClearInterface *);
void STACKCALL ClearMMX_8(HermesClearInterface *);
void ConvertMMXpII32_24RGB888();
void ConvertMMXpII32_16RGB565();
void ConvertMMXpII32_16BGR565();
void ConvertMMXpII32_16RGB555();
void ConvertMMXpII32_16BGR565();
void ConvertMMXpII32_16BGR555();
void ConvertMMXp32_16RGB555();
#ifdef __cplusplus
}
#endif
/* Fix the underscore business with ELF compilers */
#if (defined(__ELF__) && defined(__GNUC__)) || defined(__SUNPRO_C)
#ifdef __cplusplus
extern "C" {
#endif
extern void _ConvertMMX(HermesConverterInterface *);
extern void _ConvertMMXpII32_24RGB888();
extern void _ConvertMMXpII32_16RGB565();
extern void _ConvertMMXpII32_16BGR565();
extern void _ConvertMMXpII32_16RGB555();
extern void _ConvertMMXpII32_16BGR555();
#define ConvertMMX _ConvertMMX
#define ConvertMMXpII32_24RGB888 _ConvertMMXpII32_24RGB888
#define ConvertMMXpII32_16RGB565 _ConvertMMXpII32_16RGB565
#define ConvertMMXpII32_16BGR565 _ConvertMMXpII32_16BGR565
#define ConvertMMXpII32_16RGB555 _ConvertMMXpII32_16RGB555
#define ConvertMMXpII32_16BGR555 _ConvertMMXpII32_16BGR555
#ifdef __cplusplus
}
#endif
#endif /* ELF and GNUC */
/* Make it work with Watcom */
#ifdef __WATCOMC__
#pragma warning 601 9
#pragma aux ConvertMMX "_*" modify [EAX EBX ECX EDX ESI EDI]
#pragma aux ClearMMX_32 "_*" modify [EAX EBX ECX EDX ESI EDI]
#pragma aux ClearMMX_24 "_*" modify [EAX EBX ECX EDX ESI EDI]
#pragma aux ClearMMX_16 "_*" modify [EAX EBX ECX EDX ESI EDI]
#pragma aux ClearMMX_8 "_*" modify [EAX EBX ECX EDX ESI EDI]
#pragma aux ConvertMMXpII32_24RGB888 "_*"
#pragma aux ConvertMMXpII32_16RGB565 "_*"
#pragma aux ConvertMMXpII32_16BGR565 "_*"
#pragma aux ConvertMMXpII32_16RGB555 "_*"
#pragma aux ConvertMMXpII32_16BGR555 "_*"
#pragma aux ConvertMMXp32_16RGB555 "_*"
#endif /* WATCOM */
#endif /* X86_ASSEMBLER */
#endif

View file

@ -1,186 +0,0 @@
/*
Header definitions for the x86 routines for the HERMES library
Copyright (c) 1998 Christian Nentwich (brn@eleet.mcb.at)
This source code is licensed under the GNU LGPL
Please refer to the file COPYING.LIB contained in the distribution for
licensing conditions
*/
#ifndef __HERMES_HEAD_X86__
#define __HERMES_HEAD_X86__
#ifdef X86_ASSEMBLER
/* If you can't stand IFDEFS, then close your eyes now, please :) */
/* Ok, we start with normal function definitions */
#ifdef __cplusplus
extern "C" {
#endif
void STACKCALL ConvertX86(HermesConverterInterface *);
void STACKCALL ClearX86_32(HermesClearInterface *);
void STACKCALL ClearX86_24(HermesClearInterface *);
void STACKCALL ClearX86_16(HermesClearInterface *);
void STACKCALL ClearX86_8(HermesClearInterface *);
int STACKCALL Hermes_X86_CPU();
void ConvertX86p32_32BGR888();
void ConvertX86p32_32RGBA888();
void ConvertX86p32_32BGRA888();
void ConvertX86p32_24RGB888();
void ConvertX86p32_24BGR888();
void ConvertX86p32_16RGB565();
void ConvertX86p32_16BGR565();
void ConvertX86p32_16RGB555();
void ConvertX86p32_16BGR555();
void ConvertX86p32_8RGB332();
void ConvertX86p16_32RGB888();
void ConvertX86p16_32BGR888();
void ConvertX86p16_32RGBA888();
void ConvertX86p16_32BGRA888();
void ConvertX86p16_24RGB888();
void ConvertX86p16_24BGR888();
void ConvertX86p16_16BGR565();
void ConvertX86p16_16RGB555();
void ConvertX86p16_16BGR555();
void ConvertX86p16_8RGB332();
void CopyX86p_4byte();
void CopyX86p_3byte();
void CopyX86p_2byte();
void CopyX86p_1byte();
void ConvertX86pI8_32();
void ConvertX86pI8_24();
void ConvertX86pI8_16();
extern int ConvertX86p16_32RGB888_LUT_X86[512];
extern int ConvertX86p16_32BGR888_LUT_X86[512];
extern int ConvertX86p16_32RGBA888_LUT_X86[512];
extern int ConvertX86p16_32BGRA888_LUT_X86[512];
#ifdef __cplusplus
}
#endif
/* Now fix up the ELF underscore problem */
#if (defined(__ELF__) && defined(__GNUC__)) || defined(__SUNPRO_C)
#ifdef __cplusplus
extern "C" {
#endif
extern int _Hermes_X86_CPU();
extern void _ConvertX86(HermesConverterInterface *);
extern void _ConvertX86p32_32BGR888();
extern void _ConvertX86p32_32RGBA888();
extern void _ConvertX86p32_32BGRA888();
extern void _ConvertX86p32_24RGB888();
extern void _ConvertX86p32_24BGR888();
extern void _ConvertX86p32_16RGB565();
extern void _ConvertX86p32_16BGR565();
extern void _ConvertX86p32_16RGB555();
extern void _ConvertX86p32_16BGR555();
extern void _ConvertX86p32_8RGB332();
extern void _ConvertX86p16_16BGR565();
extern void _ConvertX86p16_16RGB555();
extern void _ConvertX86p16_16BGR555();
extern void _ConvertX86p16_8RGB332();
#define Hermes_X86_CPU _Hermes_X86_CPU
#define ConvertX86 _ConvertX86
#define ConvertX86p32_32BGR888 _ConvertX86p32_32BGR888
#define ConvertX86p32_32RGBA888 _ConvertX86p32_32RGBA888
#define ConvertX86p32_32BGRA888 _ConvertX86p32_32BGRA888
#define ConvertX86p32_24RGB888 _ConvertX86p32_24RGB888
#define ConvertX86p32_24BGR888 _ConvertX86p32_24BGR888
#define ConvertX86p32_16RGB565 _ConvertX86p32_16RGB565
#define ConvertX86p32_16BGR565 _ConvertX86p32_16BGR565
#define ConvertX86p32_16RGB555 _ConvertX86p32_16RGB555
#define ConvertX86p32_16BGR555 _ConvertX86p32_16BGR555
#define ConvertX86p32_8RGB332 _ConvertX86p32_8RGB332
#define ConvertX86p16_16BGR565 _ConvertX86p16_16BGR565
#define ConvertX86p16_16RGB555 _ConvertX86p16_16RGB555
#define ConvertX86p16_16BGR555 _ConvertX86p16_16BGR555
#define ConvertX86p16_8RGB332 _ConvertX86p16_8RGB332
#ifdef __cplusplus
}
#endif
#endif /* ELF & GNU */
/* Make it run with WATCOM C */
#ifdef __WATCOMC__
#pragma warning 601 9
#pragma aux Hermes_X86_CPU "_*"
#pragma aux ConvertX86 "_*" modify [EAX EBX ECX EDX ESI EDI]
#pragma aux ClearX86_32 "_*" modify [EAX EBX ECX EDX ESI EDI]
#pragma aux ClearX86_24 "_*" modify [EAX EBX ECX EDX ESI EDI]
#pragma aux ClearX86_16 "_*" modify [EAX EBX ECX EDX ESI EDI]
#pragma aux ClearX86_8 "_*" modify [EAX EBX ECX EDX ESI EDI]
#pragma aux ConvertX86p32_32BGR888 "_*"
#pragma aux ConvertX86p32_32RGBA888 "_*"
#pragma aux ConvertX86p32_32BGRA888 "_*"
#pragma aux ConvertX86p32_24RGB888 "_*"
#pragma aux ConvertX86p32_24BGR888 "_*"
#pragma aux ConvertX86p32_16RGB565 "_*"
#pragma aux ConvertX86p32_16BGR565 "_*"
#pragma aux ConvertX86p32_16RGB555 "_*"
#pragma aux ConvertX86p32_16BGR555 "_*"
#pragma aux ConvertX86p32_8RGB332 "_*"
#pragma aux ConvertX86p16_32RGB888 "_*"
#pragma aux ConvertX86p16_32BGR888 "_*"
#pragma aux ConvertX86p16_32RGBA888 "_*"
#pragma aux ConvertX86p16_32BGRA888 "_*"
#pragma aux ConvertX86p16_24RGB888 "_*"
#pragma aux ConvertX86p16_24BGR888 "_*"
#pragma aux ConvertX86p16_16BGR565 "_*"
#pragma aux ConvertX86p16_16RGB555 "_*"
#pragma aux ConvertX86p16_16BGR555 "_*"
#pragma aux ConvertX86p16_8RGB332 "_*"
#pragma aux CopyX86p_4byte "_*"
#pragma aux CopyX86p_3byte "_*"
#pragma aux CopyX86p_2byte "_*"
#pragma aux CopyX86p_1byte "_*"
#pragma aux ConvertX86pI8_32 "_*"
#pragma aux ConvertX86pI8_24 "_*"
#pragma aux ConvertX86pI8_16 "_*"
#pragma aux ConvertX86p16_32RGB888_LUT_X86 "_*"
#pragma aux ConvertX86p16_32BGR888_LUT_X86 "_*"
#pragma aux ConvertX86p16_32RGBA888_LUT_X86 "_*"
#pragma aux ConvertX86p16_32BGRA888_LUT_X86 "_*"
#endif /* __WATCOMC__ */
#endif /* X86_ASSEMBLER */
#endif

View file

@ -1,13 +0,0 @@
HERMES 1.2.4 (c)1998 Christian Nentwich (brn) (c.nentwich@cs.ucl.ac.uk)
and quite a few assembler routines (c) Glenn Fielder (gaffer@gaffer.org)
This library and all the files enclosed in this package are free software
under the terms of the GNU Library General Public License (LGPL). Please
refer to the included file COPYING.LIB for the exact terms.
----------------------------------------------------------------------------
This is a stripped down version of HERMES, including only the x86 assembler
converters, for use with Simple DirectMedia Layer.
The full HERMES library is available at: http://hermes.terminal.at/

View file

@ -1,9 +0,0 @@
; Some common macros for hermes nasm code
%macro SDL_FUNC 1
%ifdef HIDDEN_VISIBILITY
GLOBAL %1:function hidden
%else
GLOBAL %1
%endif
%endmacro

View file

@ -1,74 +0,0 @@
;
; mmx format converter main loops for HERMES
; Some routines Copyright (c) 1998 Christian Nentwich (c.nentwich@cs.ucl.ac.uk)
; This source code is licensed under the GNU LGPL
;
; Please refer to the file COPYING.LIB contained in the distribution for
; licensing conditions
;
BITS 32
%include "common.inc"
SDL_FUNC _ConvertMMX
SECTION .text
;; _ConvertMMX:
;; [ESP+8] ConverterInfo*
;; --------------------------------------------------------------------------
;; ConverterInfo (ebp+..)
;; 0: void *s_pixels
;; 4: int s_width
;; 8: int s_height
;; 12: int s_add
;; 16: void *d_pixels
;; 20: int d_width
;; 24: int d_height
;; 28: int d_add
;; 32: void (*converter_function)()
;; 36: int32 *lookup
_ConvertMMX:
push ebp
mov ebp,esp
; Save the registers used by the blitters, necessary for optimized code
pusha
mov eax,[ebp+8]
cmp dword [eax+4],BYTE 0
je endconvert
mov ebp,eax
mov esi,[ebp+0]
mov edi,[ebp+16]
y_loop:
mov ecx,[ebp+4]
call [ebp+32]
add esi,[ebp+12]
add edi,[ebp+28]
dec dword [ebp+8]
jnz y_loop
; Restore the registers used by the blitters, necessary for optimized code
popa
pop ebp
endconvert:
emms
ret
%ifidn __OUTPUT_FORMAT__,elf32
section .note.GNU-stack noalloc noexec nowrite progbits
%endif

View file

@ -1,405 +0,0 @@
;
; pII-optimised MMX format converters for HERMES
; Copyright (c) 1998 Christian Nentwich (c.nentwich@cs.ucl.ac.uk)
; and (c) 1999 Jonathan Matthew (jmatthew@uq.net.au)
; This source code is licensed under the GNU LGPL
;
; Please refer to the file COPYING.LIB contained in the distribution for
; licensing conditions
;
; COPYRIGHT NOTICE
;
; This file partly contains code that is (c) Intel Corporation, specifically
; the mode detection routine, and the converter to 15 bit (8 pixel
; conversion routine from the mmx programming tutorial pages).
;
;
; These routines aren't exactly pII optimised - it's just that as they
; are, they're terrible on p5 MMXs, but less so on pIIs. Someone needs to
; optimise them for p5 MMXs..
BITS 32
%include "common.inc"
SDL_FUNC _ConvertMMXpII32_24RGB888
SDL_FUNC _ConvertMMXpII32_16RGB565
SDL_FUNC _ConvertMMXpII32_16BGR565
SDL_FUNC _ConvertMMXpII32_16RGB555
SDL_FUNC _ConvertMMXpII32_16BGR555
;; Macros for conversion routines
%macro _push_immq_mask 1
push dword %1
push dword %1
%endmacro
%macro load_immq 2
_push_immq_mask %2
movq %1, [esp]
%endmacro
%macro pand_immq 2
_push_immq_mask %2
pand %1, [esp]
%endmacro
%define CLEANUP_IMMQ_LOADS(num) \
add esp, byte 8 * num
%define mmx32_rgb888_mask 00ffffffh
%define mmx32_rgb565_b 000000f8h
%define mmx32_rgb565_g 0000fc00h
%define mmx32_rgb565_r 00f80000h
%define mmx32_rgb555_rb 00f800f8h
%define mmx32_rgb555_g 0000f800h
%define mmx32_rgb555_mul 20000008h
%define mmx32_bgr555_mul 00082000h
SECTION .text
_ConvertMMXpII32_24RGB888:
; set up mm6 as the mask, mm7 as zero
load_immq mm6, mmx32_rgb888_mask
CLEANUP_IMMQ_LOADS(1)
pxor mm7, mm7
mov edx, ecx ; save ecx
and ecx, 0fffffffch ; clear lower two bits
jnz .L1
jmp .L2
.L1:
movq mm0, [esi] ; A R G B a r g b
pand mm0, mm6 ; 0 R G B 0 r g b
movq mm1, [esi+8] ; A R G B a r g b
pand mm1, mm6 ; 0 R G B 0 r g b
movq mm2, mm0 ; 0 R G B 0 r g b
punpckhdq mm2, mm7 ; 0 0 0 0 0 R G B
punpckldq mm0, mm7 ; 0 0 0 0 0 r g b
psllq mm2, 24 ; 0 0 R G B 0 0 0
por mm0, mm2 ; 0 0 R G B r g b
movq mm3, mm1 ; 0 R G B 0 r g b
psllq mm3, 48 ; g b 0 0 0 0 0 0
por mm0, mm3 ; g b R G B r g b
movq mm4, mm1 ; 0 R G B 0 r g b
punpckhdq mm4, mm7 ; 0 0 0 0 0 R G B
punpckldq mm1, mm7 ; 0 0 0 0 0 r g b
psrlq mm1, 16 ; 0 0 0 R G B 0 r
psllq mm4, 8 ; 0 0 0 0 R G B 0
por mm1, mm4 ; 0 0 0 0 R G B r
movq [edi], mm0
add esi, BYTE 16
movd [edi+8], mm1
add edi, BYTE 12
sub ecx, BYTE 4
jnz .L1
.L2:
mov ecx, edx
and ecx, BYTE 3
jz .L4
.L3:
mov al, [esi]
mov bl, [esi+1]
mov dl, [esi+2]
mov [edi], al
mov [edi+1], bl
mov [edi+2], dl
add esi, BYTE 4
add edi, BYTE 3
dec ecx
jnz .L3
.L4:
retn
_ConvertMMXpII32_16RGB565:
; set up masks
load_immq mm5, mmx32_rgb565_b
load_immq mm6, mmx32_rgb565_g
load_immq mm7, mmx32_rgb565_r
CLEANUP_IMMQ_LOADS(3)
mov edx, ecx
shr ecx, 2
jnz .L1
jmp .L2 ; not necessary at the moment, but doesn't hurt (much)
.L1:
movq mm0, [esi] ; argb
movq mm1, mm0 ; argb
pand mm0, mm6 ; 00g0
movq mm3, mm1 ; argb
pand mm1, mm5 ; 000b
pand mm3, mm7 ; 0r00
pslld mm1, 2 ; 0 0 000000bb bbb00000
por mm0, mm1 ; 0 0 ggggggbb bbb00000
psrld mm0, 5 ; 0 0 00000ggg gggbbbbb
movq mm4, [esi+8] ; argb
movq mm2, mm4 ; argb
pand mm4, mm6 ; 00g0
movq mm1, mm2 ; argb
pand mm2, mm5 ; 000b
pand mm1, mm7 ; 0r00
pslld mm2, 2 ; 0 0 000000bb bbb00000
por mm4, mm2 ; 0 0 ggggggbb bbb00000
psrld mm4, 5 ; 0 0 00000ggg gggbbbbb
packuswb mm3, mm1 ; R 0 r 0
packssdw mm0, mm4 ; as above.. ish
por mm0, mm3 ; done.
movq [edi], mm0
add esi, 16
add edi, 8
dec ecx
jnz .L1
.L2:
mov ecx, edx
and ecx, BYTE 3
jz .L4
.L3:
mov al, [esi]
mov bh, [esi+1]
mov ah, [esi+2]
shr al, 3
and eax, 0F81Fh ; BYTE?
shr ebx, 5
and ebx, 07E0h ; BYTE?
add eax, ebx
mov [edi], al
mov [edi+1], ah
add esi, BYTE 4
add edi, BYTE 2
dec ecx
jnz .L3
.L4:
retn
_ConvertMMXpII32_16BGR565:
load_immq mm5, mmx32_rgb565_r
load_immq mm6, mmx32_rgb565_g
load_immq mm7, mmx32_rgb565_b
CLEANUP_IMMQ_LOADS(3)
mov edx, ecx
shr ecx, 2
jnz .L1
jmp .L2
.L1:
movq mm0, [esi] ; a r g b
movq mm1, mm0 ; a r g b
pand mm0, mm6 ; 0 0 g 0
movq mm3, mm1 ; a r g b
pand mm1, mm5 ; 0 r 0 0
pand mm3, mm7 ; 0 0 0 b
psllq mm3, 16 ; 0 b 0 0
psrld mm1, 14 ; 0 0 000000rr rrr00000
por mm0, mm1 ; 0 0 ggggggrr rrr00000
psrld mm0, 5 ; 0 0 00000ggg gggrrrrr
movq mm4, [esi+8] ; a r g b
movq mm2, mm4 ; a r g b
pand mm4, mm6 ; 0 0 g 0
movq mm1, mm2 ; a r g b
pand mm2, mm5 ; 0 r 0 0
pand mm1, mm7 ; 0 0 0 b
psllq mm1, 16 ; 0 b 0 0
psrld mm2, 14 ; 0 0 000000rr rrr00000
por mm4, mm2 ; 0 0 ggggggrr rrr00000
psrld mm4, 5 ; 0 0 00000ggg gggrrrrr
packuswb mm3, mm1 ; BBBBB000 00000000 bbbbb000 00000000
packssdw mm0, mm4 ; 00000GGG GGGRRRRR 00000GGG GGGRRRRR
por mm0, mm3 ; BBBBBGGG GGGRRRRR bbbbbggg gggrrrrr
movq [edi], mm0
add esi, BYTE 16
add edi, BYTE 8
dec ecx
jnz .L1
.L2:
and edx, BYTE 3
jz .L4
.L3:
mov al, [esi+2]
mov bh, [esi+1]
mov ah, [esi]
shr al, 3
and eax, 0F81Fh ; BYTE ?
shr ebx, 5
and ebx, 07E0h ; BYTE ?
add eax, ebx
mov [edi], al
mov [edi+1], ah
add esi, BYTE 4
add edi, BYTE 2
dec edx
jnz .L3
.L4:
retn
_ConvertMMXpII32_16BGR555:
; the 16BGR555 converter is identical to the RGB555 one,
; except it uses a different multiplier for the pmaddwd
; instruction. cool huh.
load_immq mm7, mmx32_bgr555_mul
jmp _convert_bgr555_cheat
; This is the same as the Intel version.. they obviously went to
; much more trouble to expand/coil the loop than I did, so theirs
; would almost certainly be faster, even if only a little.
; I did rename 'mmx32_rgb555_add' to 'mmx32_rgb555_mul', which is
; (I think) a more accurate name..
_ConvertMMXpII32_16RGB555:
load_immq mm7, mmx32_rgb555_mul
_convert_bgr555_cheat:
load_immq mm6, mmx32_rgb555_g
CLEANUP_IMMQ_LOADS(2)
mov edx,ecx ; Save ecx
and ecx,DWORD 0fffffff8h ; clear lower three bits
jnz .L_OK
jmp near .L2
.L_OK:
movq mm2,[esi+8]
movq mm0,[esi]
movq mm3,mm2
pand_immq mm3, mmx32_rgb555_rb
movq mm1,mm0
pand_immq mm1, mmx32_rgb555_rb
pmaddwd mm3,mm7
CLEANUP_IMMQ_LOADS(2)
pmaddwd mm1,mm7
pand mm2,mm6
.L1:
movq mm4,[esi+24]
pand mm0,mm6
movq mm5,[esi+16]
por mm3,mm2
psrld mm3,6
por mm1,mm0
movq mm0,mm4
psrld mm1,6
pand_immq mm0, mmx32_rgb555_rb
packssdw mm1,mm3
movq mm3,mm5
pmaddwd mm0,mm7
pand_immq mm3, mmx32_rgb555_rb
pand mm4,mm6
movq [edi],mm1
pmaddwd mm3,mm7
add esi,BYTE 32
por mm4,mm0
pand mm5,mm6
psrld mm4,6
movq mm2,[esi+8]
por mm5,mm3
movq mm0,[esi]
psrld mm5,6
movq mm3,mm2
movq mm1,mm0
pand_immq mm3, mmx32_rgb555_rb
packssdw mm5,mm4
pand_immq mm1, mmx32_rgb555_rb
pand mm2,mm6
CLEANUP_IMMQ_LOADS(4)
movq [edi+8],mm5
pmaddwd mm3,mm7
pmaddwd mm1,mm7
add edi,BYTE 16
sub ecx,BYTE 8
jz .L2
jmp .L1
.L2:
mov ecx,edx
and ecx,BYTE 7
jz .L4
.L3:
mov ebx,[esi]
add esi,BYTE 4
mov eax,ebx
mov edx,ebx
shr eax,3
shr edx,6
and eax,BYTE 0000000000011111b
and edx, 0000001111100000b
shr ebx,9
or eax,edx
and ebx, 0111110000000000b
or eax,ebx
mov [edi],ax
add edi,BYTE 2
dec ecx
jnz .L3
.L4:
retn
%ifidn __OUTPUT_FORMAT__,elf32
section .note.GNU-stack noalloc noexec nowrite progbits
%endif

View file

@ -1,75 +0,0 @@
;
; x86 format converters for HERMES
; Some routines Copyright (c) 1998 Christian Nentwich (brn@eleet.mcb.at)
; This source code is licensed under the GNU LGPL
;
; Please refer to the file COPYING.LIB contained in the distribution for
; licensing conditions
;
; Most routines are (c) Glenn Fiedler (ptc@gaffer.org), used with permission
;
BITS 32
%include "common.inc"
SDL_FUNC _ConvertX86
SECTION .text
;; _ConvertX86:
;; [ESP+8] ConverterInfo*
;; --------------------------------------------------------------------------
;; ConverterInfo (ebp+..)
;; 0: void *s_pixels
;; 4: int s_width
;; 8: int s_height
;; 12: int s_add
;; 16: void *d_pixels
;; 20: int d_width
;; 24: int d_height
;; 28: int d_add
;; 32: void (*converter_function)()
;; 36: int32 *lookup
_ConvertX86:
push ebp
mov ebp,esp
; Save the registers used by the blitters, necessary for optimized code
pusha
mov eax,[ebp+8]
cmp dword [eax+4],BYTE 0
je endconvert
mov ebp,eax
mov esi,[ebp+0]
mov edi,[ebp+16]
y_loop:
mov ecx,[ebp+4]
call [ebp+32]
add esi,[ebp+12]
add edi,[ebp+28]
dec dword [ebp+8]
jnz y_loop
; Restore the registers used by the blitters, necessary for optimized code
popa
pop ebp
endconvert:
ret
%ifidn __OUTPUT_FORMAT__,elf32
section .note.GNU-stack noalloc noexec nowrite progbits
%endif

View file

@ -1,490 +0,0 @@
;
; x86 format converters for HERMES
; Copyright (c) 1998 Glenn Fielder (gaffer@gaffer.org)
; This source code is licensed under the GNU LGPL
;
; Please refer to the file COPYING.LIB contained in the distribution for
; licensing conditions
;
; Routines adjusted for Hermes by Christian Nentwich (brn@eleet.mcb.at)
; Used with permission.
;
BITS 32
%include "common.inc"
SDL_FUNC _ConvertX86p16_16BGR565
SDL_FUNC _ConvertX86p16_16RGB555
SDL_FUNC _ConvertX86p16_16BGR555
SDL_FUNC _ConvertX86p16_8RGB332
EXTERN _ConvertX86
SECTION .text
_ConvertX86p16_16BGR565:
; check short
cmp ecx,BYTE 16
ja .L3
.L1: ; short loop
mov al,[esi]
mov ah,[esi+1]
mov ebx,eax
mov edx,eax
shr eax,11
and eax,BYTE 11111b
and ebx,11111100000b
shl edx,11
add eax,ebx
add eax,edx
mov [edi],al
mov [edi+1],ah
add esi,BYTE 2
add edi,BYTE 2
dec ecx
jnz .L1
.L2:
retn
.L3: ; head
mov eax,edi
and eax,BYTE 11b
jz .L4
mov al,[esi]
mov ah,[esi+1]
mov ebx,eax
mov edx,eax
shr eax,11
and eax,BYTE 11111b
and ebx,11111100000b
shl edx,11
add eax,ebx
add eax,edx
mov [edi],al
mov [edi+1],ah
add esi,BYTE 2
add edi,BYTE 2
dec ecx
.L4: ; save count
push ecx
; unroll twice
shr ecx,1
; point arrays to end
lea esi,[esi+ecx*4]
lea edi,[edi+ecx*4]
; negative counter
neg ecx
jmp SHORT .L6
.L5: mov [edi+ecx*4-4],eax
.L6: mov eax,[esi+ecx*4]
mov ebx,[esi+ecx*4]
and eax,07E007E0h
mov edx,[esi+ecx*4]
and ebx,0F800F800h
shr ebx,11
and edx,001F001Fh
shl edx,11
add eax,ebx
add eax,edx
inc ecx
jnz .L5
mov [edi+ecx*4-4],eax
; tail
pop ecx
and ecx,BYTE 1
jz .L7
mov al,[esi]
mov ah,[esi+1]
mov ebx,eax
mov edx,eax
shr eax,11
and eax,BYTE 11111b
and ebx,11111100000b
shl edx,11
add eax,ebx
add eax,edx
mov [edi],al
mov [edi+1],ah
add esi,BYTE 2
add edi,BYTE 2
.L7:
retn
_ConvertX86p16_16RGB555:
; check short
cmp ecx,BYTE 32
ja .L3
.L1: ; short loop
mov al,[esi]
mov ah,[esi+1]
mov ebx,eax
shr ebx,1
and ebx, 0111111111100000b
and eax,BYTE 0000000000011111b
add eax,ebx
mov [edi],al
mov [edi+1],ah
add esi,BYTE 2
add edi,BYTE 2
dec ecx
jnz .L1
.L2:
retn
.L3: ; head
mov eax,edi
and eax,BYTE 11b
jz .L4
mov al,[esi]
mov ah,[esi+1]
mov ebx,eax
shr ebx,1
and ebx, 0111111111100000b
and eax,BYTE 0000000000011111b
add eax,ebx
mov [edi],al
mov [edi+1],ah
add esi,BYTE 2
add edi,BYTE 2
dec ecx
.L4: ; save ebp
push ebp
; save count
push ecx
; unroll four times
shr ecx,2
; point arrays to end
lea esi,[esi+ecx*8]
lea edi,[edi+ecx*8]
; negative counter
xor ebp,ebp
sub ebp,ecx
.L5: mov eax,[esi+ebp*8] ; agi?
mov ecx,[esi+ebp*8+4]
mov ebx,eax
mov edx,ecx
and eax,0FFC0FFC0h
and ecx,0FFC0FFC0h
shr eax,1
and ebx,001F001Fh
shr ecx,1
and edx,001F001Fh
add eax,ebx
add ecx,edx
mov [edi+ebp*8],eax
mov [edi+ebp*8+4],ecx
inc ebp
jnz .L5
; tail
pop ecx
.L6: and ecx,BYTE 11b
jz .L7
mov al,[esi]
mov ah,[esi+1]
mov ebx,eax
shr ebx,1
and ebx, 0111111111100000b
and eax,BYTE 0000000000011111b
add eax,ebx
mov [edi],al
mov [edi+1],ah
add esi,BYTE 2
add edi,BYTE 2
dec ecx
jmp SHORT .L6
.L7: pop ebp
retn
_ConvertX86p16_16BGR555:
; check short
cmp ecx,BYTE 16
ja .L3
.L1: ; short loop
mov al,[esi]
mov ah,[esi+1]
mov ebx,eax
mov edx,eax
shr eax,11
and eax,BYTE 11111b
shr ebx,1
and ebx,1111100000b
shl edx,10
and edx,0111110000000000b
add eax,ebx
add eax,edx
mov [edi],al
mov [edi+1],ah
add esi,BYTE 2
add edi,BYTE 2
dec ecx
jnz .L1
.L2:
retn
.L3: ; head
mov eax,edi
and eax,BYTE 11b
jz .L4
mov al,[esi]
mov ah,[esi+1]
mov ebx,eax
mov edx,eax
shr eax,11
and eax,BYTE 11111b
shr ebx,1
and ebx,1111100000b
shl edx,10
and edx,0111110000000000b
add eax,ebx
add eax,edx
mov [edi],al
mov [edi+1],ah
add esi,BYTE 2
add edi,BYTE 2
dec ecx
.L4: ; save count
push ecx
; unroll twice
shr ecx,1
; point arrays to end
lea esi,[esi+ecx*4]
lea edi,[edi+ecx*4]
; negative counter
neg ecx
jmp SHORT .L6
.L5: mov [edi+ecx*4-4],eax
.L6: mov eax,[esi+ecx*4]
shr eax,1
mov ebx,[esi+ecx*4]
and eax,03E003E0h
mov edx,[esi+ecx*4]
and ebx,0F800F800h
shr ebx,11
and edx,001F001Fh
shl edx,10
add eax,ebx
add eax,edx
inc ecx
jnz .L5
mov [edi+ecx*4-4],eax
; tail
pop ecx
and ecx,BYTE 1
jz .L7
mov al,[esi]
mov ah,[esi+1]
mov ebx,eax
mov edx,eax
shr eax,11
and eax,BYTE 11111b
shr ebx,1
and ebx,1111100000b
shl edx,10
and edx,0111110000000000b
add eax,ebx
add eax,edx
mov [edi],al
mov [edi+1],ah
add esi,BYTE 2
add edi,BYTE 2
.L7:
retn
_ConvertX86p16_8RGB332:
; check short
cmp ecx,BYTE 16
ja .L3
.L1: ; short loop
mov al,[esi+0]
mov ah,[esi+1]
mov ebx,eax
mov edx,eax
and eax,BYTE 11000b ; blue
shr eax,3
and ebx,11100000000b ; green
shr ebx,6
and edx,1110000000000000b ; red
shr edx,8
add eax,ebx
add eax,edx
mov [edi],al
add esi,BYTE 2
inc edi
dec ecx
jnz .L1
.L2:
retn
.L3: mov eax,edi
and eax,BYTE 11b
jz .L4
mov al,[esi+0]
mov ah,[esi+1]
mov ebx,eax
mov edx,eax
and eax,BYTE 11000b ; blue
shr eax,3
and ebx,11100000000b ; green
shr ebx,6
and edx,1110000000000000b ; red
shr edx,8
add eax,ebx
add eax,edx
mov [edi],al
add esi,BYTE 2
inc edi
dec ecx
jmp SHORT .L3
.L4: ; save ebp
push ebp
; save count
push ecx
; unroll 4 times
shr ecx,2
; prestep
mov dl,[esi+0]
mov bl,[esi+1]
mov dh,[esi+2]
.L5: shl edx,16
mov bh,[esi+3]
shl ebx,16
mov dl,[esi+4]
mov dh,[esi+6]
mov bl,[esi+5]
and edx,00011000000110000001100000011000b
mov bh,[esi+7]
ror edx,16+3
mov eax,ebx ; setup eax for reds
and ebx,00000111000001110000011100000111b
and eax,11100000111000001110000011100000b ; reds
ror ebx,16-2
add esi,BYTE 8
ror eax,16
add edi,BYTE 4
add eax,ebx
mov bl,[esi+1] ; greens
add eax,edx
mov dl,[esi+0] ; blues
mov [edi-4],eax
mov dh,[esi+2]
dec ecx
jnz .L5
; check tail
pop ecx
and ecx,BYTE 11b
jz .L7
.L6: ; tail
mov al,[esi+0]
mov ah,[esi+1]
mov ebx,eax
mov edx,eax
and eax,BYTE 11000b ; blue
shr eax,3
and ebx,11100000000b ; green
shr ebx,6
and edx,1110000000000000b ; red
shr edx,8
add eax,ebx
add eax,edx
mov [edi],al
add esi,BYTE 2
inc edi
dec ecx
jnz .L6
.L7: pop ebp
retn
%ifidn __OUTPUT_FORMAT__,elf32
section .note.GNU-stack noalloc noexec nowrite progbits
%endif

File diff suppressed because it is too large Load diff

Some files were not shown because too many files have changed in this diff Show more