Logo Search packages:      
Sourcecode: ia32-libs-sdl version File versions  Download package

sloader.c

/*    MikMod sound library
      (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for
      complete list.

      This library is free software; you can redistribute it and/or modify
      it under the terms of the GNU Library General Public License as
      published by the Free Software Foundation; either version 2 of
      the License, or (at your option) any later version.

      This program 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 Library General Public License for more details.

      You should have received a copy of the GNU Library General Public
      License along with this library; if not, write to the Free Software
      Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
      02111-1307, USA.
*/

/*==============================================================================

  $Id: sloader.c,v 1.3 1999/12/28 18:51:11 hercules Exp $

  Routines for loading samples. The sample loader utilizes the routines
  provided by the "registered" sample loader.

==============================================================================*/

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <mikmod_internals.h>

static      int sl_rlength;
static      SWORD sl_old;
static      SWORD *sl_buffer=NULL;
static      SAMPLOAD *musiclist=NULL,*sndfxlist=NULL;

/* size of the loader buffer in words */
#define SLBUFSIZE 2048

/* IT-Compressed status structure */
typedef struct ITPACK {
      UWORD bits;    /* current number of bits */
      UWORD bufbits; /* bits in buffer */
      SWORD last;    /* last output */
      UBYTE buf;     /* bit buffer */
} ITPACK;

BOOL SL_Init(SAMPLOAD* s)
{
      if(!sl_buffer)
            if(!(sl_buffer=_mm_malloc(SLBUFSIZE*sizeof(SWORD)))) 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->reader,sl_rlength,SEEK_CUR);
      if(sl_buffer) {
            free(sl_buffer);
            sl_buffer=NULL;
      }
}

/* unpack a 8bit IT packed sample */
static BOOL read_itcompr8(ITPACK* status,MREADER *reader,SWORD *sl_buffer,UWORD count,UWORD* incnt)
{
      SWORD *dest=sl_buffer,*end=sl_buffer+count;
      UWORD x,y,needbits,havebits,new_count=0;
      UWORD bits = status->bits;
      UWORD bufbits = status->bufbits;
      SBYTE last = status->last;
      UBYTE buf = status->buf;

      while (dest<end) {
            needbits=new_count?3:bits;
            x=havebits=0;
            while (needbits) {
                  /* feed buffer */
                  if (!bufbits) {
                        if((*incnt)--)
                              buf=_mm_read_UBYTE(reader);
                        else
                              buf=0;
                        bufbits=8;
                  }
                  /* get as many bits as necessary */
                  y = needbits<bufbits?needbits:bufbits;
                  x|= (buf & ((1<<y)- 1))<<havebits;
                  buf>>=y;
                  bufbits-=y;
                  needbits-=y;
                  havebits+=y;
            }
            if (new_count) {
                  new_count = 0;
                  if (++x >= bits)
                        x++;
                  bits = x;
                  continue;
            }
            if (bits<7) {
                  if (x==(1<<(bits-1))) {
                        new_count = 1;
                        continue;
                  }
            }
            else if (bits<9) {
                  y = (0xff >> (9-bits)) - 4;
                  if ((x>y)&&(x<=y+8)) {
                        if ((x-=y)>=bits)
                              x++;
                        bits = x;
                        continue;
                  }
            }
            else if (bits<10) {
                  if (x>=0x100) {
                        bits=x-0x100+1;
                        continue;
                  }
            } else {
                  /* error in compressed data... */
                  _mm_errno=MMERR_ITPACK_INVALID_DATA;
                  return 0;
            }

            if (bits<8) /* extend sign */
                  x = ((SBYTE)(x <<(8-bits))) >> (8-bits);
            *(dest++)= (last+=x) << 8; /* convert to 16 bit */
      }
      status->bits = bits;
      status->bufbits = bufbits;
      status->last = last;
      status->buf = buf;
      return dest-sl_buffer;
}

