mirror of
https://github.com/ZDoom/raze-gles.git
synced 2024-11-10 23:02:03 +00:00
- hooked up ZMusic.
This commit is contained in:
parent
29d16868c9
commit
ec6ce8b1ec
13 changed files with 165 additions and 1644 deletions
|
@ -650,35 +650,6 @@ set( FASTMATH_SOURCES
|
|||
libsmackerdec/src/LogError.cpp
|
||||
libsmackerdec/src/SmackerDecoder.cpp
|
||||
|
||||
# This will go away once GZDoom's music backend has been plugged in.
|
||||
libxmp-lite/src/common.c
|
||||
libxmp-lite/src/control.c
|
||||
libxmp-lite/src/dataio.c
|
||||
libxmp-lite/src/effects.c
|
||||
libxmp-lite/src/filter.c
|
||||
libxmp-lite/src/format.c
|
||||
libxmp-lite/src/hio.c
|
||||
libxmp-lite/src/itsex.c
|
||||
libxmp-lite/src/it_load.c
|
||||
libxmp-lite/src/lfo.c
|
||||
libxmp-lite/src/load.c
|
||||
libxmp-lite/src/load_helpers.c
|
||||
libxmp-lite/src/memio.c
|
||||
libxmp-lite/src/mixer.c
|
||||
libxmp-lite/src/mix_all.c
|
||||
libxmp-lite/src/mod_load.c
|
||||
libxmp-lite/src/mtm_load.c
|
||||
libxmp-lite/src/period.c
|
||||
libxmp-lite/src/player.c
|
||||
libxmp-lite/src/read_event.c
|
||||
libxmp-lite/src/s3m_load.c
|
||||
libxmp-lite/src/sample.c
|
||||
libxmp-lite/src/scan.c
|
||||
libxmp-lite/src/smix.c
|
||||
libxmp-lite/src/virtual.c
|
||||
libxmp-lite/src/win32.c
|
||||
libxmp-lite/src/xm_load.c
|
||||
|
||||
# The rest is only here because it is C, not C++
|
||||
glad/src/glad.c
|
||||
|
||||
|
@ -694,7 +665,6 @@ set (PCH_SOURCES
|
|||
audiolib/src/driver_nosound.cpp
|
||||
audiolib/src/driver_sdl.cpp
|
||||
audiolib/src/driver_winmm.cpp
|
||||
audiolib/src/flac.cpp
|
||||
audiolib/src/formats.cpp
|
||||
audiolib/src/fx_man.cpp
|
||||
audiolib/src/gmtimbre.cpp
|
||||
|
@ -706,8 +676,6 @@ set (PCH_SOURCES
|
|||
audiolib/src/opl3.cpp
|
||||
audiolib/src/pitch.cpp
|
||||
audiolib/src/vorbis.cpp
|
||||
audiolib/src/xa.cpp
|
||||
audiolib/src/xmp.cpp
|
||||
|
||||
glbackend/gl_hwtexture.cpp
|
||||
glbackend/gl_samplers.cpp
|
||||
|
@ -844,6 +812,7 @@ set (PCH_SOURCES
|
|||
common/music/i_soundfont.cpp
|
||||
common/music/music_config.cpp
|
||||
common/music/music_midi_base.cpp
|
||||
common/music/musicstream.cpp
|
||||
|
||||
|
||||
)
|
||||
|
|
|
@ -97,8 +97,6 @@ static FORCE_INLINE int FX_GetReverbDelay(void) { return MV_GetReverbDelay(); }
|
|||
static FORCE_INLINE void FX_SetReverbDelay(int delay) { MV_SetReverbDelay(delay); }
|
||||
static FORCE_INLINE int FX_VoiceAvailable(int priority) { return MV_VoiceAvailable(priority); }
|
||||
static FORCE_INLINE int FX_PauseVoice(int handle, int pause) { return FX_CheckMVErr(MV_PauseVoice(handle, pause)); }
|
||||
static FORCE_INLINE int FX_GetPosition(int handle, int *position) { return FX_CheckMVErr(MV_GetPosition(handle, position)); }
|
||||
static FORCE_INLINE int FX_SetPosition(int handle, int position) { return FX_CheckMVErr(MV_SetPosition(handle, position)); }
|
||||
static FORCE_INLINE int FX_EndLooping(int handle) { return FX_CheckMVErr(MV_EndLooping(handle)); }
|
||||
static FORCE_INLINE int FX_SetPan(int handle, int vol, int left, int right)
|
||||
{
|
||||
|
|
|
@ -40,10 +40,11 @@ typedef enum : char
|
|||
FMT_RAW,
|
||||
FMT_VOC,
|
||||
FMT_WAV,
|
||||
FMT_SNDFILE,
|
||||
FMT_ZMUSIC,
|
||||
// soon to be obsolete.
|
||||
FMT_VORBIS,
|
||||
FMT_FLAC,
|
||||
FMT_XA,
|
||||
FMT_XMP,
|
||||
FMT_MAX
|
||||
} wavefmt_t;
|
||||
|
||||
|
@ -109,15 +110,10 @@ decltype(MV_PlayVOC3D) MV_PlayVorbis3D;
|
|||
decltype(MV_PlayVOC) MV_PlayVorbis;
|
||||
decltype(MV_PlayVOC3D) MV_PlayFLAC3D;
|
||||
decltype(MV_PlayVOC) MV_PlayFLAC;
|
||||
decltype(MV_PlayVOC3D) MV_PlayXA3D;
|
||||
decltype(MV_PlayVOC) MV_PlayXA;
|
||||
decltype(MV_PlayVOC3D) MV_PlayXMP3D;
|
||||
decltype(MV_PlayVOC) MV_PlayXMP;
|
||||
|
||||
int MV_PlayRAW(char *ptr, uint32_t length, int rate, char *loopstart, char *loopend, int pitchoffset, int vol,
|
||||
int left, int right, int priority, float volume, intptr_t callbackval);
|
||||
|
||||
int MV_IdentifyXMP(char const *ptr, uint32_t length);
|
||||
int MV_GetPosition(int handle, int *position);
|
||||
int MV_SetPosition(int handle, int position);
|
||||
void MV_SetVolume(int volume);
|
||||
|
|
|
@ -261,6 +261,7 @@ int MV_GetXMPPosition(VoiceNode *voice);
|
|||
void MV_SetXMPPosition(VoiceNode *voice, int position);
|
||||
|
||||
void MV_ReleaseVorbisVoice(VoiceNode *voice);
|
||||
void MV_ReleaseZMusicVoice(VoiceNode* voice);
|
||||
void MV_ReleaseFLACVoice(VoiceNode *voice);
|
||||
void MV_ReleaseXAVoice(VoiceNode *voice);
|
||||
void MV_ReleaseXMPVoice(VoiceNode *voice);
|
||||
|
|
|
@ -1,695 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2009 Jonathon Fowler <jf@jonof.id.au>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
* FLAC source support for MultiVoc
|
||||
*/
|
||||
|
||||
#include "compat.h"
|
||||
|
||||
#ifdef HAVE_FLAC
|
||||
|
||||
#define FLAC__NO_DLL
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <FLAC/all.h>
|
||||
#else
|
||||
#include "FLAC/all.h"
|
||||
#endif
|
||||
|
||||
#include "_multivc.h"
|
||||
#include "multivoc.h"
|
||||
#include "pitch.h"
|
||||
#include "pragmas.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void *ptr;
|
||||
size_t length;
|
||||
size_t pos;
|
||||
|
||||
FLAC__StreamDecoder *stream;
|
||||
FLAC__uint64 sample_pos;
|
||||
|
||||
char *block;
|
||||
size_t blocksize;
|
||||
|
||||
VoiceNode *owner;
|
||||
} flac_data;
|
||||
|
||||
// callbacks, round 1
|
||||
|
||||
static size_t read_flac(void *ptr, size_t size, size_t nmemb, FLAC__IOHandle datasource)
|
||||
{
|
||||
flac_data *flac = (flac_data *)datasource;
|
||||
size_t nread = 0;
|
||||
size_t bytes;
|
||||
|
||||
errno = 0;
|
||||
|
||||
if (flac->length == flac->pos)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (; nmemb > 0; nmemb--, nread++)
|
||||
{
|
||||
bytes = flac->length - flac->pos;
|
||||
if (size < bytes)
|
||||
{
|
||||
bytes = size;
|
||||
}
|
||||
|
||||
memcpy(ptr, (uint8_t *)flac->ptr + flac->pos, bytes);
|
||||
flac->pos += bytes;
|
||||
ptr = (uint8_t *)ptr + bytes;
|
||||
|
||||
if (flac->length == flac->pos)
|
||||
{
|
||||
nread++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return nread;
|
||||
}
|
||||
|
||||
static size_t write_flac(const void *ptr, size_t size, size_t nmemb, FLAC__IOHandle datasource)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(ptr);
|
||||
UNREFERENCED_PARAMETER(size);
|
||||
UNREFERENCED_PARAMETER(nmemb);
|
||||
UNREFERENCED_PARAMETER(datasource);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int seek_flac(FLAC__IOHandle datasource, FLAC__int64 offset, int whence)
|
||||
{
|
||||
flac_data *flac = (flac_data *)datasource;
|
||||
|
||||
switch (whence)
|
||||
{
|
||||
case SEEK_SET: flac->pos = 0; break;
|
||||
case SEEK_CUR: break;
|
||||
case SEEK_END: flac->pos = flac->length; break;
|
||||
}
|
||||
|
||||
flac->pos += offset;
|
||||
|
||||
if (flac->pos > flac->length)
|
||||
{
|
||||
flac->pos = flac->length;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static FLAC__int64 tell_flac(FLAC__IOHandle datasource)
|
||||
{
|
||||
flac_data *flac = (flac_data *)datasource;
|
||||
|
||||
return flac->pos;
|
||||
}
|
||||
|
||||
static FLAC__int64 length_flac(FLAC__IOHandle datasource)
|
||||
{
|
||||
flac_data *flac = (flac_data *)datasource;
|
||||
|
||||
return flac->length;
|
||||
}
|
||||
|
||||
static int eof_flac(FLAC__IOHandle datasource)
|
||||
{
|
||||
flac_data *flac = (flac_data *)datasource;
|
||||
|
||||
return (flac->pos == flac->length);
|
||||
}
|
||||
|
||||
static int close_flac(FLAC__IOHandle datasource)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(datasource);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static FLAC__IOCallbacks flac_callbacks = {
|
||||
read_flac, write_flac, seek_flac, tell_flac, eof_flac, close_flac,
|
||||
};
|
||||
|
||||
|
||||
// callbacks, round 2
|
||||
|
||||
FLAC__StreamDecoderReadStatus read_flac_stream(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes,
|
||||
void *client_data)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(decoder);
|
||||
if (*bytes > 0)
|
||||
{
|
||||
*bytes = read_flac(buffer, sizeof(FLAC__byte), *bytes, client_data);
|
||||
if (errno)
|
||||
return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
|
||||
else if (*bytes == 0)
|
||||
return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
|
||||
else
|
||||
return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
|
||||
}
|
||||
else
|
||||
return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
|
||||
}
|
||||
|
||||
FLAC__StreamDecoderSeekStatus seek_flac_stream(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset,
|
||||
void *client_data)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(decoder);
|
||||
if (seek_flac(client_data, absolute_byte_offset, SEEK_SET) < 0)
|
||||
return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
|
||||
else
|
||||
return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
|
||||
}
|
||||
|
||||
FLAC__StreamDecoderTellStatus tell_flac_stream(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset,
|
||||
void *client_data)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(decoder);
|
||||
*absolute_byte_offset = tell_flac(client_data);
|
||||
return FLAC__STREAM_DECODER_TELL_STATUS_OK;
|
||||
}
|
||||
|
||||
FLAC__StreamDecoderLengthStatus length_flac_stream(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length,
|
||||
void *client_data)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(decoder);
|
||||
*stream_length = length_flac(client_data);
|
||||
return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
|
||||
}
|
||||
|
||||
FLAC__bool eof_flac_stream(const FLAC__StreamDecoder *decoder, void *client_data)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(decoder);
|
||||
return eof_flac(client_data);
|
||||
}
|
||||
|
||||
FLAC__StreamDecoderWriteStatus write_flac_stream(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame,
|
||||
const FLAC__int32 *const ibuffer[], void *client_data)
|
||||
{
|
||||
flac_data *fd = (flac_data *)client_data;
|
||||
VoiceNode *voice = fd->owner;
|
||||
FLAC__uint64 samples = frame->header.blocksize;
|
||||
|
||||
UNREFERENCED_PARAMETER(decoder);
|
||||
|
||||
voice->channels = frame->header.channels;
|
||||
voice->bits = frame->header.bits_per_sample;
|
||||
voice->SamplingRate = frame->header.sample_rate;
|
||||
|
||||
if (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER)
|
||||
fd->sample_pos = frame->header.number.frame_number;
|
||||
else if (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER)
|
||||
fd->sample_pos = frame->header.number.sample_number;
|
||||
|
||||
if ((FLAC__uint64)(uintptr_t)voice->LoopEnd > 0 &&
|
||||
fd->sample_pos + samples >= (FLAC__uint64)(uintptr_t)voice->LoopEnd)
|
||||
{
|
||||
samples = (FLAC__uint64)(uintptr_t)voice->LoopEnd - fd->sample_pos;
|
||||
if (!FLAC__stream_decoder_seek_absolute(fd->stream, (FLAC__uint64)(uintptr_t)voice->LoopStart))
|
||||
MV_Printf("MV_GetNextFLACBlock FLAC__stream_decoder_seek_absolute: LOOP_START %ul, LOOP_END %ul\n",
|
||||
(FLAC__uint64)(uintptr_t)voice->LoopStart, (FLAC__uint64)(uintptr_t)voice->LoopEnd);
|
||||
}
|
||||
|
||||
size_t const size = samples * voice->channels * (voice->bits >> 3);
|
||||
|
||||
voice->position = 0;
|
||||
voice->BlockLength = 0;
|
||||
// CODEDUP multivoc.c MV_SetVoicePitch
|
||||
voice->RateScale = divideu32(voice->SamplingRate * voice->PitchScale, MV_MixRate);
|
||||
voice->FixedPointBufferSize = (voice->RateScale * MV_MIXBUFFERSIZE) - voice->RateScale;
|
||||
MV_SetVoiceMixMode(voice);
|
||||
|
||||
char * block = fd->block;
|
||||
|
||||
if (size > fd->blocksize)
|
||||
{
|
||||
block = (char *)Xmalloc(size);
|
||||
|
||||
if (block == nullptr)
|
||||
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
|
||||
}
|
||||
|
||||
{
|
||||
char *obuffer = block;
|
||||
FLAC__uint64 sample;
|
||||
uint8_t channel;
|
||||
|
||||
// this loop is adapted from code in ov_read_filter() in vorbisfile.c in libvorbis
|
||||
for (sample = 0; sample < samples; ++sample)
|
||||
for (channel = 0; channel < frame->header.channels; ++channel)
|
||||
{
|
||||
int8_t byte;
|
||||
FLAC__int32 val = ibuffer[channel][sample];
|
||||
if (val > (1 << (voice->bits - 1)) - 1)
|
||||
val = (1 << (voice->bits - 1)) - 1;
|
||||
else if (val < -(1 << (voice->bits - 1)))
|
||||
val = -(1 << (voice->bits - 1));
|
||||
for (byte = 0; byte < voice->bits; byte += 8) *obuffer++ = ((val >> byte) & 0x000000FF);
|
||||
}
|
||||
}
|
||||
|
||||
voice->sound = block;
|
||||
voice->length = samples << 16;
|
||||
|
||||
if (block != fd->block)
|
||||
{
|
||||
char * oldblock = fd->block;
|
||||
fd->block = block;
|
||||
fd->blocksize = size;
|
||||
Xfree(oldblock);
|
||||
}
|
||||
|
||||
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
|
||||
}
|
||||
|
||||
void error_flac_stream(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
|
||||
{
|
||||
// flac_data * fd = (flac_data *) client_data;
|
||||
UNREFERENCED_PARAMETER(client_data);
|
||||
UNREFERENCED_PARAMETER(decoder);
|
||||
MV_Printf("%s\n", FLAC__StreamDecoderErrorStatusString[status]);
|
||||
// FLAC__stream_decoder_flush(fd->stream);
|
||||
}
|
||||
|
||||
int MV_GetFLACPosition(VoiceNode *voice)
|
||||
{
|
||||
FLAC__uint64 position = 0;
|
||||
flac_data *fd = (flac_data *)voice->rawdataptr;
|
||||
|
||||
FLAC__stream_decoder_get_decode_position(fd->stream, &position);
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
void MV_SetFLACPosition(VoiceNode *voice, int position)
|
||||
{
|
||||
flac_data *fd = (flac_data *)voice->rawdataptr;
|
||||
|
||||
FLAC__stream_decoder_seek_absolute(fd->stream, position);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
Function: MV_GetNextFLACBlock
|
||||
|
||||
Controls playback of FLAC data
|
||||
---------------------------------------------------------------------*/
|
||||
|
||||
static playbackstatus MV_GetNextFLACBlock(VoiceNode *voice)
|
||||
|
||||
{
|
||||
flac_data *fd = (flac_data *)voice->rawdataptr;
|
||||
FLAC__StreamDecoderState decode_state;
|
||||
// FLAC__bool decode_status;
|
||||
|
||||
if ((FLAC__uint64)(uintptr_t)voice->LoopEnd > 0 && fd->sample_pos >= (FLAC__uint64)(uintptr_t)voice->LoopEnd)
|
||||
if (!FLAC__stream_decoder_seek_absolute(fd->stream, (FLAC__uint64)(uintptr_t)voice->LoopStart))
|
||||
MV_Printf("MV_GetNextFLACBlock FLAC__stream_decoder_seek_absolute: LOOP_START %ul, LOOP_END %ul\n",
|
||||
(FLAC__uint64)(uintptr_t)voice->LoopStart, (FLAC__uint64)(uintptr_t)voice->LoopEnd);
|
||||
|
||||
/*decode_status =*/FLAC__stream_decoder_process_single(fd->stream);
|
||||
decode_state = FLAC__stream_decoder_get_state(fd->stream);
|
||||
|
||||
/*
|
||||
if (!decode_status)
|
||||
{
|
||||
MV_Printf("MV_GetNextFLACBlock: %s\n", FLAC__StreamDecoderStateString[decode_state]);
|
||||
return NoMoreData;
|
||||
}
|
||||
*/
|
||||
|
||||
if (decode_state == FLAC__STREAM_DECODER_SEEK_ERROR)
|
||||
{
|
||||
FLAC__stream_decoder_flush(fd->stream);
|
||||
decode_state = FLAC__stream_decoder_get_state(fd->stream);
|
||||
}
|
||||
|
||||
if (decode_state == FLAC__STREAM_DECODER_END_OF_STREAM)
|
||||
{
|
||||
if (voice->LoopSize > 0)
|
||||
{
|
||||
if (!FLAC__stream_decoder_seek_absolute(fd->stream, (FLAC__uint64)(uintptr_t)voice->LoopStart))
|
||||
MV_Printf("MV_GetNextFLACBlock FLAC__stream_decoder_seek_absolute: LOOP_START %ul\n",
|
||||
(FLAC__uint64)(uintptr_t)voice->LoopStart);
|
||||
}
|
||||
else
|
||||
return NoMoreData;
|
||||
}
|
||||
|
||||
#if 0
|
||||
// unnecessary: duplicated in write_flac_stream()
|
||||
voice->channels = FLAC__stream_decoder_get_channels(fd->stream);
|
||||
voice->bits = FLAC__stream_decoder_get_bits_per_sample(fd->stream);
|
||||
voice->SamplingRate = FLAC__stream_decoder_get_sample_rate(fd->stream);
|
||||
// CODEDUP multivoc.c MV_SetVoicePitch
|
||||
voice->RateScale = ( voice->SamplingRate * voice->PitchScale ) / MV_MixRate;
|
||||
voice->FixedPointBufferSize = ( voice->RateScale * MV_MIXBUFFERSIZE ) - voice->RateScale;
|
||||
MV_SetVoiceMixMode( voice );
|
||||
#endif
|
||||
|
||||
return KeepPlaying;
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
Function: MV_PlayFLAC3D
|
||||
|
||||
Begin playback of sound data at specified angle and distance
|
||||
from listener.
|
||||
---------------------------------------------------------------------*/
|
||||
|
||||
int MV_PlayFLAC3D(char *ptr, uint32_t length, int loophow, int pitchoffset, int angle, int distance, int priority, float volume, intptr_t callbackval)
|
||||
{
|
||||
int left;
|
||||
int right;
|
||||
int mid;
|
||||
int vol;
|
||||
int status;
|
||||
|
||||
if (!MV_Installed)
|
||||
return MV_SetErrorCode(MV_NotInstalled);
|
||||
|
||||
if (distance < 0)
|
||||
{
|
||||
distance = -distance;
|
||||
angle += MV_NUMPANPOSITIONS / 2;
|
||||
}
|
||||
|
||||
vol = MIX_VOLUME(distance);
|
||||
|
||||
// Ensure angle is within 0 - 127
|
||||
angle &= MV_MAXPANPOSITION;
|
||||
|
||||
left = MV_PanTable[angle][vol].left;
|
||||
right = MV_PanTable[angle][vol].right;
|
||||
mid = max(0, 255 - distance);
|
||||
|
||||
status = MV_PlayFLAC(ptr, length, loophow, -1, pitchoffset, mid, left, right, priority, volume, callbackval);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
Function: MV_PlayFLAC
|
||||
|
||||
Begin playback of sound data with the given sound levels and
|
||||
priority.
|
||||
---------------------------------------------------------------------*/
|
||||
|
||||
int MV_PlayFLAC(char *ptr, uint32_t length, int loopstart, int loopend, int pitchoffset, int vol, int left, int right, int priority, float volume, intptr_t callbackval)
|
||||
{
|
||||
VoiceNode *voice;
|
||||
flac_data *fd = 0;
|
||||
FLAC__Metadata_Chain *metadata_chain;
|
||||
|
||||
UNREFERENCED_PARAMETER(loopend);
|
||||
|
||||
if (!MV_Installed)
|
||||
return MV_SetErrorCode(MV_NotInstalled);
|
||||
|
||||
fd = (flac_data *)Xcalloc(1, sizeof(flac_data));
|
||||
if (!fd)
|
||||
return MV_SetErrorCode(MV_InvalidFile);
|
||||
|
||||
fd->ptr = ptr;
|
||||
fd->pos = 0;
|
||||
fd->blocksize = 0;
|
||||
fd->length = length;
|
||||
|
||||
fd->block = nullptr;
|
||||
|
||||
fd->stream = FLAC__stream_decoder_new();
|
||||
fd->sample_pos = 0;
|
||||
|
||||
FLAC__stream_decoder_set_metadata_ignore_all(fd->stream);
|
||||
|
||||
if (FLAC__stream_decoder_init_stream(fd->stream, read_flac_stream, seek_flac_stream, tell_flac_stream,
|
||||
length_flac_stream, eof_flac_stream, write_flac_stream,
|
||||
/*metadata_flac_stream*/ nullptr, error_flac_stream,
|
||||
(void *)fd) != FLAC__STREAM_DECODER_INIT_STATUS_OK)
|
||||
{
|
||||
Xfree(fd);
|
||||
MV_Printf("MV_PlayFLAC: %s\n", FLAC__stream_decoder_get_resolved_state_string(fd->stream));
|
||||
return MV_SetErrorCode(MV_InvalidFile);
|
||||
}
|
||||
|
||||
// Request a voice from the voice pool
|
||||
voice = MV_AllocVoice(priority);
|
||||
if (voice == nullptr)
|
||||
{
|
||||
FLAC__stream_decoder_finish(fd->stream);
|
||||
FLAC__stream_decoder_delete(fd->stream);
|
||||
Xfree(fd);
|
||||
return MV_SetErrorCode(MV_NoVoices);
|
||||
}
|
||||
|
||||
fd->owner = voice;
|
||||
|
||||
voice->wavetype = FMT_FLAC;
|
||||
voice->rawdataptr = (void *)fd;
|
||||
voice->GetSound = MV_GetNextFLACBlock;
|
||||
voice->NextBlock = fd->block;
|
||||
voice->LoopCount = 0;
|
||||
voice->BlockLength = 0;
|
||||
voice->PitchScale = PITCH_GetScale(pitchoffset);
|
||||
voice->next = nullptr;
|
||||
voice->prev = nullptr;
|
||||
voice->priority = priority;
|
||||
voice->callbackval = callbackval;
|
||||
|
||||
voice->Paused = FALSE;
|
||||
|
||||
voice->LoopStart = 0;
|
||||
voice->LoopEnd = 0;
|
||||
voice->LoopSize = (loopstart >= 0 ? 1 : 0);
|
||||
|
||||
// parse metadata
|
||||
// loop parsing designed with multiple repetitions in mind
|
||||
// In retrospect, it may be possible to MV_GetVorbisCommentLoops(voice, (vorbis_comment *)
|
||||
// &tags->data.vorbis_comment)
|
||||
// but libvorbisfile may be confused by the signedness of char* vs FLAC__byte* and this code does not depend on
|
||||
// HAVE_VORBIS.
|
||||
metadata_chain = FLAC__metadata_chain_new();
|
||||
if (metadata_chain != nullptr)
|
||||
{
|
||||
if (FLAC__metadata_chain_read_with_callbacks(metadata_chain, fd, flac_callbacks))
|
||||
{
|
||||
FLAC__Metadata_Iterator *metadata_iterator = FLAC__metadata_iterator_new();
|
||||
if (metadata_iterator != nullptr)
|
||||
{
|
||||
char *vc_loopstart = nullptr;
|
||||
char *vc_loopend = nullptr;
|
||||
char *vc_looplength = nullptr;
|
||||
|
||||
FLAC__metadata_iterator_init(metadata_iterator, metadata_chain);
|
||||
|
||||
do
|
||||
{
|
||||
FLAC__StreamMetadata *tags = FLAC__metadata_iterator_get_block(metadata_iterator);
|
||||
|
||||
if (tags->type == FLAC__METADATA_TYPE_STREAMINFO)
|
||||
{
|
||||
const FLAC__StreamMetadata_StreamInfo *info = &tags->data.stream_info;
|
||||
|
||||
if (info->channels != 1 && info->channels != 2)
|
||||
{
|
||||
FLAC__metadata_object_delete(tags);
|
||||
FLAC__metadata_iterator_delete(metadata_iterator);
|
||||
// FLAC__metadata_chain_delete(metadata_chain);
|
||||
FLAC__stream_decoder_finish(fd->stream);
|
||||
FLAC__stream_decoder_delete(fd->stream);
|
||||
Xfree(fd);
|
||||
return MV_SetErrorCode(MV_InvalidFile);
|
||||
}
|
||||
|
||||
voice->channels = info->channels;
|
||||
voice->bits = info->bits_per_sample;
|
||||
voice->SamplingRate = info->sample_rate;
|
||||
}
|
||||
|
||||
// load loop tags from metadata
|
||||
if (tags->type == FLAC__METADATA_TYPE_VORBIS_COMMENT)
|
||||
{
|
||||
FLAC__uint32 comment;
|
||||
for (comment = 0; comment < tags->data.vorbis_comment.num_comments; ++comment)
|
||||
{
|
||||
const char *entry = (const char *)tags->data.vorbis_comment.comments[comment].entry;
|
||||
if (entry != nullptr && entry[0] != '\0')
|
||||
{
|
||||
const char *value = strchr(entry, '=');
|
||||
const size_t field = value - entry;
|
||||
value += 1;
|
||||
|
||||
for (int t = 0; t < loopStartTagCount && vc_loopstart == nullptr; ++t)
|
||||
{
|
||||
char const * const tag = loopStartTags[t];
|
||||
if (field == strlen(tag) && Bstrncasecmp(entry, tag, field) == 0)
|
||||
vc_loopstart = Xstrdup(value);
|
||||
}
|
||||
|
||||
for (int t = 0; t < loopEndTagCount && vc_loopend == nullptr; ++t)
|
||||
{
|
||||
char const * const tag = loopEndTags[t];
|
||||
if (field == strlen(tag) && Bstrncasecmp(entry, tag, field) == 0)
|
||||
vc_loopend = Xstrdup(value);
|
||||
}
|
||||
|
||||
for (int t = 0; t < loopLengthTagCount && vc_looplength == nullptr; ++t)
|
||||
{
|
||||
char const * const tag = loopLengthTags[t];
|
||||
if (field == strlen(tag) && Bstrncasecmp(entry, tag, field) == 0)
|
||||
vc_looplength = Xstrdup(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FLAC__metadata_object_delete(
|
||||
tags); // If it were not for this, I would assign pointers instead of strdup().
|
||||
} while (FLAC__metadata_iterator_next(metadata_iterator));
|
||||
|
||||
if (vc_loopstart != nullptr)
|
||||
{
|
||||
{
|
||||
const FLAC__int64 flac_loopstart = atol(vc_loopstart);
|
||||
if (flac_loopstart >= 0) // a loop starting at 0 is valid
|
||||
{
|
||||
voice->LoopStart = (const char *)(intptr_t)flac_loopstart;
|
||||
voice->LoopSize = 1;
|
||||
}
|
||||
}
|
||||
free(vc_loopstart);
|
||||
}
|
||||
if (vc_loopend != nullptr)
|
||||
{
|
||||
if (voice->LoopSize > 0)
|
||||
{
|
||||
const FLAC__int64 flac_loopend = atol(vc_loopend);
|
||||
if (flac_loopend > 0) // a loop ending at 0 is invalid
|
||||
voice->LoopEnd = (const char *)(intptr_t)flac_loopend;
|
||||
}
|
||||
free(vc_loopend);
|
||||
}
|
||||
if (vc_looplength != nullptr)
|
||||
{
|
||||
if (voice->LoopSize > 0 && voice->LoopEnd == 0)
|
||||
{
|
||||
const FLAC__int64 flac_looplength = atol(vc_looplength);
|
||||
if (flac_looplength > 0) // a loop of length 0 is invalid
|
||||
voice->LoopEnd = (const char *)((intptr_t)flac_looplength + (intptr_t)voice->LoopStart);
|
||||
}
|
||||
free(vc_looplength);
|
||||
}
|
||||
|
||||
FLAC__metadata_iterator_delete(metadata_iterator);
|
||||
}
|
||||
else
|
||||
MV_Printf("Error allocating FLAC__Metadata_Iterator!\n");
|
||||
}
|
||||
else
|
||||
MV_Printf("%s\n", FLAC__Metadata_ChainStatusString[FLAC__metadata_chain_status(metadata_chain)]);
|
||||
|
||||
// FLAC__metadata_chain_delete(metadata_chain); // when run with GDB, this throws SIGTRAP about freed heap
|
||||
// memory being modified
|
||||
}
|
||||
else
|
||||
MV_Printf("Error allocating FLAC__Metadata_Chain!\n");
|
||||
|
||||
// CODEDUP multivoc.c MV_SetVoicePitch
|
||||
voice->RateScale = divideu32(voice->SamplingRate * voice->PitchScale, MV_MixRate);
|
||||
voice->FixedPointBufferSize = (voice->RateScale * MV_MIXBUFFERSIZE) - voice->RateScale;
|
||||
MV_SetVoiceMixMode(voice);
|
||||
|
||||
MV_SetVoiceVolume(voice, vol, left, right, volume);
|
||||
MV_PlayVoice(voice);
|
||||
|
||||
return voice->handle;
|
||||
}
|
||||
|
||||
|
||||
void MV_ReleaseFLACVoice(VoiceNode *voice)
|
||||
{
|
||||
flac_data *fd = (flac_data *)voice->rawdataptr;
|
||||
|
||||
if (voice->wavetype != FMT_FLAC)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
voice->rawdataptr = 0;
|
||||
if (fd->stream != nullptr)
|
||||
{
|
||||
auto stream = fd->stream;
|
||||
fd->stream = nullptr;
|
||||
FLAC__stream_decoder_finish(stream);
|
||||
FLAC__stream_decoder_delete(stream);
|
||||
}
|
||||
auto block = fd->block;
|
||||
voice->length = 0;
|
||||
voice->sound = nullptr;
|
||||
fd->block = nullptr;
|
||||
Xfree(block);
|
||||
Xfree(fd);
|
||||
}
|
||||
#else
|
||||
#include "_multivc.h"
|
||||
|
||||
int MV_PlayFLAC(char *ptr, uint32_t ptrlength, int loopstart, int loopend, int pitchoffset,
|
||||
int vol, int left, int right, int priority, float volume, intptr_t callbackval)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(ptr);
|
||||
UNREFERENCED_PARAMETER(ptrlength);
|
||||
UNREFERENCED_PARAMETER(loopstart);
|
||||
UNREFERENCED_PARAMETER(loopend);
|
||||
UNREFERENCED_PARAMETER(pitchoffset);
|
||||
UNREFERENCED_PARAMETER(vol);
|
||||
UNREFERENCED_PARAMETER(left);
|
||||
UNREFERENCED_PARAMETER(right);
|
||||
UNREFERENCED_PARAMETER(priority);
|
||||
UNREFERENCED_PARAMETER(volume);
|
||||
UNREFERENCED_PARAMETER(callbackval);
|
||||
|
||||
MV_Printf("MV_PlayFLAC: FLAC support not included in this binary.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int MV_PlayFLAC3D(char *ptr, uint32_t ptrlength, int loophow, int pitchoffset, int angle,
|
||||
int distance, int priority, float volume, intptr_t callbackval)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(ptr);
|
||||
UNREFERENCED_PARAMETER(ptrlength);
|
||||
UNREFERENCED_PARAMETER(loophow);
|
||||
UNREFERENCED_PARAMETER(pitchoffset);
|
||||
UNREFERENCED_PARAMETER(angle);
|
||||
UNREFERENCED_PARAMETER(distance);
|
||||
UNREFERENCED_PARAMETER(priority);
|
||||
UNREFERENCED_PARAMETER(volume);
|
||||
UNREFERENCED_PARAMETER(callbackval);
|
||||
|
||||
MV_Printf("MV_PlayFLAC: FLAC support not included in this binary.\n");
|
||||
return -1;
|
||||
}
|
||||
#endif // HAVE_FLAC
|
|
@ -135,20 +135,12 @@ static wavefmt_t FX_DetectFormat(char const * const ptr, uint32_t length)
|
|||
case 'R' + ('I' << 8) + ('F' << 16) + ('F' << 24): // RIFF
|
||||
switch (B_LITTLE32(*(int const *)(ptr + 8)))
|
||||
{
|
||||
case 'C' + ('D' << 8) + ('X' << 16) + ('A' << 24): // CDXA
|
||||
fmt = FMT_XA;
|
||||
break;
|
||||
case 'W' + ('A' << 8) + ('V' << 16) + ('E' << 24): // WAVE
|
||||
fmt = FMT_WAV;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'f' + ('L' << 8) + ('a' << 16) + ('C' << 24): // fLaC
|
||||
fmt = FMT_FLAC;
|
||||
break;
|
||||
default:
|
||||
if (MV_IdentifyXMP(ptr, length))
|
||||
fmt = FMT_XMP;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -159,9 +151,9 @@ int FX_Play(char *ptr, uint32_t ptrlength, int loopstart, int loopend, int pitch
|
|||
int vol, int left, int right, int priority, float volume, intptr_t callbackval)
|
||||
{
|
||||
static constexpr decltype(MV_PlayVOC) *func[] =
|
||||
{ nullptr, nullptr, MV_PlayVOC, MV_PlayWAV, MV_PlayVorbis, MV_PlayFLAC, MV_PlayXA, MV_PlayXMP };
|
||||
{ nullptr, nullptr, MV_PlayVOC, MV_PlayWAV, nullptr, nullptr, MV_PlayVorbis, nullptr, nullptr, nullptr };
|
||||
|
||||
EDUKE32_STATIC_ASSERT(FMT_MAX == ARRAY_SIZE(func));
|
||||
//EDUKE32_STATIC_ASSERT(FMT_MAX == ARRAY_SIZE(func));
|
||||
|
||||
wavefmt_t const fmt = FX_DetectFormat(ptr, ptrlength);
|
||||
|
||||
|
@ -181,9 +173,9 @@ int FX_Play3D(char *ptr, uint32_t ptrlength, int loophow, int pitchoffset, int a
|
|||
int priority, float volume, intptr_t callbackval)
|
||||
{
|
||||
static constexpr decltype(MV_PlayVOC3D) *func[] =
|
||||
{ nullptr, nullptr, MV_PlayVOC3D, MV_PlayWAV3D, MV_PlayVorbis3D, MV_PlayFLAC3D, MV_PlayXA3D, MV_PlayXMP3D };
|
||||
{ nullptr, nullptr, MV_PlayVOC3D, MV_PlayWAV3D, nullptr, nullptr, MV_PlayVorbis3D, nullptr, nullptr, nullptr };
|
||||
|
||||
EDUKE32_STATIC_ASSERT(FMT_MAX == ARRAY_SIZE(func));
|
||||
//EDUKE32_STATIC_ASSERT(FMT_MAX == ARRAY_SIZE(func));
|
||||
|
||||
wavefmt_t const fmt = FX_DetectFormat(ptr, ptrlength);
|
||||
|
||||
|
|
|
@ -170,16 +170,8 @@ static void MV_CleanupVoice(VoiceNode *voice)
|
|||
|
||||
switch (voice->wavetype)
|
||||
{
|
||||
#ifdef HAVE_VORBIS
|
||||
case FMT_VORBIS: MV_ReleaseVorbisVoice(voice); break;
|
||||
#endif
|
||||
#ifdef HAVE_FLAC
|
||||
case FMT_FLAC: MV_ReleaseFLACVoice(voice); break;
|
||||
#endif
|
||||
case FMT_XA: MV_ReleaseXAVoice(voice); break;
|
||||
#ifdef HAVE_XMP
|
||||
case FMT_XMP: MV_ReleaseXMPVoice(voice); break;
|
||||
#endif
|
||||
case FMT_ZMUSIC: MV_ReleaseZMusicVoice(voice); break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
|
@ -571,62 +563,6 @@ int MV_PauseVoice(int handle, int pause)
|
|||
return MV_Ok;
|
||||
}
|
||||
|
||||
int MV_GetPosition(int handle, int *position)
|
||||
{
|
||||
VoiceNode *voice = MV_BeginService(handle);
|
||||
|
||||
if (voice == nullptr)
|
||||
return MV_Error;
|
||||
|
||||
switch (voice->wavetype)
|
||||
{
|
||||
#ifdef HAVE_VORBIS
|
||||
case FMT_VORBIS: *position = MV_GetVorbisPosition(voice); break;
|
||||
#endif
|
||||
#ifdef HAVE_FLAC
|
||||
case FMT_FLAC: *position = MV_GetFLACPosition(voice); break;
|
||||
#endif
|
||||
case FMT_XA: *position = MV_GetXAPosition(voice);
|
||||
default:
|
||||
break;
|
||||
#ifdef HAVE_XMP
|
||||
case FMT_XMP: *position = MV_GetXMPPosition(voice); break;
|
||||
#endif
|
||||
}
|
||||
|
||||
MV_EndService();
|
||||
|
||||
return MV_Ok;
|
||||
}
|
||||
|
||||
int MV_SetPosition(int handle, int position)
|
||||
{
|
||||
VoiceNode *voice = MV_BeginService(handle);
|
||||
|
||||
if (voice == nullptr)
|
||||
return MV_Error;
|
||||
|
||||
switch (voice->wavetype)
|
||||
{
|
||||
#ifdef HAVE_VORBIS
|
||||
case FMT_VORBIS: MV_SetVorbisPosition(voice, position); break;
|
||||
#endif
|
||||
#ifdef HAVE_FLAC
|
||||
case FMT_FLAC: MV_SetFLACPosition(voice, position); break;
|
||||
#endif
|
||||
case FMT_XA: MV_SetXAPosition(voice, position);
|
||||
default:
|
||||
break;
|
||||
#ifdef HAVE_XMP
|
||||
case FMT_XMP: MV_SetXMPPosition(voice, position); break;
|
||||
#endif
|
||||
}
|
||||
|
||||
MV_EndService();
|
||||
|
||||
return MV_Ok;
|
||||
}
|
||||
|
||||
int MV_EndLooping(int handle)
|
||||
{
|
||||
VoiceNode *voice = MV_BeginService(handle);
|
||||
|
|
|
@ -1,481 +0,0 @@
|
|||
|
||||
/**
|
||||
* PlayStation XA (ADPCM) source support for MultiVoc
|
||||
* Adapted and remixed from superxa2wav
|
||||
*/
|
||||
|
||||
#include "_multivc.h"
|
||||
#include "compat.h"
|
||||
#include "multivoc.h"
|
||||
#include "pitch.h"
|
||||
#include "pragmas.h"
|
||||
|
||||
//#define NO_XA_HEADER
|
||||
|
||||
#define USE_FXD 1
|
||||
|
||||
#define kNumOfSamples 224
|
||||
#define kNumOfSGs 18
|
||||
#define TTYWidth 80
|
||||
|
||||
#define kBufSize (kNumOfSGs*kNumOfSamples*(16/8))
|
||||
#define kSamplesMono (kNumOfSGs*kNumOfSamples)
|
||||
#define kSamplesStereo (kNumOfSGs*kNumOfSamples/2)
|
||||
|
||||
/* ADPCM */
|
||||
#define XA_DATA_START (0x44-48)
|
||||
|
||||
#define FXD_FxdToPCM(dt) (max(min((int16_t)((dt)>>16), 32767), -32768))
|
||||
#define DblToPCM(dt) (int16_t)(max(min((dt), 32767), -32768))
|
||||
|
||||
#if USE_FXD
|
||||
#define FXD_FxdToPcm16(dt) (max(min((dt)/2, 32767), -32768))
|
||||
#define FXD_Pcm16ToFxd(dt) ((int)dt*2)
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
void * ptr;
|
||||
size_t length;
|
||||
size_t pos;
|
||||
|
||||
#if USE_FXD
|
||||
int t1, t2;
|
||||
int t1_x, t2_x;
|
||||
#else
|
||||
double t1, t2;
|
||||
double t1_x, t2_x;
|
||||
#endif
|
||||
|
||||
int8_t block[kBufSize];
|
||||
|
||||
VoiceNode *owner;
|
||||
} xa_data;
|
||||
|
||||
typedef int8_t SoundGroup[128];
|
||||
|
||||
typedef struct XASector {
|
||||
int8_t sectorFiller[48];
|
||||
SoundGroup SoundGroups[18];
|
||||
} XASector;
|
||||
|
||||
#if USE_FXD
|
||||
static int K0[4] = {
|
||||
0x00000000,
|
||||
0x0000F000,
|
||||
0x0001CC00,
|
||||
0x00018800,
|
||||
};
|
||||
static int K1[4] = {
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
(int)0xFFFF3000u,
|
||||
(int)0xFFFF2400u,
|
||||
};
|
||||
#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 int FXD_FixMul(int a, int b)
|
||||
{
|
||||
int high_a, low_a, high_b, low_b;
|
||||
int hahb, halb, lahb;
|
||||
uint32_t lalb;
|
||||
int 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(int8_t *buf, int unit, int sample)
|
||||
{
|
||||
int8_t ret;
|
||||
int8_t *p;
|
||||
int 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(const int8_t *buf, int unit)
|
||||
{
|
||||
return (*(buf + 4 + unit) >> 4) & 0x03;
|
||||
}
|
||||
|
||||
|
||||
static int8_t getRange(const int8_t *buf, int unit)
|
||||
{
|
||||
return *(buf + 4 + unit) & 0x0F;
|
||||
}
|
||||
|
||||
|
||||
static void decodeSoundSectMono(XASector *ssct, xa_data * xad)
|
||||
{
|
||||
size_t count = 0;
|
||||
int8_t snddat, filt, range;
|
||||
int16_t decoded;
|
||||
int unit, sample;
|
||||
int sndgrp;
|
||||
#if USE_FXD
|
||||
int tmp2, tmp3, tmp4, tmp5;
|
||||
#else
|
||||
double tmp2, tmp3, tmp4, tmp5;
|
||||
#endif
|
||||
int8_t decodeBuf[kBufSize];
|
||||
|
||||
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 = (int)(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++] = (int8_t) ((uint16_t)decoded & 0x00FF);
|
||||
decodeBuf[count++] = (int8_t)(((uint16_t)decoded & 0xFF00) >> 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(xad->block, decodeBuf, kBufSize);
|
||||
}
|
||||
|
||||
static void decodeSoundSectStereo(XASector *ssct, xa_data * xad)
|
||||
{
|
||||
size_t count = 0;
|
||||
int8_t snddat, filt, range;
|
||||
int8_t filt1, range1;
|
||||
int16_t decoded;
|
||||
int unit, sample;
|
||||
int sndgrp;
|
||||
#if USE_FXD
|
||||
int tmp2, tmp3, tmp4, tmp5;
|
||||
#else
|
||||
double tmp2, tmp3, tmp4, tmp5;
|
||||
#endif
|
||||
int8_t decodeBuf[kBufSize];
|
||||
|
||||
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 = (int)(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++] = (int8_t) ((uint16_t)decoded & 0x00FF);
|
||||
decodeBuf[count++] = (int8_t)(((uint16_t)decoded & 0xFF00) >> 8);
|
||||
|
||||
// Channel 2
|
||||
snddat = getSoundData(ssct->SoundGroups[sndgrp], unit+1, sample);
|
||||
#if USE_FXD
|
||||
tmp2 = (int)(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++] = (int8_t) ((uint16_t)decoded & 0x00FF);
|
||||
decodeBuf[count++] = (int8_t)(((uint16_t)decoded & 0xFF00) >> 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(xad->block, decodeBuf, kBufSize);
|
||||
}
|
||||
|
||||
int MV_GetXAPosition(VoiceNode *voice)
|
||||
{
|
||||
auto xad = (xa_data *) voice->rawdataptr;
|
||||
return xad->pos;
|
||||
}
|
||||
|
||||
void MV_SetXAPosition(VoiceNode *voice, int position)
|
||||
{
|
||||
auto xad = (xa_data *) voice->rawdataptr;
|
||||
|
||||
if (position < XA_DATA_START || (size_t)position >= xad->length)
|
||||
{
|
||||
position = XA_DATA_START;
|
||||
xad->t1 = xad->t2 = xad->t1_x = xad->t2_x = 0;
|
||||
}
|
||||
|
||||
xad->pos = position;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
Function: MV_GetNextXABlock
|
||||
|
||||
Controls playback of XA data
|
||||
---------------------------------------------------------------------*/
|
||||
|
||||
static playbackstatus MV_GetNextXABlock
|
||||
(
|
||||
VoiceNode *voice
|
||||
)
|
||||
{
|
||||
auto xad = (xa_data *) voice->rawdataptr;
|
||||
XASector ssct;
|
||||
int coding;
|
||||
|
||||
do
|
||||
{
|
||||
size_t bytes = xad->length - xad->pos;
|
||||
|
||||
if (sizeof(XASector) < bytes)
|
||||
bytes = sizeof(XASector);
|
||||
|
||||
memcpy(&ssct, (int8_t *)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 = divideu32(voice->SamplingRate * voice->PitchScale, MV_MixRate);
|
||||
voice->FixedPointBufferSize = ( voice->RateScale * MV_MIXBUFFERSIZE ) - voice->RateScale;
|
||||
MV_SetVoiceMixMode( voice );
|
||||
|
||||
uint32_t samples;
|
||||
|
||||
if (voice->channels == 2)
|
||||
{
|
||||
decodeSoundSectStereo(&ssct, xad);
|
||||
samples = kSamplesStereo;
|
||||
}
|
||||
else
|
||||
{
|
||||
decodeSoundSectMono(&ssct, xad);
|
||||
samples = kSamplesMono;
|
||||
}
|
||||
|
||||
voice->sound = (char *)xad->block;
|
||||
voice->length = samples << 16;
|
||||
voice->position = 0;
|
||||
voice->BlockLength = 0;
|
||||
|
||||
if (xad->length == xad->pos)
|
||||
{
|
||||
if (voice->LoopSize > 0)
|
||||
{
|
||||
xad->pos = XA_DATA_START;
|
||||
xad->t1 = xad->t2 = xad->t1_x = xad->t2_x = 0;
|
||||
}
|
||||
else
|
||||
return NoMoreData;
|
||||
}
|
||||
|
||||
return KeepPlaying;
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
Function: MV_PlayXA3D
|
||||
|
||||
Begin playback of sound data at specified angle and distance
|
||||
from listener.
|
||||
---------------------------------------------------------------------*/
|
||||
|
||||
int MV_PlayXA3D(char *ptr, uint32_t length, int loophow, int pitchoffset, int angle, int distance, int priority, float volume,
|
||||
intptr_t callbackval)
|
||||
{
|
||||
int left;
|
||||
int right;
|
||||
int mid;
|
||||
int vol;
|
||||
int status;
|
||||
|
||||
if (!MV_Installed)
|
||||
return MV_SetErrorCode(MV_NotInstalled);
|
||||
|
||||
if (distance < 0)
|
||||
{
|
||||
distance = -distance;
|
||||
angle += MV_NUMPANPOSITIONS / 2;
|
||||
}
|
||||
|
||||
vol = MIX_VOLUME(distance);
|
||||
|
||||
// Ensure angle is within 0 - 127
|
||||
angle &= MV_MAXPANPOSITION;
|
||||
|
||||
left = MV_PanTable[angle][vol].left;
|
||||
right = MV_PanTable[angle][vol].right;
|
||||
mid = max(0, 255 - distance);
|
||||
|
||||
status = MV_PlayXA(ptr, length, loophow, -1, pitchoffset, mid, left, right, priority, volume, callbackval);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
Function: MV_PlayXA
|
||||
|
||||
Begin playback of sound data with the given sound levels and
|
||||
priority.
|
||||
---------------------------------------------------------------------*/
|
||||
|
||||
int MV_PlayXA(char *ptr, uint32_t length, int loopstart, int loopend, int pitchoffset, int vol, int left, int right,
|
||||
int priority, float volume, intptr_t callbackval)
|
||||
{
|
||||
VoiceNode *voice;
|
||||
xa_data * xad = 0;
|
||||
|
||||
UNREFERENCED_PARAMETER(loopend);
|
||||
|
||||
if (!MV_Installed)
|
||||
return MV_SetErrorCode(MV_NotInstalled);
|
||||
|
||||
xad = (xa_data *) Xcalloc( 1, sizeof(xa_data) );
|
||||
if (!xad)
|
||||
return MV_SetErrorCode(MV_InvalidFile);
|
||||
|
||||
xad->ptr = ptr;
|
||||
xad->pos = XA_DATA_START;
|
||||
xad->t1 = xad->t2 = xad->t1_x = xad->t2_x = 0;
|
||||
xad->length = length;
|
||||
|
||||
// Request a voice from the voice pool
|
||||
voice = MV_AllocVoice(priority);
|
||||
if (voice == nullptr)
|
||||
{
|
||||
Xfree(xad);
|
||||
return MV_SetErrorCode(MV_NoVoices);
|
||||
}
|
||||
|
||||
xad->owner = voice;
|
||||
|
||||
voice->wavetype = FMT_XA;
|
||||
voice->rawdataptr = (void*)xad;
|
||||
voice->GetSound = MV_GetNextXABlock;
|
||||
voice->NextBlock = (char *)xad->block;
|
||||
voice->LoopCount = 0;
|
||||
voice->BlockLength = 0;
|
||||
voice->PitchScale = PITCH_GetScale( pitchoffset );
|
||||
voice->next = nullptr;
|
||||
voice->prev = nullptr;
|
||||
voice->priority = priority;
|
||||
voice->callbackval = callbackval;
|
||||
|
||||
voice->bits = 16;
|
||||
|
||||
voice->Paused = FALSE;
|
||||
|
||||
voice->LoopStart = 0;
|
||||
voice->LoopEnd = 0;
|
||||
voice->LoopSize = (loopstart >= 0 ? 1 : 0);
|
||||
|
||||
MV_SetVoiceVolume( voice, vol, left, right, volume );
|
||||
MV_PlayVoice( voice );
|
||||
|
||||
return voice->handle;
|
||||
}
|
||||
|
||||
|
||||
void MV_ReleaseXAVoice( VoiceNode * voice )
|
||||
{
|
||||
auto xad = (xa_data *) voice->rawdataptr;
|
||||
|
||||
if (voice->wavetype != FMT_XA) {
|
||||
return;
|
||||
}
|
||||
|
||||
voice->rawdataptr = 0;
|
||||
voice->length = 0;
|
||||
voice->sound = nullptr;
|
||||
Xfree(xad);
|
||||
}
|
|
@ -1,333 +0,0 @@
|
|||
|
||||
#include "compat.h"
|
||||
|
||||
#ifdef HAVE_XMP
|
||||
|
||||
#include "_multivc.h"
|
||||
#include "multivoc.h"
|
||||
#include "pitch.h"
|
||||
#include "pragmas.h"
|
||||
|
||||
#define BUILDING_STATIC
|
||||
#include "libxmp-lite/xmp.h"
|
||||
|
||||
typedef struct {
|
||||
void * ptr;
|
||||
VoiceNode *owner;
|
||||
size_t length;
|
||||
xmp_context context;
|
||||
int time;
|
||||
} xmp_data;
|
||||
|
||||
int MV_GetXMPPosition(VoiceNode *voice)
|
||||
{
|
||||
auto xmpd = (xmp_data *)voice->rawdataptr;
|
||||
return xmpd->time;
|
||||
}
|
||||
|
||||
void MV_SetXMPPosition(VoiceNode *voice, int position)
|
||||
{
|
||||
auto xmpd = (xmp_data *)voice->rawdataptr;
|
||||
xmp_seek_time(xmpd->context, position);
|
||||
}
|
||||
|
||||
static playbackstatus MV_GetNextXMPBlock(VoiceNode *voice)
|
||||
{
|
||||
auto xmpd = (xmp_data *)voice->rawdataptr;
|
||||
struct xmp_frame_info mi;
|
||||
|
||||
if (xmp_play_frame(xmpd->context) != 0)
|
||||
{
|
||||
if (voice->LoopSize > 0)
|
||||
{
|
||||
xmp_restart_module(xmpd->context);
|
||||
if (xmp_play_frame(xmpd->context) != 0)
|
||||
return NoMoreData;
|
||||
}
|
||||
else
|
||||
return NoMoreData;
|
||||
}
|
||||
|
||||
xmp_get_frame_info(xmpd->context, &mi);
|
||||
|
||||
xmpd->time = mi.time;
|
||||
|
||||
uint32_t const samples = mi.buffer_size / (2 * (16/8)); // since 2-channel, 16-bit is hardcoded
|
||||
// uint32_t const samples = mi.buffer_size / (voice->channels * (voice->bits / 8));
|
||||
|
||||
voice->sound = (char const *)mi.buffer;
|
||||
voice->length = samples << 16;
|
||||
voice->position = 0;
|
||||
voice->BlockLength = 0;
|
||||
|
||||
MV_SetVoiceMixMode(voice);
|
||||
|
||||
return KeepPlaying;
|
||||
}
|
||||
|
||||
int MV_PlayXMP3D(char *ptr, uint32_t length, int loophow, int pitchoffset, int angle, int distance, int priority, float volume, intptr_t callbackval)
|
||||
{
|
||||
int left;
|
||||
int right;
|
||||
int mid;
|
||||
int vol;
|
||||
int status;
|
||||
|
||||
if (!MV_Installed)
|
||||
return MV_SetErrorCode(MV_NotInstalled);
|
||||
|
||||
if (distance < 0)
|
||||
{
|
||||
distance = -distance;
|
||||
angle += MV_NUMPANPOSITIONS / 2;
|
||||
}
|
||||
|
||||
vol = MIX_VOLUME(distance);
|
||||
|
||||
// Ensure angle is within 0 - 127
|
||||
angle &= MV_MAXPANPOSITION;
|
||||
|
||||
left = MV_PanTable[angle][vol].left;
|
||||
right = MV_PanTable[angle][vol].right;
|
||||
mid = max( 0, 255 - distance );
|
||||
|
||||
status = MV_PlayXMP(ptr, length, loophow, -1, pitchoffset, mid, left, right, priority, volume, callbackval);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int MV_PlayXMP(char *ptr, uint32_t length, int loopstart, int loopend, int pitchoffset, int vol, int left, int right, int priority, float volume, intptr_t callbackval)
|
||||
{
|
||||
VoiceNode *voice;
|
||||
xmp_data * xmpd = 0;
|
||||
int retval;
|
||||
|
||||
UNREFERENCED_PARAMETER(loopend);
|
||||
|
||||
if (!MV_Installed)
|
||||
return MV_SetErrorCode(MV_NotInstalled);
|
||||
|
||||
xmpd = (xmp_data *)Xcalloc(1, sizeof(xmp_data));
|
||||
if (!xmpd)
|
||||
return MV_SetErrorCode(MV_InvalidFile);
|
||||
|
||||
xmpd->ptr = ptr;
|
||||
xmpd->length = length;
|
||||
|
||||
if ((xmpd->context = xmp_create_context()) == nullptr)
|
||||
{
|
||||
Xfree(xmpd);
|
||||
return MV_SetErrorCode(MV_InvalidFile);
|
||||
}
|
||||
|
||||
if ((retval = xmp_load_module_from_memory(xmpd->context, ptr, length)) != 0)
|
||||
{
|
||||
Xfree(xmpd);
|
||||
MV_Printf("MV_PlayXMP: xmp_load_module_from_memory failed (%i)\n", retval);
|
||||
return MV_SetErrorCode(MV_InvalidFile);
|
||||
}
|
||||
|
||||
// Request a voice from the voice pool
|
||||
voice = MV_AllocVoice(priority);
|
||||
if (voice == nullptr)
|
||||
{
|
||||
xmp_release_module(xmpd->context);
|
||||
xmp_free_context(xmpd->context);
|
||||
Xfree(xmpd);
|
||||
return MV_SetErrorCode(MV_NoVoices);
|
||||
}
|
||||
|
||||
xmpd->owner = voice;
|
||||
|
||||
voice->length = 0;
|
||||
voice->sound = 0;
|
||||
|
||||
voice->wavetype = FMT_XMP;
|
||||
voice->rawdataptr = (void*)xmpd;
|
||||
voice->GetSound = MV_GetNextXMPBlock;
|
||||
voice->LoopCount = 0;
|
||||
voice->BlockLength = 0;
|
||||
voice->PitchScale = PITCH_GetScale(pitchoffset);
|
||||
voice->next = nullptr;
|
||||
voice->prev = nullptr;
|
||||
voice->priority = priority;
|
||||
voice->callbackval = callbackval;
|
||||
|
||||
voice->bits = 16;
|
||||
voice->channels = 2;
|
||||
voice->SamplingRate = MV_MixRate;
|
||||
|
||||
voice->Paused = FALSE;
|
||||
|
||||
voice->LoopStart = 0;
|
||||
voice->LoopEnd = 0;
|
||||
voice->LoopSize = loopstart >= 0 ? 1 : 0;
|
||||
|
||||
xmp_start_player(xmpd->context, MV_MixRate, 0);
|
||||
xmp_set_player(xmpd->context, XMP_PLAYER_INTERP, XMP_INTERP_SPLINE);
|
||||
|
||||
// CODEDUP multivoc.c MV_SetVoicePitch
|
||||
voice->RateScale = divideu32(voice->SamplingRate * voice->PitchScale, MV_MixRate);
|
||||
voice->FixedPointBufferSize = (voice->RateScale * MV_MIXBUFFERSIZE) - voice->RateScale;
|
||||
MV_SetVoiceMixMode(voice);
|
||||
|
||||
MV_SetVoiceVolume(voice, vol, left, right, volume);
|
||||
MV_PlayVoice(voice);
|
||||
|
||||
return voice->handle;
|
||||
}
|
||||
|
||||
void MV_ReleaseXMPVoice(VoiceNode * voice)
|
||||
{
|
||||
auto xmpd = (xmp_data *) voice->rawdataptr;
|
||||
|
||||
if (voice->wavetype != FMT_XMP)
|
||||
return;
|
||||
|
||||
voice->rawdataptr = 0;
|
||||
voice->length = 0;
|
||||
voice->sound = nullptr;
|
||||
|
||||
xmp_end_player(xmpd->context);
|
||||
xmp_release_module(xmpd->context);
|
||||
xmp_free_context(xmpd->context);
|
||||
Xfree(xmpd);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include "_multivc.h"
|
||||
|
||||
static char const NoXMP[] = "MV_PlayXMP: libxmp-lite support not included in this binary.\n";
|
||||
|
||||
int MV_PlayXMP(char *ptr, uint32_t ptrlength, int loopstart, int loopend, int pitchoffset, int vol,
|
||||
int left, int right, int priority, float volume, intptr_t callbackval)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(ptr);
|
||||
UNREFERENCED_PARAMETER(ptrlength);
|
||||
UNREFERENCED_PARAMETER(loopstart);
|
||||
UNREFERENCED_PARAMETER(loopend);
|
||||
UNREFERENCED_PARAMETER(pitchoffset);
|
||||
UNREFERENCED_PARAMETER(vol);
|
||||
UNREFERENCED_PARAMETER(left);
|
||||
UNREFERENCED_PARAMETER(right);
|
||||
UNREFERENCED_PARAMETER(priority);
|
||||
UNREFERENCED_PARAMETER(volume);
|
||||
UNREFERENCED_PARAMETER(callbackval);
|
||||
|
||||
MV_Printf(NoXMP);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int MV_PlayXMP3D(char *ptr, uint32_t ptrlength, int loophow, int pitchoffset, int angle,
|
||||
int distance, int priority, float volume, intptr_t callbackval)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(ptr);
|
||||
UNREFERENCED_PARAMETER(ptrlength);
|
||||
UNREFERENCED_PARAMETER(loophow);
|
||||
UNREFERENCED_PARAMETER(pitchoffset);
|
||||
UNREFERENCED_PARAMETER(angle);
|
||||
UNREFERENCED_PARAMETER(distance);
|
||||
UNREFERENCED_PARAMETER(priority);
|
||||
UNREFERENCED_PARAMETER(volume);
|
||||
UNREFERENCED_PARAMETER(callbackval);
|
||||
|
||||
MV_Printf(NoXMP);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// KEEPINSYNC libxmp-lite/src/*_load.c
|
||||
|
||||
static int it_test_memory(char const *ptr, uint32_t ptrlength)
|
||||
{
|
||||
static char const it_magic[] = "IMPM";
|
||||
|
||||
if (ptrlength < sizeof(it_magic)-1 ||
|
||||
memcmp(ptr, it_magic, sizeof(it_magic)-1))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mod_test_memory(char const *ptr, uint32_t ptrlength)
|
||||
{
|
||||
if (ptrlength < 1084)
|
||||
return -1;
|
||||
|
||||
char const * const buf = ptr + 1080;
|
||||
|
||||
if (!strncmp(buf + 2, "CH", 2) && isdigit((int)buf[0]) && isdigit((int)buf[1]))
|
||||
{
|
||||
int i = (buf[0] - '0') * 10 + buf[1] - '0';
|
||||
if (i > 0 && i <= 32)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strncmp(buf + 1, "CHN", 3) && isdigit((int)*buf))
|
||||
{
|
||||
if (*buf >= '0' && *buf <= '9')
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!memcmp(buf, "M.K.", 4))
|
||||
return 0;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int s3m_test_memory(char const *ptr, uint32_t ptrlength)
|
||||
{
|
||||
static char const s3m_magic[] = "SCRM";
|
||||
#define s3m_magic_offset 44
|
||||
|
||||
if (ptrlength < s3m_magic_offset + sizeof(s3m_magic)-1 ||
|
||||
memcmp(ptr + s3m_magic_offset, s3m_magic, sizeof(s3m_magic)-1) ||
|
||||
ptr[29] != 0x10)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xm_test_memory(char const *ptr, uint32_t ptrlength)
|
||||
{
|
||||
static char const xm_magic[] = "Extended Module: ";
|
||||
|
||||
if (ptrlength < sizeof(xm_magic)-1 ||
|
||||
memcmp(ptr, xm_magic, sizeof(xm_magic)-1))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mtm_test_memory(char const *ptr, uint32_t ptrlength)
|
||||
{
|
||||
static char const mtm_magic[] = "MTM\x10";
|
||||
|
||||
if (ptrlength < sizeof(mtm_magic)-1 ||
|
||||
memcmp(ptr, mtm_magic, sizeof(mtm_magic)-1))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int MV_IdentifyXMP(char const *ptr, uint32_t ptrlength)
|
||||
{
|
||||
static decltype(mod_test_memory) * const module_test_functions[] =
|
||||
{
|
||||
it_test_memory,
|
||||
mod_test_memory,
|
||||
s3m_test_memory,
|
||||
xm_test_memory,
|
||||
mtm_test_memory,
|
||||
};
|
||||
|
||||
for (auto const test_module : module_test_functions)
|
||||
{
|
||||
if (test_module(ptr, ptrlength) == 0)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -360,6 +360,19 @@ void InitFileSystem(TArray<GrpEntry>& groups)
|
|||
Files.Push(lastfn);
|
||||
}
|
||||
}
|
||||
const char* key;
|
||||
const char* value;
|
||||
if (GameConfig->SetSection("global.Autoload"))
|
||||
{
|
||||
while (GameConfig->NextInSection(key, value))
|
||||
{
|
||||
if (stricmp(key, "Path") == 0)
|
||||
{
|
||||
FString nice = NicePath(value);
|
||||
D_AddFile(Files, nice);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TArray<FString> todelete;
|
||||
fileSystem.InitMultipleFiles(Files, todelete);
|
||||
|
|
|
@ -75,23 +75,6 @@ MusicVolumeMap MusicVolumes;
|
|||
bool MusicPaused;
|
||||
|
||||
|
||||
void S_CreateStream()
|
||||
{
|
||||
}
|
||||
|
||||
void S_PauseStream(bool pause)
|
||||
{
|
||||
}
|
||||
|
||||
void S_StopStream()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void S_SetStreamVolume(float vol)
|
||||
{
|
||||
|
||||
}
|
||||
//==========================================================================
|
||||
//
|
||||
// starts playing this song
|
||||
|
|
137
source/common/music/musicstream.cpp
Normal file
137
source/common/music/musicstream.cpp
Normal file
|
@ -0,0 +1,137 @@
|
|||
|
||||
#include "compat.h"
|
||||
|
||||
#include "../../audiolib/src/_multivc.h"
|
||||
#include "multivoc.h"
|
||||
#include "../../audiolib/src/pitch.h"
|
||||
#include "pragmas.h"
|
||||
#include "zmusic/zmusic.h"
|
||||
#include "s_music.h"
|
||||
#include "templates.h"
|
||||
#include "fx_man.h"
|
||||
#include "gamecvars.h"
|
||||
|
||||
static short buffer[2][16384];
|
||||
static float readbuffer[16384];
|
||||
static int whichbuffer;
|
||||
static bool StreamPaused;
|
||||
static int StreamHandle;
|
||||
static VoiceNode* voice;
|
||||
|
||||
static bool FillStream(void* buff, int len)
|
||||
{
|
||||
if (StreamPaused)
|
||||
{
|
||||
memset((char*)buff, 0, len);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool written = ZMusic_FillStream(mus_playing.handle, buff, len);
|
||||
|
||||
if (!written)
|
||||
{
|
||||
memset((char*)buff, 0, len);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static playbackstatus MV_GetNextZMusicBlock(VoiceNode *voice)
|
||||
{
|
||||
if (!FillStream(readbuffer, 32768))
|
||||
return NoMoreData;
|
||||
|
||||
for (int i = 0; i <16384; i++)
|
||||
{
|
||||
buffer[whichbuffer][i] = (short)clamp(readbuffer[i]*32767., -32768., 32767.);
|
||||
}
|
||||
|
||||
voice->sound = (const char*)buffer[whichbuffer];
|
||||
voice->length = 8192;
|
||||
voice->position = 0;
|
||||
voice->BlockLength = 0;
|
||||
whichbuffer ^= 1;
|
||||
|
||||
MV_SetVoiceMixMode(voice);
|
||||
|
||||
return KeepPlaying;
|
||||
}
|
||||
|
||||
void S_CreateStream()
|
||||
{
|
||||
if (!MV_Installed)
|
||||
return;// MV_SetErrorCode(MV_NotInstalled);
|
||||
|
||||
// Request a voice from the voice pool
|
||||
voice = MV_AllocVoice(FX_MUSIC_PRIORITY);
|
||||
if (voice == nullptr)
|
||||
{
|
||||
return;// MV_SetErrorCode(MV_NoVoices);
|
||||
}
|
||||
|
||||
voice->length = 0;
|
||||
voice->sound = 0;
|
||||
|
||||
voice->wavetype = FMT_ZMUSIC;
|
||||
voice->rawdataptr = nullptr;
|
||||
voice->GetSound = MV_GetNextZMusicBlock;
|
||||
voice->LoopCount = 0;
|
||||
voice->BlockLength = 0;
|
||||
voice->PitchScale = PITCH_GetScale(0);
|
||||
voice->next = nullptr;
|
||||
voice->prev = nullptr;
|
||||
voice->priority = FX_MUSIC_PRIORITY;
|
||||
voice->callbackval = 0;
|
||||
|
||||
voice->bits = 16;
|
||||
voice->channels = 2;
|
||||
voice->SamplingRate = MV_MixRate;
|
||||
|
||||
voice->Paused = FALSE;
|
||||
|
||||
voice->LoopStart = 0;
|
||||
voice->LoopEnd = 0;
|
||||
voice->LoopSize = 1;
|
||||
|
||||
// CODEDUP multivoc.c MV_SetVoicePitch
|
||||
voice->RateScale = divideu32(voice->SamplingRate * voice->PitchScale, MV_MixRate);
|
||||
voice->FixedPointBufferSize = (voice->RateScale * MV_MIXBUFFERSIZE) - voice->RateScale;
|
||||
MV_SetVoiceMixMode(voice);
|
||||
|
||||
mus_volume.Callback();
|
||||
MV_PlayVoice(voice);
|
||||
|
||||
return;// voice->handle;
|
||||
}
|
||||
|
||||
void MV_ReleaseZMusicVoice(VoiceNode * voice)
|
||||
{
|
||||
if (voice->wavetype != FMT_ZMUSIC)
|
||||
return;
|
||||
|
||||
voice->rawdataptr = 0;
|
||||
voice->length = 0;
|
||||
voice->sound = nullptr;
|
||||
StreamHandle = 0;
|
||||
::voice = nullptr;
|
||||
}
|
||||
|
||||
void S_PauseStream(bool pause)
|
||||
{
|
||||
StreamPaused = true;
|
||||
}
|
||||
|
||||
void S_StopStream()
|
||||
{
|
||||
if (StreamHandle > 0)
|
||||
FX_StopSound(StreamHandle);
|
||||
StreamHandle = 0;
|
||||
voice = nullptr;
|
||||
}
|
||||
|
||||
void S_SetStreamVolume(float vol)
|
||||
{
|
||||
if (voice)
|
||||
MV_SetVoiceVolume(voice, int(vol * 255), int(vol * 255), int(vol * 255), 1);
|
||||
}
|
|
@ -32,6 +32,11 @@
|
|||
#include "tarray.h"
|
||||
#include "name.h"
|
||||
|
||||
void S_CreateStream();
|
||||
void S_PauseStream(bool pause);
|
||||
void S_StopStream();
|
||||
void S_SetStreamVolume(float vol);
|
||||
|
||||
|
||||
//
|
||||
void S_InitMusic ();
|
||||
|
|
Loading…
Reference in a new issue