2022-07-28 19:54:00 +02:00
|
|
|
#define TSF_IMPLEMENTATION
|
|
|
|
|
2022-07-28 13:43:10 +02:00
|
|
|
#include <AL/al.h>
|
|
|
|
#include <AL/alc.h>
|
|
|
|
#include <AL/alext.h>
|
|
|
|
#include <AL/alut.h>
|
2022-07-28 19:54:00 +02:00
|
|
|
#include <stdarg.h>
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <unistd.h>
|
2022-07-28 13:43:10 +02:00
|
|
|
|
2022-07-28 19:54:00 +02:00
|
|
|
#include "segaapi.h"
|
2022-07-28 13:43:10 +02:00
|
|
|
#include "segadef.h"
|
|
|
|
#include "segaeax.h"
|
|
|
|
#include "tsf.h"
|
|
|
|
|
2022-10-11 13:16:48 +02:00
|
|
|
//#define DEBUG_OUTPUT
|
2022-07-28 13:43:10 +02:00
|
|
|
|
|
|
|
const GUID EAX_NULL_GUID;
|
|
|
|
const GUID EAX_FREQUENCYSHIFTER_EFFECT;
|
|
|
|
const GUID EAX_ECHO_EFFECT;
|
|
|
|
const GUID EAX_REVERB_EFFECT;
|
|
|
|
const GUID EAX_EQUALIZER_EFFECT;
|
|
|
|
const GUID EAX_DISTORTION_EFFECT;
|
|
|
|
const GUID EAX_AGCCOMPRESSOR_EFFECT;
|
|
|
|
const GUID EAX_PITCHSHIFTER_EFFECT;
|
|
|
|
const GUID EAX_FLANGER_EFFECT;
|
|
|
|
const GUID EAX_VOCALMORPHER_EFFECT;
|
|
|
|
const GUID EAX_AUTOWAH_EFFECT;
|
|
|
|
const GUID EAX_RINGMODULATOR_EFFECT;
|
|
|
|
const GUID EAX_CHORUS_EFFECT;
|
|
|
|
|
|
|
|
const GUID EAXPROPERTYID_EAX40_FXSlot0;
|
|
|
|
const GUID EAXPROPERTYID_EAX40_FXSlot1;
|
|
|
|
const GUID EAXPROPERTYID_EAX40_FXSlot2;
|
|
|
|
const GUID EAXPROPERTYID_EAX40_FXSlot3;
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
{
|
2022-10-05 15:20:36 +02:00
|
|
|
// SEGA API Parts
|
2022-07-28 13:43:10 +02:00
|
|
|
void *userData;
|
|
|
|
HAWOSEGABUFFERCALLBACK callback;
|
|
|
|
bool synthesizer;
|
|
|
|
bool loop;
|
|
|
|
unsigned int channels;
|
|
|
|
unsigned int startLoop;
|
|
|
|
unsigned int endLoop;
|
|
|
|
unsigned int endOffset;
|
|
|
|
unsigned int sampleRate;
|
|
|
|
unsigned int sampleFormat;
|
|
|
|
uint8_t *data;
|
|
|
|
size_t size;
|
|
|
|
bool playing;
|
|
|
|
bool paused;
|
|
|
|
|
2022-10-05 15:20:36 +02:00
|
|
|
// OpenAL Parts
|
2022-07-28 13:43:10 +02:00
|
|
|
ALuint alBuffer;
|
|
|
|
ALuint alSource;
|
|
|
|
|
2022-10-05 15:20:36 +02:00
|
|
|
// TinySoundFont Parts
|
2022-07-28 13:43:10 +02:00
|
|
|
tsf *synth;
|
|
|
|
struct tsf_region *region;
|
2022-10-11 13:16:48 +02:00
|
|
|
} SEGAContext;
|
2022-07-28 13:43:10 +02:00
|
|
|
|
|
|
|
#ifdef DEBUG_OUTPUT
|
|
|
|
void dbgPrint(const char *format, ...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
va_start(args, format);
|
|
|
|
vprintf(format, args);
|
|
|
|
va_end(args);
|
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
void dbgPrint(const char *format, ...)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
ALsizei FramesToBytes(ALsizei size, ALenum channels, ALenum type)
|
|
|
|
{
|
2022-07-28 13:59:04 +02:00
|
|
|
switch (channels)
|
|
|
|
{
|
|
|
|
case AL_MONO_SOFT:
|
|
|
|
size *= 1;
|
|
|
|
break;
|
|
|
|
case AL_STEREO_SOFT:
|
|
|
|
size *= 2;
|
|
|
|
break;
|
|
|
|
case AL_REAR_SOFT:
|
|
|
|
size *= 2;
|
|
|
|
break;
|
|
|
|
case AL_QUAD_SOFT:
|
|
|
|
size *= 4;
|
|
|
|
break;
|
|
|
|
case AL_5POINT1_SOFT:
|
|
|
|
size *= 6;
|
|
|
|
break;
|
|
|
|
case AL_6POINT1_SOFT:
|
|
|
|
size *= 7;
|
|
|
|
break;
|
|
|
|
case AL_7POINT1_SOFT:
|
|
|
|
size *= 8;
|
|
|
|
break;
|
|
|
|
}
|
2022-07-28 13:43:10 +02:00
|
|
|
|
2022-07-28 13:59:04 +02:00
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case AL_BYTE_SOFT:
|
|
|
|
size *= sizeof(ALbyte);
|
|
|
|
break;
|
|
|
|
case AL_UNSIGNED_BYTE_SOFT:
|
|
|
|
size *= sizeof(ALubyte);
|
|
|
|
break;
|
|
|
|
case AL_SHORT_SOFT:
|
|
|
|
size *= sizeof(ALshort);
|
|
|
|
break;
|
|
|
|
case AL_UNSIGNED_SHORT_SOFT:
|
|
|
|
size *= sizeof(ALushort);
|
|
|
|
break;
|
|
|
|
case AL_INT_SOFT:
|
|
|
|
size *= sizeof(ALint);
|
|
|
|
break;
|
|
|
|
case AL_UNSIGNED_INT_SOFT:
|
|
|
|
size *= sizeof(ALuint);
|
|
|
|
break;
|
|
|
|
case AL_FLOAT_SOFT:
|
|
|
|
size *= sizeof(ALfloat);
|
|
|
|
break;
|
|
|
|
case AL_DOUBLE_SOFT:
|
|
|
|
size *= sizeof(ALdouble);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return size;
|
|
|
|
}
|
2022-07-28 13:43:10 +02:00
|
|
|
|
2022-10-11 13:16:48 +02:00
|
|
|
static unsigned int bufferSampleSize(SEGAContext *context)
|
2022-10-05 15:20:36 +02:00
|
|
|
{
|
2022-07-28 13:43:10 +02:00
|
|
|
return context->channels * ((context->sampleFormat == HASF_SIGNED_16PCM) ? 2 : 1);
|
|
|
|
}
|
|
|
|
|
2022-10-11 13:16:48 +02:00
|
|
|
static void updateBufferLoop(SEGAContext *context)
|
2022-10-05 15:20:36 +02:00
|
|
|
{
|
2022-10-09 23:10:30 +02:00
|
|
|
return;
|
2022-07-28 13:43:10 +02:00
|
|
|
if (context == NULL)
|
|
|
|
return;
|
2022-10-05 15:20:36 +02:00
|
|
|
|
2022-07-28 13:43:10 +02:00
|
|
|
unsigned int sampleSize = bufferSampleSize(context);
|
|
|
|
alSourcei(context->alSource, AL_BUFFER, AL_NONE);
|
2022-10-05 15:20:36 +02:00
|
|
|
|
2022-07-28 13:43:10 +02:00
|
|
|
/*
|
|
|
|
FIXME: Re-enable, only crashed before - so fix this too..
|
|
|
|
ALint loopPoints[] = { buffer->startLoop / sampleSize, buffer->endLoop / sampleSize };
|
|
|
|
alBufferiv(buffer->alBuffer,AL_LOOP_POINTS_SOFT,loopPoints);
|
|
|
|
CHECK();
|
|
|
|
*/
|
2022-08-02 13:12:27 +02:00
|
|
|
}
|
|
|
|
|
2022-10-11 13:16:48 +02:00
|
|
|
static void updateBufferData(SEGAContext *context, unsigned int offset, size_t length)
|
2022-07-28 13:43:10 +02:00
|
|
|
{
|
|
|
|
|
|
|
|
ALenum alFormat = -1;
|
|
|
|
ALenum alChannels = -1;
|
|
|
|
ALenum alType;
|
|
|
|
|
|
|
|
switch (context->sampleFormat)
|
|
|
|
{
|
|
|
|
case HASF_UNSIGNED_8PCM: /* Unsigned (offset 128) 8-bit PCM */
|
|
|
|
alType = AL_BYTE_SOFT;
|
|
|
|
switch (context->channels)
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
alFormat = AL_MONO8_SOFT;
|
|
|
|
alChannels = AL_MONO_SOFT;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
alFormat = AL_STEREO8_SOFT;
|
|
|
|
alChannels = AL_STEREO_SOFT;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case HASF_SIGNED_16PCM: /* Signed 16-bit PCM */
|
|
|
|
alType = AL_SHORT_SOFT;
|
|
|
|
switch (context->channels)
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
alFormat = AL_MONO16_SOFT;
|
|
|
|
alChannels = AL_MONO_SOFT;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
alFormat = AL_STEREO16_SOFT;
|
|
|
|
alChannels = AL_STEREO_SOFT;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2022-10-05 15:20:36 +02:00
|
|
|
|
2022-07-28 13:43:10 +02:00
|
|
|
if (alFormat == -1)
|
|
|
|
{
|
2022-10-11 13:16:48 +02:00
|
|
|
printf("SEGAAPI: Unknown format! 0x%X with %u channels!\n", context->sampleFormat, context->channels);
|
2022-10-05 15:20:36 +02:00
|
|
|
abort();
|
2022-07-28 13:43:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (offset != -1)
|
|
|
|
{
|
|
|
|
|
2022-10-09 23:10:30 +02:00
|
|
|
unsigned int sampleSize = bufferSampleSize(context);
|
2022-07-28 13:43:10 +02:00
|
|
|
|
2022-10-05 15:20:36 +02:00
|
|
|
ALint position;
|
2022-10-09 23:10:30 +02:00
|
|
|
alGetSourcei(context->alSource, AL_SAMPLE_OFFSET, &position);
|
|
|
|
|
2022-07-28 13:43:10 +02:00
|
|
|
alSourcei(context->alSource, AL_BUFFER, AL_NONE);
|
2022-10-09 23:10:30 +02:00
|
|
|
// alBufferData(context->alBuffer, alFormat, context->data + (offset / sampleSize), FramesToBytes(context->size / bufferSampleSize(context), alChannels, alType), context->sampleRate);
|
2022-10-05 15:20:36 +02:00
|
|
|
alBufferData(context->alBuffer, alFormat, context->data, FramesToBytes(context->size / bufferSampleSize(context), alChannels, alType), context->sampleRate);
|
2022-07-28 13:43:10 +02:00
|
|
|
alSourcei(context->alSource, AL_BUFFER, context->alBuffer);
|
2022-10-09 23:10:30 +02:00
|
|
|
alSourcei(context->alSource, AL_SAMPLE_OFFSET, position);
|
2022-10-05 15:20:36 +02:00
|
|
|
return;
|
2022-07-28 13:43:10 +02:00
|
|
|
}
|
2022-10-05 15:20:36 +02:00
|
|
|
|
|
|
|
alSourcei(context->alSource, AL_BUFFER, AL_NONE);
|
|
|
|
alBufferData(context->alBuffer, alFormat, context->data, FramesToBytes(context->size / bufferSampleSize(context), alChannels, alType), context->sampleRate);
|
|
|
|
alSourcei(context->alSource, AL_BUFFER, context->alBuffer);
|
2022-10-11 13:16:48 +02:00
|
|
|
|
2022-10-05 15:20:36 +02:00
|
|
|
// updateBufferLoop(context);
|
2022-07-28 13:43:10 +02:00
|
|
|
}
|
|
|
|
|
2022-10-11 13:16:48 +02:00
|
|
|
static void resetBuffer(SEGAContext *context)
|
2022-07-28 13:43:10 +02:00
|
|
|
{ // printf("%s %d\n", __func__, __LINE__);
|
|
|
|
// * - Send Routing
|
|
|
|
// * - for 1 channel buffer, channel is routed to Front-Left and Front-Right.
|
|
|
|
// * - for 2 channel buffer, channel 0 is routed Front-Left, channel 1 is routed Front-Right
|
|
|
|
// * - Send Levels are set to 0 (infinite attenuation)
|
|
|
|
// * - Channel Volume is set to 0xFFFFFFFF (no attenuation)
|
|
|
|
// * - No notification.
|
|
|
|
// * - StartLoopOffset is set to 0.
|
|
|
|
// * - EndLoopOffset and EndOffset are set to pConfig->mapdata.dwSize.
|
2022-10-11 13:16:48 +02:00
|
|
|
// * - No loop.
|
|
|
|
|
|
|
|
context->startLoop = 0;
|
2022-07-28 13:43:10 +02:00
|
|
|
context->endOffset = context->size;
|
|
|
|
context->endLoop = context->size;
|
|
|
|
context->loop = false;
|
|
|
|
context->paused = false;
|
|
|
|
|
|
|
|
tsf *res = (tsf *)TSF_MALLOC(sizeof(tsf));
|
|
|
|
TSF_MEMSET(res, 0, sizeof(tsf));
|
|
|
|
res->presetNum = 0;
|
|
|
|
res->outSampleRate = context->sampleRate;
|
|
|
|
|
|
|
|
context->synth = res;
|
|
|
|
|
|
|
|
struct tsf_region *region = malloc(sizeof(struct tsf_region));
|
|
|
|
memset(region, 0, sizeof(struct tsf_region));
|
|
|
|
|
|
|
|
tsf_region_clear(region, 0);
|
|
|
|
|
|
|
|
region->ampenv.delay = 0;
|
|
|
|
region->ampenv.hold = 300.0f;
|
|
|
|
region->ampenv.attack = 0;
|
|
|
|
region->ampenv.decay = 0;
|
|
|
|
region->ampenv.release = 0;
|
|
|
|
region->ampenv.sustain = 0;
|
|
|
|
|
|
|
|
context->region = region;
|
|
|
|
|
|
|
|
// * - Buffer is in the stop state.
|
|
|
|
// * - Play position is set to 0.
|
|
|
|
updateBufferData(context, -1, -1);
|
|
|
|
}
|
|
|
|
|
2022-08-02 13:12:27 +02:00
|
|
|
int SEGAAPI_Play(void *hHandle)
|
2022-07-28 13:43:10 +02:00
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_Play() 0x%x", hHandle);
|
2022-10-05 15:20:36 +02:00
|
|
|
|
2022-10-11 13:16:48 +02:00
|
|
|
SEGAContext *context = hHandle;
|
2022-07-28 13:43:10 +02:00
|
|
|
if (context == NULL)
|
|
|
|
return SEGAERR_BAD_PARAM;
|
|
|
|
|
2022-10-09 23:10:30 +02:00
|
|
|
// alSourcei(context->alSource, AL_LOOPING, context->loop ? AL_TRUE : AL_FALSE);
|
|
|
|
alSourcei(context->alSource, AL_LOOPING, AL_FALSE);
|
2022-07-28 13:43:10 +02:00
|
|
|
alSourcei(context->alSource, AL_BUFFER, context->alBuffer);
|
|
|
|
alSourcePlay(context->alSource);
|
|
|
|
return SEGA_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2022-08-02 13:12:27 +02:00
|
|
|
int SEGAAPI_Pause(void *hHandle)
|
2022-07-28 13:43:10 +02:00
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_Pause() 0x%x", hHandle);
|
2022-10-11 13:16:48 +02:00
|
|
|
SEGAContext *context = hHandle;
|
2022-07-28 13:43:10 +02:00
|
|
|
if (context == NULL)
|
|
|
|
return SEGAERR_BAD_PARAM;
|
|
|
|
alSourcePause(context->alSource);
|
|
|
|
return SEGA_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2022-08-02 13:12:27 +02:00
|
|
|
int SEGAAPI_Stop(void *hHandle)
|
2022-07-28 13:43:10 +02:00
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_Stop() 0x%x", hHandle);
|
2022-10-11 13:16:48 +02:00
|
|
|
SEGAContext *context = hHandle;
|
2022-07-28 13:43:10 +02:00
|
|
|
if (context == NULL)
|
|
|
|
return SEGAERR_BAD_PARAM;
|
|
|
|
alSourceStop(context->alSource);
|
|
|
|
return SEGA_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2022-08-02 13:12:27 +02:00
|
|
|
int SEGAAPI_PlayWithSetup(void *hHandle)
|
2022-07-28 13:43:10 +02:00
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_PlayWithSetup() 0x%x", hHandle);
|
2022-10-11 13:16:48 +02:00
|
|
|
SEGAContext *context = hHandle;
|
2022-07-28 13:43:10 +02:00
|
|
|
if (context == NULL)
|
|
|
|
return SEGAERR_BAD_PARAM;
|
|
|
|
alSourcei(context->alSource, AL_LOOPING, context->loop ? AL_TRUE : AL_FALSE);
|
|
|
|
alSourcei(context->alSource, AL_BUFFER, context->alBuffer);
|
|
|
|
alSourcePlay(context->alSource);
|
|
|
|
return SEGAERR_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
|
2022-08-02 13:12:27 +02:00
|
|
|
PlaybackStatus SEGAAPI_GetPlaybackStatus(void *hHandle)
|
2022-07-28 13:43:10 +02:00
|
|
|
{
|
|
|
|
ALint state;
|
|
|
|
|
|
|
|
dbgPrint("SEGAAPI_GetPlaybackStatus() 0x%x", hHandle);
|
2022-10-11 13:16:48 +02:00
|
|
|
SEGAContext *context = hHandle;
|
2022-07-28 13:43:10 +02:00
|
|
|
if (context == NULL)
|
2022-07-28 13:59:04 +02:00
|
|
|
return PLAYBACK_STATUS_INVALID;
|
2022-07-28 13:43:10 +02:00
|
|
|
|
|
|
|
alGetSourcei(context->alSource, AL_SOURCE_STATE, &state);
|
|
|
|
switch (state)
|
|
|
|
{
|
|
|
|
case AL_PLAYING:
|
2022-07-28 13:59:04 +02:00
|
|
|
return PLAYBACK_STATUS_ACTIVE;
|
2022-07-28 13:43:10 +02:00
|
|
|
case AL_PAUSED:
|
2022-07-28 13:59:04 +02:00
|
|
|
return PLAYBACK_STATUS_PAUSE;
|
2022-07-28 13:43:10 +02:00
|
|
|
case AL_INITIAL:
|
|
|
|
case AL_STOPPED:
|
2022-07-28 13:59:04 +02:00
|
|
|
return PLAYBACK_STATUS_STOP;
|
2022-07-28 13:43:10 +02:00
|
|
|
default:
|
2022-07-28 13:59:04 +02:00
|
|
|
return PLAYBACK_STATUS_INVALID;
|
2022-07-28 13:43:10 +02:00
|
|
|
}
|
|
|
|
|
2022-07-28 13:59:04 +02:00
|
|
|
return PLAYBACK_STATUS_INVALID;
|
2022-07-28 13:43:10 +02:00
|
|
|
}
|
|
|
|
|
2022-08-02 13:12:27 +02:00
|
|
|
int SEGAAPI_SetFormat(void *hHandle, HAWOSEFORMAT *pFormat)
|
2022-07-28 13:43:10 +02:00
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_SetFormat() 0x%x", hHandle);
|
|
|
|
return SEGAERR_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
|
2022-08-02 13:12:27 +02:00
|
|
|
int SEGAAPI_GetFormat(void *hHandle, HAWOSEFORMAT *pFormat)
|
2022-07-28 13:43:10 +02:00
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_GetFormat() 0x%x", hHandle);
|
|
|
|
return SEGAERR_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
|
2022-08-02 13:12:27 +02:00
|
|
|
int SEGAAPI_SetSampleRate(void *hHandle, unsigned int dwSampleRate)
|
2022-07-28 13:43:10 +02:00
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_SetSampleRate() 0x%x 0x%x", hHandle, dwSampleRate);
|
2022-10-05 15:20:36 +02:00
|
|
|
|
2022-07-28 13:43:10 +02:00
|
|
|
if (hHandle == NULL)
|
|
|
|
return SEGAERR_BAD_HANDLE;
|
2022-10-05 15:20:36 +02:00
|
|
|
|
2022-10-11 13:16:48 +02:00
|
|
|
SEGAContext *context = hHandle;
|
2022-07-28 13:43:10 +02:00
|
|
|
context->sampleRate = dwSampleRate;
|
|
|
|
updateBufferData(context, -1, -1);
|
|
|
|
return SEGA_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2022-08-02 13:12:27 +02:00
|
|
|
unsigned int SEGAAPI_GetSampleRate(void *hHandle)
|
2022-07-28 13:43:10 +02:00
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_GetSampleRate() 0x%x", hHandle);
|
2022-10-11 13:16:48 +02:00
|
|
|
if (hHandle == NULL)
|
|
|
|
return SEGAERR_BAD_HANDLE;
|
|
|
|
|
|
|
|
SEGAContext *context = hHandle;
|
|
|
|
return context->sampleRate;
|
2022-07-28 13:43:10 +02:00
|
|
|
}
|
|
|
|
|
2022-08-02 13:12:27 +02:00
|
|
|
int SEGAAPI_SetPriority(void *hHandle, unsigned int dwPriority)
|
2022-07-28 13:43:10 +02:00
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_SetPriority() 0x%x 0x%x", hHandle, dwPriority);
|
|
|
|
return SEGAERR_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
|
2022-08-02 13:12:27 +02:00
|
|
|
unsigned int SEGAAPI_GetPriority(void *hHandle)
|
2022-07-28 13:43:10 +02:00
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_GetPriority() 0x%x", hHandle);
|
|
|
|
return SEGAERR_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
|
2022-08-02 13:12:27 +02:00
|
|
|
int SEGAAPI_SetUserData(void *hHandle, void *hUserData)
|
2022-07-28 13:43:10 +02:00
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_SetUserData() 0x%x 0x%x", hHandle, hUserData);
|
|
|
|
if (hHandle == NULL)
|
|
|
|
return SEGAERR_BAD_HANDLE;
|
2022-10-11 13:16:48 +02:00
|
|
|
|
|
|
|
SEGAContext *context = hHandle;
|
2022-07-28 13:43:10 +02:00
|
|
|
context->userData = hUserData;
|
|
|
|
return SEGA_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2022-08-02 13:12:27 +02:00
|
|
|
void *SEGAAPI_GetUserData(void *hHandle)
|
2022-07-28 13:43:10 +02:00
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_GetPriority() 0x%x", hHandle);
|
|
|
|
if (hHandle == NULL)
|
|
|
|
return NULL;
|
2022-10-11 13:16:48 +02:00
|
|
|
|
|
|
|
SEGAContext *context = hHandle;
|
2022-07-28 13:43:10 +02:00
|
|
|
return context->userData;
|
|
|
|
}
|
|
|
|
|
2022-08-02 13:12:27 +02:00
|
|
|
int SEGAAPI_SetSendRouting(void *hHandle, unsigned int dwChannel, unsigned int dwSend, HAROUTING dwDest)
|
2022-07-28 13:43:10 +02:00
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_SetSendRouting() 0x%x 0x%x 0x%x 0x%x", hHandle, dwChannel, dwSend, dwDest);
|
|
|
|
return SEGA_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2022-08-02 13:12:27 +02:00
|
|
|
HAROUTING SEGAAPI_GetSendRouting(void *hHandle, unsigned int dwChannel, unsigned int dwSend)
|
2022-07-28 13:43:10 +02:00
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_GetSendRouting() 0x%x 0x%x 0x%x", hHandle, dwChannel, dwSend);
|
|
|
|
return HA_UNUSED_PORT;
|
|
|
|
}
|
|
|
|
|
2022-08-02 13:12:27 +02:00
|
|
|
int SEGAAPI_SetSendLevel(void *hHandle, unsigned int dwChannel, unsigned int dwSend, unsigned int dwLevel)
|
2022-07-28 13:43:10 +02:00
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_SetSendLevel() 0x%x 0x%x 0x%x 0x%x", hHandle, dwChannel, dwSend, dwLevel);
|
|
|
|
return SEGA_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2022-08-02 13:12:27 +02:00
|
|
|
unsigned int SEGAAPI_GetSendLevel(void *hHandle, unsigned int dwChannel, unsigned int dwSend)
|
2022-07-28 13:43:10 +02:00
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_GetSendLevel() 0x%x 0x%x 0x%x", hHandle, dwChannel, dwSend);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-08-02 13:12:27 +02:00
|
|
|
int SEGAAPI_SetChannelVolume(void *hHandle, unsigned int dwChannel, unsigned int dwVolume)
|
2022-07-28 13:43:10 +02:00
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_SetChannelVolume() 0x%x 0x%x 0x%x", hHandle, dwChannel, dwVolume);
|
|
|
|
return SEGAERR_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
|
2022-08-02 13:12:27 +02:00
|
|
|
unsigned int SEGAAPI_GetChannelVolume(void *hHandle, unsigned int dwChannel)
|
2022-07-28 13:43:10 +02:00
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_GetChannelVolume() 0x%x 0x%x", hHandle, dwChannel);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-08-02 13:12:27 +02:00
|
|
|
int SEGAAPI_SetPlaybackPosition(void *hHandle, unsigned int dwPlaybackPos)
|
2022-07-28 13:43:10 +02:00
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_SetPlaybackPosition() 0x%x 0x%x", hHandle, dwPlaybackPos);
|
2022-10-11 13:16:48 +02:00
|
|
|
if (hHandle == NULL)
|
|
|
|
return SEGAERR_BAD_HANDLE;
|
|
|
|
|
|
|
|
SEGAContext *context = hHandle;
|
2022-07-28 13:43:10 +02:00
|
|
|
alSourcei(context->alSource, AL_BYTE_OFFSET, dwPlaybackPos);
|
2022-10-11 13:16:48 +02:00
|
|
|
|
2022-07-28 13:43:10 +02:00
|
|
|
return SEGA_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2022-08-02 13:12:27 +02:00
|
|
|
unsigned int SEGAAPI_GetPlaybackPosition(void *hHandle)
|
2022-07-28 13:43:10 +02:00
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_GetPlaybackPosition() 0x%x", hHandle);
|
2022-10-11 13:16:48 +02:00
|
|
|
|
|
|
|
if (hHandle == NULL)
|
|
|
|
return SEGAERR_BAD_HANDLE;
|
|
|
|
|
|
|
|
SEGAContext *context = hHandle;
|
|
|
|
|
|
|
|
ALint position;
|
2022-07-28 13:43:10 +02:00
|
|
|
alGetSourcei(context->alSource, AL_BYTE_OFFSET, &position);
|
2022-10-11 13:16:48 +02:00
|
|
|
|
2022-07-28 13:43:10 +02:00
|
|
|
return position;
|
|
|
|
}
|
|
|
|
|
2022-08-02 13:12:27 +02:00
|
|
|
int SEGAAPI_SetNotificationFrequency(void *hHandle, unsigned int dwFrameCount)
|
2022-07-28 13:43:10 +02:00
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_SetNotificationFrequency() 0x%x 0x%x", hHandle, dwFrameCount);
|
|
|
|
return SEGAERR_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
|
2022-08-02 13:12:27 +02:00
|
|
|
int SEGAAPI_SetNotificationPoint(void *hHandle, unsigned int dwBufferOffset)
|
2022-07-28 13:43:10 +02:00
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_SetNotificationPoint() 0x%x 0x%x", hHandle, dwBufferOffset);
|
|
|
|
return SEGAERR_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
|
2022-08-02 13:12:27 +02:00
|
|
|
int SEGAAPI_ClearNotificationPoint(void *hHandle, unsigned int dwBufferOffset)
|
2022-07-28 13:43:10 +02:00
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_ClearNotificationPoint() 0x%x 0x%x", hHandle, dwBufferOffset);
|
|
|
|
return SEGAERR_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
|
2022-08-02 13:12:27 +02:00
|
|
|
int SEGAAPI_SetStartLoopOffset(void *hHandle, unsigned int dwOffset)
|
2022-07-28 13:43:10 +02:00
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_SetStartLoopOffset() 0x%x 0x%x", hHandle, dwOffset);
|
|
|
|
if (hHandle == NULL)
|
|
|
|
return SEGAERR_BAD_HANDLE;
|
2022-10-11 13:16:48 +02:00
|
|
|
|
|
|
|
SEGAContext *context = hHandle;
|
|
|
|
|
2022-07-28 13:43:10 +02:00
|
|
|
context->startLoop = dwOffset;
|
|
|
|
updateBufferLoop(context);
|
2022-10-11 13:16:48 +02:00
|
|
|
|
2022-07-28 13:43:10 +02:00
|
|
|
return SEGA_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2022-08-02 13:12:27 +02:00
|
|
|
unsigned int SEGAAPI_GetStartLoopOffset(void *hHandle)
|
2022-07-28 13:43:10 +02:00
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_GetStartLoopOffset() 0x%x", hHandle);
|
2022-10-11 13:16:48 +02:00
|
|
|
if (hHandle == NULL)
|
|
|
|
return SEGAERR_BAD_HANDLE;
|
|
|
|
|
|
|
|
SEGAContext *context = hHandle;
|
|
|
|
|
|
|
|
return context->startLoop;
|
2022-07-28 13:43:10 +02:00
|
|
|
}
|
|
|
|
|
2022-08-02 13:12:27 +02:00
|
|
|
int SEGAAPI_SetEndLoopOffset(void *hHandle, unsigned int dwOffset)
|
2022-07-28 13:43:10 +02:00
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_SetEndLoopOffset() 0x%x 0x%x", hHandle, dwOffset);
|
|
|
|
if (hHandle == NULL)
|
|
|
|
return SEGAERR_BAD_HANDLE;
|
2022-10-11 13:16:48 +02:00
|
|
|
|
|
|
|
SEGAContext *context = hHandle;
|
2022-07-28 13:43:10 +02:00
|
|
|
context->endLoop = dwOffset;
|
|
|
|
updateBufferLoop(context);
|
2022-10-11 13:16:48 +02:00
|
|
|
|
2022-07-28 13:43:10 +02:00
|
|
|
return SEGA_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2022-08-02 13:12:27 +02:00
|
|
|
unsigned int SEGAAPI_GetEndLoopOffset(void *hHandle)
|
2022-07-28 13:43:10 +02:00
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_GetEndLoopOffset() 0x%x", hHandle);
|
2022-10-11 13:16:48 +02:00
|
|
|
if (hHandle == NULL)
|
|
|
|
return SEGAERR_BAD_HANDLE;
|
|
|
|
|
|
|
|
SEGAContext *context = hHandle;
|
|
|
|
|
|
|
|
return context->endLoop;
|
2022-07-28 13:43:10 +02:00
|
|
|
}
|
|
|
|
|
2022-08-02 13:12:27 +02:00
|
|
|
int SEGAAPI_SetEndOffset(void *hHandle, unsigned int dwOffset)
|
2022-07-28 13:43:10 +02:00
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_SetEndOffset() 0x%x 0x%x", hHandle, dwOffset);
|
2022-10-11 13:16:48 +02:00
|
|
|
if (hHandle == NULL)
|
|
|
|
return SEGAERR_BAD_HANDLE;
|
|
|
|
|
|
|
|
SEGAContext *context = hHandle;
|
|
|
|
context->endOffset = dwOffset;
|
|
|
|
|
|
|
|
return SEGA_SUCCESS;
|
2022-07-28 13:43:10 +02:00
|
|
|
}
|
|
|
|
|
2022-08-02 13:12:27 +02:00
|
|
|
unsigned int SEGAAPI_GetEndOffset(void *hHandle)
|
2022-07-28 13:43:10 +02:00
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_GetEndOffset() 0x%x", hHandle);
|
2022-10-11 13:16:48 +02:00
|
|
|
if (hHandle == NULL)
|
|
|
|
return SEGAERR_BAD_HANDLE;
|
|
|
|
|
|
|
|
SEGAContext *context = hHandle;
|
|
|
|
|
|
|
|
return context->endOffset;
|
2022-07-28 13:43:10 +02:00
|
|
|
}
|
|
|
|
|
2022-10-11 13:16:48 +02:00
|
|
|
int SEGAAPI_SetLoopState(void *hHandle, int loop)
|
2022-07-28 13:43:10 +02:00
|
|
|
{
|
2022-10-11 13:16:48 +02:00
|
|
|
dbgPrint("SEGAAPI_SetLoopState() 0x%x 0x%x", hHandle, loop);
|
|
|
|
if (hHandle == NULL)
|
|
|
|
return SEGAERR_BAD_HANDLE;
|
|
|
|
|
|
|
|
SEGAContext *context = hHandle;
|
|
|
|
context->loop = loop;
|
2022-07-28 13:43:10 +02:00
|
|
|
alSourcei(context->alSource, AL_LOOPING, context->loop ? AL_TRUE : AL_FALSE);
|
|
|
|
return SEGA_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2022-08-02 13:12:27 +02:00
|
|
|
int SEGAAPI_GetLoopState(void *hHandle)
|
2022-07-28 13:43:10 +02:00
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_GetLoopState() 0x%x", hHandle);
|
2022-10-11 13:16:48 +02:00
|
|
|
if (hHandle == NULL)
|
|
|
|
return SEGAERR_BAD_HANDLE;
|
|
|
|
|
|
|
|
SEGAContext *context = hHandle;
|
|
|
|
|
|
|
|
return context->loop;
|
2022-07-28 13:43:10 +02:00
|
|
|
}
|
|
|
|
|
2022-08-02 13:12:27 +02:00
|
|
|
int SEGAAPI_UpdateBuffer(void *hHandle, unsigned int dwStartOffset, unsigned int dwLength)
|
2022-07-28 13:43:10 +02:00
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_UpdateBuffer() 0x%x 0x%x 0x%x", hHandle, dwStartOffset, dwLength);
|
|
|
|
if (hHandle == NULL)
|
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_UpdateBuffer() SEGAERR_BAD_HANDLE");
|
|
|
|
return SEGAERR_BAD_HANDLE;
|
|
|
|
}
|
2022-10-11 13:16:48 +02:00
|
|
|
SEGAContext *context = hHandle;
|
2022-07-28 13:43:10 +02:00
|
|
|
updateBufferData(context, dwStartOffset, dwLength);
|
|
|
|
return SEGA_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2022-08-02 13:12:27 +02:00
|
|
|
int SEGAAPI_SetSynthParam(void *hHandle, HASYNTHPARAMSEXT param, int lPARWValue)
|
2022-07-28 13:43:10 +02:00
|
|
|
{
|
|
|
|
float volume;
|
|
|
|
float semiTones;
|
|
|
|
float freqRatio;
|
|
|
|
|
|
|
|
dbgPrint("SEGAAPI_SetSynthParam() 0x%x 0x%x 0x%x", hHandle, param, lPARWValue);
|
|
|
|
|
2022-10-11 13:16:48 +02:00
|
|
|
SEGAContext *context = hHandle;
|
2022-07-28 13:59:04 +02:00
|
|
|
|
2022-07-28 13:43:10 +02:00
|
|
|
if (context == NULL)
|
|
|
|
return SEGAERR_BAD_PARAM;
|
|
|
|
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
StartAddrsOffset,
|
|
|
|
EndAddrsOffset,
|
|
|
|
StartloopAddrsOffset,
|
|
|
|
EndloopAddrsOffset,
|
|
|
|
StartAddrsCoarseOffset,
|
|
|
|
ModLfoToPitch,
|
|
|
|
VibLfoToPitch,
|
|
|
|
ModEnvToPitch,
|
|
|
|
InitialFilterFc,
|
|
|
|
InitialFilterQ,
|
|
|
|
ModLfoToFilterFc,
|
|
|
|
ModEnvToFilterFc,
|
|
|
|
EndAddrsCoarseOffset,
|
|
|
|
ModLfoToVolume,
|
|
|
|
Unused1,
|
|
|
|
ChorusEffectsSend,
|
|
|
|
ReverbEffectsSend,
|
|
|
|
Pan,
|
|
|
|
Unused2,
|
|
|
|
Unused3,
|
|
|
|
Unused4,
|
|
|
|
DelayModLFO,
|
|
|
|
FreqModLFO,
|
|
|
|
DelayVibLFO,
|
|
|
|
FreqVibLFO,
|
|
|
|
DelayModEnv,
|
|
|
|
AttackModEnv,
|
|
|
|
HoldModEnv,
|
|
|
|
DecayModEnv,
|
|
|
|
SustainModEnv,
|
|
|
|
ReleaseModEnv,
|
|
|
|
KeynumToModEnvHold,
|
|
|
|
KeynumToModEnvDecay,
|
|
|
|
DelayVolEnv,
|
|
|
|
AttackVolEnv,
|
|
|
|
HoldVolEnv,
|
|
|
|
DecayVolEnv,
|
|
|
|
SustainVolEnv,
|
|
|
|
ReleaseVolEnv,
|
|
|
|
KeynumToVolEnvHold,
|
|
|
|
KeynumToVolEnvDecay,
|
|
|
|
Instrument,
|
|
|
|
Reserved1,
|
|
|
|
KeyRange,
|
|
|
|
VelRange,
|
|
|
|
StartloopAddrsCoarseOffset,
|
|
|
|
Keynum,
|
|
|
|
Velocity,
|
|
|
|
InitialAttenuation,
|
|
|
|
Reserved2,
|
|
|
|
EndloopAddrsCoarseOffset,
|
|
|
|
CoarseTune,
|
|
|
|
FineTune,
|
|
|
|
SampleID,
|
|
|
|
SampleModes,
|
|
|
|
Reserved3,
|
|
|
|
ScaleTuning,
|
|
|
|
ExclusiveClass,
|
|
|
|
OverridingRootKey,
|
|
|
|
Unused5,
|
|
|
|
EndOper
|
|
|
|
};
|
|
|
|
|
|
|
|
int mapping[26] = {
|
|
|
|
InitialAttenuation, ///< 0, 0x00, initialAttenuation
|
|
|
|
FineTune, ///< 1, 0x01, fineTune + coarseTune * 100
|
|
|
|
InitialFilterFc, ///< 2, 0x02, initialFilterFc
|
|
|
|
InitialFilterQ, ///< 3, 0x03, initialFilterQ
|
|
|
|
DelayVolEnv, ///< 4, 0x04, delayVolEnv
|
|
|
|
AttackVolEnv, ///< 5, 0x05, attackVolEnv
|
|
|
|
HoldVolEnv, ///< 6, 0x06, holdVolEnv
|
|
|
|
DecayVolEnv, ///< 7, 0x07, decayVolEnv
|
|
|
|
SustainVolEnv, ///< 8, 0x08, sustainVolEnv
|
|
|
|
ReleaseVolEnv, ///< 9, 0x09, releaseVolEnv
|
|
|
|
DelayModEnv, ///< 10, 0x0A, delayModEnv
|
|
|
|
AttackModEnv, ///< 11, 0x0B, attackModEnv
|
|
|
|
HoldModEnv, ///< 12, 0x0C, holdModEnv
|
|
|
|
DecayModEnv, ///< 13, 0x0D, decayModEnv
|
|
|
|
SustainModEnv, ///< 14, 0x0E, sustainModEnv
|
|
|
|
ReleaseModEnv, ///< 15, 0x0F, releaseModEnv
|
|
|
|
DelayModLFO, ///< 16, 0x10, delayModLFO
|
|
|
|
FreqModLFO, ///< 17, 0x11, freqModLFO
|
|
|
|
DelayVibLFO, ///< 18, 0x12, delayVibLFO
|
|
|
|
FreqVibLFO, ///< 19, 0x13, freqVibLFO
|
|
|
|
ModLfoToPitch, ///< 20, 0x14, modLfoToPitch
|
|
|
|
VibLfoToPitch, ///< 21, 0x15, vibLfoToPitch
|
|
|
|
ModLfoToFilterFc, ///< 22, 0x16, modLfoToFilterFc
|
|
|
|
ModLfoToVolume, ///< 23, 0x17, modLfoToVolume
|
|
|
|
ModEnvToPitch, ///< 24, 0x18, modEnvToPitch
|
|
|
|
ModEnvToFilterFc ///< 25, 0x19, modEnvToFilterFc
|
|
|
|
};
|
|
|
|
|
|
|
|
int realParam = mapping[param];
|
|
|
|
|
|
|
|
switch (param)
|
|
|
|
{
|
|
|
|
case HAVP_ATTENUATION:
|
|
|
|
volume = tsf_decibelsToGain(0.0f - lPARWValue / 10.0f);
|
|
|
|
alListenerf(AL_GAIN, volume);
|
|
|
|
// buffer->xaVoice->SetVolume(volume);
|
|
|
|
dbgPrint("SEGAAPI_SetSynthParam() HAVP_ATTENUATION gain: %f dB: %d", volume, lPARWValue);
|
|
|
|
break;
|
|
|
|
case HAVP_PITCH:
|
|
|
|
semiTones = lPARWValue / 100.0f;
|
|
|
|
// freqRatio = XAudio2SemitonesToFrequencyRatio(semiTones);
|
|
|
|
// http://www-personal.umich.edu/~bazald/l/api/_x_audio2_8h_source.html
|
|
|
|
freqRatio = powf(2.0f, semiTones / 12.0f);
|
|
|
|
|
|
|
|
// buffer->xaVoice->SetFrequencyRatio(freqRatio);
|
|
|
|
alSourcef(context->alSource, AL_PITCH, freqRatio);
|
|
|
|
dbgPrint("SEGAAPI_SetSynthParam() HAVP_PITCH hHandle: %08X semitones: %f freqRatio: %f", hHandle, semiTones, freqRatio);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
dbgPrint("SEGAAPI_SetSynthParam() unsupported param: 0x%x", param);
|
|
|
|
}
|
|
|
|
|
|
|
|
return SEGAERR_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
|
2022-08-02 13:12:27 +02:00
|
|
|
int SEGAAPI_GetSynthParam(void *hHandle, HASYNTHPARAMSEXT param)
|
2022-07-28 13:43:10 +02:00
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_GetSynthParam() 0x%x 0x%x", hHandle, param);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-08-02 13:12:27 +02:00
|
|
|
int SEGAAPI_SetSynthParamMultiple(void *hHandle, unsigned int dwNumParams, SynthParamSet *pSynthParams)
|
2022-07-28 13:43:10 +02:00
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_SetSynthParamMultiple() 0x%x 0x%x 0x%x", hHandle, dwNumParams, pSynthParams);
|
2022-10-11 13:16:48 +02:00
|
|
|
SEGAContext *context = hHandle;
|
2022-07-28 13:43:10 +02:00
|
|
|
if (context == NULL)
|
|
|
|
return SEGAERR_BAD_PARAM;
|
|
|
|
|
|
|
|
for (int i = 0; i < dwNumParams; i++)
|
|
|
|
{
|
|
|
|
SEGAAPI_SetSynthParam(hHandle, pSynthParams[i].param, pSynthParams[i].lPARWValue);
|
|
|
|
}
|
|
|
|
|
|
|
|
return SEGAERR_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
|
2022-08-02 13:12:27 +02:00
|
|
|
int SEGAAPI_GetSynthParamMultiple(void *hHandle, unsigned int dwNumParams, SynthParamSet *pSynthParams)
|
2022-07-28 13:43:10 +02:00
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_GetSynthParamMultiple() 0x%x 0x%x 0x%x", hHandle, dwNumParams, pSynthParams);
|
|
|
|
return SEGAERR_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
|
2022-08-02 13:12:27 +02:00
|
|
|
int SEGAAPI_SetReleaseState(void *hHandle, int bSet)
|
2022-07-28 13:43:10 +02:00
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_SetReleaseState() 0x%x 0x%x", hHandle, bSet);
|
|
|
|
return SEGAERR_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
|
2022-08-02 13:12:27 +02:00
|
|
|
int SEGAAPI_CreateBuffer(HAWOSEBUFFERCONFIG *pConfig, HAWOSEGABUFFERCALLBACK pCallback, unsigned int dwFlags, void **phHandle)
|
2022-07-28 13:43:10 +02:00
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_CreateBuffer() 0x%x 0x%x 0x%x 0x%x", pConfig, pCallback, dwFlags, phHandle);
|
|
|
|
if ((phHandle == NULL) || (pConfig == NULL))
|
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_CreateBuffer() SEGAERR_BAD_POINTER");
|
|
|
|
return SEGAERR_BAD_POINTER;
|
|
|
|
}
|
2022-10-05 15:20:36 +02:00
|
|
|
|
2022-10-11 13:16:48 +02:00
|
|
|
SEGAContext *context = malloc(sizeof(SEGAContext));
|
2022-07-28 13:43:10 +02:00
|
|
|
if (context == NULL)
|
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_CreateBuffer() SEGAERR_OUT_OF_MEMORY");
|
|
|
|
return SEGAERR_OUT_OF_MEMORY;
|
|
|
|
}
|
2022-10-05 15:20:36 +02:00
|
|
|
|
2022-10-11 13:16:48 +02:00
|
|
|
// dbgPrint("SEGAAPI_CreateBuffer() allocated %i bytes",sizeof(SEGAContext));
|
2022-07-28 13:43:10 +02:00
|
|
|
context->playing = false;
|
|
|
|
context->callback = pCallback;
|
|
|
|
context->synthesizer = dwFlags & HABUF_SYNTH_BUFFER;
|
|
|
|
context->sampleRate = pConfig->dwSampleRate;
|
|
|
|
context->sampleFormat = pConfig->dwSampleFormat;
|
|
|
|
context->channels = pConfig->byNumChans;
|
|
|
|
context->userData = pConfig->hUserData;
|
|
|
|
context->size = pConfig->mapData.dwSize;
|
|
|
|
pConfig->mapData.dwOffset = 0;
|
|
|
|
|
|
|
|
// can't have all 3 types at once - sanity check
|
|
|
|
if ((dwFlags & 0x06) == 0x06)
|
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_CreateBuffer() SEGAERR_BAD_PARAM");
|
|
|
|
free(context);
|
|
|
|
return SEGAERR_BAD_PARAM;
|
|
|
|
}
|
2022-10-11 13:16:48 +02:00
|
|
|
|
2022-07-28 13:43:10 +02:00
|
|
|
// indiate that caller allocate memory
|
|
|
|
if (dwFlags & HABUF_ALLOC_USER_MEM)
|
|
|
|
{
|
|
|
|
context->data = pConfig->mapData.hBufferHdr;
|
|
|
|
dbgPrint("SEGAAPI_CreateBuffer() user memory 0x%x", context->data);
|
|
|
|
}
|
2022-10-11 13:16:48 +02:00
|
|
|
|
2022-07-28 13:43:10 +02:00
|
|
|
// reuse memory
|
|
|
|
else if (dwFlags & HABUF_USE_MAPPED_MEM)
|
|
|
|
{
|
|
|
|
context->data = pConfig->mapData.hBufferHdr;
|
|
|
|
if (context->data == NULL)
|
|
|
|
{
|
|
|
|
// null pointer, allocate memory
|
|
|
|
context->data = malloc(context->size);
|
|
|
|
if (context->data == NULL)
|
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_CreateBuffer() SEGAERR_OUT_OF_MEMORY");
|
|
|
|
return SEGAERR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
dbgPrint("SEGAAPI_CreateBuffer() bad pointer, allocated %i data bytes", context->size);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
dbgPrint("SEGAAPI_CreateBuffer() reusing memory 0x%x", context->data);
|
|
|
|
}
|
|
|
|
// Allocate new buffer (caller will fill it later)
|
|
|
|
else
|
|
|
|
{
|
|
|
|
context->data = malloc(context->size);
|
|
|
|
if (context->data == NULL)
|
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_CreateBuffer() SEGAERR_OUT_OF_MEMORY");
|
|
|
|
return SEGAERR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
dbgPrint("SEGAAPI_CreateBuffer() allocated %i data bytes", context->size);
|
|
|
|
}
|
|
|
|
|
|
|
|
pConfig->mapData.hBufferHdr = context->data;
|
|
|
|
|
|
|
|
alGenBuffers(1, &context->alBuffer);
|
|
|
|
alGenSources(1, &context->alSource);
|
|
|
|
|
|
|
|
/*
|
|
|
|
TODO:
|
|
|
|
* HABUF_ALLOC_USER_MEM bit when set indicates caller allocate sound data memory buffer.
|
|
|
|
* HABUF_USE_MAPPED_MEM
|
|
|
|
Can't be used at the same time!!!
|
|
|
|
*/
|
|
|
|
if (context->synthesizer)
|
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_CreateBuffer() !!! Doesn't support synth buffers yet!");
|
|
|
|
// https://stackoverflow.com/questions/44157238/can-i-produce-a-synthetic-sound-using-openal
|
|
|
|
}
|
|
|
|
|
|
|
|
resetBuffer(context);
|
|
|
|
*phHandle = context;
|
|
|
|
|
|
|
|
return SEGA_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2022-08-02 13:12:27 +02:00
|
|
|
int SEGAAPI_DestroyBuffer(void *hHandle)
|
2022-07-28 13:43:10 +02:00
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_DestroyBuffer() 0x%x", hHandle);
|
|
|
|
if (hHandle == NULL)
|
|
|
|
return SEGAERR_BAD_PARAM;
|
2022-10-11 13:16:48 +02:00
|
|
|
|
2022-07-28 13:43:10 +02:00
|
|
|
free(hHandle);
|
2022-10-11 13:16:48 +02:00
|
|
|
|
2022-07-28 13:43:10 +02:00
|
|
|
return SEGA_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2022-07-28 19:54:00 +02:00
|
|
|
int SEGAAPI_SetGlobalEAXProperty(GUID *guid, unsigned long ulProperty, void *pData, unsigned long ulDataSize)
|
2022-07-28 13:43:10 +02:00
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_SetGlobalEAXProperty() 0x%x 0x%x 0x%x 0x%x", guid, ulProperty, pData, ulDataSize);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-07-28 19:54:00 +02:00
|
|
|
int SEGAAPI_GetGlobalEAXProperty(GUID *guid, unsigned long ulProperty, void *pData, unsigned long ulDataSize)
|
2022-07-28 13:43:10 +02:00
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_GetGlobalEAXProperty() 0x%x 0x%x 0x%x 0x%x", guid, ulProperty, pData, ulDataSize);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-07-28 19:54:00 +02:00
|
|
|
int SEGAAPI_SetSPDIFOutChannelStatus(unsigned int dwChannelStatus, unsigned int dwExtChannelStatus)
|
2022-07-28 13:43:10 +02:00
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_SetSPDIFOutChannelStatus() 0x%x 0x%x", dwChannelStatus, dwExtChannelStatus);
|
|
|
|
return SEGAERR_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
|
2022-07-28 19:54:00 +02:00
|
|
|
int SEGAAPI_GetSPDIFOutChannelStatus(unsigned int *pdwChannelStatus, unsigned int *pdwExtChannelStatus)
|
2022-07-28 13:43:10 +02:00
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_GetSPDIFOutChannelStatus() 0x%x 0x%x", pdwChannelStatus, pdwExtChannelStatus);
|
|
|
|
return SEGAERR_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
|
2022-07-28 19:54:00 +02:00
|
|
|
int SEGAAPI_SetSPDIFOutSampleRate(HASPDIFOUTRATE dwSamplingRate)
|
2022-07-28 13:43:10 +02:00
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_SetSPDIFOutSampleRate() 0x%x", dwSamplingRate);
|
|
|
|
return SEGAERR_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
HASPDIFOUTRATE SEGAAPI_GetSPDIFOutSampleRate(void)
|
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_GetSPDIFOutSampleRate()");
|
|
|
|
return HASPDIFOUT_48KHZ;
|
|
|
|
}
|
|
|
|
|
2022-07-28 19:54:00 +02:00
|
|
|
int SEGAAPI_SetSPDIFOutChannelRouting(unsigned int dwChannel, HAROUTING dwSource)
|
2022-07-28 13:43:10 +02:00
|
|
|
{
|
|
|
|
switch (dwChannel)
|
|
|
|
{
|
|
|
|
case 0: // left
|
|
|
|
dbgPrint("SEGAAPI_SetSPDIFOutChannelRouting() dwChannel = LEFT; dwSource = 0x%x", dwSource);
|
|
|
|
break;
|
|
|
|
case 1: // right
|
|
|
|
dbgPrint("SEGAAPI_SetSPDIFOutChannelRouting() dwChannel = RIGHT; dwSource = 0x%x", dwSource);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
dbgPrint("SEGAAPI_SetSPDIFOutChannelRouting() dwChannel = UNKNOWN; dwSource = 0x%x", dwSource);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return SEGAERR_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
|
2022-07-28 19:54:00 +02:00
|
|
|
HAROUTING SEGAAPI_GetSPDIFOutChannelRouting(unsigned int dwChannel)
|
2022-07-28 13:43:10 +02:00
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_GetSPDIFOutChannelRouting() 0x%x", dwChannel);
|
|
|
|
return HA_UNUSED_PORT;
|
|
|
|
}
|
|
|
|
|
2022-07-28 19:54:00 +02:00
|
|
|
int SEGAAPI_SetIOVolume(HAPHYSICALIO dwPhysIO, unsigned int dwVolume)
|
2022-07-28 13:43:10 +02:00
|
|
|
{
|
|
|
|
// float v = (dwVolume >> 16) & 0xffff;
|
|
|
|
dbgPrint("SEGAAPI_SetIOVolume() 0x%x 0x%x", dwPhysIO, dwVolume);
|
|
|
|
// alListenerf(AL_GAIN, v);
|
|
|
|
return SEGA_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2022-07-28 19:54:00 +02:00
|
|
|
unsigned int SEGAAPI_GetIOVolume(HAPHYSICALIO dwPhysIO)
|
2022-07-28 13:43:10 +02:00
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_GetIOVolume() 0x%x", dwPhysIO);
|
|
|
|
return 0xffffffff;
|
|
|
|
}
|
|
|
|
|
2022-07-28 19:54:00 +02:00
|
|
|
void SEGAAPI_SetLastStatus(int LastStatus)
|
2022-07-28 13:43:10 +02:00
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_SetLastStatus() 0x%x", LastStatus);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-07-28 19:54:00 +02:00
|
|
|
int SEGAAPI_GetLastStatus(void)
|
2022-07-28 13:43:10 +02:00
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_GetLastStatus()");
|
|
|
|
return SEGA_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2022-07-28 19:54:00 +02:00
|
|
|
int SEGAAPI_Reset(void)
|
2022-07-28 13:43:10 +02:00
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_Reset()");
|
|
|
|
return SEGA_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2022-07-28 19:54:00 +02:00
|
|
|
int SEGAAPI_Init(void)
|
2022-07-28 13:43:10 +02:00
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_Init()");
|
|
|
|
|
2022-10-05 15:20:36 +02:00
|
|
|
if (alutInit(NULL, NULL) == AL_FALSE)
|
2022-07-28 13:43:10 +02:00
|
|
|
{
|
2022-10-05 15:20:36 +02:00
|
|
|
dbgPrint("SEGAAPI_Init() alutInit() failed!");
|
2022-07-28 13:43:10 +02:00
|
|
|
return SEGAERR_FAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
SEGAAPI_SetGlobalEAXProperty((GUID *)&EAXPROPERTYID_EAX40_FXSlot2, 0, (void *)&EAX_NULL_GUID, 16);
|
|
|
|
|
|
|
|
return SEGA_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2022-07-28 19:54:00 +02:00
|
|
|
int SEGAAPI_Exit(void)
|
2022-07-28 13:43:10 +02:00
|
|
|
{
|
|
|
|
dbgPrint("SEGAAPI_Exit()");
|
|
|
|
alutExit();
|
|
|
|
return SEGA_SUCCESS;
|
|
|
|
}
|