/* unpack a 16bit IT packed sample */
static BOOL read_itcompr16(ITPACK *status,MREADER *reader,SWORD *sl_buffer,UWORD count,UWORD* incnt)
{
      SWORD *dest=sl_buffer,*end=sl_buffer+count;
      SLONG x,y,needbits,havebits,new_count=0;
      UWORD bits = status->bits;
      UWORD bufbits = status->bufbits;
      SWORD last = status->last;
      UBYTE buf = status->buf;

      while (dest<end) {
            needbits=new_count?4:bits;
            x=havebits=0;
            while (needbits) {
                  /* feed buffer */
                  if (!bufbits) {
                        if((*incnt)--)
                              buf=_mm_read_UBYTE(reader);
                        else
                              buf=0;
                        bufbits=8;
                  }
                  /* get as many bits as necessary */
                  y=needbits<bufbits?needbits:bufbits;
                  x|=(buf &((1<<y)-1))<<havebits;
                  buf>>=y;
                  bufbits-=y;
                  needbits-=y;
                  havebits+=y;
            }
            if (new_count) {
                  new_count = 0;
                  if (++x >= bits)
                        x++;
                  bits = x;
                  continue;
            }
            if (bits<7) {
                  if (x==(1<<(bits-1))) {
                        new_count=1;
                        continue;
                  }
            }
            else if (bits<17) {
                  y=(0xffff>>(17-bits))-8;
                  if ((x>y)&&(x<=y+16)) {
                        if ((x-=y)>=bits)
                              x++;
                        bits = x;
                        continue;
                  }
            }
            else if (bits<18) {
                  if (x>=0x10000) {
                        bits=x-0x10000+1;
                        continue;
                  }
            } else {
                   /* error in compressed data... */
                  _mm_errno=MMERR_ITPACK_INVALID_DATA;
                  return 0;
            }

            if (bits<16) /* extend sign */
                  x = ((SWORD)(x<<(16-bits)))>>(16-bits);
            *(dest++)=(last+=x);
      }
      status->bits = bits;
      status->bufbits = bufbits;
      status->last = last;
      status->buf = buf;
      return dest-sl_buffer;
}

static BOOL SL_LoadInternal(void* buffer,UWORD infmt,UWORD outfmt,int scalefactor,ULONG length,MREADER* reader,BOOL dither)
{
      SBYTE *bptr = (SBYTE*)buffer;
      SWORD *wptr = (SWORD*)buffer;
      int stodo,t,u;

      int result,c_block=0;   /* compression bytes until next block */
      ITPACK status;
      UWORD incnt;

      while(length) {
            stodo=(length<SLBUFSIZE)?length:SLBUFSIZE;

            if(infmt&SF_ITPACKED) {
                  sl_rlength=0;
                  if (!c_block) {
                        status.bits = (infmt & SF_16BITS) ? 17 : 9;
                        status.last = status.bufbits = 0;
                        incnt=_mm_read_I_UWORD(reader);
                        c_block = (infmt & SF_16BITS) ? 0x4000 : 0x8000;
                        if(infmt&SF_DELTA) sl_old=0;
                  }
                  if (infmt & SF_16BITS) {
                        if(!(result=read_itcompr16(&status,reader,sl_buffer,stodo,&incnt)))
                              return 1;
                  } else {
                        if(!(result=read_itcompr8(&status,reader,sl_buffer,stodo,&incnt)))
                              return 1;
                  }
                  if(result!=stodo) {
                        _mm_errno=MMERR_ITPACK_INVALID_DATA;
                        return 1;
                  }
                  c_block -= stodo;
            } else {
                  if(infmt&SF_16BITS) {
                        if(infmt&SF_BIG_ENDIAN)
                              _mm_read_M_SWORDS(sl_buffer,stodo,reader);
                        else
                              _mm_read_I_SWORDS(sl_buffer,stodo,reader);
                  } else {
                        SBYTE *src;
                        SWORD *dest;

                        reader->Read(reader,sl_buffer,sizeof(SBYTE)*stodo);
                        src = (SBYTE*)sl_buffer;
                        dest  = sl_buffer;
                        src += stodo;dest += stodo;

                        for(t=0;t<stodo;t++) {
                              src--;dest--;
                              *dest = (*src)<<8;
                        }
                  }
                  sl_rlength-=stodo;
            }

            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(scalefactor) {
                  int idx = 0;
                  SLONG scaleval;

                  /* Sample Scaling... average values for better results. */
                  t= 0;
                  while(t<stodo && length) {
                        scaleval = 0;
                        for(u=scalefactor;u && t<stodo;u--,t++)
                              scaleval+=sl_buffer[t];
                        sl_buffer[idx++]=scaleval/(scalefactor-u);
                        length--;
                  }
                  stodo = idx;
            } else
                  length -= stodo;

            if (dither) {
                  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;
            }
      }
      return 0;
}

