Add functionality for tracker module playback using the libxmp library. New formats supported: MOD, IT, S3M, XM.
This commit is contained in:
11
Makefile
11
Makefile
@@ -172,6 +172,10 @@ ifndef USE_CODEC_VORBIS
|
||||
USE_CODEC_VORBIS=0
|
||||
endif
|
||||
|
||||
ifndef USE_CODEC_XMP
|
||||
USE_CODEC_XMP=1
|
||||
endif
|
||||
|
||||
ifndef USE_CODEC_OPUS
|
||||
USE_CODEC_OPUS=1
|
||||
endif
|
||||
@@ -1000,6 +1004,12 @@ ifeq ($(USE_CODEC_VORBIS),1)
|
||||
NEED_OGG=1
|
||||
endif
|
||||
|
||||
ifeq ($(USE_CODEC_XMP),1)
|
||||
CLIENT_CFLAGS += -DUSE_CODEC_XMP
|
||||
CLIENT_LIBS += -lxmp
|
||||
NEED_OGG=1
|
||||
endif
|
||||
|
||||
ifeq ($(USE_CODEC_OPUS),1)
|
||||
CLIENT_CFLAGS += -DUSE_CODEC_OPUS
|
||||
ifeq ($(USE_INTERNAL_OPUS),1)
|
||||
@@ -1534,6 +1544,7 @@ Q3OBJ = \
|
||||
$(B)/client/snd_codec_wav.o \
|
||||
$(B)/client/snd_codec_ogg.o \
|
||||
$(B)/client/snd_codec_opus.o \
|
||||
$(B)/client/snd_codec_xmp.o \
|
||||
\
|
||||
$(B)/client/qal.o \
|
||||
$(B)/client/snd_openal.o \
|
||||
|
@@ -18,8 +18,13 @@ VERSION=1.36+0.8.8
|
||||
USE_CODEC_VORBIS=1
|
||||
USE_CODEC_OPUS=0
|
||||
|
||||
USE_CODEC_XMP=1
|
||||
|
||||
# Can't use CURL on my system atm
|
||||
USE_CURL=0
|
||||
|
||||
# This doesn't work with OpenArena yet
|
||||
BUILD_RENDERER_OPENGL2=0
|
||||
BUILD_RENDERER_OPENGL2=1
|
||||
# You can disable the renderer libraries and build in the OA renderer by default
|
||||
USE_RENDERER_DLOPEN=1
|
||||
|
||||
|
@@ -84,7 +84,6 @@ $ ./openarena.x86_64 +set cl_renderer opengl2
|
||||
* Potential GLSL debugging fix that was made available after 0.8.8 release
|
||||
- Need to find a link to this. Is this real?
|
||||
* Fix Ogg Vorbis music looping hitching bug.
|
||||
* Module player for music as an alternative to streams (.mod, .it, .xm and .s3m formats)
|
||||
* Software rendering module based on TinyGL, optimized for performance.
|
||||
* Direct3D7 rendering module. 7 particularly, for compatibility with more legacy graphics chipsets and underperforming onboard video chipsets without a good OpenGL driver.
|
||||
* Restore Win9X support (Regressions are in PSAPI and the TCP stack)
|
||||
@@ -128,12 +127,16 @@ $ ./openarena.x86_64 +set cl_renderer opengl2
|
||||
|
||||
* Widescreen horizontal expansion support
|
||||
* Paletted texturing support, for the few older cards that support the paletted texture extensions (3dfx)
|
||||
* Many changes to the flares code - sun flares, support for custom flare shaders, a lower quality flare option (huge frametate jump on oa_pvomit), additional lens reflection effects, configurable lens reflection types for dynamic lights, sun or map lights
|
||||
* Many changes to the flares code - sun flares, support for custom flare shaders, a lower quality flare option (huge framerate jump on oa_pvomit), additional lens reflection effects, configurable lens reflection types for dynamic lights, sun or map lights
|
||||
* Brightness by blended quad, allowing overbrights to work in a window without the need for a fragment shader
|
||||
* More postprocessing effects, including a multipass shader effect for simulating the looks of a popular 1996 3d card
|
||||
* Slowness feature to simulate the rough speed of a typical 6th generation computer setup by default (common 1998 computers), potentially useful for content producers looking to optimize their stuff
|
||||
|
||||
|
||||
## client changes ##
|
||||
|
||||
* Module player for music as an alternative to streams (.mod, .it, .xm and .s3m formats). Uses the libxmp library.
|
||||
|
||||
|
||||
# ioquake3 README #
|
||||
|
||||
|
@@ -124,6 +124,14 @@ void S_CodecInit()
|
||||
{
|
||||
codecs = NULL;
|
||||
|
||||
#ifdef USE_CODEC_XMP
|
||||
S_CodecRegister(&xmp_codec);
|
||||
S_CodecRegister(&xmp_mod_codec);
|
||||
S_CodecRegister(&xmp_s3m_codec);
|
||||
S_CodecRegister(&xmp_xm_codec);
|
||||
S_CodecRegister(&xmp_it_codec);
|
||||
#endif
|
||||
|
||||
#ifdef USE_CODEC_OPUS
|
||||
S_CodecRegister(&opus_codec);
|
||||
#endif
|
||||
|
@@ -104,4 +104,13 @@ void S_OggOpus_CodecCloseStream(snd_stream_t *stream);
|
||||
int S_OggOpus_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer);
|
||||
#endif // USE_CODEC_OPUS
|
||||
|
||||
// XMP (tracker music) codec
|
||||
#ifdef USE_CODEC_XMP
|
||||
extern snd_codec_t xmp_codec;
|
||||
extern snd_codec_t xmp_mod_codec;
|
||||
extern snd_codec_t xmp_xm_codec;
|
||||
extern snd_codec_t xmp_it_codec;
|
||||
extern snd_codec_t xmp_s3m_codec;
|
||||
#endif // USE_CODEC_XMP
|
||||
|
||||
#endif // !_SND_CODEC_H_
|
||||
|
290
code/client/snd_codec_xmp.c
Normal file
290
code/client/snd_codec_xmp.c
Normal file
@@ -0,0 +1,290 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
Copyright (C) 2005 Stuart Dalton (badcdev@gmail.com)
|
||||
Copyright (C) 2014 leilei
|
||||
|
||||
This file is part of Quake III Arena source code.
|
||||
|
||||
Quake III Arena source code 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.
|
||||
|
||||
Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifdef USE_CODEC_XMP
|
||||
|
||||
// includes for the Q3 sound system
|
||||
#include "client.h"
|
||||
#include "snd_codec.h"
|
||||
|
||||
// includes for XMP
|
||||
#include <xmp.h>
|
||||
|
||||
|
||||
|
||||
|
||||
// leilei - XMP
|
||||
xmp_context xmpsong;
|
||||
//int sound_init(int, int);
|
||||
void sound_play(void *, int);
|
||||
void sound_deinit(void);
|
||||
|
||||
|
||||
|
||||
extern int samplingrate; // from snd_dma
|
||||
|
||||
void S_XMP_StartSong ( void ){
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
void S_XMP_EndSong ( void ){
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
int aintistreaming = 0;
|
||||
char *streamilename;
|
||||
/*
|
||||
=================
|
||||
S_XMP_CodecLoad
|
||||
=================
|
||||
*/
|
||||
void *S_XMP_CodecLoad(const char *filename, snd_info_t *info)
|
||||
{
|
||||
// This is not a codec for sound effects
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
S_XMP_CodecOpenStream
|
||||
=================
|
||||
*/
|
||||
|
||||
// FIXME: there's a memory leak here if you start the same song many many many many times.
|
||||
snd_stream_t *S_XMP_CodecOpenStream(const char *filename)
|
||||
{
|
||||
snd_stream_t *rv;
|
||||
|
||||
// First let's close whatever song we had....
|
||||
|
||||
// Open
|
||||
rv = S_CodecUtilOpen(filename, &xmp_codec);
|
||||
if(!rv)
|
||||
return NULL;
|
||||
|
||||
// Com_Printf("OPENSTREAM %s\n", filename);
|
||||
|
||||
{
|
||||
fileHandle_t file;
|
||||
void *buffer;
|
||||
|
||||
// Try to open the file
|
||||
FS_FOpenFileRead(filename, &file, qtrue);
|
||||
if(!file)
|
||||
{
|
||||
Com_Printf( S_COLOR_RED "ERROR: No.\"%s\"\n",filename);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// Allocate some memory
|
||||
long thelength = FS_ReadFile(filename, buffer);
|
||||
|
||||
|
||||
buffer = Hunk_AllocateTempMemory(thelength);
|
||||
if(!buffer)
|
||||
{
|
||||
FS_FCloseFile(file);
|
||||
Com_Printf( S_COLOR_RED "ERROR: Out of memory reading \"%s\"\n",
|
||||
filename);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FS_Read(buffer, thelength, file);
|
||||
|
||||
|
||||
// OK!
|
||||
struct xmp_module_info mi;
|
||||
|
||||
xmpsong = xmp_create_context();
|
||||
int itsloaded = 0;
|
||||
|
||||
itsloaded = xmp_load_module_from_memory(xmpsong, buffer, 0);
|
||||
|
||||
// Free our memory and close the file.
|
||||
Hunk_FreeTempMemory(buffer);
|
||||
FS_FCloseFile(file); // unfortunately these do not help with the leak
|
||||
|
||||
if (itsloaded == 0)
|
||||
itsloaded = xmp_start_player(xmpsong, 44100, 0); // TODO: do sample rate of the mixer.
|
||||
|
||||
if (itsloaded == 0){
|
||||
|
||||
// Com_Printf("XMP loaded our buffer of the file %s which is %i long \n", filename, thelength);
|
||||
xmp_get_module_info(xmpsong, &mi);
|
||||
// Com_Printf("Song Name: %s\n", mi.mod->name);
|
||||
// Com_Printf("CODECLOAD %s\n", filename);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
rv->info.size = 1337; // This doesn't matter!
|
||||
rv->pos = 0;
|
||||
|
||||
rv->info.rate = 44100;
|
||||
rv->info.width = 2;
|
||||
rv->info.channels = 2;
|
||||
rv->info.samples = 12;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
S_XMP_CodecCloseStream
|
||||
=================
|
||||
*/
|
||||
void S_XMP_CodecCloseStream(snd_stream_t *stream)
|
||||
{
|
||||
xmp_end_player(xmpsong);
|
||||
xmp_release_module(xmpsong);
|
||||
xmp_free_context(xmpsong);
|
||||
S_CodecUtilClose(&stream);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
S_OGG_CodecReadStream
|
||||
=================
|
||||
*/
|
||||
int S_XMP_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer)
|
||||
{
|
||||
// buffer handling
|
||||
struct xmp_module_info mi;
|
||||
struct xmp_frame_info fi;
|
||||
|
||||
int bytesRead, bytesLeft, c;
|
||||
char *bufPtr;
|
||||
|
||||
// check if input is valid
|
||||
if(!(stream && buffer))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(bytes <= 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
bytesRead = 0;
|
||||
bytesLeft = bytes;
|
||||
bufPtr = buffer;
|
||||
|
||||
// cycle until we have the requested or all available bytes read
|
||||
while(-1)
|
||||
{
|
||||
int yeah=xmp_play_buffer(xmpsong, buffer, bytesLeft, 0);
|
||||
|
||||
if (yeah == 0){ // if we can play it...
|
||||
xmp_get_frame_info(xmpsong, &fi);
|
||||
|
||||
c = fi.buffer;
|
||||
|
||||
// no more bytes are left
|
||||
if(c <= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
bytesRead += c;
|
||||
bytesLeft -= c;
|
||||
bufPtr += c;
|
||||
xmp_get_module_info(xmpsong, &mi);
|
||||
|
||||
// we have enough bytes
|
||||
if(bytesLeft <= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else // if we can't play it JUST STOP OK
|
||||
{
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
|
||||
snd_codec_t xmp_codec =
|
||||
{
|
||||
"umx",
|
||||
S_XMP_CodecLoad,
|
||||
S_XMP_CodecOpenStream,
|
||||
S_XMP_CodecReadStream,
|
||||
S_XMP_CodecCloseStream,
|
||||
NULL
|
||||
};
|
||||
|
||||
snd_codec_t xmp_mod_codec =
|
||||
{
|
||||
"mod",
|
||||
S_XMP_CodecLoad,
|
||||
S_XMP_CodecOpenStream,
|
||||
S_XMP_CodecReadStream,
|
||||
S_XMP_CodecCloseStream,
|
||||
NULL
|
||||
};
|
||||
|
||||
snd_codec_t xmp_it_codec =
|
||||
{
|
||||
"it",
|
||||
S_XMP_CodecLoad,
|
||||
S_XMP_CodecOpenStream,
|
||||
S_XMP_CodecReadStream,
|
||||
S_XMP_CodecCloseStream,
|
||||
NULL
|
||||
};
|
||||
|
||||
snd_codec_t xmp_s3m_codec =
|
||||
{
|
||||
"s3m",
|
||||
S_XMP_CodecLoad,
|
||||
S_XMP_CodecOpenStream,
|
||||
S_XMP_CodecReadStream,
|
||||
S_XMP_CodecCloseStream,
|
||||
NULL
|
||||
};
|
||||
|
||||
snd_codec_t xmp_xm_codec =
|
||||
{
|
||||
"xm",
|
||||
S_XMP_CodecLoad,
|
||||
S_XMP_CodecOpenStream,
|
||||
S_XMP_CodecReadStream,
|
||||
S_XMP_CodecCloseStream,
|
||||
NULL
|
||||
};
|
||||
|
||||
#endif // USE_CODEC_XMP
|
@@ -33,6 +33,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#include "snd_codec.h"
|
||||
#include "client.h"
|
||||
|
||||
// leilei - mod playabck support
|
||||
|
||||
|
||||
void S_Update_( void );
|
||||
void S_Base_StopAllSounds(void);
|
||||
void S_Base_StopBackgroundTrack( void );
|
||||
@@ -55,6 +58,8 @@ channel_t s_channels[MAX_CHANNELS];
|
||||
channel_t loop_channels[MAX_CHANNELS];
|
||||
int numLoopChannels;
|
||||
|
||||
int samplingrate; // leilei - for snd_xmp
|
||||
|
||||
static int s_soundStarted;
|
||||
static qboolean s_soundMuted;
|
||||
|
||||
@@ -1198,6 +1203,9 @@ qboolean S_ScanChannelStarts( void ) {
|
||||
return newSamples;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
S_Update
|
||||
@@ -1325,6 +1333,7 @@ void S_Update_(void) {
|
||||
sane = 11; // 85hz
|
||||
}
|
||||
|
||||
samplingrate = dma.speed;
|
||||
ma = s_mixahead->value * dma.speed;
|
||||
op = s_mixPreStep->value + sane*dma.speed*0.01;
|
||||
|
||||
@@ -1404,6 +1413,7 @@ static void S_OpenBackgroundStream( const char *filename ) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
======================
|
||||
S_StartBackgroundTrack
|
||||
|
@@ -220,6 +220,8 @@ qboolean S_LoadSound( sfx_t *sfx )
|
||||
if(!data)
|
||||
return qfalse;
|
||||
|
||||
// leilei - don't be so paranoid about these
|
||||
#if 0
|
||||
if ( info.width == 1 ) {
|
||||
Com_DPrintf(S_COLOR_YELLOW "WARNING: %s is a 8 bit audio file\n", sfx->soundName);
|
||||
}
|
||||
@@ -227,7 +229,7 @@ qboolean S_LoadSound( sfx_t *sfx )
|
||||
if ( info.rate != 22050 ) {
|
||||
Com_DPrintf(S_COLOR_YELLOW "WARNING: %s is not a 22kHz audio file\n", sfx->soundName);
|
||||
}
|
||||
|
||||
#endif
|
||||
samples = Hunk_AllocateTempMemory(info.channels * info.samples * sizeof(short) * 2);
|
||||
|
||||
sfx->lastTimeUsed = Com_Milliseconds()+1;
|
||||
|
Reference in New Issue
Block a user