/* =========================================================================== 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 =========================================================================== */ int xmpspeed = 22050; // assume 22050hz unless........ #ifdef USE_CODEC_XMP // includes for the Q3 sound system #include "client.h" #include "snd_codec.h" // includes for XMP #include // 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) { // First let's close whatever song we had.... // Open snd_stream_t *rv = S_CodecUtilOpen(filename, &xmp_codec); if(!rv) return NULL; // Com_Printf("OPENSTREAM %s\n", filename); { fileHandle_t file; // 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, NULL); void *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, xmpspeed, 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 = xmpspeed; 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; // check if input is valid if(!(stream && buffer)) { return 0; } if(bytes <= 0) { return 0; } int bytesRead = 0; int bytesLeft = bytes; char* 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); int c = fi.buffer_size; // 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