mirror of
https://github.com/ZDoom/raze-gles.git
synced 2024-12-25 03:00:46 +00:00
audiolib: Introduce support for PlayStation CD-XA audio, a simple ADPCM format.
It's functional, but due to the odd 37.8 KHz nature of the format, I will need to add a resampler to the audiolib to prevent the aliasing artifacts that occur at present. I also hear clicks/pops every so often, but I do not know if a resampler would fix these as well or if they are a separate problem. Note that you cannot directly use the four XA files on the Total Meltdown disc because they each contain eight songs. They would need to be split using a utility I wrote that is outside the scope of this SVN. git-svn-id: https://svn.eduke32.com/eduke32@4268 1a8010ca-5511-0410-912e-c29ae57300e0
This commit is contained in:
parent
fedfcd81e3
commit
b2a3aec334
7 changed files with 546 additions and 1 deletions
|
@ -46,6 +46,7 @@ OBJECTS=$(OBJ)/drivers.o \
|
||||||
$(OBJ)/formats.o \
|
$(OBJ)/formats.o \
|
||||||
$(OBJ)/vorbis.o \
|
$(OBJ)/vorbis.o \
|
||||||
$(OBJ)/flac.o \
|
$(OBJ)/flac.o \
|
||||||
|
$(OBJ)/xa.o \
|
||||||
$(OBJ)/driver_nosound.o
|
$(OBJ)/driver_nosound.o
|
||||||
|
|
||||||
ifeq ($(PLATFORM),DARWIN)
|
ifeq ($(PLATFORM),DARWIN)
|
||||||
|
|
|
@ -35,6 +35,7 @@ OBJECTS=$(OBJ)\drivers.o \
|
||||||
$(OBJ)\pitch.o \
|
$(OBJ)\pitch.o \
|
||||||
$(OBJ)\formats.o \
|
$(OBJ)\formats.o \
|
||||||
$(OBJ)\vorbis.o \
|
$(OBJ)\vorbis.o \
|
||||||
|
$(OBJ)\xa.o \
|
||||||
$(OBJ)\driver_nosound.o \
|
$(OBJ)\driver_nosound.o \
|
||||||
$(OBJ)\driver_directsound.o
|
$(OBJ)\driver_directsound.o
|
||||||
|
|
||||||
|
|
|
@ -229,6 +229,7 @@ void MV_SetVoicePitch ( VoiceNode *voice, uint32_t rate, int32_t pitchoffset );
|
||||||
|
|
||||||
void MV_ReleaseVorbisVoice( VoiceNode * voice );
|
void MV_ReleaseVorbisVoice( VoiceNode * voice );
|
||||||
void MV_ReleaseFLACVoice( VoiceNode * voice );
|
void MV_ReleaseFLACVoice( VoiceNode * voice );
|
||||||
|
void MV_ReleaseXAVoice( VoiceNode * voice );
|
||||||
|
|
||||||
// implemented in mix.c
|
// implemented in mix.c
|
||||||
void ClearBuffer_DW( void *ptr, unsigned data, int32_t length );
|
void ClearBuffer_DW( void *ptr, unsigned data, int32_t length );
|
||||||
|
|
|
@ -885,8 +885,16 @@ static wavedata FX_AutoDetectFormat(const char *ptr, uint32_t length)
|
||||||
return VOC;
|
return VOC;
|
||||||
break;
|
break;
|
||||||
case 'R'+('I'<<8)+('F'<<16)+('F'<<24): // RIFF
|
case 'R'+('I'<<8)+('F'<<16)+('F'<<24): // RIFF
|
||||||
|
switch (LITTLE32(*(int32_t *)(ptr + 8)))
|
||||||
|
{
|
||||||
|
case 'C'+('D'<<8)+('X'<<16)+('A'<<24): // CDXA
|
||||||
|
return XA;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
return WAV;
|
return WAV;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 'O'+('g'<<8)+('g'<<16)+('S'<<24): // OggS
|
case 'O'+('g'<<8)+('g'<<16)+('S'<<24): // OggS
|
||||||
return Vorbis;
|
return Vorbis;
|
||||||
break;
|
break;
|
||||||
|
@ -950,6 +958,9 @@ int32_t FX_PlayLoopedAuto(char *ptr, uint32_t length, int32_t loopstart, int32_t
|
||||||
MV_Printf("FX_PlayLoopedAuto: FLAC support not included in this binary.\n");
|
MV_Printf("FX_PlayLoopedAuto: FLAC support not included in this binary.\n");
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
case XA:
|
||||||
|
handle = MV_PlayXA(ptr, length, loopstart, loopend, pitchoffset, vol, left, right, priority, callbackval);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
MV_Printf("FX_PlayLoopedAuto: Unknown or unsupported format.\n");
|
MV_Printf("FX_PlayLoopedAuto: Unknown or unsupported format.\n");
|
||||||
break;
|
break;
|
||||||
|
@ -998,6 +1009,9 @@ int32_t FX_PlayAuto3D(char *ptr, uint32_t length, int32_t loophow, int32_t pitch
|
||||||
MV_Printf("FX_PlayAuto3D: FLAC support not included in this binary.\n");
|
MV_Printf("FX_PlayAuto3D: FLAC support not included in this binary.\n");
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
case XA:
|
||||||
|
handle = MV_PlayXA3D(ptr, length, loophow, pitchoffset, angle, distance, priority, callbackval);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
MV_Printf("FX_PlayAuto3D: Unknown or unsupported format.\n");
|
MV_Printf("FX_PlayAuto3D: Unknown or unsupported format.\n");
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -183,6 +183,9 @@ const char *MV_ErrorString(int32_t ErrorNumber)
|
||||||
case MV_InvalidFLACFile :
|
case MV_InvalidFLACFile :
|
||||||
return "Invalid FLAC file passed in to Multivoc.";
|
return "Invalid FLAC file passed in to Multivoc.";
|
||||||
|
|
||||||
|
case MV_InvalidXAFile :
|
||||||
|
return "Invalid XA file passed in to Multivoc.";
|
||||||
|
|
||||||
case MV_InvalidMixMode :
|
case MV_InvalidMixMode :
|
||||||
return "Invalid mix mode request in Multivoc.";
|
return "Invalid mix mode request in Multivoc.";
|
||||||
|
|
||||||
|
@ -310,6 +313,8 @@ static void MV_StopVoice(VoiceNode *voice)
|
||||||
if (voice->wavetype == FLAC)
|
if (voice->wavetype == FLAC)
|
||||||
MV_ReleaseFLACVoice(voice);
|
MV_ReleaseFLACVoice(voice);
|
||||||
#endif
|
#endif
|
||||||
|
if (voice->wavetype == XA)
|
||||||
|
MV_ReleaseXAVoice(voice);
|
||||||
|
|
||||||
voice->handle = 0;
|
voice->handle = 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,6 +86,7 @@ typedef enum
|
||||||
WAV,
|
WAV,
|
||||||
Vorbis,
|
Vorbis,
|
||||||
FLAC,
|
FLAC,
|
||||||
|
XA,
|
||||||
} wavedata;
|
} wavedata;
|
||||||
|
|
||||||
#define MV_MINVOICEHANDLE 1
|
#define MV_MINVOICEHANDLE 1
|
||||||
|
@ -107,6 +108,7 @@ enum MV_Errors
|
||||||
MV_InvalidWAVFile,
|
MV_InvalidWAVFile,
|
||||||
MV_InvalidVorbisFile,
|
MV_InvalidVorbisFile,
|
||||||
MV_InvalidFLACFile,
|
MV_InvalidFLACFile,
|
||||||
|
MV_InvalidXAFile,
|
||||||
MV_InvalidMixMode,
|
MV_InvalidMixMode,
|
||||||
MV_NullRecordFunction
|
MV_NullRecordFunction
|
||||||
};
|
};
|
||||||
|
@ -159,6 +161,11 @@ int32_t MV_PlayFLAC3D( char *ptr, uint32_t length, int32_t loophow, int32_t pi
|
||||||
int32_t MV_PlayFLAC( char *ptr, uint32_t length, int32_t loopstart, int32_t loopend,
|
int32_t MV_PlayFLAC( char *ptr, uint32_t length, int32_t loopstart, int32_t loopend,
|
||||||
int32_t pitchoffset, int32_t vol, int32_t left, int32_t right, int32_t priority,
|
int32_t pitchoffset, int32_t vol, int32_t left, int32_t right, int32_t priority,
|
||||||
uint32_t callbackval );
|
uint32_t callbackval );
|
||||||
|
int32_t MV_PlayXA3D( char *ptr, uint32_t length, int32_t loophow, int32_t pitchoffset, int32_t angle, int32_t distance,
|
||||||
|
int32_t priority, uint32_t callbackval );
|
||||||
|
int32_t MV_PlayXA( char *ptr, uint32_t length, int32_t loopstart, int32_t loopend,
|
||||||
|
int32_t pitchoffset, int32_t vol, int32_t left, int32_t right, int32_t priority,
|
||||||
|
uint32_t callbackval );
|
||||||
//void MV_CreateVolumeTable( int32_t index, int32_t volume, int32_t MaxVolume );
|
//void MV_CreateVolumeTable( int32_t index, int32_t volume, int32_t MaxVolume );
|
||||||
void MV_SetVolume( int32_t volume );
|
void MV_SetVolume( int32_t volume );
|
||||||
int32_t MV_GetVolume( void );
|
int32_t MV_GetVolume( void );
|
||||||
|
|
516
polymer/eduke32/source/jaudiolib/src/xa.c
Normal file
516
polymer/eduke32/source/jaudiolib/src/xa.c
Normal file
|
@ -0,0 +1,516 @@
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PlayStation XA (ADPCM) source support for MultiVoc
|
||||||
|
* Adapted and remixed from superxa2wav
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "pitch.h"
|
||||||
|
#include "multivoc.h"
|
||||||
|
#include "_multivc.h"
|
||||||
|
|
||||||
|
//#define NO_XA_HEADER
|
||||||
|
|
||||||
|
#define USE_FXD 1
|
||||||
|
|
||||||
|
#define kNumOfSamples 224
|
||||||
|
#define kNumOfSGs 18
|
||||||
|
#define TTYWidth 80
|
||||||
|
|
||||||
|
#ifndef max
|
||||||
|
# define max(a,b) ( ((a) > (b)) ? (a) : (b))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef min
|
||||||
|
# define min(a,b) ( ((a) < (b)) ? (a) : (b))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* ADPCM */
|
||||||
|
#define XA_DATA_START (0x44-48)
|
||||||
|
|
||||||
|
#define FXD_FxdToPCM(dt) (max(min((short)((dt)>>16), 32767), -32768))
|
||||||
|
#define DblToPCM(dt) (short)(max(min((dt), 32767), -32768))
|
||||||
|
|
||||||
|
#if USE_FXD
|
||||||
|
#define FXD_FxdToPcm16(dt) (max(min((dt)/2, 32767), -32768))
|
||||||
|
#define FXD_Pcm16ToFxd(dt) ((int32_t)dt*2)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
void * ptr;
|
||||||
|
size_t length;
|
||||||
|
size_t pos;
|
||||||
|
|
||||||
|
#if USE_FXD
|
||||||
|
int32_t t1, t2;
|
||||||
|
int32_t t1_x, t2_x;
|
||||||
|
#else
|
||||||
|
double t1, t2;
|
||||||
|
double t1_x, t2_x;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
char *block;
|
||||||
|
size_t blocksize;
|
||||||
|
|
||||||
|
VoiceNode *owner;
|
||||||
|
} xa_data;
|
||||||
|
|
||||||
|
typedef char SoundGroup[128];
|
||||||
|
|
||||||
|
typedef struct XASector {
|
||||||
|
char sectorFiller[48];
|
||||||
|
SoundGroup SoundGroups[18];
|
||||||
|
} XASector;
|
||||||
|
|
||||||
|
#if USE_FXD
|
||||||
|
static int32_t K0[4] = {
|
||||||
|
0x00000000,
|
||||||
|
0x0000F000,
|
||||||
|
0x0001CC00,
|
||||||
|
0x00018800,
|
||||||
|
};
|
||||||
|
static int32_t K1[4] = {
|
||||||
|
0x00000000,
|
||||||
|
0x00000000,
|
||||||
|
-53248, // 0xFFFF3000,
|
||||||
|
-56320, // 0xFFFF2400,
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
static double K0[4] = {
|
||||||
|
0.0,
|
||||||
|
0.9375,
|
||||||
|
1.796875,
|
||||||
|
1.53125
|
||||||
|
};
|
||||||
|
static double K1[4] = {
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
-0.8125,
|
||||||
|
-0.859375
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if USE_FXD
|
||||||
|
static int32_t FXD_FixMul(int32_t a, int32_t b)
|
||||||
|
{
|
||||||
|
int32_t high_a, low_a, high_b, low_b;
|
||||||
|
int32_t hahb, halb, lahb;
|
||||||
|
uint32_t lalb;
|
||||||
|
int32_t ret;
|
||||||
|
|
||||||
|
high_a = a >> 16;
|
||||||
|
low_a = a & 0x0000FFFF;
|
||||||
|
high_b = b >> 16;
|
||||||
|
low_b = b & 0x0000FFFF;
|
||||||
|
|
||||||
|
hahb = (high_a * high_b) << 16;
|
||||||
|
halb = high_a * low_b;
|
||||||
|
lahb = low_a * high_b;
|
||||||
|
lalb = (uint32_t)(low_a * low_b) >> 16;
|
||||||
|
|
||||||
|
ret = hahb + halb + lahb + lalb;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static int8_t getSoundData(char *buf, int32_t unit, int32_t sample)
|
||||||
|
{
|
||||||
|
int8_t ret;
|
||||||
|
char *p;
|
||||||
|
int32_t offset, shift;
|
||||||
|
|
||||||
|
p = buf;
|
||||||
|
shift = (unit%2) * 4;
|
||||||
|
|
||||||
|
offset = 16 + (unit / 2) + (sample * 4);
|
||||||
|
p += offset;
|
||||||
|
|
||||||
|
ret = (*p >> shift) & 0x0F;
|
||||||
|
|
||||||
|
if (ret > 7) {
|
||||||
|
ret -= 16;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int8_t getFilter(char *buf, int32_t unit)
|
||||||
|
{
|
||||||
|
return (*(buf + 4 + unit) >> 4) & 0x03;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int8_t getRange(char *buf, int32_t unit)
|
||||||
|
{
|
||||||
|
return *(buf + 4 + unit) & 0x0F;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void decodeSoundSectMono(XASector *ssct, xa_data * xad)
|
||||||
|
{
|
||||||
|
size_t count = 0;
|
||||||
|
int8_t snddat, filt, range;
|
||||||
|
short decoded;
|
||||||
|
int32_t unit, sample;
|
||||||
|
int32_t sndgrp;
|
||||||
|
#if USE_FXD
|
||||||
|
int32_t tmp2, tmp3, tmp4, tmp5;
|
||||||
|
#else
|
||||||
|
double tmp2, tmp3, tmp4, tmp5;
|
||||||
|
#endif
|
||||||
|
char decodeBuf[kNumOfSGs*kNumOfSamples*2];
|
||||||
|
|
||||||
|
for (sndgrp = 0; sndgrp < kNumOfSGs; sndgrp++)
|
||||||
|
{
|
||||||
|
for (unit = 0; unit < 8; unit++)
|
||||||
|
{
|
||||||
|
range = getRange(ssct->SoundGroups[sndgrp], unit);
|
||||||
|
filt = getFilter(ssct->SoundGroups[sndgrp], unit);
|
||||||
|
for (sample = 0; sample < 28; sample++)
|
||||||
|
{
|
||||||
|
snddat = getSoundData(ssct->SoundGroups[sndgrp], unit, sample);
|
||||||
|
#if USE_FXD
|
||||||
|
tmp2 = (int32_t)(snddat) << (12 - range);
|
||||||
|
tmp3 = FXD_Pcm16ToFxd(tmp2);
|
||||||
|
tmp4 = FXD_FixMul(K0[filt], xad->t1);
|
||||||
|
tmp5 = FXD_FixMul(K1[filt], xad->t2);
|
||||||
|
xad->t2 = xad->t1;
|
||||||
|
xad->t1 = tmp3 + tmp4 + tmp5;
|
||||||
|
decoded = FXD_FxdToPcm16(xad->t1);
|
||||||
|
#else
|
||||||
|
tmp2 = (double)(1 << (12 - range));
|
||||||
|
tmp3 = (double)snddat * tmp2;
|
||||||
|
tmp4 = xad->t1 * K0[filt];
|
||||||
|
tmp5 = xad->t2 * K1[filt];
|
||||||
|
xad->t2 = xad->t1;
|
||||||
|
xad->t1 = tmp3 + tmp4 + tmp5;
|
||||||
|
decoded = DblToPCM(xad->t1);
|
||||||
|
#endif
|
||||||
|
decodeBuf[count++] = (char)(decoded & 0x0000ffff);
|
||||||
|
decodeBuf[count++] = (char)(decoded >> 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count > xad->blocksize)
|
||||||
|
xad->block = (char*)realloc(xad->block, count);
|
||||||
|
|
||||||
|
memcpy(xad->block, decodeBuf, count);
|
||||||
|
xad->blocksize = count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void decodeSoundSectStereo(XASector *ssct, xa_data * xad)
|
||||||
|
{
|
||||||
|
size_t count = 0;
|
||||||
|
int8_t snddat, filt, range;
|
||||||
|
int8_t filt1, range1;
|
||||||
|
short decoded;
|
||||||
|
int32_t unit, sample;
|
||||||
|
int32_t sndgrp;
|
||||||
|
#if USE_FXD
|
||||||
|
int32_t tmp2, tmp3, tmp4, tmp5;
|
||||||
|
#else
|
||||||
|
double tmp2, tmp3, tmp4, tmp5;
|
||||||
|
#endif
|
||||||
|
char decodeBuf[kNumOfSGs*kNumOfSamples*2];
|
||||||
|
|
||||||
|
for (sndgrp = 0; sndgrp < kNumOfSGs; sndgrp++)
|
||||||
|
{
|
||||||
|
for (unit = 0; unit < 8; unit+= 2)
|
||||||
|
{
|
||||||
|
range = getRange(ssct->SoundGroups[sndgrp], unit);
|
||||||
|
filt = getFilter(ssct->SoundGroups[sndgrp], unit);
|
||||||
|
range1 = getRange(ssct->SoundGroups[sndgrp], unit+1);
|
||||||
|
filt1 = getFilter(ssct->SoundGroups[sndgrp], unit+1);
|
||||||
|
|
||||||
|
for (sample = 0; sample < 28; sample++)
|
||||||
|
{
|
||||||
|
// Channel 1
|
||||||
|
snddat = getSoundData(ssct->SoundGroups[sndgrp], unit, sample);
|
||||||
|
#if USE_FXD
|
||||||
|
tmp2 = (int32_t)(snddat) << (12 - range);
|
||||||
|
tmp3 = FXD_Pcm16ToFxd(tmp2);
|
||||||
|
tmp4 = FXD_FixMul(K0[filt], xad->t1);
|
||||||
|
tmp5 = FXD_FixMul(K1[filt], xad->t2);
|
||||||
|
xad->t2 = xad->t1;
|
||||||
|
xad->t1 = tmp3 + tmp4 + tmp5;
|
||||||
|
decoded = FXD_FxdToPcm16(xad->t1);
|
||||||
|
#else
|
||||||
|
tmp2 = (double)(1 << (12 - range));
|
||||||
|
tmp3 = (double)snddat * tmp2;
|
||||||
|
tmp4 = xad->t1 * K0[filt];
|
||||||
|
tmp5 = xad->t2 * K1[filt];
|
||||||
|
xad->t2 = xad->t1;
|
||||||
|
xad->t1 = tmp3 + tmp4 + tmp5;
|
||||||
|
decoded = DblToPCM(xad->t1);
|
||||||
|
#endif
|
||||||
|
decodeBuf[count++] = (char)(decoded & 0x0000ffff);
|
||||||
|
decodeBuf[count++] = (char)(decoded >> 8);
|
||||||
|
|
||||||
|
// Channel 2
|
||||||
|
snddat = getSoundData(ssct->SoundGroups[sndgrp], unit+1, sample);
|
||||||
|
#if USE_FXD
|
||||||
|
tmp2 = (int32_t)(snddat) << (12 - range1);
|
||||||
|
tmp3 = FXD_Pcm16ToFxd(tmp2);
|
||||||
|
tmp4 = FXD_FixMul(K0[filt1], xad->t1_x);
|
||||||
|
tmp5 = FXD_FixMul(K1[filt1], xad->t2_x);
|
||||||
|
xad->t2_x = xad->t1_x;
|
||||||
|
xad->t1_x = tmp3 + tmp4 + tmp5;
|
||||||
|
decoded = FXD_FxdToPcm16(xad->t1_x);
|
||||||
|
#else
|
||||||
|
tmp2 = (double)(1 << (12 - range1));
|
||||||
|
tmp3 = (double)snddat * tmp2;
|
||||||
|
tmp4 = xad->t1_x * K0[filt1];
|
||||||
|
tmp5 = xad->t2_x * K1[filt1];
|
||||||
|
xad->t2_x = xad->t1_x;
|
||||||
|
xad->t1_x = tmp3 + tmp4 + tmp5;
|
||||||
|
decoded = DblToPCM(xad->t1_x);
|
||||||
|
#endif
|
||||||
|
decodeBuf[count++] = (char)(decoded & 0x0000ffff);
|
||||||
|
decodeBuf[count++] = (char)(decoded >> 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count > xad->blocksize)
|
||||||
|
xad->block = (char*)realloc(xad->block, count);
|
||||||
|
|
||||||
|
memcpy(xad->block, decodeBuf, count);
|
||||||
|
xad->blocksize = count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------
|
||||||
|
Function: MV_GetNextXABlock
|
||||||
|
|
||||||
|
Controls playback of XA data
|
||||||
|
---------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
static playbackstatus MV_GetNextXABlock
|
||||||
|
(
|
||||||
|
VoiceNode *voice
|
||||||
|
)
|
||||||
|
|
||||||
|
{
|
||||||
|
xa_data * xad = (xa_data *) voice->extra;
|
||||||
|
XASector ssct;
|
||||||
|
int coding;
|
||||||
|
|
||||||
|
voice->Playing = TRUE;
|
||||||
|
|
||||||
|
xad->t1 = xad->t2 = xad->t1_x = xad->t2_x = 0;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
size_t bytes = xad->length - xad->pos;
|
||||||
|
|
||||||
|
if (sizeof(XASector) < bytes)
|
||||||
|
bytes = sizeof(XASector);
|
||||||
|
|
||||||
|
memcpy(&ssct, (char*) xad->ptr + xad->pos, bytes);
|
||||||
|
xad->pos += bytes;
|
||||||
|
}
|
||||||
|
#define SUBMODE_REAL_TIME_SECTOR (1 << 6)
|
||||||
|
#define SUBMODE_FORM (1 << 5)
|
||||||
|
#define SUBMODE_AUDIO_DATA (1 << 2)
|
||||||
|
while (ssct.sectorFiller[46] != (SUBMODE_REAL_TIME_SECTOR | SUBMODE_FORM | SUBMODE_AUDIO_DATA));
|
||||||
|
|
||||||
|
coding = ssct.sectorFiller[47];
|
||||||
|
|
||||||
|
voice->channels = (coding & 3) + 1;
|
||||||
|
voice->SamplingRate = (((coding >> 2) & 3) == 1) ? 18900 : 37800;
|
||||||
|
|
||||||
|
// CODEDUP multivoc.c MV_SetVoicePitch
|
||||||
|
voice->RateScale = ( voice->SamplingRate * voice->PitchScale ) / MV_MixRate;
|
||||||
|
voice->FixedPointBufferSize = ( voice->RateScale * MV_MIXBUFFERSIZE ) - voice->RateScale;
|
||||||
|
MV_SetVoiceMixMode( voice );
|
||||||
|
|
||||||
|
if (voice->channels == 2)
|
||||||
|
decodeSoundSectStereo(&ssct, xad);
|
||||||
|
else
|
||||||
|
decodeSoundSectMono(&ssct, xad);
|
||||||
|
|
||||||
|
voice->sound = xad->block;
|
||||||
|
voice->length = (((xad->blocksize * (voice->bits/8))/2)<<voice->bits) / 4;
|
||||||
|
voice->position = 0;
|
||||||
|
voice->BlockLength = 0;
|
||||||
|
|
||||||
|
if (xad->length == xad->pos)
|
||||||
|
{
|
||||||
|
if (voice->LoopSize > 0)
|
||||||
|
xad->pos = XA_DATA_START;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
voice->Playing = FALSE;
|
||||||
|
return NoMoreData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return KeepPlaying;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------
|
||||||
|
Function: MV_PlayXA3D
|
||||||
|
|
||||||
|
Begin playback of sound data at specified angle and distance
|
||||||
|
from listener.
|
||||||
|
---------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
int32_t MV_PlayXA3D
|
||||||
|
(
|
||||||
|
char *ptr,
|
||||||
|
uint32_t ptrlength,
|
||||||
|
int32_t loophow,
|
||||||
|
int32_t pitchoffset,
|
||||||
|
int32_t angle,
|
||||||
|
int32_t distance,
|
||||||
|
int32_t priority,
|
||||||
|
uint32_t callbackval
|
||||||
|
)
|
||||||
|
|
||||||
|
{
|
||||||
|
int32_t left;
|
||||||
|
int32_t right;
|
||||||
|
int32_t mid;
|
||||||
|
int32_t volume;
|
||||||
|
int32_t status;
|
||||||
|
|
||||||
|
if ( !MV_Installed )
|
||||||
|
{
|
||||||
|
MV_SetErrorCode( MV_NotInstalled );
|
||||||
|
return MV_Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( distance < 0 )
|
||||||
|
{
|
||||||
|
distance = -distance;
|
||||||
|
angle += MV_NUMPANPOSITIONS / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
volume = MIX_VOLUME( distance );
|
||||||
|
|
||||||
|
// Ensure angle is within 0 - 127
|
||||||
|
angle &= MV_MAXPANPOSITION;
|
||||||
|
|
||||||
|
left = MV_PanTable[ angle ][ volume ].left;
|
||||||
|
right = MV_PanTable[ angle ][ volume ].right;
|
||||||
|
mid = max( 0, 255 - distance );
|
||||||
|
|
||||||
|
status = MV_PlayXA(ptr, ptrlength, pitchoffset, loophow, -1, mid, left, right, priority, callbackval);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------
|
||||||
|
Function: MV_PlayXA
|
||||||
|
|
||||||
|
Begin playback of sound data with the given sound levels and
|
||||||
|
priority.
|
||||||
|
---------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
int32_t MV_PlayXA
|
||||||
|
(
|
||||||
|
char *ptr,
|
||||||
|
uint32_t ptrlength,
|
||||||
|
int32_t loopstart,
|
||||||
|
int32_t loopend,
|
||||||
|
int32_t pitchoffset,
|
||||||
|
int32_t vol,
|
||||||
|
int32_t left,
|
||||||
|
int32_t right,
|
||||||
|
int32_t priority,
|
||||||
|
uint32_t callbackval
|
||||||
|
)
|
||||||
|
|
||||||
|
{
|
||||||
|
VoiceNode *voice;
|
||||||
|
xa_data * xad = 0;
|
||||||
|
|
||||||
|
UNREFERENCED_PARAMETER(loopend);
|
||||||
|
|
||||||
|
if ( !MV_Installed )
|
||||||
|
{
|
||||||
|
MV_SetErrorCode( MV_NotInstalled );
|
||||||
|
return MV_Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
xad = (xa_data *) malloc( sizeof(xa_data) );
|
||||||
|
if (!xad) {
|
||||||
|
MV_SetErrorCode( MV_InvalidXAFile );
|
||||||
|
return MV_Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(xad, 0, sizeof(xa_data));
|
||||||
|
xad->ptr = ptr;
|
||||||
|
xad->pos = XA_DATA_START;
|
||||||
|
xad->blocksize = 0;
|
||||||
|
xad->length = ptrlength;
|
||||||
|
|
||||||
|
xad->block = NULL;
|
||||||
|
|
||||||
|
// Request a voice from the voice pool
|
||||||
|
voice = MV_AllocVoice( priority );
|
||||||
|
if ( voice == NULL )
|
||||||
|
{
|
||||||
|
|
||||||
|
free(xad);
|
||||||
|
MV_SetErrorCode( MV_NoVoices );
|
||||||
|
return MV_Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
xad->owner = voice;
|
||||||
|
|
||||||
|
voice->wavetype = XA;
|
||||||
|
voice->extra = (void*)xad;
|
||||||
|
voice->GetSound = MV_GetNextXABlock;
|
||||||
|
voice->NextBlock = xad->block;
|
||||||
|
voice->DemandFeed = NULL;
|
||||||
|
voice->LoopCount = 0;
|
||||||
|
voice->BlockLength = 0;
|
||||||
|
voice->PitchScale = PITCH_GetScale( pitchoffset );
|
||||||
|
voice->next = NULL;
|
||||||
|
voice->prev = NULL;
|
||||||
|
voice->priority = priority;
|
||||||
|
voice->callbackval = callbackval;
|
||||||
|
|
||||||
|
voice->bits = 16;
|
||||||
|
|
||||||
|
voice->bits = 16;
|
||||||
|
|
||||||
|
voice->Playing = TRUE;
|
||||||
|
voice->Paused = FALSE;
|
||||||
|
|
||||||
|
voice->LoopStart = 0;
|
||||||
|
voice->LoopEnd = 0;
|
||||||
|
voice->LoopSize = (loopstart >= 0 ? 1 : 0);
|
||||||
|
|
||||||
|
MV_SetVoiceVolume( voice, vol, left, right );
|
||||||
|
MV_PlayVoice( voice );
|
||||||
|
|
||||||
|
return voice->handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MV_ReleaseXAVoice( VoiceNode * voice )
|
||||||
|
{
|
||||||
|
xa_data * xad = (xa_data *) voice->extra;
|
||||||
|
|
||||||
|
if (voice->wavetype != XA) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xad->block != NULL)
|
||||||
|
free(xad->block);
|
||||||
|
free(xad);
|
||||||
|
|
||||||
|
voice->extra = 0;
|
||||||
|
}
|
Loading…
Reference in a new issue