- hooked up ZMusic.

This commit is contained in:
Christoph Oelckers 2019-11-11 19:10:46 +01:00
parent 29d16868c9
commit ec6ce8b1ec
13 changed files with 165 additions and 1644 deletions

View file

@ -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
)

View file

@ -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)
{

View file

@ -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);

View file

@ -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);

View file

@ -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

View file

@ -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);

View file

@ -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);

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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);

View file

@ -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

View 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);
}

View file

@ -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 ();