forked from len0rd/rockbox
Add MikMod plugin, ported by Jason Yu, with some minor work by Craig Mann and William Peters (FS#8806)
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@28810 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
d192bdf11e
commit
26f2bfde03
47 changed files with 22320 additions and 1 deletions
519
apps/plugins/mikmod/sloader.c
Normal file
519
apps/plugins/mikmod/sloader.c
Normal file
|
@ -0,0 +1,519 @@
|
|||
/* 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.3 2007/12/06 17:46:08 denis111 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;
|
||||
|
||||
int SL_Init(SAMPLOAD* s)
|
||||
{
|
||||
if(!sl_buffer)
|
||||
if(!(sl_buffer=MikMod_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) {
|
||||
MikMod_free(sl_buffer);
|
||||
sl_buffer=NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* unpack a 8bit IT packed sample */
|
||||
static int 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 int 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-=(UWORD)y;
|
||||
needbits-=(UWORD)y;
|
||||
havebits+=(UWORD)y;
|
||||
}
|
||||
if (new_count) {
|
||||
new_count = 0;
|
||||
if (++x >= bits)
|
||||
x++;
|
||||
bits = (UWORD)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 = (UWORD)x;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (bits<18) {
|
||||
if (x>=0x10000) {
|
||||
bits=(UWORD)(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 int SL_LoadInternal(void* buffer,UWORD infmt,UWORD outfmt,int scalefactor,ULONG length,MREADER* reader,int 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++]=(UWORD)(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++]=(SWORD)(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;
|
||||
}
|
||||
|
||||
int 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*)MikMod_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;
|
||||
MikMod_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 int 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;
|
||||
}
|
||||
|
||||
int SL_LoadSamples(void)
|
||||
{
|
||||
int 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: */
|
Loading…
Add table
Add a link
Reference in a new issue