📄 sloader.c
字号:
/* MikMod sound library (c) 1998, 1999, 2000, 2001 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.1.1.1 2004/01/21 01:36:35 raph 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#ifdef HAVE_UNISTD_H#include <unistd.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: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -