--- /dev/null
+/* MikMod sound library\r
+ (c) 1998, 1999, 2000, 2001 Miodrag Vallat and others - see file AUTHORS\r
+ for complete list.\r
+\r
+ This library is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU Library General Public License as\r
+ published by the Free Software Foundation; either version 2 of\r
+ the License, or (at your option) any later version.\r
+ \r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU Library General Public License for more details.\r
+ \r
+ You should have received a copy of the GNU Library General Public\r
+ License along with this library; if not, write to the Free Software\r
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA\r
+ 02111-1307, USA.\r
+*/\r
+\r
+/*==============================================================================\r
+\r
+ $Id: sloader.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $\r
+\r
+ Routines for loading samples. The sample loader utilizes the routines\r
+ provided by the "registered" sample loader.\r
+\r
+==============================================================================*/\r
+\r
+#ifdef HAVE_CONFIG_H\r
+#include "config.h"\r
+#endif\r
+\r
+#ifdef HAVE_UNISTD_H\r
+#include <unistd.h>\r
+#endif\r
+\r
+#include "mikmod_internals.h"\r
+\r
+static int sl_rlength;\r
+static SWORD sl_old;\r
+static SWORD *sl_buffer=NULL;\r
+static SAMPLOAD *musiclist=NULL,*sndfxlist=NULL;\r
+\r
+/* size of the loader buffer in words */\r
+#define SLBUFSIZE 2048\r
+\r
+/* IT-Compressed status structure */\r
+typedef struct ITPACK {\r
+ UWORD bits; /* current number of bits */\r
+ UWORD bufbits; /* bits in buffer */\r
+ SWORD last; /* last output */\r
+ UBYTE buf; /* bit buffer */\r
+} ITPACK;\r
+\r
+BOOL SL_Init(SAMPLOAD* s)\r
+{\r
+ if(!sl_buffer)\r
+ if(!(sl_buffer=_mm_malloc(SLBUFSIZE*sizeof(SWORD)))) return 0;\r
+\r
+ sl_rlength = s->length;\r
+ if(s->infmt & SF_16BITS) sl_rlength>>=1;\r
+ sl_old = 0;\r
+\r
+ return 1;\r
+}\r
+\r
+void SL_Exit(SAMPLOAD *s)\r
+{\r
+ if(sl_rlength>0) _mm_fseek(s->reader,sl_rlength,SEEK_CUR);\r
+ if(sl_buffer) {\r
+ free(sl_buffer);\r
+ sl_buffer=NULL;\r
+ }\r
+}\r
+\r
+/* unpack a 8bit IT packed sample */\r
+static BOOL read_itcompr8(ITPACK* status,MREADER *reader,SWORD *sl_buffer,UWORD count,UWORD* incnt)\r
+{\r
+ SWORD *dest=sl_buffer,*end=sl_buffer+count;\r
+ UWORD x,y,needbits,havebits,new_count=0;\r
+ UWORD bits = status->bits;\r
+ UWORD bufbits = status->bufbits;\r
+ SBYTE last = status->last;\r
+ UBYTE buf = status->buf;\r
+\r
+ while (dest<end) {\r
+ needbits=new_count?3:bits;\r
+ x=havebits=0;\r
+ while (needbits) {\r
+ /* feed buffer */\r
+ if (!bufbits) {\r
+ if((*incnt)--)\r
+ buf=_mm_read_UBYTE(reader);\r
+ else\r
+ buf=0;\r
+ bufbits=8;\r
+ }\r
+ /* get as many bits as necessary */\r
+ y = needbits<bufbits?needbits:bufbits;\r
+ x|= (buf & ((1<<y)- 1))<<havebits;\r
+ buf>>=y;\r
+ bufbits-=y;\r
+ needbits-=y;\r
+ havebits+=y;\r
+ }\r
+ if (new_count) {\r
+ new_count = 0;\r
+ if (++x >= bits)\r
+ x++;\r
+ bits = x;\r
+ continue;\r
+ }\r
+ if (bits<7) {\r
+ if (x==(1<<(bits-1))) {\r
+ new_count = 1;\r
+ continue;\r
+ }\r
+ }\r
+ else if (bits<9) {\r
+ y = (0xff >> (9-bits)) - 4;\r
+ if ((x>y)&&(x<=y+8)) {\r
+ if ((x-=y)>=bits)\r
+ x++;\r
+ bits = x;\r
+ continue;\r
+ }\r
+ }\r
+ else if (bits<10) {\r
+ if (x>=0x100) {\r
+ bits=x-0x100+1;\r
+ continue;\r
+ }\r
+ } else {\r
+ /* error in compressed data... */\r
+ _mm_errno=MMERR_ITPACK_INVALID_DATA;\r
+ return 0;\r
+ }\r
+\r
+ if (bits<8) /* extend sign */\r
+ x = ((SBYTE)(x <<(8-bits))) >> (8-bits);\r
+ *(dest++)= (last+=x) << 8; /* convert to 16 bit */\r
+ }\r
+ status->bits = bits;\r
+ status->bufbits = bufbits;\r
+ status->last = last;\r
+ status->buf = buf;\r
+ return dest-sl_buffer;\r
+}\r
+\r
+/* unpack a 16bit IT packed sample */\r
+static BOOL read_itcompr16(ITPACK *status,MREADER *reader,SWORD *sl_buffer,UWORD count,UWORD* incnt)\r
+{\r
+ SWORD *dest=sl_buffer,*end=sl_buffer+count;\r
+ SLONG x,y,needbits,havebits,new_count=0;\r
+ UWORD bits = status->bits;\r
+ UWORD bufbits = status->bufbits;\r
+ SWORD last = status->last;\r
+ UBYTE buf = status->buf;\r
+\r
+ while (dest<end) {\r
+ needbits=new_count?4:bits;\r
+ x=havebits=0;\r
+ while (needbits) {\r
+ /* feed buffer */\r
+ if (!bufbits) {\r
+ if((*incnt)--)\r
+ buf=_mm_read_UBYTE(reader);\r
+ else\r
+ buf=0;\r
+ bufbits=8;\r
+ }\r
+ /* get as many bits as necessary */\r
+ y=needbits<bufbits?needbits:bufbits;\r
+ x|=(buf &((1<<y)-1))<<havebits;\r
+ buf>>=y;\r
+ bufbits-=y;\r
+ needbits-=y;\r
+ havebits+=y;\r
+ }\r
+ if (new_count) {\r
+ new_count = 0;\r
+ if (++x >= bits)\r
+ x++;\r
+ bits = x;\r
+ continue;\r
+ }\r
+ if (bits<7) {\r
+ if (x==(1<<(bits-1))) {\r
+ new_count=1;\r
+ continue;\r
+ }\r
+ }\r
+ else if (bits<17) {\r
+ y=(0xffff>>(17-bits))-8;\r
+ if ((x>y)&&(x<=y+16)) {\r
+ if ((x-=y)>=bits)\r
+ x++;\r
+ bits = x;\r
+ continue;\r
+ }\r
+ }\r
+ else if (bits<18) {\r
+ if (x>=0x10000) {\r
+ bits=x-0x10000+1;\r
+ continue;\r
+ }\r
+ } else {\r
+ /* error in compressed data... */\r
+ _mm_errno=MMERR_ITPACK_INVALID_DATA;\r
+ return 0;\r
+ }\r
+\r
+ if (bits<16) /* extend sign */\r
+ x = ((SWORD)(x<<(16-bits)))>>(16-bits);\r
+ *(dest++)=(last+=x);\r
+ }\r
+ status->bits = bits;\r
+ status->bufbits = bufbits;\r
+ status->last = last;\r
+ status->buf = buf;\r
+ return dest-sl_buffer;\r
+}\r
+\r
+static BOOL SL_LoadInternal(void* buffer,UWORD infmt,UWORD outfmt,int scalefactor,ULONG length,MREADER* reader,BOOL dither)\r
+{\r
+ SBYTE *bptr = (SBYTE*)buffer;\r
+ SWORD *wptr = (SWORD*)buffer;\r
+ int stodo,t,u;\r
+\r
+ int result,c_block=0; /* compression bytes until next block */\r
+ ITPACK status;\r
+ UWORD incnt;\r
+\r
+ while(length) {\r
+ stodo=(length<SLBUFSIZE)?length:SLBUFSIZE;\r
+\r
+ if(infmt&SF_ITPACKED) {\r
+ sl_rlength=0;\r
+ if (!c_block) {\r
+ status.bits = (infmt & SF_16BITS) ? 17 : 9;\r
+ status.last = status.bufbits = 0;\r
+ incnt=_mm_read_I_UWORD(reader);\r
+ c_block = (infmt & SF_16BITS) ? 0x4000 : 0x8000;\r
+ if(infmt&SF_DELTA) sl_old=0;\r
+ }\r
+ if (infmt & SF_16BITS) {\r
+ if(!(result=read_itcompr16(&status,reader,sl_buffer,stodo,&incnt)))\r
+ return 1;\r
+ } else {\r
+ if(!(result=read_itcompr8(&status,reader,sl_buffer,stodo,&incnt)))\r
+ return 1;\r
+ }\r
+ if(result!=stodo) {\r
+ _mm_errno=MMERR_ITPACK_INVALID_DATA;\r
+ return 1;\r
+ }\r
+ c_block -= stodo;\r
+ } else {\r
+ if(infmt&SF_16BITS) {\r
+ if(infmt&SF_BIG_ENDIAN)\r
+ _mm_read_M_SWORDS(sl_buffer,stodo,reader);\r
+ else\r
+ _mm_read_I_SWORDS(sl_buffer,stodo,reader);\r
+ } else {\r
+ SBYTE *src;\r
+ SWORD *dest;\r
+\r
+ reader->Read(reader,sl_buffer,sizeof(SBYTE)*stodo);\r
+ src = (SBYTE*)sl_buffer;\r
+ dest = sl_buffer;\r
+ src += stodo;dest += stodo;\r
+\r
+ for(t=0;t<stodo;t++) {\r
+ src--;dest--;\r
+ *dest = (*src)<<8;\r
+ }\r
+ }\r
+ sl_rlength-=stodo;\r
+ }\r
+\r
+ if(infmt & SF_DELTA)\r
+ for(t=0;t<stodo;t++) {\r
+ sl_buffer[t] += sl_old;\r
+ sl_old = sl_buffer[t];\r
+ }\r
+\r
+ if((infmt^outfmt) & SF_SIGNED) \r
+ for(t=0;t<stodo;t++)\r
+ sl_buffer[t]^= 0x8000;\r
+\r
+ if(scalefactor) {\r
+ int idx = 0;\r
+ SLONG scaleval;\r
+\r
+ /* Sample Scaling... average values for better results. */\r
+ t= 0;\r
+ while(t<stodo && length) {\r
+ scaleval = 0;\r
+ for(u=scalefactor;u && t<stodo;u--,t++)\r
+ scaleval+=sl_buffer[t];\r
+ sl_buffer[idx++]=scaleval/(scalefactor-u);\r
+ length--;\r
+ }\r
+ stodo = idx;\r
+ } else\r
+ length -= stodo;\r
+\r
+ if (dither) {\r
+ if((infmt & SF_STEREO) && !(outfmt & SF_STEREO)) {\r
+ /* dither stereo to mono, average together every two samples */\r
+ SLONG avgval;\r
+ int idx = 0;\r
+\r
+ t=0;\r
+ while(t<stodo && length) {\r
+ avgval=sl_buffer[t++];\r
+ avgval+=sl_buffer[t++];\r
+ sl_buffer[idx++]=avgval>>1;\r
+ length-=2;\r
+ }\r
+ stodo = idx;\r
+ }\r
+ }\r
+\r
+ if(outfmt & SF_16BITS) {\r
+ for(t=0;t<stodo;t++)\r
+ *(wptr++)=sl_buffer[t];\r
+ } else {\r
+ for(t=0;t<stodo;t++)\r
+ *(bptr++)=sl_buffer[t]>>8;\r
+ }\r
+ }\r
+ return 0;\r
+}\r
+\r
+BOOL SL_Load(void* buffer,SAMPLOAD *smp,ULONG length)\r
+{\r
+ return SL_LoadInternal(buffer,smp->infmt,smp->outfmt,smp->scalefactor,\r
+ length,smp->reader,0);\r
+}\r
+\r
+/* Registers a sample for loading when SL_LoadSamples() is called. */\r
+SAMPLOAD* SL_RegisterSample(SAMPLE* s,int type,MREADER* reader)\r
+{\r
+ SAMPLOAD *news,**samplist,*cruise;\r
+\r
+ if(type==MD_MUSIC) {\r
+ samplist = &musiclist;\r
+ cruise = musiclist;\r
+ } else\r
+ if (type==MD_SNDFX) {\r
+ samplist = &sndfxlist;\r
+ cruise = sndfxlist;\r
+ } else\r
+ return NULL;\r
+ \r
+ /* Allocate and add structure to the END of the list */\r
+ if(!(news=(SAMPLOAD*)_mm_malloc(sizeof(SAMPLOAD)))) return NULL;\r
+\r
+ if(cruise) {\r
+ while(cruise->next) cruise=cruise->next;\r
+ cruise->next = news;\r
+ } else\r
+ *samplist = news;\r
+\r
+ news->infmt = s->flags & SF_FORMATMASK;\r
+ news->outfmt = news->infmt;\r
+ news->reader = reader;\r
+ news->sample = s;\r
+ news->length = s->length;\r
+ news->loopstart = s->loopstart;\r
+ news->loopend = s->loopend;\r
+\r
+ return news;\r
+}\r
+\r
+static void FreeSampleList(SAMPLOAD* s)\r
+{\r
+ SAMPLOAD *old;\r
+\r
+ while(s) {\r
+ old = s;\r
+ s = s->next;\r
+ free(old);\r
+ }\r
+}\r
+\r
+/* Returns the total amount of memory required by the samplelist queue. */\r
+static ULONG SampleTotal(SAMPLOAD* samplist,int type)\r
+{\r
+ int total = 0;\r
+\r
+ while(samplist) {\r
+ samplist->sample->flags=\r
+ (samplist->sample->flags&~SF_FORMATMASK)|samplist->outfmt;\r
+ total += MD_SampleLength(type,samplist->sample);\r
+ samplist=samplist->next;\r
+ }\r
+\r
+ return total;\r
+}\r
+\r
+static ULONG RealSpeed(SAMPLOAD *s)\r
+{\r
+ return(s->sample->speed/(s->scalefactor?s->scalefactor:1));\r
+} \r
+\r
+static BOOL DitherSamples(SAMPLOAD* samplist,int type)\r
+{\r
+ SAMPLOAD *c2smp=NULL;\r
+ ULONG maxsize, speed;\r
+ SAMPLOAD *s;\r
+\r
+ if(!samplist) return 0;\r
+\r
+ if((maxsize=MD_SampleSpace(type)*1024)) \r
+ while(SampleTotal(samplist,type)>maxsize) {\r
+ /* First Pass - check for any 16 bit samples */\r
+ s = samplist;\r
+ while(s) {\r
+ if(s->outfmt & SF_16BITS) {\r
+ SL_Sample16to8(s);\r
+ break;\r
+ }\r
+ s=s->next;\r
+ }\r
+ /* Second pass (if no 16bits found above) is to take the sample with\r
+ the highest speed and dither it by half. */\r
+ if(!s) {\r
+ s = samplist;\r
+ speed = 0;\r
+ while(s) {\r
+ if((s->sample->length) && (RealSpeed(s)>speed)) {\r
+ speed=RealSpeed(s);\r
+ c2smp=s;\r
+ }\r
+ s=s->next;\r
+ }\r
+ if (c2smp)\r
+ SL_HalveSample(c2smp,2);\r
+ }\r
+ }\r
+\r
+ /* Samples dithered, now load them ! */\r
+ s = samplist;\r
+ while(s) {\r
+ /* sample has to be loaded ? -> increase number of samples, allocate\r
+ memory and load sample. */\r
+ if(s->sample->length) {\r
+ if(s->sample->seekpos)\r
+ _mm_fseek(s->reader, s->sample->seekpos, SEEK_SET);\r
+\r
+ /* Call the sample load routine of the driver module. It has to\r
+ return a 'handle' (>=0) that identifies the sample. */\r
+ s->sample->handle = MD_SampleLoad(s, type);\r
+ s->sample->flags = (s->sample->flags & ~SF_FORMATMASK) | s->outfmt;\r
+ if(s->sample->handle<0) {\r
+ FreeSampleList(samplist);\r
+ if(_mm_errorhandler) _mm_errorhandler();\r
+ return 1;\r
+ }\r
+ }\r
+ s = s->next;\r
+ }\r
+\r
+ FreeSampleList(samplist);\r
+ return 0;\r
+}\r
+\r
+BOOL SL_LoadSamples(void)\r
+{\r
+ BOOL ok;\r
+\r
+ _mm_critical = 0;\r
+\r
+ if((!musiclist)&&(!sndfxlist)) return 0;\r
+ ok=DitherSamples(musiclist,MD_MUSIC)||DitherSamples(sndfxlist,MD_SNDFX);\r
+ musiclist=sndfxlist=NULL;\r
+\r
+ return ok;\r
+}\r
+\r
+void SL_Sample16to8(SAMPLOAD* s)\r
+{\r
+ s->outfmt &= ~SF_16BITS;\r
+ s->sample->flags = (s->sample->flags&~SF_FORMATMASK) | s->outfmt;\r
+}\r
+\r
+void SL_Sample8to16(SAMPLOAD* s)\r
+{\r
+ s->outfmt |= SF_16BITS;\r
+ s->sample->flags = (s->sample->flags&~SF_FORMATMASK) | s->outfmt;\r
+}\r
+\r
+void SL_SampleSigned(SAMPLOAD* s)\r
+{\r
+ s->outfmt |= SF_SIGNED;\r
+ s->sample->flags = (s->sample->flags&~SF_FORMATMASK) | s->outfmt;\r
+}\r
+\r
+void SL_SampleUnsigned(SAMPLOAD* s)\r
+{\r
+ s->outfmt &= ~SF_SIGNED;\r
+ s->sample->flags = (s->sample->flags&~SF_FORMATMASK) | s->outfmt;\r
+}\r
+\r
+void SL_HalveSample(SAMPLOAD* s,int factor)\r
+{\r
+ s->scalefactor=factor>0?factor:2;\r
+\r
+ s->sample->divfactor = s->scalefactor;\r
+ s->sample->length = s->length / s->scalefactor;\r
+ s->sample->loopstart = s->loopstart / s->scalefactor;\r
+ s->sample->loopend = s->loopend / s->scalefactor;\r
+}\r
+\r
+\r
+/* ex:set ts=4: */\r