Mercurial > ~darius > hgwebdir.cgi > mikmod
diff playercode/sloader.c @ 6:d14fd386d182
Initial entry of mikmod into the CVS tree.
author | darius |
---|---|
date | Fri, 23 Jan 1998 16:05:09 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/playercode/sloader.c Fri Jan 23 16:05:09 1998 +0000 @@ -0,0 +1,407 @@ +/* + --> Sample Loaders and Sample Processing + +Name: sloader.c + +Description: +Routines for loading samples. The sample loader utilizes the routines +provided by the "registered" sample loader. See SAMPLELOADER in +MIKMOD.H for the sample loader structure. + +Portability: +All systems - all compilers + +*/ + +#include "mikmod.h" + + +static int sl_rlength; +static SWORD sl_old; +static SWORD *sl_buffer = NULL; +static SAMPLOAD *musiclist = NULL, + *sndfxlist = NULL; + + + +BOOL SL_Init(SAMPLOAD *s) // returns 0 on error! +{ + if(sl_buffer==NULL) + if((sl_buffer=_mm_malloc(4100)) == NULL) return 0; + + sl_rlength = s->length; + if(s->infmt & SF_16BITS) sl_rlength>>=1; + sl_old = 0; + + return 1; +} + + +void SL_Exit(SAMPLOAD *s) +{ + if(sl_rlength > 0) _mm_fseek(s->fp,sl_rlength,SEEK_CUR); +} + + +void SL_Reset(void) +{ + sl_old = 0; +} + + +void SL_Load(void *buffer, SAMPLOAD *smp, int length) +{ + UWORD infmt = smp->infmt, outfmt = smp->outfmt; + SBYTE *bptr = (SBYTE *)buffer; + SWORD *wptr = (SWORD *)buffer; + int stodo; + int t, u; + + while(length) + { stodo = (length<2048) ? length : 2048; + + if(infmt & SF_16BITS) + { if(infmt & SF_BIG_ENDIAN) + _mm_read_M_SWORDS(sl_buffer,stodo,smp->fp); + else + _mm_read_I_SWORDS(sl_buffer,stodo,smp->fp); + } else + { SBYTE *s; + SWORD *d; + + fread(sl_buffer,sizeof(SBYTE),stodo,smp->fp); + + s = (SBYTE *)sl_buffer; + d = sl_buffer; + s += stodo; + d += stodo; + + for(t=0; t<stodo; t++) + { s--; + d--; + *d = (*s)<<8; + } + } + + if(infmt & SF_DELTA) + { for(t=0; t<stodo; t++) + { sl_buffer[t] += sl_old; + sl_old = sl_buffer[t]; + } + } + + if((infmt^outfmt) & SF_SIGNED) + { for(t=0; t<stodo; t++) + sl_buffer[t] ^= 0x8000; + } + + if(smp->scalefactor) + { int idx = 0; + SLONG scaleval; + + // Sample Scaling... average values for better results. + t = 0; + while(t<stodo && length) + { scaleval = 0; + for(u=smp->scalefactor; u && t<stodo; u--, t++) + scaleval += sl_buffer[t]; + sl_buffer[idx++] = scaleval / (smp->scalefactor-u); + length--; + } + sl_rlength -= stodo; + stodo = idx; + } else + { length -= stodo; + sl_rlength -= stodo; + } + + if(outfmt & SF_16BITS) + { for(t=0; t<stodo; t++) *(wptr++) = sl_buffer[t]; + } else + { for(t=0; t<stodo; t++) *(bptr++) = sl_buffer[t]>>8; + } + } +} + + +void SL_LoadStream(void *buffer, UWORD infmt, UWORD outfmt, int length, FILE *fp) + +// This is like SL_Load, but does not perform sample scaling, and does not +// require calls to SL_Init / SL_Exit. + +{ + SBYTE *bptr = (SBYTE *)buffer; + SWORD *wptr = (SWORD *)buffer; + int stodo; + int t; + + // compute number of samples to load + + if(sl_buffer==NULL) + if((sl_buffer=_mm_malloc(4100)) == NULL) return; + + while(length) + { stodo = (length<2048) ? length : 2048; + + if(infmt & SF_16BITS) + { if(infmt & SF_BIG_ENDIAN) + _mm_read_M_SWORDS(sl_buffer,stodo,fp); + else + _mm_read_I_SWORDS(sl_buffer,stodo,fp); + } else + { SBYTE *s; + SWORD *d; + + fread(sl_buffer,sizeof(SBYTE),stodo,fp); + + s = (SBYTE *)sl_buffer; + d = sl_buffer; + s += stodo; + d += stodo; + + for(t=0; t<stodo; t++) + { s--; + d--; + *d = (*s)<<8; + } + } + + if(infmt & SF_DELTA) + { for(t=0; t<stodo; t++) + { sl_buffer[t] += sl_old; + sl_old = sl_buffer[t]; + } + } + + if((infmt^outfmt) & SF_SIGNED) + { for(t=0; t<stodo; t++) + sl_buffer[t] ^= 0x8000; + } + + length -= stodo; + + if((infmt & SF_STEREO) && !(outfmt & SF_STEREO)) + { // Dither stereo to mono .. average together every two samples + SLONG avgval; + int idx = 0; + + t = 0; + while(t<stodo && length) + { avgval = sl_buffer[t++]; + avgval += sl_buffer[t++]; + sl_buffer[idx++] = avgval >> 1; + length-=2; + } + stodo = idx; + } + + if(outfmt & SF_16BITS) + { for(t=0; t<stodo; t++) *(wptr++) = sl_buffer[t]; + } else + { for(t=0; t<stodo; t++) *(bptr++) = sl_buffer[t]>>8; + } + } +} + + +SAMPLOAD *SL_RegisterSample(SAMPLE *s, int type, FILE *fp) // Returns 1 on error! + +// Registers a sample for loading when SL_LoadSamples() is called. +// type - type of sample to be loaded .. +// MD_MUSIC, MD_SNDFX + +{ + SAMPLOAD *news, **samplist, *cruise; + + if(type==MD_MUSIC) + { samplist = & musiclist; + cruise = musiclist; + } else + { samplist = &sndfxlist; + cruise = sndfxlist; + } + + // Allocate and add structure to the END of the list + + if((news=(SAMPLOAD *)_mm_calloc(1,sizeof(SAMPLOAD))) == NULL) return NULL; + + if(cruise!=NULL) + { while(cruise->next!=NULL) cruise = cruise->next; + cruise->next = news; + } else + *samplist = news; + + news->infmt = s->flags & 31; + news->outfmt = news->infmt; + news->fp = fp; + news->sample = s; + news->length = s->length; + news->loopstart = s->loopstart; + news->loopend = s->loopend; + + return news; +} + + +static void FreeSampleList(SAMPLOAD *s) +{ + SAMPLOAD *old; + + while(s!=NULL) + { old = s; + s = s->next; + free(old); + } +} + + +static ULONG SampleTotal(SAMPLOAD *samplist, int type) +// Returns the total amount of memory required by the samplelist queue. +{ + int total = 0; + + while(samplist!=NULL) + { samplist->sample->flags = (samplist->sample->flags&~31) | samplist->outfmt; + total += MD_SampleLength(type,samplist->sample); + samplist = samplist->next; + } + + return total; +} + + +static ULONG RealSpeed(SAMPLOAD *s) +{ + return(s->sample->speed / ((s->scalefactor==0) ? 1 : s->scalefactor)); +} + + +static BOOL DitherSamples(SAMPLOAD *samplist, int type) +{ + SAMPLOAD *c2smp; + ULONG maxsize, speed; + SAMPLOAD *s; + + if(samplist==NULL) return 0; + + // make sure the samples will fit inside available RAM + if((maxsize = MD_SampleSpace(type)*1024) != 0) + { while(SampleTotal(samplist, type) > maxsize) + { // First Pass - check for any 16 bit samples + s = samplist; + while(s!=NULL) + { if(s->outfmt & SF_16BITS) + { SL_Sample16to8(s); + break; + } + s = s->next; + } + + // Second pass (if no 16bits found above) is to take the sample + // with the highest speed and dither it by half. + if(s==NULL) + { s = samplist; + speed = 0; + while(s!=NULL) + { if((s->sample->length) && (RealSpeed(s) > speed)) + { speed = RealSpeed(s); + c2smp = s; + } + s = s->next; + } + SL_HalveSample(c2smp); + } + } + } + + + // Samples dithered, now load them! + // ================================ + + s = samplist; + while(s != NULL) + { // sample has to be loaded ? -> increase number of + // samples, allocate memory and load sample. + + if(s->sample->length) + { if(s->sample->seekpos) + _mm_fseek(s->fp, s->sample->seekpos, SEEK_SET); + + // Call the sample load routine of the driver module. + // It has to return a 'handle' (>=0) that identifies + // the sample. + + s->sample->handle = MD_SampleLoad(s, type, s->fp); + s->sample->flags = (s->sample->flags & ~31) | s->outfmt; + if(s->sample->handle < 0) + { FreeSampleList(samplist); + if(_mm_errorhandler!=NULL) _mm_errorhandler(); + return 1; + } + } + s = s->next; + } + + FreeSampleList(samplist); + return 0; +} + + +BOOL SL_LoadSamples(void) // Returns 1 on error! +{ + BOOL ok; + + _mm_critical = 0; + + if((musiclist==NULL) && (sndfxlist==NULL)) return 0; +// MikMod_Exit(); +// exit(1); + ok = DitherSamples(musiclist,MD_MUSIC) || DitherSamples(sndfxlist,MD_SNDFX); + + musiclist = sndfxlist = NULL; + + return ok; +} + + +void SL_Sample16to8(SAMPLOAD *s) +{ + s->outfmt &= ~SF_16BITS; + s->sample->flags = (s->sample->flags&~31) | s->outfmt; +} + + +void SL_Sample8to16(SAMPLOAD *s) +{ + s->outfmt |= SF_16BITS; + s->sample->flags = (s->sample->flags&~31) | s->outfmt; +} + + +void SL_SampleSigned(SAMPLOAD *s) +{ + s->outfmt |= SF_SIGNED; + s->sample->flags = (s->sample->flags&~31) | s->outfmt; +} + + +void SL_SampleUnsigned(SAMPLOAD *s) +{ + s->outfmt &= ~SF_SIGNED; + s->sample->flags = (s->sample->flags&~31) | s->outfmt; +} + + +void SL_HalveSample(SAMPLOAD *s) +{ + if(s->scalefactor) + s->scalefactor++; + else + s->scalefactor = 2; + + s->sample->divfactor = s->scalefactor; + s->sample->length = s->length / s->scalefactor; + s->sample->loopstart = s->loopstart / s->scalefactor; + s->sample->loopend = s->loopend / s->scalefactor; +} +