/* =========================================================================== Copyright (C) 1999-2005 Id Software, Inc. Copyright (C) 2005 Stuart Dalton (badcdev@gmail.com) Copyright (C) 2005-2006 Joerg Dietrich Copyright (C) 2006 Thilo Schulz 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 =========================================================================== */ // MP3 support is enabled by this define #if USE_CODEC_MP3 // includes for the Q3 sound system #include "client.h" #include "snd_codec.h" // includes for the MP3 codec #include "../libmad/mad.h" #define MP3_SAMPLE_WIDTH 2 #define MP3_PCMSAMPLES_PERSLICE 32 // buffer size used when reading through the mp3 #define MP3_DATA_BUFSIZ 128*1024 // undefine this if you don't want any dithering. #define MP3_DITHERING // Q3 MP3 codec snd_codec_t mp3_codec = { "mp3", S_MP3_CodecLoad, S_MP3_CodecOpenStream, S_MP3_CodecReadStream, S_MP3_CodecCloseStream, NULL }; // structure used for info purposes struct snd_codec_mp3_info { byte encbuf[MP3_DATA_BUFSIZ]; // left over bytes not consumed // by the decoder. struct mad_stream madstream; // uses encbuf as buffer. struct mad_frame madframe; // control structures for libmad. struct mad_synth madsynth; byte *pcmbuf; // buffer for not-used samples. int buflen; // length of buffer data. int pcmbufsize; // amount of allocated memory for // pcmbuf. This should have at least // the size of a decoded mp3 frame. byte *dest; // copy decoded data here. int destlen; // amount of already copied data. int destsize; // amount of bytes we must decode. }; /*************** MP3 utility functions ***************/ /* ================= S_MP3_ReadData ================= */ // feed libmad with data int S_MP3_ReadData(snd_stream_t *stream, struct mad_stream *madstream, byte *encbuf, int encbufsize) { int retval; int leftover; if(!stream) return -1; leftover = madstream->bufend - madstream->next_frame; if(leftover > 0) memmove(encbuf, madstream->this_frame, leftover); // Fill the buffer right to the end retval = FS_Read(&encbuf[leftover], encbufsize - leftover, stream->file); if(retval <= 0) { // EOF reached, that's ok. return 0; } mad_stream_buffer(madstream, encbuf, retval + leftover); return retval; } /* ================= S_MP3_Scanfile to determine the samplecount, we apparently must get *all* headers :( I basically used the xmms-mad plugin source to see how this stuff works. returns a value < 0 on error. ================= */ int S_MP3_Scanfile(snd_stream_t *stream) { struct mad_stream madstream; struct mad_header madheader; int retval; int samplecount; byte encbuf[MP3_DATA_BUFSIZ]; // error out on invalid input. if(!stream) return -1; mad_stream_init(&madstream); mad_header_init(&madheader); while(1) { retval = S_MP3_ReadData(stream, &madstream, encbuf, sizeof(encbuf)); if(retval < 0) return -1; else if(retval == 0) break; // Start decoding the headers. while(1) { if((retval = mad_header_decode(&madheader, &madstream)) < 0) { if(madstream.error == MAD_ERROR_BUFLEN) { // We need to read more data break; } if(!MAD_RECOVERABLE (madstream.error)) { // unrecoverable error... we must bail out. return retval; } mad_stream_skip(&madstream, madstream.skiplen); continue; } // we got a valid header. if(madheader.layer != MAD_LAYER_III) { // we don't support non-mp3s return -1; } if(!stream->info.samples) { // This here is the very first frame. Set initial values now, // that we expect to stay constant throughout the whole mp3. stream->info.rate = madheader.samplerate; stream->info.width = MP3_SAMPLE_WIDTH; stream->info.channels = MAD_NCHANNELS(&madheader); stream->info.samples = 0; stream->info.size = 0; // same here. stream->info.dataofs = 0; } else { // Check whether something changed that shouldn't. if(stream->info.rate != madheader.samplerate || stream->info.channels != MAD_NCHANNELS(&madheader)) return -1; } // Update the counters samplecount = MAD_NSBSAMPLES(&madheader) * MP3_PCMSAMPLES_PERSLICE; stream->info.samples += samplecount; stream->info.size += samplecount * stream->info.channels * stream->info.width; } } // Reset the file pointer so we can do the real decoding. FS_Seek(stream->file, 0, FS_SEEK_SET); return 0; } /************************ dithering functions ***************************/ #ifdef MP3_DITHERING // All dithering done here is taken from the GPL'ed xmms-mad plugin. /* Copyright (C) 1997 Makoto Matsumoto and Takuji Nishimura. */ /* Any feedback is very welcome. For any question, comments, */ /* see http://www.math.keio.ac.jp/matumoto/emt.html or email */ /* matumoto@math.keio.ac.jp */ /* Period parameters */ #define MP3_DITH_N 624 #define MP3_DITH_M 397 #define MATRIX_A 0x9908b0df /* constant vector a */ #define UPPER_MASK 0x80000000 /* most significant w-r bits */ #define LOWER_MASK 0x7fffffff /* least significant r bits */ /* Tempering parameters */ #define TEMPERING_MASK_B 0x9d2c5680 #define TEMPERING_MASK_C 0xefc60000 #define TEMPERING_SHIFT_U(y) (y >> 11) #define TEMPERING_SHIFT_S(y) (y << 7) #define TEMPERING_SHIFT_T(y) (y << 15) #define TEMPERING_SHIFT_L(y) (y >> 18) static unsigned long mt[MP3_DITH_N]; /* the array for the state vector */ static int mti=MP3_DITH_N+1; /* mti==MP3_DITH_N+1 means mt[MP3_DITH_N] is not initialized */ /* initializing the array with a NONZERO seed */ void sgenrand(unsigned long seed) { /* setting initial seeds to mt[MP3_DITH_N] using */ /* the generator Line 25 of Table 1 in */ /* [KNUTH 1981, The Art of Computer Programming */ /* Vol. 2 (2nd Ed.), pp102] */ mt[0]= seed & 0xffffffff; for (mti=1; mti= MP3_DITH_N) { /* generate MP3_DITH_N words at one time */ int kk; if (mti == MP3_DITH_N+1) /* if sgenrand() has not been called, */ sgenrand(4357); /* a default initial seed is used */ for (kk=0;kk> 1) ^ mag01[y & 0x1]; } for (;kk> 1) ^ mag01[y & 0x1]; } y = (mt[MP3_DITH_N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK); mt[MP3_DITH_N-1] = mt[MP3_DITH_M-1] ^ (y >> 1) ^ mag01[y & 0x1]; mti = 0; } y = mt[mti++]; y ^= TEMPERING_SHIFT_U(y); y ^= TEMPERING_SHIFT_S(y) & TEMPERING_MASK_B; y ^= TEMPERING_SHIFT_T(y) & TEMPERING_MASK_C; y ^= TEMPERING_SHIFT_L(y); return y; } long triangular_dither_noise(int nbits) { // parameter nbits : the peak-to-peak amplitude desired (in bits) // use with nbits set to 2 + nber of bits to be trimmed. // (because triangular is made from two uniformly distributed processes, // it starts at 2 bits peak-to-peak amplitude) // see The Theory of Dithered Quantization by Robert Alexander Wannamaker // for complete proof of why that's optimal long v = (genrand()/2 - genrand()/2); // in ]-2^31, 2^31[ //int signe = (v>0) ? 1 : -1; long P = 1 << (32 - nbits); // the power of 2 v /= P; // now v in ]-2^(nbits-1), 2^(nbits-1) [ return v; } #endif // MP3_DITHERING /************************ decoder functions ***************************/ /* ================= S_MP3_Scale Converts the signal to 16 bit LE-PCM data and does dithering. - borrowed from xmms-mad plugin source. ================= */ /* * xmms-mad - mp3 plugin for xmms * Copyright (C) 2001-2002 Sam Clegg */ signed int S_MP3_Scale(mad_fixed_t sample) { int n_bits_to_loose = MAD_F_FRACBITS + 1 - 16; #ifdef MP3_DITHERING int dither; #endif // round sample += (1L << (n_bits_to_loose - 1)); #ifdef MP3_DITHERING dither = triangular_dither_noise(n_bits_to_loose + 1); sample += dither; #endif /* clip */ if (sample >= MAD_F_ONE) sample = MAD_F_ONE - 1; else if (sample < -MAD_F_ONE) sample = -MAD_F_ONE; /* quantize */ return sample >> n_bits_to_loose; } /* ================= S_MP3_PCMCopy Copy and convert pcm data until bytecount bytes have been written. return the position in pcm->samples. indicate the amount of actually written bytes in wrotecnt. ================= */ int S_MP3_PCMCopy(byte *buf, struct mad_pcm *pcm, int bufofs, int sampleofs, int bytecount, int *wrotecnt) { int written = 0; signed int sample; int framesize = pcm->channels * MP3_SAMPLE_WIDTH; // add new pcm data. while(written < bytecount && sampleofs < pcm->length) { sample = S_MP3_Scale(pcm->samples[0][sampleofs]); #ifdef Q3_BIG_ENDIAN // output to 16 bit big endian PCM buf[bufofs++] = (sample >> 8) & 0xff; buf[bufofs++] = sample & 0xff; #else // output to 16 bit little endian PCM buf[bufofs++] = sample & 0xff; buf[bufofs++] = (sample >> 8) & 0xff; #endif if(pcm->channels == 2) { sample = S_MP3_Scale(pcm->samples[1][sampleofs]); #ifdef Q3_BIG_ENDIAN buf[bufofs++] = (sample >> 8) & 0xff; buf[bufofs++] = sample & 0xff; #else buf[bufofs++] = sample & 0xff; buf[bufofs++] = (sample >> 8) & 0xff; #endif } sampleofs++; written += framesize; } if(wrotecnt) *wrotecnt = written; return sampleofs; } /* ================= S_MP3_Decode ================= */ // gets executed for every decoded frame. int S_MP3_Decode(snd_stream_t *stream) { struct snd_codec_mp3_info *mp3info; struct mad_stream *madstream; struct mad_frame *madframe; struct mad_synth *madsynth; struct mad_pcm *pcm; int cursize; int samplecount; int needcount; int wrote; int retval; if(!stream) return -1; mp3info = stream->ptr; madstream = &mp3info->madstream; madframe = &mp3info->madframe; if(mad_frame_decode(madframe, madstream)) { if(madstream->error == MAD_ERROR_BUFLEN) { // we need more data. Read another chunk. retval = S_MP3_ReadData(stream, madstream, mp3info->encbuf, sizeof(mp3info->encbuf)); // call myself again now that buffer is full. if(retval > 0) retval = S_MP3_Decode(stream); } else if(MAD_RECOVERABLE(madstream->error)) { mad_stream_skip(madstream, madstream->skiplen); return S_MP3_Decode(stream); } else retval = -1; return retval; } // check whether this really is an mp3 if(madframe->header.layer != MAD_LAYER_III) return -1; // generate pcm data madsynth = &mp3info->madsynth; mad_synth_frame(madsynth, madframe); pcm = &madsynth->pcm; // perform a few checks to see whether something changed that shouldn't. if(stream->info.rate != pcm->samplerate || stream->info.channels != pcm->channels) { return -1; } // see whether we have got enough data now. cursize = pcm->length * pcm->channels * stream->info.width; needcount = mp3info->destsize - mp3info->destlen; // Copy exactly as many samples as required. samplecount = S_MP3_PCMCopy(mp3info->dest, pcm, mp3info->destlen, 0, needcount, &wrote); mp3info->destlen += wrote; if(samplecount < pcm->length) { // Not all samples got copied. Copy the rest into the pcm buffer. samplecount = S_MP3_PCMCopy(mp3info->pcmbuf, pcm, mp3info->buflen, samplecount, mp3info->pcmbufsize - mp3info->buflen, &wrote); mp3info->buflen += wrote; if(samplecount < pcm->length) { // The pcm buffer was not large enough. Make it bigger. byte *newbuf = Z_Malloc(cursize); if(mp3info->pcmbuf) { memcpy(newbuf, mp3info->pcmbuf, mp3info->buflen); Z_Free(mp3info->pcmbuf); } mp3info->pcmbuf = newbuf; mp3info->pcmbufsize = cursize; samplecount = S_MP3_PCMCopy(mp3info->pcmbuf, pcm, mp3info->buflen, samplecount, mp3info->pcmbufsize - mp3info->buflen, &wrote); mp3info->buflen += wrote; } // we're definitely done. retval = 0; } else if(mp3info->destlen >= mp3info->destsize) retval = 0; else retval = 1; return retval; } /*************** Callback functions for quake3 ***************/ /* ================= S_MP3_CodecOpenStream ================= */ snd_stream_t *S_MP3_CodecOpenStream(const char *filename) { snd_stream_t *stream; struct snd_codec_mp3_info *mp3info; // Open the stream stream = S_CodecUtilOpen(filename, &mp3_codec); if(!stream || stream->length <= 0) return NULL; // We have to scan through the MP3 to determine the important mp3 info. if(S_MP3_Scanfile(stream) < 0) { // scanning didn't work out... S_CodecUtilClose(&stream); return NULL; } // Initialize the mp3 info structure we need for streaming mp3info = Z_Malloc(sizeof(*mp3info)); if(!mp3info) { S_CodecUtilClose(&stream); return NULL; } stream->ptr = mp3info; // initialize the libmad control structures. mad_stream_init(&mp3info->madstream); mad_frame_init(&mp3info->madframe); mad_synth_init(&mp3info->madsynth); if(S_MP3_ReadData(stream, &mp3info->madstream, mp3info->encbuf, sizeof(mp3info->encbuf)) <= 0) { // we didnt read anything, that's bad. S_MP3_CodecCloseStream(stream); return NULL; } return stream; } /* ================= S_MP3_CodecCloseStream ================= */ // free all memory we allocated. void S_MP3_CodecCloseStream(snd_stream_t *stream) { struct snd_codec_mp3_info *mp3info; if(!stream) return; // free all data in our mp3info tree if(stream->ptr) { mp3info = stream->ptr; if(mp3info->pcmbuf) Z_Free(mp3info->pcmbuf); mad_synth_finish(&mp3info->madsynth); mad_frame_finish(&mp3info->madframe); mad_stream_finish(&mp3info->madstream); Z_Free(stream->ptr); } S_CodecUtilClose(&stream); } /* ================= S_MP3_CodecReadStream ================= */ int S_MP3_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer) { struct snd_codec_mp3_info *mp3info; int retval; if(!stream) return -1; mp3info = stream->ptr; // Make sure we get complete frames all the way through. bytes -= bytes % (stream->info.channels * stream->info.width); if(mp3info->buflen) { if(bytes < mp3info->buflen) { // we still have enough bytes in our decoded pcm buffer memcpy(buffer, mp3info->pcmbuf, bytes); // remove the portion from our buffer. mp3info->buflen -= bytes; memmove(mp3info->pcmbuf, &mp3info->pcmbuf[bytes], mp3info->buflen); return bytes; } else { // copy over the samples we already have. memcpy(buffer, mp3info->pcmbuf, mp3info->buflen); mp3info->destlen = mp3info->buflen; mp3info->buflen = 0; } } else mp3info->destlen = 0; mp3info->dest = buffer; mp3info->destsize = bytes; do { retval = S_MP3_Decode(stream); } while(retval > 0); // if there was an error return nothing. if(retval < 0) return 0; return mp3info->destlen; } /* ===================================================================== S_MP3_CodecLoad We handle S_MP3_CodecLoad as a special case of the streaming functions where we read the whole stream at once. ====================================================================== */ void *S_MP3_CodecLoad(const char *filename, snd_info_t *info) { snd_stream_t *stream; byte *pcmbuffer; // check if input is valid if(!filename) return NULL; stream = S_MP3_CodecOpenStream(filename); if(!stream) return NULL; // copy over the info info->rate = stream->info.rate; info->width = stream->info.width; info->channels = stream->info.channels; info->samples = stream->info.samples; info->dataofs = stream->info.dataofs; // allocate enough buffer for all pcm data pcmbuffer = Hunk_AllocateTempMemory(stream->info.size); if(!pcmbuffer) { S_MP3_CodecCloseStream(stream); return NULL; } info->size = S_MP3_CodecReadStream(stream, stream->info.size, pcmbuffer); if(info->size <= 0) { // we didn't read anything at all. darn. Hunk_FreeTempMemory(pcmbuffer); pcmbuffer = NULL; } S_MP3_CodecCloseStream(stream); return pcmbuffer; } #endif // USE_CODEC_MP3