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