BOOL SL_Load(void* buffer,SAMPLOAD *smp,ULONG length)
{
      return SL_LoadInternal(buffer,smp->infmt,smp->outfmt,smp->scalefactor,
                             length,smp->reader,0);
}

/* Registers a sample for loading when SL_LoadSamples() is called. */
SAMPLOAD* SL_RegisterSample(SAMPLE* s,int type,MREADER* reader)
{
      SAMPLOAD *news,**samplist,*cruise;

      if(type==MD_MUSIC) {
            samplist = &musiclist;
            cruise = musiclist;
      } else
        if (type==MD_SNDFX) {
            samplist = &sndfxlist;
            cruise = sndfxlist;
      } else
            return NULL;

      /* Allocate and add structure to the END of the list */
      if(!(news=(SAMPLOAD*)_mm_malloc(sizeof(SAMPLOAD)))) return NULL;

      if(cruise) {
            while(cruise->next) cruise=cruise->next;
            cruise->next = news;
      } else
            *samplist = news;

      news->infmt     = s->flags & SF_FORMATMASK;
      news->outfmt    = news->infmt;
      news->reader    = reader;
      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) {
            old = s;
            s = s->next;
            free(old);
      }
}

/* Returns the total amount of memory required by the samplelist queue. */
static ULONG SampleTotal(SAMPLOAD* samplist,int type)
{
      int total = 0;

      while(samplist) {
            samplist->sample->flags=
              (samplist->sample->flags&~SF_FORMATMASK)|samplist->outfmt;
            total += MD_SampleLength(type,samplist->sample);
            samplist=samplist->next;
      }

      return total;
}

static ULONG RealSpeed(SAMPLOAD *s)
{
      return(s->sample->speed/(s->scalefactor?s->scalefactor:1));
}

static BOOL DitherSamples(SAMPLOAD* samplist,int type)
{
      SAMPLOAD *c2smp=NULL;
      ULONG maxsize, speed;
      SAMPLOAD *s;

      if(!samplist) return 0;

      if((maxsize=MD_SampleSpace(type)*1024))
            while(SampleTotal(samplist,type)>maxsize) {
                  /* First Pass - check for any 16 bit samples */
                  s = samplist;
                  while(s) {
                        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) {
                        s = samplist;
                        speed = 0;
                        while(s) {
                              if((s->sample->length) && (RealSpeed(s)>speed)) {
                                    speed=RealSpeed(s);
                                    c2smp=s;
                              }
                              s=s->next;
                        }
                        if (c2smp)
                              SL_HalveSample(c2smp,2);
                  }
            }

      /* Samples dithered, now load them ! */
      s = samplist;
      while(s) {
            /* 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->reader, 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->sample->flags  = (s->sample->flags & ~SF_FORMATMASK) | s->outfmt;
                  if(s->sample->handle<0) {
                        FreeSampleList(samplist);
                        if(_mm_errorhandler) _mm_errorhandler();
                        return 1;
                  }
            }
            s = s->next;
      }

      FreeSampleList(samplist);
      return 0;
}

BOOL SL_LoadSamples(void)
{
      BOOL ok;

      _mm_critical = 0;

      if((!musiclist)&&(!sndfxlist)) return 0;
      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&~SF_FORMATMASK) | s->outfmt;
}

void SL_Sample8to16(SAMPLOAD* s)
{
      s->outfmt |= SF_16BITS;
      s->sample->flags = (s->sample->flags&~SF_FORMATMASK) | s->outfmt;
}

void SL_SampleSigned(SAMPLOAD* s)
{
      s->outfmt |= SF_SIGNED;
      s->sample->flags = (s->sample->flags&~SF_FORMATMASK) | s->outfmt;
}

void SL_SampleUnsigned(SAMPLOAD* s)
{
      s->outfmt &= ~SF_SIGNED;
      s->sample->flags = (s->sample->flags&~SF_FORMATMASK) | s->outfmt;
}

void SL_HalveSample(SAMPLOAD* s,int factor)
{
      s->scalefactor=factor>0?factor: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;
}


/* ex:set ts=4: */

Generated by  Doxygen 1.6.0   Back to index