Add "MikMod for Rockbox 0.1" from 2007-06-29
[mikmod-rockbox.git] / apps / plugins / mikmod / playercode / sloader.c
1 /*      MikMod sound library\r
2         (c) 1998, 1999, 2000, 2001 Miodrag Vallat and others - see file AUTHORS\r
3         for complete list.\r
4 \r
5         This library is free software; you can redistribute it and/or modify\r
6         it under the terms of the GNU Library General Public License as\r
7         published by the Free Software Foundation; either version 2 of\r
8         the License, or (at your option) any later version.\r
9  \r
10         This program is distributed in the hope that it will be useful,\r
11         but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13         GNU Library General Public License for more details.\r
14  \r
15         You should have received a copy of the GNU Library General Public\r
16         License along with this library; if not, write to the Free Software\r
17         Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA\r
18         02111-1307, USA.\r
19 */\r
20 \r
21 /*==============================================================================\r
22 \r
23   $Id: sloader.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $\r
24 \r
25   Routines for loading samples. The sample loader utilizes the routines\r
26   provided by the "registered" sample loader.\r
27 \r
28 ==============================================================================*/\r
29 \r
30 #ifdef HAVE_CONFIG_H\r
31 #include "config.h"\r
32 #endif\r
33 \r
34 #ifdef HAVE_UNISTD_H\r
35 #include <unistd.h>\r
36 #endif\r
37 \r
38 #include "mikmod_internals.h"\r
39 \r
40 static  int sl_rlength;\r
41 static  SWORD sl_old;\r
42 static  SWORD *sl_buffer=NULL;\r
43 static  SAMPLOAD *musiclist=NULL,*sndfxlist=NULL;\r
44 \r
45 /* size of the loader buffer in words */\r
46 #define SLBUFSIZE 2048\r
47 \r
48 /* IT-Compressed status structure */\r
49 typedef struct ITPACK {\r
50         UWORD bits;    /* current number of bits */\r
51         UWORD bufbits; /* bits in buffer */\r
52         SWORD last;    /* last output */\r
53         UBYTE buf;     /* bit buffer */\r
54 } ITPACK;\r
55 \r
56 BOOL SL_Init(SAMPLOAD* s)\r
57 {\r
58         if(!sl_buffer)\r
59                 if(!(sl_buffer=_mm_malloc(SLBUFSIZE*sizeof(SWORD)))) return 0;\r
60 \r
61         sl_rlength = s->length;\r
62         if(s->infmt & SF_16BITS) sl_rlength>>=1;\r
63         sl_old = 0;\r
64 \r
65         return 1;\r
66 }\r
67 \r
68 void SL_Exit(SAMPLOAD *s)\r
69 {\r
70         if(sl_rlength>0) _mm_fseek(s->reader,sl_rlength,SEEK_CUR);\r
71         if(sl_buffer) {\r
72                 free(sl_buffer);\r
73                 sl_buffer=NULL;\r
74         }\r
75 }\r
76 \r
77 /* unpack a 8bit IT packed sample */\r
78 static BOOL read_itcompr8(ITPACK* status,MREADER *reader,SWORD *sl_buffer,UWORD count,UWORD* incnt)\r
79 {\r
80         SWORD *dest=sl_buffer,*end=sl_buffer+count;\r
81         UWORD x,y,needbits,havebits,new_count=0;\r
82         UWORD bits = status->bits;\r
83         UWORD bufbits = status->bufbits;\r
84         SBYTE last = status->last;\r
85         UBYTE buf = status->buf;\r
86 \r
87         while (dest<end) {\r
88                 needbits=new_count?3:bits;\r
89                 x=havebits=0;\r
90                 while (needbits) {\r
91                         /* feed buffer */\r
92                         if (!bufbits) {\r
93                                 if((*incnt)--)\r
94                                         buf=_mm_read_UBYTE(reader);\r
95                                 else\r
96                                         buf=0;\r
97                                 bufbits=8;\r
98                         }\r
99                         /* get as many bits as necessary */\r
100                         y = needbits<bufbits?needbits:bufbits;\r
101                         x|= (buf & ((1<<y)- 1))<<havebits;\r
102                         buf>>=y;\r
103                         bufbits-=y;\r
104                         needbits-=y;\r
105                         havebits+=y;\r
106                 }\r
107                 if (new_count) {\r
108                         new_count = 0;\r
109                         if (++x >= bits)\r
110                                 x++;\r
111                         bits = x;\r
112                         continue;\r
113                 }\r
114                 if (bits<7) {\r
115                         if (x==(1<<(bits-1))) {\r
116                                 new_count = 1;\r
117                                 continue;\r
118                         }\r
119                 }\r
120                 else if (bits<9) {\r
121                         y = (0xff >> (9-bits)) - 4;\r
122                         if ((x>y)&&(x<=y+8)) {\r
123                                 if ((x-=y)>=bits)\r
124                                         x++;\r
125                                 bits = x;\r
126                                 continue;\r
127                         }\r
128                 }\r
129                 else if (bits<10) {\r
130                         if (x>=0x100) {\r
131                                 bits=x-0x100+1;\r
132                                 continue;\r
133                         }\r
134                 } else {\r
135                         /* error in compressed data... */\r
136                         _mm_errno=MMERR_ITPACK_INVALID_DATA;\r
137                         return 0;\r
138                 }\r
139 \r
140                 if (bits<8) /* extend sign */\r
141                         x = ((SBYTE)(x <<(8-bits))) >> (8-bits);\r
142                 *(dest++)= (last+=x) << 8; /* convert to 16 bit */\r
143         }\r
144         status->bits = bits;\r
145         status->bufbits = bufbits;\r
146         status->last = last;\r
147         status->buf = buf;\r
148         return dest-sl_buffer;\r
149 }\r
150 \r
151 /* unpack a 16bit IT packed sample */\r
152 static BOOL read_itcompr16(ITPACK *status,MREADER *reader,SWORD *sl_buffer,UWORD count,UWORD* incnt)\r
153 {\r
154         SWORD *dest=sl_buffer,*end=sl_buffer+count;\r
155         SLONG x,y,needbits,havebits,new_count=0;\r
156         UWORD bits = status->bits;\r
157         UWORD bufbits = status->bufbits;\r
158         SWORD last = status->last;\r
159         UBYTE buf = status->buf;\r
160 \r
161         while (dest<end) {\r
162                 needbits=new_count?4:bits;\r
163                 x=havebits=0;\r
164                 while (needbits) {\r
165                         /* feed buffer */\r
166                         if (!bufbits) {\r
167                                 if((*incnt)--)\r
168                                         buf=_mm_read_UBYTE(reader);\r
169                                 else\r
170                                         buf=0;\r
171                                 bufbits=8;\r
172                         }\r
173                         /* get as many bits as necessary */\r
174                         y=needbits<bufbits?needbits:bufbits;\r
175                         x|=(buf &((1<<y)-1))<<havebits;\r
176                         buf>>=y;\r
177                         bufbits-=y;\r
178                         needbits-=y;\r
179                         havebits+=y;\r
180                 }\r
181                 if (new_count) {\r
182                         new_count = 0;\r
183                         if (++x >= bits)\r
184                                 x++;\r
185                         bits = x;\r
186                         continue;\r
187                 }\r
188                 if (bits<7) {\r
189                         if (x==(1<<(bits-1))) {\r
190                                 new_count=1;\r
191                                 continue;\r
192                         }\r
193                 }\r
194                 else if (bits<17) {\r
195                         y=(0xffff>>(17-bits))-8;\r
196                         if ((x>y)&&(x<=y+16)) {\r
197                                 if ((x-=y)>=bits)\r
198                                         x++;\r
199                                 bits = x;\r
200                                 continue;\r
201                         }\r
202                 }\r
203                 else if (bits<18) {\r
204                         if (x>=0x10000) {\r
205                                 bits=x-0x10000+1;\r
206                                 continue;\r
207                         }\r
208                 } else {\r
209                          /* error in compressed data... */\r
210                         _mm_errno=MMERR_ITPACK_INVALID_DATA;\r
211                         return 0;\r
212                 }\r
213 \r
214                 if (bits<16) /* extend sign */\r
215                         x = ((SWORD)(x<<(16-bits)))>>(16-bits);\r
216                 *(dest++)=(last+=x);\r
217         }\r
218         status->bits = bits;\r
219         status->bufbits = bufbits;\r
220         status->last = last;\r
221         status->buf = buf;\r
222         return dest-sl_buffer;\r
223 }\r
224 \r
225 static BOOL SL_LoadInternal(void* buffer,UWORD infmt,UWORD outfmt,int scalefactor,ULONG length,MREADER* reader,BOOL dither)\r
226 {\r
227         SBYTE *bptr = (SBYTE*)buffer;\r
228         SWORD *wptr = (SWORD*)buffer;\r
229         int stodo,t,u;\r
230 \r
231         int result,c_block=0;   /* compression bytes until next block */\r
232         ITPACK status;\r
233         UWORD incnt;\r
234 \r
235         while(length) {\r
236                 stodo=(length<SLBUFSIZE)?length:SLBUFSIZE;\r
237 \r
238                 if(infmt&SF_ITPACKED) {\r
239                         sl_rlength=0;\r
240                         if (!c_block) {\r
241                                 status.bits = (infmt & SF_16BITS) ? 17 : 9;\r
242                                 status.last = status.bufbits = 0;\r
243                                 incnt=_mm_read_I_UWORD(reader);\r
244                                 c_block = (infmt & SF_16BITS) ? 0x4000 : 0x8000;\r
245                                 if(infmt&SF_DELTA) sl_old=0;\r
246                         }\r
247                         if (infmt & SF_16BITS) {\r
248                                 if(!(result=read_itcompr16(&status,reader,sl_buffer,stodo,&incnt)))\r
249                                         return 1;\r
250                         } else {\r
251                                 if(!(result=read_itcompr8(&status,reader,sl_buffer,stodo,&incnt)))\r
252                                         return 1;\r
253                         }\r
254                         if(result!=stodo) {\r
255                                 _mm_errno=MMERR_ITPACK_INVALID_DATA;\r
256                                 return 1;\r
257                         }\r
258                         c_block -= stodo;\r
259                 } else {\r
260                         if(infmt&SF_16BITS) {\r
261                                 if(infmt&SF_BIG_ENDIAN)\r
262                                         _mm_read_M_SWORDS(sl_buffer,stodo,reader);\r
263                                 else\r
264                                         _mm_read_I_SWORDS(sl_buffer,stodo,reader);\r
265                         } else {\r
266                                 SBYTE *src;\r
267                                 SWORD *dest;\r
268 \r
269                                 reader->Read(reader,sl_buffer,sizeof(SBYTE)*stodo);\r
270                                 src = (SBYTE*)sl_buffer;\r
271                                 dest  = sl_buffer;\r
272                                 src += stodo;dest += stodo;\r
273 \r
274                                 for(t=0;t<stodo;t++) {\r
275                                         src--;dest--;\r
276                                         *dest = (*src)<<8;\r
277                                 }\r
278                         }\r
279                         sl_rlength-=stodo;\r
280                 }\r
281 \r
282                 if(infmt & SF_DELTA)\r
283                         for(t=0;t<stodo;t++) {\r
284                                 sl_buffer[t] += sl_old;\r
285                                 sl_old = sl_buffer[t];\r
286                         }\r
287 \r
288                 if((infmt^outfmt) & SF_SIGNED) \r
289                         for(t=0;t<stodo;t++)\r
290                                 sl_buffer[t]^= 0x8000;\r
291 \r
292                 if(scalefactor) {\r
293                         int idx = 0;\r
294                         SLONG scaleval;\r
295 \r
296                         /* Sample Scaling... average values for better results. */\r
297                         t= 0;\r
298                         while(t<stodo && length) {\r
299                                 scaleval = 0;\r
300                                 for(u=scalefactor;u && t<stodo;u--,t++)\r
301                                         scaleval+=sl_buffer[t];\r
302                                 sl_buffer[idx++]=scaleval/(scalefactor-u);\r
303                                 length--;\r
304                         }\r
305                         stodo = idx;\r
306                 } else\r
307                         length -= stodo;\r
308 \r
309                 if (dither) {\r
310                         if((infmt & SF_STEREO) && !(outfmt & SF_STEREO)) {\r
311                                 /* dither stereo to mono, average together every two samples */\r
312                                 SLONG avgval;\r
313                                 int idx = 0;\r
314 \r
315                                 t=0;\r
316                                 while(t<stodo && length) {\r
317                                         avgval=sl_buffer[t++];\r
318                                         avgval+=sl_buffer[t++];\r
319                                         sl_buffer[idx++]=avgval>>1;\r
320                                         length-=2;\r
321                                 }\r
322                                 stodo = idx;\r
323                         }\r
324                 }\r
325 \r
326                 if(outfmt & SF_16BITS) {\r
327                         for(t=0;t<stodo;t++)\r
328                                 *(wptr++)=sl_buffer[t];\r
329                 } else {\r
330                         for(t=0;t<stodo;t++)\r
331                                 *(bptr++)=sl_buffer[t]>>8;\r
332                 }\r
333         }\r
334         return 0;\r
335 }\r
336 \r
337 BOOL SL_Load(void* buffer,SAMPLOAD *smp,ULONG length)\r
338 {\r
339         return SL_LoadInternal(buffer,smp->infmt,smp->outfmt,smp->scalefactor,\r
340                                length,smp->reader,0);\r
341 }\r
342 \r
343 /* Registers a sample for loading when SL_LoadSamples() is called. */\r
344 SAMPLOAD* SL_RegisterSample(SAMPLE* s,int type,MREADER* reader)\r
345 {\r
346         SAMPLOAD *news,**samplist,*cruise;\r
347 \r
348         if(type==MD_MUSIC) {\r
349                 samplist = &musiclist;\r
350                 cruise = musiclist;\r
351         } else\r
352           if (type==MD_SNDFX) {\r
353                 samplist = &sndfxlist;\r
354                 cruise = sndfxlist;\r
355         } else\r
356                 return NULL;\r
357         \r
358         /* Allocate and add structure to the END of the list */\r
359         if(!(news=(SAMPLOAD*)_mm_malloc(sizeof(SAMPLOAD)))) return NULL;\r
360 \r
361         if(cruise) {\r
362                 while(cruise->next) cruise=cruise->next;\r
363                 cruise->next = news;\r
364         } else\r
365                 *samplist = news;\r
366 \r
367         news->infmt     = s->flags & SF_FORMATMASK;\r
368         news->outfmt    = news->infmt;\r
369         news->reader    = reader;\r
370         news->sample    = s;\r
371         news->length    = s->length;\r
372         news->loopstart = s->loopstart;\r
373         news->loopend   = s->loopend;\r
374 \r
375         return news;\r
376 }\r
377 \r
378 static void FreeSampleList(SAMPLOAD* s)\r
379 {\r
380         SAMPLOAD *old;\r
381 \r
382         while(s) {\r
383                 old = s;\r
384                 s = s->next;\r
385                 free(old);\r
386         }\r
387 }\r
388 \r
389 /* Returns the total amount of memory required by the samplelist queue. */\r
390 static ULONG SampleTotal(SAMPLOAD* samplist,int type)\r
391 {\r
392         int total = 0;\r
393 \r
394         while(samplist) {\r
395                 samplist->sample->flags=\r
396                   (samplist->sample->flags&~SF_FORMATMASK)|samplist->outfmt;\r
397                 total += MD_SampleLength(type,samplist->sample);\r
398                 samplist=samplist->next;\r
399         }\r
400 \r
401         return total;\r
402 }\r
403 \r
404 static ULONG RealSpeed(SAMPLOAD *s)\r
405 {\r
406         return(s->sample->speed/(s->scalefactor?s->scalefactor:1));\r
407 }    \r
408 \r
409 static BOOL DitherSamples(SAMPLOAD* samplist,int type)\r
410 {\r
411         SAMPLOAD *c2smp=NULL;\r
412         ULONG maxsize, speed;\r
413         SAMPLOAD *s;\r
414 \r
415         if(!samplist) return 0;\r
416 \r
417         if((maxsize=MD_SampleSpace(type)*1024)) \r
418                 while(SampleTotal(samplist,type)>maxsize) {\r
419                         /* First Pass - check for any 16 bit samples */\r
420                         s = samplist;\r
421                         while(s) {\r
422                                 if(s->outfmt & SF_16BITS) {\r
423                                         SL_Sample16to8(s);\r
424                                         break;\r
425                                 }\r
426                                 s=s->next;\r
427                         }\r
428                         /* Second pass (if no 16bits found above) is to take the sample with\r
429                            the highest speed and dither it by half. */\r
430                         if(!s) {\r
431                                 s = samplist;\r
432                                 speed = 0;\r
433                                 while(s) {\r
434                                         if((s->sample->length) && (RealSpeed(s)>speed)) {\r
435                                                 speed=RealSpeed(s);\r
436                                                 c2smp=s;\r
437                                         }\r
438                                         s=s->next;\r
439                                 }\r
440                                 if (c2smp)\r
441                                         SL_HalveSample(c2smp,2);\r
442                         }\r
443                 }\r
444 \r
445         /* Samples dithered, now load them ! */\r
446         s = samplist;\r
447         while(s) {\r
448                 /* sample has to be loaded ? -> increase number of samples, allocate\r
449                    memory and load sample. */\r
450                 if(s->sample->length) {\r
451                         if(s->sample->seekpos)\r
452                                 _mm_fseek(s->reader, s->sample->seekpos, SEEK_SET);\r
453 \r
454                         /* Call the sample load routine of the driver module. It has to\r
455                            return a 'handle' (>=0) that identifies the sample. */\r
456                         s->sample->handle = MD_SampleLoad(s, type);\r
457                         s->sample->flags  = (s->sample->flags & ~SF_FORMATMASK) | s->outfmt;\r
458                         if(s->sample->handle<0) {\r
459                                 FreeSampleList(samplist);\r
460                                 if(_mm_errorhandler) _mm_errorhandler();\r
461                                 return 1;\r
462                         }\r
463                 }\r
464                 s = s->next;\r
465         }\r
466 \r
467         FreeSampleList(samplist);\r
468         return 0;\r
469 }\r
470 \r
471 BOOL SL_LoadSamples(void)\r
472 {\r
473         BOOL ok;\r
474 \r
475         _mm_critical = 0;\r
476 \r
477         if((!musiclist)&&(!sndfxlist)) return 0;\r
478         ok=DitherSamples(musiclist,MD_MUSIC)||DitherSamples(sndfxlist,MD_SNDFX);\r
479         musiclist=sndfxlist=NULL;\r
480 \r
481         return ok;\r
482 }\r
483 \r
484 void SL_Sample16to8(SAMPLOAD* s)\r
485 {\r
486         s->outfmt &= ~SF_16BITS;\r
487         s->sample->flags = (s->sample->flags&~SF_FORMATMASK) | s->outfmt;\r
488 }\r
489 \r
490 void SL_Sample8to16(SAMPLOAD* s)\r
491 {\r
492         s->outfmt |= SF_16BITS;\r
493         s->sample->flags = (s->sample->flags&~SF_FORMATMASK) | s->outfmt;\r
494 }\r
495 \r
496 void SL_SampleSigned(SAMPLOAD* s)\r
497 {\r
498         s->outfmt |= SF_SIGNED;\r
499         s->sample->flags = (s->sample->flags&~SF_FORMATMASK) | s->outfmt;\r
500 }\r
501 \r
502 void SL_SampleUnsigned(SAMPLOAD* s)\r
503 {\r
504         s->outfmt &= ~SF_SIGNED;\r
505         s->sample->flags = (s->sample->flags&~SF_FORMATMASK) | s->outfmt;\r
506 }\r
507 \r
508 void SL_HalveSample(SAMPLOAD* s,int factor)\r
509 {\r
510         s->scalefactor=factor>0?factor:2;\r
511 \r
512         s->sample->divfactor = s->scalefactor;\r
513         s->sample->length    = s->length / s->scalefactor;\r
514         s->sample->loopstart = s->loopstart / s->scalefactor;\r
515         s->sample->loopend   = s->loopend / s->scalefactor;\r
516 }\r
517 \r
518 \r
519 /* ex:set ts=4: */\r