Add functionality for tracker module playback using the libxmp library. New formats supported: MOD, IT, S3M, XM.

This commit is contained in:
leilei-
2014-05-02 21:55:39 -04:00
parent 254b8ab22a
commit 74021abbf0
8 changed files with 342 additions and 4 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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