diff options
Diffstat (limited to 'apps')
46 files changed, 22317 insertions, 0 deletions
diff --git a/apps/plugins/CATEGORIES b/apps/plugins/CATEGORIES index 983e52c88a..c310a2cdb8 100644 --- a/apps/plugins/CATEGORIES +++ b/apps/plugins/CATEGORIES | |||
@@ -56,6 +56,7 @@ mem_mon,apps | |||
56 | metronome,apps | 56 | metronome,apps |
57 | midi2wav,viewers | 57 | midi2wav,viewers |
58 | midi,viewers | 58 | midi,viewers |
59 | mikmod,viewers | ||
59 | minesweeper,games | 60 | minesweeper,games |
60 | mosaique,demos | 61 | mosaique,demos |
61 | mp3_encoder,apps | 62 | mp3_encoder,apps |
diff --git a/apps/plugins/SUBDIRS b/apps/plugins/SUBDIRS index 33efc5f12d..c497c49b14 100644 --- a/apps/plugins/SUBDIRS +++ b/apps/plugins/SUBDIRS | |||
@@ -66,6 +66,7 @@ doom | |||
66 | 66 | ||
67 | #if MEMORYSIZE > 2 /* we need a lot of RAM for instruments */ | 67 | #if MEMORYSIZE > 2 /* we need a lot of RAM for instruments */ |
68 | midi | 68 | midi |
69 | mikmod | ||
69 | #endif | 70 | #endif |
70 | 71 | ||
71 | /* beatbox */ | 72 | /* beatbox */ |
diff --git a/apps/plugins/mikmod/SOURCES b/apps/plugins/mikmod/SOURCES new file mode 100644 index 0000000000..1de5bb2149 --- /dev/null +++ b/apps/plugins/mikmod/SOURCES | |||
@@ -0,0 +1,39 @@ | |||
1 | drv_nos.c | ||
2 | load_669.c | ||
3 | load_amf.c | ||
4 | load_asy.c | ||
5 | load_dsm.c | ||
6 | load_far.c | ||
7 | load_gdm.c | ||
8 | load_gt2.c | ||
9 | load_imf.c | ||
10 | load_it.c | ||
11 | load_m15.c | ||
12 | load_med.c | ||
13 | load_mod.c | ||
14 | load_mtm.c | ||
15 | load_okt.c | ||
16 | load_s3m.c | ||
17 | load_stm.c | ||
18 | load_stx.c | ||
19 | load_ult.c | ||
20 | load_uni.c | ||
21 | load_xm.c | ||
22 | mdreg.c | ||
23 | mdriver.c | ||
24 | mloader.c | ||
25 | mlreg.c | ||
26 | mlutil.c | ||
27 | mmalloc.c | ||
28 | mmerror.c | ||
29 | mmio.c | ||
30 | mplayer.c | ||
31 | munitrk.c | ||
32 | npertab.c | ||
33 | sloader.c | ||
34 | strdup.c | ||
35 | strstr.c | ||
36 | virtch.c | ||
37 | virtch_common.c | ||
38 | mikmod.c | ||
39 | |||
diff --git a/apps/plugins/mikmod/drv_nos.c b/apps/plugins/mikmod/drv_nos.c new file mode 100644 index 0000000000..08d70466d1 --- /dev/null +++ b/apps/plugins/mikmod/drv_nos.c | |||
@@ -0,0 +1,107 @@ | |||
1 | /* MikMod sound library | ||
2 | (c) 1998, 1999, 2000 Miodrag Vallat and others - see file AUTHORS for | ||
3 | 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: drv_nos.c,v 1.2 2005/03/30 19:09:11 realtech Exp $ | ||
24 | |||
25 | Driver for no output | ||
26 | |||
27 | ==============================================================================*/ | ||
28 | |||
29 | /* | ||
30 | |||
31 | Written by Jean-Paul Mikkers <mikmak@via.nl> | ||
32 | |||
33 | */ | ||
34 | |||
35 | #ifdef HAVE_CONFIG_H | ||
36 | #include "config.h" | ||
37 | #endif | ||
38 | |||
39 | #ifdef HAVE_UNISTD_H | ||
40 | #include <unistd.h> | ||
41 | #endif | ||
42 | |||
43 | #include "mikmod_internals.h" | ||
44 | |||
45 | #define ZEROLEN 32768 | ||
46 | |||
47 | //static SBYTE *zerobuf=NULL; | ||
48 | |||
49 | static int NS_IsThere(void) | ||
50 | { | ||
51 | return 1; | ||
52 | } | ||
53 | |||
54 | static int NS_Init(void) | ||
55 | { | ||
56 | //zerobuf=(SBYTE*)MikMod_malloc(ZEROLEN); | ||
57 | return VC_Init(); | ||
58 | } | ||
59 | |||
60 | static void NS_Exit(void) | ||
61 | { | ||
62 | VC_Exit(); | ||
63 | //MikMod_free(zerobuf); | ||
64 | } | ||
65 | |||
66 | static void NS_Update(void) | ||
67 | { | ||
68 | //if (zerobuf) | ||
69 | // VC_WriteBytes(zerobuf,ZEROLEN); | ||
70 | } | ||
71 | |||
72 | MIKMODAPI MDRIVER drv_nos={ | ||
73 | NULL, | ||
74 | "No Sound", | ||
75 | "Nosound Driver v3.0", | ||
76 | 255,255, | ||
77 | "nosound", | ||
78 | NULL, | ||
79 | NULL, | ||
80 | NS_IsThere, | ||
81 | VC_SampleLoad, | ||
82 | VC_SampleUnload, | ||
83 | VC_SampleSpace, | ||
84 | VC_SampleLength, | ||
85 | NS_Init, | ||
86 | NS_Exit, | ||
87 | NULL, | ||
88 | VC_SetNumVoices, | ||
89 | VC_PlayStart, | ||
90 | VC_PlayStop, | ||
91 | NS_Update, | ||
92 | NULL, | ||
93 | VC_VoiceSetVolume, | ||
94 | VC_VoiceGetVolume, | ||
95 | VC_VoiceSetFrequency, | ||
96 | VC_VoiceGetFrequency, | ||
97 | VC_VoiceSetPanning, | ||
98 | VC_VoiceGetPanning, | ||
99 | VC_VoicePlay, | ||
100 | VC_VoiceStop, | ||
101 | VC_VoiceStopped, | ||
102 | VC_VoiceGetPosition, | ||
103 | VC_VoiceRealVolume | ||
104 | }; | ||
105 | |||
106 | |||
107 | /* ex:set ts=4: */ | ||
diff --git a/apps/plugins/mikmod/load_669.c b/apps/plugins/mikmod/load_669.c new file mode 100644 index 0000000000..95b04aa5b1 --- /dev/null +++ b/apps/plugins/mikmod/load_669.c | |||
@@ -0,0 +1,368 @@ | |||
1 | /* MikMod sound library | ||
2 | (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file | ||
3 | AUTHORS 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: load_669.c,v 1.3 2005/04/07 19:57:38 realtech Exp $ | ||
24 | |||
25 | Composer 669 module loader | ||
26 | |||
27 | ==============================================================================*/ | ||
28 | |||
29 | #ifdef HAVE_CONFIG_H | ||
30 | #include "config.h" | ||
31 | #endif | ||
32 | |||
33 | #ifdef HAVE_UNISTD_H | ||
34 | #include <unistd.h> | ||
35 | #endif | ||
36 | |||
37 | #include <stdio.h> | ||
38 | #ifdef HAVE_MEMORY_H | ||
39 | #include <memory.h> | ||
40 | #endif | ||
41 | #include <string.h> | ||
42 | |||
43 | #include "mikmod_internals.h" | ||
44 | |||
45 | #ifdef SUNOS | ||
46 | extern int fprintf(FILE *, const char *, ...); | ||
47 | #endif | ||
48 | |||
49 | /*========== Module structure */ | ||
50 | |||
51 | /* header */ | ||
52 | typedef struct S69HEADER { | ||
53 | UBYTE marker[2]; | ||
54 | CHAR message[108]; | ||
55 | UBYTE nos; | ||
56 | UBYTE rbnop; | ||
57 | UBYTE looporder; | ||
58 | UBYTE orders[0x80]; | ||
59 | UBYTE tempos[0x80]; | ||
60 | UBYTE breaks[0x80]; | ||
61 | } S69HEADER; | ||
62 | |||
63 | /* sample information */ | ||
64 | typedef struct S69SAMPLE { | ||
65 | CHAR filename[13]; | ||
66 | SLONG length; | ||
67 | SLONG loopbeg; | ||
68 | SLONG loopend; | ||
69 | } S69SAMPLE; | ||
70 | |||
71 | /* encoded note */ | ||
72 | typedef struct S69NOTE { | ||
73 | UBYTE a,b,c; | ||
74 | } S69NOTE; | ||
75 | |||
76 | /*========== Loader variables */ | ||
77 | |||
78 | /* current pattern */ | ||
79 | static S69NOTE* s69pat=NULL; | ||
80 | /* Module header */ | ||
81 | static S69HEADER* mh=NULL; | ||
82 | |||
83 | /* file type identification */ | ||
84 | static CHAR* S69_Version[]={ | ||
85 | "Composer 669", | ||
86 | "Extended 669" | ||
87 | }; | ||
88 | |||
89 | /*========== Loader code */ | ||
90 | |||
91 | int S69_Test(void) | ||
92 | { | ||
93 | UBYTE buf[0x80]; | ||
94 | |||
95 | if(!_mm_read_UBYTES(buf,2,modreader)) | ||
96 | return 0; | ||
97 | /* look for id */ | ||
98 | if(!memcmp(buf,"if",2) || !memcmp(buf,"JN",2)) { | ||
99 | int i; | ||
100 | |||
101 | /* skip song message */ | ||
102 | _mm_fseek(modreader,108,SEEK_CUR); | ||
103 | /* sanity checks */ | ||
104 | if(_mm_read_UBYTE(modreader) > 64) return 0; | ||
105 | if(_mm_read_UBYTE(modreader) > 128) return 0; | ||
106 | if(_mm_read_UBYTE(modreader) > 127) return 0; | ||
107 | /* check order table */ | ||
108 | if(!_mm_read_UBYTES(buf,0x80,modreader)) return 0; | ||
109 | for(i=0;i<0x80;i++) | ||
110 | if((buf[i]>=0x80)&&(buf[i]!=0xff)) return 0; | ||
111 | /* check tempos table */ | ||
112 | if(!_mm_read_UBYTES(buf,0x80,modreader)) return 0; | ||
113 | for(i=0;i<0x80;i++) | ||
114 | if((!buf[i])||(buf[i]>32)) return 0; | ||
115 | /* check pattern length table */ | ||
116 | if(!_mm_read_UBYTES(buf,0x80,modreader)) return 0; | ||
117 | for(i=0;i<0x80;i++) | ||
118 | if(buf[i]>0x3f) return 0; | ||
119 | } else | ||
120 | return 0; | ||
121 | |||
122 | return 1; | ||
123 | } | ||
124 | |||
125 | int S69_Init(void) | ||
126 | { | ||
127 | if(!(s69pat=(S69NOTE *)MikMod_malloc(64*8*sizeof(S69NOTE)))) return 0; | ||
128 | if(!(mh=(S69HEADER *)MikMod_malloc(sizeof(S69HEADER)))) return 0; | ||
129 | |||
130 | return 1; | ||
131 | } | ||
132 | |||
133 | void S69_Cleanup(void) | ||
134 | { | ||
135 | MikMod_free(s69pat); | ||
136 | MikMod_free(mh); | ||
137 | } | ||
138 | |||
139 | static int S69_LoadPatterns(void) | ||
140 | { | ||
141 | int track,row,channel; | ||
142 | UBYTE note,inst,vol,effect,lastfx,lastval; | ||
143 | S69NOTE *cur; | ||
144 | int tracks=0; | ||
145 | |||
146 | if(!AllocPatterns()) return 0; | ||
147 | if(!AllocTracks()) return 0; | ||
148 | |||
149 | for(track=0;track<of.numpat;track++) { | ||
150 | /* set pattern break locations */ | ||
151 | of.pattrows[track]=mh->breaks[track]+1; | ||
152 | |||
153 | /* load the 669 pattern */ | ||
154 | cur=s69pat; | ||
155 | for(row=0;row<64;row++) { | ||
156 | for(channel=0;channel<8;channel++,cur++) { | ||
157 | cur->a = _mm_read_UBYTE(modreader); | ||
158 | cur->b = _mm_read_UBYTE(modreader); | ||
159 | cur->c = _mm_read_UBYTE(modreader); | ||
160 | } | ||
161 | } | ||
162 | |||
163 | if(_mm_eof(modreader)) { | ||
164 | _mm_errno = MMERR_LOADING_PATTERN; | ||
165 | return 0; | ||
166 | } | ||
167 | |||
168 | /* translate the pattern */ | ||
169 | for(channel=0;channel<8;channel++) { | ||
170 | UniReset(); | ||
171 | /* set pattern tempo */ | ||
172 | UniPTEffect(0xf,78); | ||
173 | UniPTEffect(0xf,mh->tempos[track]); | ||
174 | |||
175 | lastfx=0xff,lastval=0; | ||
176 | |||
177 | for(row=0;row<=mh->breaks[track];row++) { | ||
178 | int a,b,c; | ||
179 | |||
180 | /* fetch the encoded note */ | ||
181 | a=s69pat[(row*8)+channel].a; | ||
182 | b=s69pat[(row*8)+channel].b; | ||
183 | c=s69pat[(row*8)+channel].c; | ||
184 | |||
185 | /* decode it */ | ||
186 | note=a>>2; | ||
187 | inst=((a&0x3)<<4)|((b&0xf0)>>4); | ||
188 | vol=b&0xf; | ||
189 | |||
190 | if (a<0xff) { | ||
191 | if (a<0xfe) { | ||
192 | UniInstrument(inst); | ||
193 | UniNote(note+2*OCTAVE); | ||
194 | lastfx=0xff; /* reset background effect memory */ | ||
195 | } | ||
196 | UniPTEffect(0xc,vol<<2); | ||
197 | } | ||
198 | |||
199 | if ((c!=0xff)||(lastfx!=0xff)) { | ||
200 | if(c==0xff) | ||
201 | c=lastfx,effect=lastval; | ||
202 | else | ||
203 | effect=c&0xf; | ||
204 | |||
205 | switch(c>>4) { | ||
206 | case 0: /* porta up */ | ||
207 | UniPTEffect(0x1,effect); | ||
208 | lastfx=c,lastval=effect; | ||
209 | break; | ||
210 | case 1: /* porta down */ | ||
211 | UniPTEffect(0x2,effect); | ||
212 | lastfx=c,lastval=effect; | ||
213 | break; | ||
214 | case 2: /* porta to note */ | ||
215 | UniPTEffect(0x3,effect); | ||
216 | lastfx=c,lastval=effect; | ||
217 | break; | ||
218 | case 3: /* frequency adjust */ | ||
219 | /* DMP converts this effect to S3M FF1. Why not ? */ | ||
220 | UniEffect(UNI_S3MEFFECTF,0xf0|effect); | ||
221 | break; | ||
222 | case 4: /* vibrato */ | ||
223 | UniPTEffect(0x4,effect); | ||
224 | lastfx=c,lastval=effect; | ||
225 | break; | ||
226 | case 5: /* set speed */ | ||
227 | if (effect) | ||
228 | UniPTEffect(0xf,effect); | ||
229 | else | ||
230 | if(mh->marker[0]!=0x69) { | ||
231 | #ifdef MIKMOD_DEBUG | ||
232 | fprintf(stderr,"\r669: unsupported super fast tempo at pat=%d row=%d chan=%d\n", | ||
233 | track,row,channel); | ||
234 | #endif | ||
235 | } | ||
236 | break; | ||
237 | } | ||
238 | } | ||
239 | UniNewline(); | ||
240 | } | ||
241 | if(!(of.tracks[tracks++]=UniDup())) return 0; | ||
242 | } | ||
243 | } | ||
244 | |||
245 | return 1; | ||
246 | } | ||
247 | |||
248 | int S69_Load(int curious) | ||
249 | { | ||
250 | int i; | ||
251 | SAMPLE *current; | ||
252 | S69SAMPLE sample; | ||
253 | |||
254 | /* module header */ | ||
255 | _mm_read_UBYTES(mh->marker,2,modreader); | ||
256 | _mm_read_UBYTES(mh->message,108,modreader); | ||
257 | mh->nos=_mm_read_UBYTE(modreader); | ||
258 | mh->rbnop=_mm_read_UBYTE(modreader); | ||
259 | mh->looporder=_mm_read_UBYTE(modreader); | ||
260 | _mm_read_UBYTES(mh->orders,0x80,modreader); | ||
261 | for(i=0;i<0x80;i++) | ||
262 | if ((mh->orders[i]>=0x80)&&(mh->orders[i]!=0xff)) { | ||
263 | _mm_errno=MMERR_NOT_A_MODULE; | ||
264 | return 1; | ||
265 | } | ||
266 | _mm_read_UBYTES(mh->tempos,0x80,modreader); | ||
267 | for(i=0;i<0x80;i++) | ||
268 | if ((!mh->tempos[i])||(mh->tempos[i]>32)) { | ||
269 | _mm_errno=MMERR_NOT_A_MODULE; | ||
270 | return 1; | ||
271 | } | ||
272 | _mm_read_UBYTES(mh->breaks,0x80,modreader); | ||
273 | for(i=0;i<0x80;i++) | ||
274 | if (mh->breaks[i]>0x3f) { | ||
275 | _mm_errno=MMERR_NOT_A_MODULE; | ||
276 | return 1; | ||
277 | } | ||
278 | |||
279 | /* set module variables */ | ||
280 | of.initspeed=4; | ||
281 | of.inittempo=78; | ||
282 | of.songname=DupStr(mh->message,36,1); | ||
283 | of.modtype=StrDup(S69_Version[memcmp(mh->marker,"JN",2)==0]); | ||
284 | of.numchn=8; | ||
285 | of.numpat=mh->rbnop; | ||
286 | of.numins=of.numsmp=mh->nos; | ||
287 | of.numtrk=of.numchn*of.numpat; | ||
288 | of.flags=UF_XMPERIODS|UF_LINEAR; | ||
289 | |||
290 | for(i= 35;(i>= 0)&&(mh->message[i]==' ');i--) mh->message[i]=0; | ||
291 | for(i=36+35;(i>=36+0)&&(mh->message[i]==' ');i--) mh->message[i]=0; | ||
292 | for(i=72+35;(i>=72+0)&&(mh->message[i]==' ');i--) mh->message[i]=0; | ||
293 | if((mh->message[0])||(mh->message[36])||(mh->message[72])) | ||
294 | if((of.comment=(CHAR*)MikMod_malloc(3*(36+1)+1))) { | ||
295 | strncpy(of.comment,mh->message,36); | ||
296 | strcat(of.comment,"\r"); | ||
297 | if (mh->message[36]) strncat(of.comment,mh->message+36,36); | ||
298 | strcat(of.comment,"\r"); | ||
299 | if (mh->message[72]) strncat(of.comment,mh->message+72,36); | ||
300 | strcat(of.comment,"\r"); | ||
301 | of.comment[3*(36+1)]=0; | ||
302 | } | ||
303 | |||
304 | if(!AllocPositions(0x80)) return 0; | ||
305 | for(i=0;i<0x80;i++) { | ||
306 | if(mh->orders[i]>=mh->rbnop) break; | ||
307 | of.positions[i]=mh->orders[i]; | ||
308 | } | ||
309 | of.numpos=i; | ||
310 | of.reppos=mh->looporder<of.numpos?mh->looporder:0; | ||
311 | |||
312 | if(!AllocSamples()) return 0; | ||
313 | current=of.samples; | ||
314 | |||
315 | for(i=0;i<of.numins;i++) { | ||
316 | /* sample information */ | ||
317 | _mm_read_UBYTES((UBYTE*)sample.filename,13,modreader); | ||
318 | sample.length=_mm_read_I_SLONG(modreader); | ||
319 | sample.loopbeg=_mm_read_I_SLONG(modreader); | ||
320 | sample.loopend=_mm_read_I_SLONG(modreader); | ||
321 | if (sample.loopend==0xfffff) sample.loopend=0; | ||
322 | |||
323 | if((sample.length<0)||(sample.loopbeg<-1)||(sample.loopend<-1)) { | ||
324 | _mm_errno = MMERR_LOADING_HEADER; | ||
325 | return 0; | ||
326 | } | ||
327 | |||
328 | current->samplename=DupStr(sample.filename,13,1); | ||
329 | current->seekpos=0; | ||
330 | current->speed=0; | ||
331 | current->length=sample.length; | ||
332 | current->loopstart=sample.loopbeg; | ||
333 | current->loopend=sample.loopend; | ||
334 | current->flags=(sample.loopbeg<sample.loopend)?SF_LOOP:0; | ||
335 | current->volume=64; | ||
336 | |||
337 | current++; | ||
338 | } | ||
339 | |||
340 | if(!S69_LoadPatterns()) return 0; | ||
341 | |||
342 | return 1; | ||
343 | } | ||
344 | |||
345 | CHAR *S69_LoadTitle(void) | ||
346 | { | ||
347 | CHAR s[36]; | ||
348 | |||
349 | _mm_fseek(modreader,2,SEEK_SET); | ||
350 | if(!_mm_read_UBYTES(s,36,modreader)) return NULL; | ||
351 | |||
352 | return(DupStr(s,36,1)); | ||
353 | } | ||
354 | |||
355 | /*========== Loader information */ | ||
356 | |||
357 | MIKMODAPI MLOADER load_669={ | ||
358 | NULL, | ||
359 | "669", | ||
360 | "669 (Composer 669, Unis 669)", | ||
361 | S69_Init, | ||
362 | S69_Test, | ||
363 | S69_Load, | ||
364 | S69_Cleanup, | ||
365 | S69_LoadTitle | ||
366 | }; | ||
367 | |||
368 | /* ex:set ts=4: */ | ||
diff --git a/apps/plugins/mikmod/load_amf.c b/apps/plugins/mikmod/load_amf.c new file mode 100644 index 0000000000..12e0af0738 --- /dev/null +++ b/apps/plugins/mikmod/load_amf.c | |||
@@ -0,0 +1,569 @@ | |||
1 | /* MikMod sound library | ||
2 | (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file | ||
3 | AUTHORS 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: load_amf.c,v 1.3 2005/04/07 19:57:38 realtech Exp $ | ||
24 | |||
25 | DMP Advanced Module Format loader | ||
26 | |||
27 | ==============================================================================*/ | ||
28 | |||
29 | #ifdef HAVE_CONFIG_H | ||
30 | #include "config.h" | ||
31 | #endif | ||
32 | |||
33 | #ifdef HAVE_UNISTD_H | ||
34 | #include <unistd.h> | ||
35 | #endif | ||
36 | |||
37 | #include <stdio.h> | ||
38 | #ifdef HAVE_MEMORY_H | ||
39 | #include <memory.h> | ||
40 | #endif | ||
41 | #include <string.h> | ||
42 | |||
43 | #include "mikmod_internals.h" | ||
44 | |||
45 | #ifdef SUNOS | ||
46 | extern int fprintf(FILE *, const char *, ...); | ||
47 | #endif | ||
48 | |||
49 | /*========== Module structure */ | ||
50 | |||
51 | typedef struct AMFHEADER { | ||
52 | UBYTE id[3]; /* AMF file marker */ | ||
53 | UBYTE version; /* upper major, lower nibble minor version number */ | ||
54 | CHAR songname[32]; /* ASCIIZ songname */ | ||
55 | UBYTE numsamples; /* number of samples saved */ | ||
56 | UBYTE numorders; | ||
57 | UWORD numtracks; /* number of tracks saved */ | ||
58 | UBYTE numchannels; /* number of channels used */ | ||
59 | SBYTE panpos[32]; /* voice pan positions */ | ||
60 | UBYTE songbpm; | ||
61 | UBYTE songspd; | ||
62 | } AMFHEADER; | ||
63 | |||
64 | typedef struct AMFSAMPLE { | ||
65 | UBYTE type; | ||
66 | CHAR samplename[32]; | ||
67 | CHAR filename[13]; | ||
68 | ULONG offset; | ||
69 | ULONG length; | ||
70 | UWORD c2spd; | ||
71 | UBYTE volume; | ||
72 | ULONG reppos; | ||
73 | ULONG repend; | ||
74 | } AMFSAMPLE; | ||
75 | |||
76 | typedef struct AMFNOTE { | ||
77 | UBYTE note,instr,volume,fxcnt; | ||
78 | UBYTE effect[3]; | ||
79 | SBYTE parameter[3]; | ||
80 | } AMFNOTE; | ||
81 | |||
82 | /*========== Loader variables */ | ||
83 | |||
84 | static AMFHEADER *mh = NULL; | ||
85 | #define AMFTEXTLEN 22 | ||
86 | static CHAR AMF_Version[AMFTEXTLEN+1] = "DSMI Module Format 0.0"; | ||
87 | static AMFNOTE *track = NULL; | ||
88 | |||
89 | /*========== Loader code */ | ||
90 | |||
91 | int AMF_Test(void) | ||
92 | { | ||
93 | UBYTE id[3],ver; | ||
94 | |||
95 | if(!_mm_read_UBYTES(id,3,modreader)) return 0; | ||
96 | if(memcmp(id,"AMF",3)) return 0; | ||
97 | |||
98 | ver=_mm_read_UBYTE(modreader); | ||
99 | if((ver>=10)&&(ver<=14)) return 1; | ||
100 | return 0; | ||
101 | } | ||
102 | |||
103 | int AMF_Init(void) | ||
104 | { | ||
105 | if(!(mh=(AMFHEADER*)MikMod_malloc(sizeof(AMFHEADER)))) return 0; | ||
106 | if(!(track=(AMFNOTE*)MikMod_calloc(64,sizeof(AMFNOTE)))) return 0; | ||
107 | |||
108 | return 1; | ||
109 | } | ||
110 | |||
111 | void AMF_Cleanup(void) | ||
112 | { | ||
113 | MikMod_free(mh); | ||
114 | MikMod_free(track); | ||
115 | } | ||
116 | |||
117 | static int AMF_UnpackTrack(MREADER* modreader) | ||
118 | { | ||
119 | ULONG tracksize; | ||
120 | UBYTE row,cmd; | ||
121 | SBYTE arg; | ||
122 | |||
123 | /* empty track */ | ||
124 | memset(track,0,64*sizeof(AMFNOTE)); | ||
125 | |||
126 | /* read packed track */ | ||
127 | if (modreader) { | ||
128 | tracksize=_mm_read_I_UWORD(modreader); | ||
129 | tracksize+=((ULONG)_mm_read_UBYTE(modreader))<<16; | ||
130 | if (tracksize) | ||
131 | while(tracksize--) { | ||
132 | row=_mm_read_UBYTE(modreader); | ||
133 | cmd=_mm_read_UBYTE(modreader); | ||
134 | arg=_mm_read_SBYTE(modreader); | ||
135 | /* unexpected end of track */ | ||
136 | if(!tracksize) { | ||
137 | if((row==0xff)&&(cmd==0xff)&&(arg==-1)) | ||
138 | break; | ||
139 | /* the last triplet should be FF FF FF, but this is not | ||
140 | always the case... maybe a bug in m2amf ? | ||
141 | else | ||
142 | return 0; | ||
143 | */ | ||
144 | |||
145 | } | ||
146 | /* invalid row (probably unexpected end of row) */ | ||
147 | if (row>=64) | ||
148 | return 0; | ||
149 | if (cmd<0x7f) { | ||
150 | /* note, vol */ | ||
151 | track[row].note=cmd; | ||
152 | track[row].volume=(UBYTE)arg+1; | ||
153 | } else | ||
154 | if (cmd==0x7f) { | ||
155 | /* duplicate row */ | ||
156 | if ((arg<0)&&(row+arg>=0)) { | ||
157 | memcpy(track+row,track+(row+arg),sizeof(AMFNOTE)); | ||
158 | } | ||
159 | } else | ||
160 | if (cmd==0x80) { | ||
161 | /* instr */ | ||
162 | track[row].instr=arg+1; | ||
163 | } else | ||
164 | if (cmd==0x83) { | ||
165 | /* volume without note */ | ||
166 | track[row].volume=(UBYTE)arg+1; | ||
167 | } else | ||
168 | if (cmd==0xff) { | ||
169 | /* apparently, some M2AMF version fail to estimate the | ||
170 | size of the compressed patterns correctly, and end | ||
171 | up with blanks, i.e. dead triplets. Those are marked | ||
172 | with cmd == 0xff. Let's ignore them. */ | ||
173 | } else | ||
174 | if(track[row].fxcnt<3) { | ||
175 | /* effect, param */ | ||
176 | if(cmd>0x97) | ||
177 | return 0; | ||
178 | track[row].effect[track[row].fxcnt]=cmd&0x7f; | ||
179 | track[row].parameter[track[row].fxcnt]=arg; | ||
180 | track[row].fxcnt++; | ||
181 | } else | ||
182 | return 0; | ||
183 | } | ||
184 | } | ||
185 | return 1; | ||
186 | } | ||
187 | |||
188 | static UBYTE* AMF_ConvertTrack(void) | ||
189 | { | ||
190 | int row,fx4memory=0; | ||
191 | |||
192 | /* convert track */ | ||
193 | UniReset(); | ||
194 | for (row=0;row<64;row++) { | ||
195 | if (track[row].instr) UniInstrument(track[row].instr-1); | ||
196 | if (track[row].note>OCTAVE) UniNote(track[row].note-OCTAVE); | ||
197 | |||
198 | /* AMF effects */ | ||
199 | while(track[row].fxcnt--) { | ||
200 | SBYTE inf=track[row].parameter[track[row].fxcnt]; | ||
201 | |||
202 | switch(track[row].effect[track[row].fxcnt]) { | ||
203 | case 1: /* Set speed */ | ||
204 | UniEffect(UNI_S3MEFFECTA,inf); | ||
205 | break; | ||
206 | case 2: /* Volume slide */ | ||
207 | if(inf) { | ||
208 | UniWriteByte(UNI_S3MEFFECTD); | ||
209 | if (inf>=0) | ||
210 | UniWriteByte((inf&0xf)<<4); | ||
211 | else | ||
212 | UniWriteByte((-inf)&0xf); | ||
213 | } | ||
214 | break; | ||
215 | /* effect 3, set channel volume, done in UnpackTrack */ | ||
216 | case 4: /* Porta up/down */ | ||
217 | if(inf) { | ||
218 | if(inf>0) { | ||
219 | UniEffect(UNI_S3MEFFECTE,inf); | ||
220 | fx4memory=UNI_S3MEFFECTE; | ||
221 | } else { | ||
222 | UniEffect(UNI_S3MEFFECTF,-inf); | ||
223 | fx4memory=UNI_S3MEFFECTF; | ||
224 | } | ||
225 | } else if(fx4memory) | ||
226 | UniEffect(fx4memory,0); | ||
227 | break; | ||
228 | /* effect 5, "Porta abs", not supported */ | ||
229 | case 6: /* Porta to note */ | ||
230 | UniEffect(UNI_ITEFFECTG,inf); | ||
231 | break; | ||
232 | case 7: /* Tremor */ | ||
233 | UniEffect(UNI_S3MEFFECTI,inf); | ||
234 | break; | ||
235 | case 8: /* Arpeggio */ | ||
236 | UniPTEffect(0x0,inf); | ||
237 | break; | ||
238 | case 9: /* Vibrato */ | ||
239 | UniPTEffect(0x4,inf); | ||
240 | break; | ||
241 | case 0xa: /* Porta + Volume slide */ | ||
242 | UniPTEffect(0x3,0); | ||
243 | if(inf) { | ||
244 | UniWriteByte(UNI_S3MEFFECTD); | ||
245 | if (inf>=0) | ||
246 | UniWriteByte((inf&0xf)<<4); | ||
247 | else | ||
248 | UniWriteByte((-inf)&0xf); | ||
249 | } | ||
250 | break; | ||
251 | case 0xb: /* Vibrato + Volume slide */ | ||
252 | UniPTEffect(0x4,0); | ||
253 | if(inf) { | ||
254 | UniWriteByte(UNI_S3MEFFECTD); | ||
255 | if (inf>=0) | ||
256 | UniWriteByte((inf&0xf)<<4); | ||
257 | else | ||
258 | UniWriteByte((-inf)&0xf); | ||
259 | } | ||
260 | break; | ||
261 | case 0xc: /* Pattern break (in hex) */ | ||
262 | UniPTEffect(0xd,inf); | ||
263 | break; | ||
264 | case 0xd: /* Pattern jump */ | ||
265 | UniPTEffect(0xb,inf); | ||
266 | break; | ||
267 | /* effect 0xe, "Sync", not supported */ | ||
268 | case 0xf: /* Retrig */ | ||
269 | UniEffect(UNI_S3MEFFECTQ,inf&0xf); | ||
270 | break; | ||
271 | case 0x10: /* Sample offset */ | ||
272 | UniPTEffect(0x9,inf); | ||
273 | break; | ||
274 | case 0x11: /* Fine volume slide */ | ||
275 | if(inf) { | ||
276 | UniWriteByte(UNI_S3MEFFECTD); | ||
277 | if (inf>=0) | ||
278 | UniWriteByte((inf&0xf)<<4|0xf); | ||
279 | else | ||
280 | UniWriteByte(0xf0|((-inf)&0xf)); | ||
281 | } | ||
282 | break; | ||
283 | case 0x12: /* Fine portamento */ | ||
284 | if(inf) { | ||
285 | if(inf>0) { | ||
286 | UniEffect(UNI_S3MEFFECTE,0xf0|(inf&0xf)); | ||
287 | fx4memory=UNI_S3MEFFECTE; | ||
288 | } else { | ||
289 | UniEffect(UNI_S3MEFFECTF,0xf0|((-inf)&0xf)); | ||
290 | fx4memory=UNI_S3MEFFECTF; | ||
291 | } | ||
292 | } else if(fx4memory) | ||
293 | UniEffect(fx4memory,0); | ||
294 | break; | ||
295 | case 0x13: /* Delay note */ | ||
296 | UniPTEffect(0xe,0xd0|(inf&0xf)); | ||
297 | break; | ||
298 | case 0x14: /* Note cut */ | ||
299 | UniPTEffect(0xc,0); | ||
300 | track[row].volume=0; | ||
301 | break; | ||
302 | case 0x15: /* Set tempo */ | ||
303 | UniEffect(UNI_S3MEFFECTT,inf); | ||
304 | break; | ||
305 | case 0x16: /* Extra fine portamento */ | ||
306 | if(inf) { | ||
307 | if(inf>0) { | ||
308 | UniEffect(UNI_S3MEFFECTE,0xe0|((inf>>2)&0xf)); | ||
309 | fx4memory=UNI_S3MEFFECTE; | ||
310 | } else { | ||
311 | UniEffect(UNI_S3MEFFECTF,0xe0|(((-inf)>>2)&0xf)); | ||
312 | fx4memory=UNI_S3MEFFECTF; | ||
313 | } | ||
314 | } else if(fx4memory) | ||
315 | UniEffect(fx4memory,0); | ||
316 | break; | ||
317 | case 0x17: /* Panning */ | ||
318 | if (inf>64) | ||
319 | UniEffect(UNI_ITEFFECTS0,0x91); /* surround */ | ||
320 | else | ||
321 | UniPTEffect(0x8,(inf==64)?255:(inf+64)<<1); | ||
322 | of.flags |= UF_PANNING; | ||
323 | break; | ||
324 | } | ||
325 | |||
326 | } | ||
327 | if (track[row].volume) UniVolEffect(VOL_VOLUME,track[row].volume-1); | ||
328 | UniNewline(); | ||
329 | } | ||
330 | return UniDup(); | ||
331 | } | ||
332 | |||
333 | int AMF_Load(int curious) | ||
334 | { | ||
335 | int t,u,realtrackcnt,realsmpcnt,defaultpanning; | ||
336 | AMFSAMPLE s; | ||
337 | SAMPLE *q; | ||
338 | UWORD *track_remap; | ||
339 | ULONG samplepos; | ||
340 | int channel_remap[16]; | ||
341 | |||
342 | /* try to read module header */ | ||
343 | _mm_read_UBYTES(mh->id,3,modreader); | ||
344 | mh->version =_mm_read_UBYTE(modreader); | ||
345 | _mm_read_string(mh->songname,32,modreader); | ||
346 | mh->numsamples =_mm_read_UBYTE(modreader); | ||
347 | mh->numorders =_mm_read_UBYTE(modreader); | ||
348 | mh->numtracks =_mm_read_I_UWORD(modreader); | ||
349 | mh->numchannels =_mm_read_UBYTE(modreader); | ||
350 | if((!mh->numchannels)||(mh->numchannels>(mh->version>=12?32:16))) { | ||
351 | _mm_errno=MMERR_NOT_A_MODULE; | ||
352 | return 0; | ||
353 | } | ||
354 | |||
355 | if(mh->version>=11) { | ||
356 | memset(mh->panpos,0,32); | ||
357 | _mm_read_SBYTES(mh->panpos,(mh->version>=13)?32:16,modreader); | ||
358 | } else | ||
359 | _mm_read_UBYTES(channel_remap,16,modreader); | ||
360 | |||
361 | if (mh->version>=13) { | ||
362 | mh->songbpm=_mm_read_UBYTE(modreader); | ||
363 | if(mh->songbpm<32) { | ||
364 | _mm_errno=MMERR_NOT_A_MODULE; | ||
365 | return 0; | ||
366 | } | ||
367 | mh->songspd=_mm_read_UBYTE(modreader); | ||
368 | if(mh->songspd>32) { | ||
369 | _mm_errno=MMERR_NOT_A_MODULE; | ||
370 | return 0; | ||
371 | } | ||
372 | } else { | ||
373 | mh->songbpm=125; | ||
374 | mh->songspd=6; | ||
375 | } | ||
376 | |||
377 | if(_mm_eof(modreader)) { | ||
378 | _mm_errno = MMERR_LOADING_HEADER; | ||
379 | return 0; | ||
380 | } | ||
381 | |||
382 | /* set module variables */ | ||
383 | of.initspeed = mh->songspd; | ||
384 | of.inittempo = mh->songbpm; | ||
385 | AMF_Version[AMFTEXTLEN-3]='0'+(mh->version/10); | ||
386 | AMF_Version[AMFTEXTLEN-1]='0'+(mh->version%10); | ||
387 | of.modtype = StrDup(AMF_Version); | ||
388 | of.numchn = mh->numchannels; | ||
389 | of.numtrk = mh->numorders*mh->numchannels; | ||
390 | if (mh->numtracks>of.numtrk) | ||
391 | of.numtrk=mh->numtracks; | ||
392 | of.numtrk++; /* add room for extra, empty track */ | ||
393 | of.songname = DupStr(mh->songname,32,1); | ||
394 | of.numpos = mh->numorders; | ||
395 | of.numpat = mh->numorders; | ||
396 | of.reppos = 0; | ||
397 | of.flags |= UF_S3MSLIDES; | ||
398 | /* XXX whenever possible, we should try to determine the original format. | ||
399 | Here we assume it was S3M-style wrt bpmlimit... */ | ||
400 | of.bpmlimit = 32; | ||
401 | |||
402 | /* | ||
403 | * Play with the panning table. Although the AMF format embeds a | ||
404 | * panning table, if the module was a MOD or an S3M with default | ||
405 | * panning and didn't use any panning commands, don't flag | ||
406 | * UF_PANNING, to use our preferred panning table for this case. | ||
407 | */ | ||
408 | defaultpanning = 1; | ||
409 | for (t = 0; t < 32; t++) { | ||
410 | if (mh->panpos[t] > 64) { | ||
411 | of.panning[t] = PAN_SURROUND; | ||
412 | defaultpanning = 0; | ||
413 | } else | ||
414 | if (mh->panpos[t] == 64) | ||
415 | of.panning[t] = PAN_RIGHT; | ||
416 | else | ||
417 | of.panning[t] = (mh->panpos[t] + 64) << 1; | ||
418 | } | ||
419 | if (defaultpanning) { | ||
420 | for (t = 0; t < of.numchn; t++) | ||
421 | if (of.panning[t] == (((t + 1) & 2) ? PAN_RIGHT : PAN_LEFT)) { | ||
422 | defaultpanning = 0; /* not MOD canonical panning */ | ||
423 | break; | ||
424 | } | ||
425 | } | ||
426 | if (defaultpanning) | ||
427 | of.flags |= UF_PANNING; | ||
428 | |||
429 | of.numins=of.numsmp=mh->numsamples; | ||
430 | |||
431 | if(!AllocPositions(of.numpos)) return 0; | ||
432 | for(t=0;t<of.numpos;t++) | ||
433 | of.positions[t]=t; | ||
434 | |||
435 | if(!AllocTracks()) return 0; | ||
436 | if(!AllocPatterns()) return 0; | ||
437 | |||
438 | /* read AMF order table */ | ||
439 | for (t=0;t<of.numpat;t++) { | ||
440 | if (mh->version>=14) | ||
441 | /* track size */ | ||
442 | of.pattrows[t]=_mm_read_I_UWORD(modreader); | ||
443 | if (mh->version>=10) | ||
444 | _mm_read_I_UWORDS(of.patterns+(t*of.numchn),of.numchn,modreader); | ||
445 | else | ||
446 | for(u=0;u<of.numchn;u++) | ||
447 | of.patterns[t*of.numchn+channel_remap[u]]=_mm_read_I_UWORD(modreader); | ||
448 | } | ||
449 | if(_mm_eof(modreader)) { | ||
450 | _mm_errno = MMERR_LOADING_HEADER; | ||
451 | return 0; | ||
452 | } | ||
453 | |||
454 | /* read sample information */ | ||
455 | if(!AllocSamples()) return 0; | ||
456 | q=of.samples; | ||
457 | for(t=0;t<of.numins;t++) { | ||
458 | /* try to read sample info */ | ||
459 | s.type=_mm_read_UBYTE(modreader); | ||
460 | _mm_read_string(s.samplename,32,modreader); | ||
461 | _mm_read_string(s.filename,13,modreader); | ||
462 | s.offset =_mm_read_I_ULONG(modreader); | ||
463 | s.length =_mm_read_I_ULONG(modreader); | ||
464 | s.c2spd =_mm_read_I_UWORD(modreader); | ||
465 | if(s.c2spd==8368) s.c2spd=8363; | ||
466 | s.volume =_mm_read_UBYTE(modreader); | ||
467 | if(mh->version>=11) { | ||
468 | s.reppos =_mm_read_I_ULONG(modreader); | ||
469 | s.repend =_mm_read_I_ULONG(modreader); | ||
470 | } else { | ||
471 | s.reppos =_mm_read_I_UWORD(modreader); | ||
472 | s.repend =s.length; | ||
473 | } | ||
474 | |||
475 | if(_mm_eof(modreader)) { | ||
476 | _mm_errno = MMERR_LOADING_SAMPLEINFO; | ||
477 | return 0; | ||
478 | } | ||
479 | |||
480 | q->samplename = DupStr(s.samplename,32,1); | ||
481 | q->speed = s.c2spd; | ||
482 | q->volume = s.volume; | ||
483 | if (s.type) { | ||
484 | q->seekpos = s.offset; | ||
485 | q->length = s.length; | ||
486 | q->loopstart = s.reppos; | ||
487 | q->loopend = s.repend; | ||
488 | if((s.repend-s.reppos)>2) q->flags |= SF_LOOP; | ||
489 | } | ||
490 | q++; | ||
491 | } | ||
492 | |||
493 | /* read track table */ | ||
494 | if(!(track_remap=MikMod_calloc(mh->numtracks+1,sizeof(UWORD)))) | ||
495 | return 0; | ||
496 | _mm_read_I_UWORDS(track_remap+1,mh->numtracks,modreader); | ||
497 | if(_mm_eof(modreader)) { | ||
498 | MikMod_free(track_remap); | ||
499 | _mm_errno=MMERR_LOADING_TRACK; | ||
500 | return 0; | ||
501 | } | ||
502 | |||
503 | for(realtrackcnt=t=0;t<=mh->numtracks;t++) | ||
504 | if (realtrackcnt<track_remap[t]) | ||
505 | realtrackcnt=track_remap[t]; | ||
506 | for(t=0;t<of.numpat*of.numchn;t++) | ||
507 | of.patterns[t]=(of.patterns[t]<=mh->numtracks)? | ||
508 | track_remap[of.patterns[t]]-1:realtrackcnt; | ||
509 | |||
510 | MikMod_free(track_remap); | ||
511 | |||
512 | /* unpack tracks */ | ||
513 | for(t=0;t<realtrackcnt;t++) { | ||
514 | if(_mm_eof(modreader)) { | ||
515 | _mm_errno = MMERR_LOADING_TRACK; | ||
516 | return 0; | ||
517 | } | ||
518 | if (!AMF_UnpackTrack(modreader)) { | ||
519 | _mm_errno = MMERR_LOADING_TRACK; | ||
520 | return 0; | ||
521 | } | ||
522 | if(!(of.tracks[t]=AMF_ConvertTrack())) | ||
523 | return 0; | ||
524 | } | ||
525 | /* add an extra void track */ | ||
526 | UniReset(); | ||
527 | for(t=0;t<64;t++) UniNewline(); | ||
528 | of.tracks[realtrackcnt++]=UniDup(); | ||
529 | for(t=realtrackcnt;t<of.numtrk;t++) of.tracks[t]=NULL; | ||
530 | |||
531 | /* compute sample offsets */ | ||
532 | samplepos=_mm_ftell(modreader); | ||
533 | for(realsmpcnt=t=0;t<of.numsmp;t++) | ||
534 | if(realsmpcnt<of.samples[t].seekpos) | ||
535 | realsmpcnt=of.samples[t].seekpos; | ||
536 | for(t=1;t<=realsmpcnt;t++) { | ||
537 | q=of.samples; | ||
538 | while(q->seekpos!=t) q++; | ||
539 | q->seekpos=samplepos; | ||
540 | samplepos+=q->length; | ||
541 | } | ||
542 | |||
543 | return 1; | ||
544 | } | ||
545 | |||
546 | CHAR *AMF_LoadTitle(void) | ||
547 | { | ||
548 | CHAR s[32]; | ||
549 | |||
550 | _mm_fseek(modreader,4,SEEK_SET); | ||
551 | if(!_mm_read_UBYTES(s,32,modreader)) return NULL; | ||
552 | |||
553 | return(DupStr(s,32,1)); | ||
554 | } | ||
555 | |||
556 | /*========== Loader information */ | ||
557 | |||
558 | MIKMODAPI MLOADER load_amf={ | ||
559 | NULL, | ||
560 | "AMF", | ||
561 | "AMF (DSMI Advanced Module Format)", | ||
562 | AMF_Init, | ||
563 | AMF_Test, | ||
564 | AMF_Load, | ||
565 | AMF_Cleanup, | ||
566 | AMF_LoadTitle | ||
567 | }; | ||
568 | |||
569 | /* ex:set ts=4: */ | ||
diff --git a/apps/plugins/mikmod/load_asy.c b/apps/plugins/mikmod/load_asy.c new file mode 100644 index 0000000000..356a686d92 --- /dev/null +++ b/apps/plugins/mikmod/load_asy.c | |||
@@ -0,0 +1,398 @@ | |||
1 | /* MikMod sound library | ||
2 | (c) 2004, Raphael Assenat and others - see file AUTHORS for | ||
3 | 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: load_asy.c,v 1.3 2005/04/07 19:57:38 realtech Exp $ | ||
24 | |||
25 | ASYLUM Music Format v1.0 (.amf) loader | ||
26 | adapted from load_mod.c by Raphael Assenat <raph@raphnet.net>, | ||
27 | with the help of the AMF2MOD utility sourcecode, | ||
28 | written to convert crusader's amf files into 8 | ||
29 | channels mod file in 1995 by Mr. P / Powersource | ||
30 | mrp@fish.share.net, ac054@sfn.saskatoon.sk.ca | ||
31 | |||
32 | |||
33 | ==============================================================================*/ | ||
34 | |||
35 | #ifdef HAVE_CONFIG_H | ||
36 | #include "config.h" | ||
37 | #endif | ||
38 | |||
39 | #ifdef HAVE_UNISTD_H | ||
40 | #include <unistd.h> | ||
41 | #endif | ||
42 | |||
43 | #include <ctype.h> | ||
44 | #include <string.h> | ||
45 | |||
46 | #include "mikmod_internals.h" | ||
47 | |||
48 | /*========== Module structure */ | ||
49 | |||
50 | typedef struct MSAMPINFO { | ||
51 | CHAR samplename[24]; | ||
52 | UBYTE finetune; | ||
53 | UBYTE volume; | ||
54 | ULONG length; | ||
55 | ULONG reppos; | ||
56 | ULONG replen; | ||
57 | } MSAMPINFO; | ||
58 | |||
59 | typedef struct MODULEHEADER { | ||
60 | CHAR songname[21]; | ||
61 | UBYTE num_patterns; /* number of patterns used */ | ||
62 | UBYTE num_orders; | ||
63 | UBYTE positions[256]; /* which pattern to play at pos */ | ||
64 | MSAMPINFO samples[64]; /* all sampleinfo */ | ||
65 | } MODULEHEADER; | ||
66 | |||
67 | typedef struct MODTYPE { | ||
68 | CHAR id[5]; | ||
69 | UBYTE channels; | ||
70 | CHAR *name; | ||
71 | } MODTYPE; | ||
72 | |||
73 | typedef struct MODNOTE { | ||
74 | UBYTE a, b, c, d; | ||
75 | } MODNOTE; | ||
76 | |||
77 | /* This table is taken from AMF2MOD.C | ||
78 | * written in 1995 by Mr. P / Powersource | ||
79 | * mrp@fish.share.net, ac054@sfn.saskatoon.sk.ca */ | ||
80 | UWORD periodtable[]={6848,6464,6096,5760,5424,5120,4832,4560,4304, | ||
81 | 4064,3840,3628,3424,3232,3048,2880,2712,2560, | ||
82 | 2416,2280,2152,2032,1920,1814,1712,1616,1524, | ||
83 | 1440,1356,1280,1208,1140,1076,1016, 960, 907, | ||
84 | 856, 808, 762, 720, 678, 640, 604, 570, 538, | ||
85 | 508, 480, 453, 428, 404, 381, 360, 339, 320, | ||
86 | 302, 285, 269, 254, 240, 226, 214, 202, 190, | ||
87 | 180, 170, 160, 151, 143, 135, 127, 120, 113, | ||
88 | 107, 101, 95, 90, 85, 80, 75, 71, 67, | ||
89 | 63, 60, 56, 53, 50, 47, 45, 42, 40, | ||
90 | 37, 35, 33, 31, 30, 28}; | ||
91 | |||
92 | /*========== Loader variables */ | ||
93 | |||
94 | static CHAR asylum[] = "Asylum 1.0"; | ||
95 | |||
96 | static MODULEHEADER *mh = NULL; | ||
97 | static MODNOTE *patbuf = NULL; | ||
98 | static int modtype = 0; | ||
99 | |||
100 | /*========== Loader code */ | ||
101 | |||
102 | static int ASY_CheckType(UBYTE *id, UBYTE *numchn, CHAR **descr) | ||
103 | { | ||
104 | if (!memcmp(id, "ASYLUM Music Format V1.0", 24)) | ||
105 | { | ||
106 | *descr = asylum; | ||
107 | *numchn = 8; | ||
108 | modtype = 1; | ||
109 | return 1; | ||
110 | } | ||
111 | |||
112 | return 0; | ||
113 | } | ||
114 | |||
115 | static int ASY_Test(void) | ||
116 | { | ||
117 | UBYTE namestring[24], numchn; | ||
118 | CHAR *descr; | ||
119 | |||
120 | /* Read the magic string */ | ||
121 | _mm_fseek(modreader, 0, SEEK_SET); | ||
122 | if (!_mm_read_UBYTES(namestring, 24, modreader)) | ||
123 | return 0; | ||
124 | |||
125 | /* Test if the string is what we expect */ | ||
126 | if (ASY_CheckType(namestring, &numchn, &descr)) | ||
127 | return 1; | ||
128 | |||
129 | return 0; | ||
130 | } | ||
131 | |||
132 | static int ASY_Init(void) | ||
133 | { | ||
134 | if (!(mh = (MODULEHEADER *)MikMod_malloc(sizeof(MODULEHEADER)))) | ||
135 | return 0; | ||
136 | return 1; | ||
137 | } | ||
138 | |||
139 | static void ASY_Cleanup(void) | ||
140 | { | ||
141 | MikMod_free(mh); | ||
142 | MikMod_free(patbuf); | ||
143 | } | ||
144 | |||
145 | static void ConvertNote(MODNOTE *n) | ||
146 | { | ||
147 | UBYTE instrument, effect, effdat, note; | ||
148 | UWORD period; | ||
149 | UBYTE lastnote = 0; | ||
150 | |||
151 | instrument = n->b&0x1f; | ||
152 | effect = n->c; | ||
153 | effdat = n->d; | ||
154 | |||
155 | /* convert amf note to mod period */ | ||
156 | if (n->a) { | ||
157 | period = periodtable[n->a]; | ||
158 | } else { | ||
159 | period = 0; | ||
160 | } | ||
161 | |||
162 | /* Convert the period to a note number */ | ||
163 | note = 0; | ||
164 | if (period) | ||
165 | { | ||
166 | for (note = 0; note < 7 * OCTAVE; note++) | ||
167 | if (period >= npertab[note]) | ||
168 | break; | ||
169 | if (note == 7 * OCTAVE) | ||
170 | note = 0; | ||
171 | else | ||
172 | note++; | ||
173 | } | ||
174 | |||
175 | if (instrument) { | ||
176 | /* if instrument does not exist, note cut */ | ||
177 | if ((instrument > 31) || (!mh->samples[instrument - 1].length)) { | ||
178 | UniPTEffect(0xc, 0); | ||
179 | if (effect == 0xc) | ||
180 | effect = effdat = 0; | ||
181 | } else { | ||
182 | /* Protracker handling */ | ||
183 | if (!modtype) { | ||
184 | /* if we had a note, then change instrument...*/ | ||
185 | if (note) | ||
186 | UniInstrument(instrument - 1); | ||
187 | /* ...otherwise, only adjust volume... */ | ||
188 | else { | ||
189 | /* ...unless an effect was specified, | ||
190 | * which forces a new note to be | ||
191 | * played */ | ||
192 | if (effect || effdat) { | ||
193 | UniInstrument(instrument - 1); | ||
194 | note = lastnote; | ||
195 | } else | ||
196 | UniPTEffect(0xc, | ||
197 | mh->samples[instrument - | ||
198 | 1].volume & 0x7f); | ||
199 | } | ||
200 | } else { | ||
201 | /* Fasttracker handling */ | ||
202 | UniInstrument(instrument - 1); | ||
203 | if (!note) | ||
204 | note = lastnote; | ||
205 | } | ||
206 | } | ||
207 | } | ||
208 | if (note) { | ||
209 | UniNote(note + 2 * OCTAVE - 1); | ||
210 | lastnote = note; | ||
211 | } | ||
212 | |||
213 | /* Convert pattern jump from Dec to Hex */ | ||
214 | if (effect == 0xd) | ||
215 | effdat = (((effdat & 0xf0) >> 4) * 10) + (effdat & 0xf); | ||
216 | |||
217 | /* Volume slide, up has priority */ | ||
218 | if ((effect == 0xa) && (effdat & 0xf) && (effdat & 0xf0)) | ||
219 | effdat &= 0xf0; | ||
220 | |||
221 | UniPTEffect(effect, effdat); | ||
222 | } | ||
223 | |||
224 | static UBYTE *ConvertTrack(MODNOTE *n) | ||
225 | { | ||
226 | int t; | ||
227 | |||
228 | UniReset(); | ||
229 | for (t = 0; t < 64; t++) { | ||
230 | ConvertNote(n); | ||
231 | UniNewline(); | ||
232 | n += of.numchn; | ||
233 | } | ||
234 | return UniDup(); | ||
235 | } | ||
236 | |||
237 | /* Loads all patterns of a modfile and converts them into the 3 byte format. */ | ||
238 | static int ML_LoadPatterns(void) | ||
239 | { | ||
240 | int t, s, tracks = 0; | ||
241 | |||
242 | if (!AllocPatterns()) { | ||
243 | return 0; | ||
244 | } | ||
245 | if (!AllocTracks()) { | ||
246 | return 0; | ||
247 | } | ||
248 | |||
249 | /* Allocate temporary buffer for loading and converting the patterns */ | ||
250 | if (!(patbuf = (MODNOTE *)MikMod_calloc(64U * of.numchn, sizeof(MODNOTE)))) | ||
251 | return 0; | ||
252 | |||
253 | |||
254 | /* patterns start here */ | ||
255 | _mm_fseek(modreader, 0xA66, SEEK_SET); | ||
256 | for (t = 0; t < of.numpat; t++) { | ||
257 | /* Load the pattern into the temp buffer and convert it */ | ||
258 | for (s = 0; s < (64U * of.numchn); s++) { | ||
259 | patbuf[s].a = _mm_read_UBYTE(modreader); | ||
260 | patbuf[s].b = _mm_read_UBYTE(modreader); | ||
261 | patbuf[s].c = _mm_read_UBYTE(modreader); | ||
262 | patbuf[s].d = _mm_read_UBYTE(modreader); | ||
263 | } | ||
264 | for (s = 0; s < of.numchn; s++) { | ||
265 | if (!(of.tracks[tracks++] = ConvertTrack(patbuf + s))) { | ||
266 | return 0; | ||
267 | } | ||
268 | } | ||
269 | } | ||
270 | return 1; | ||
271 | } | ||
272 | |||
273 | static int ASY_Load(int curious) | ||
274 | { | ||
275 | int t; | ||
276 | SAMPLE *q; | ||
277 | MSAMPINFO *s; | ||
278 | CHAR *descr=asylum; | ||
279 | ULONG seekpos; | ||
280 | |||
281 | // no title in asylum amf files :( | ||
282 | strcpy(mh->songname, ""); | ||
283 | |||
284 | _mm_fseek(modreader, 0x23, SEEK_SET); | ||
285 | mh->num_patterns = _mm_read_UBYTE(modreader); | ||
286 | mh->num_orders = _mm_read_UBYTE(modreader); | ||
287 | |||
288 | // skip unknown byte | ||
289 | _mm_read_UBYTE(modreader); | ||
290 | _mm_read_UBYTES(mh->positions, 256, modreader); | ||
291 | |||
292 | /* read samples headers*/ | ||
293 | for (t = 0; t < 64; t++) { | ||
294 | s = &mh->samples[t]; | ||
295 | |||
296 | _mm_fseek(modreader, 0x126 + (t*37), SEEK_SET); | ||
297 | |||
298 | _mm_read_string(s->samplename, 22, modreader); | ||
299 | s->samplename[21] = 0; /* just in case */ | ||
300 | |||
301 | s->finetune = _mm_read_UBYTE(modreader); | ||
302 | s->volume = _mm_read_UBYTE(modreader); | ||
303 | _mm_read_UBYTE(modreader); // skip unknown byte | ||
304 | s->length = _mm_read_I_ULONG(modreader); | ||
305 | s->reppos = _mm_read_I_ULONG(modreader); | ||
306 | s->replen = _mm_read_I_ULONG(modreader); | ||
307 | } | ||
308 | |||
309 | if (_mm_eof(modreader)) { | ||
310 | _mm_errno = MMERR_LOADING_HEADER; | ||
311 | return 0; | ||
312 | } | ||
313 | |||
314 | /* set module variables */ | ||
315 | of.initspeed = 6; | ||
316 | of.inittempo = 125; | ||
317 | of.numchn = 8; | ||
318 | modtype = 0; | ||
319 | of.songname = DupStr(mh->songname, 21, 1); | ||
320 | of.numpos = mh->num_orders; | ||
321 | of.reppos = 0; | ||
322 | of.numpat = mh->num_patterns; | ||
323 | of.numtrk = of.numpat * of.numchn; | ||
324 | |||
325 | |||
326 | /* Copy positions (orders) */ | ||
327 | if (!AllocPositions(of.numpos)) | ||
328 | return 0; | ||
329 | for (t = 0; t < of.numpos; t++) { | ||
330 | of.positions[t] = mh->positions[t]; | ||
331 | } | ||
332 | |||
333 | /* Finally, init the sampleinfo structures */ | ||
334 | of.numins = 31; | ||
335 | of.numsmp = 31; | ||
336 | if (!AllocSamples()) | ||
337 | return 0; | ||
338 | s = mh->samples; | ||
339 | q = of.samples; | ||
340 | seekpos = 2662+(2048*(of.numpat)); | ||
341 | for (t = 0; t < of.numins; t++) { | ||
342 | /* convert the samplename */ | ||
343 | q->samplename = DupStr(s->samplename, 23, 1); | ||
344 | |||
345 | /* init the sampleinfo variables */ | ||
346 | q->speed = finetune[s->finetune & 0xf]; | ||
347 | q->volume = s->volume & 0x7f; | ||
348 | |||
349 | q->loopstart = (ULONG)s->reppos; | ||
350 | q->loopend = (ULONG)q->loopstart + (s->replen); | ||
351 | q->length = (ULONG)s->length; | ||
352 | |||
353 | q->flags = SF_SIGNED; | ||
354 | |||
355 | q->seekpos = seekpos; | ||
356 | seekpos += q->length; | ||
357 | |||
358 | if ((s->replen) > 2) { | ||
359 | q->flags |= SF_LOOP; | ||
360 | } | ||
361 | |||
362 | /* fix replen if repend > length */ | ||
363 | if (q->loopend > q->length) | ||
364 | q->loopend = q->length; | ||
365 | |||
366 | s++; | ||
367 | q++; | ||
368 | } | ||
369 | |||
370 | of.modtype = StrDup(descr); | ||
371 | |||
372 | if (!ML_LoadPatterns()) | ||
373 | return 0; | ||
374 | |||
375 | return 1; | ||
376 | } | ||
377 | |||
378 | static CHAR *ASY_LoadTitle(void) | ||
379 | { | ||
380 | CHAR *s = ""; // no titles | ||
381 | |||
382 | return (DupStr(s, 21, 1)); | ||
383 | } | ||
384 | |||
385 | /*========== Loader information */ | ||
386 | |||
387 | MLOADER load_asy = { | ||
388 | NULL, | ||
389 | "AMF", | ||
390 | "AMF (ASYLUM Music Format V1.0)", | ||
391 | ASY_Init, | ||
392 | ASY_Test, | ||
393 | ASY_Load, | ||
394 | ASY_Cleanup, | ||
395 | ASY_LoadTitle | ||
396 | }; | ||
397 | |||
398 | /* ex:set ts=4: */ | ||
diff --git a/apps/plugins/mikmod/load_dsm.c b/apps/plugins/mikmod/load_dsm.c new file mode 100644 index 0000000000..09d6d3e297 --- /dev/null +++ b/apps/plugins/mikmod/load_dsm.c | |||
@@ -0,0 +1,364 @@ | |||
1 | /* MikMod sound library | ||
2 | (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file | ||
3 | AUTHORS 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: load_dsm.c,v 1.3 2005/04/07 19:57:38 realtech Exp $ | ||
24 | |||
25 | DSIK internal format (DSM) module loader | ||
26 | |||
27 | ==============================================================================*/ | ||
28 | |||
29 | #ifdef HAVE_CONFIG_H | ||
30 | #include "config.h" | ||
31 | #endif | ||
32 | |||
33 | #ifdef HAVE_UNISTD_H | ||
34 | #include <unistd.h> | ||
35 | #endif | ||
36 | |||
37 | #include <stdio.h> | ||
38 | #ifdef HAVE_MEMORY_H | ||
39 | #include <memory.h> | ||
40 | #endif | ||
41 | #include <string.h> | ||
42 | |||
43 | #include "mikmod_internals.h" | ||
44 | |||
45 | #ifdef SUNOS | ||
46 | extern int fprintf(FILE *, const char *, ...); | ||
47 | #endif | ||
48 | |||
49 | /*========== Module structure */ | ||
50 | |||
51 | #define DSM_MAXCHAN (16) | ||
52 | #define DSM_MAXORDERS (128) | ||
53 | |||
54 | typedef struct DSMSONG { | ||
55 | CHAR songname[28]; | ||
56 | UWORD version; | ||
57 | UWORD flags; | ||
58 | ULONG reserved2; | ||
59 | UWORD numord; | ||
60 | UWORD numsmp; | ||
61 | UWORD numpat; | ||
62 | UWORD numtrk; | ||
63 | UBYTE globalvol; | ||
64 | UBYTE mastervol; | ||
65 | UBYTE speed; | ||
66 | UBYTE bpm; | ||
67 | UBYTE panpos[DSM_MAXCHAN]; | ||
68 | UBYTE orders[DSM_MAXORDERS]; | ||
69 | } DSMSONG; | ||
70 | |||
71 | typedef struct DSMINST { | ||
72 | CHAR filename[13]; | ||
73 | UWORD flags; | ||
74 | UBYTE volume; | ||
75 | ULONG length; | ||
76 | ULONG loopstart; | ||
77 | ULONG loopend; | ||
78 | ULONG reserved1; | ||
79 | UWORD c2spd; | ||
80 | UWORD period; | ||
81 | CHAR samplename[28]; | ||
82 | } DSMINST; | ||
83 | |||
84 | typedef struct DSMNOTE { | ||
85 | UBYTE note,ins,vol,cmd,inf; | ||
86 | } DSMNOTE; | ||
87 | |||
88 | #define DSM_SURROUND (0xa4) | ||
89 | |||
90 | /*========== Loader variables */ | ||
91 | |||
92 | static CHAR* SONGID="SONG"; | ||
93 | static CHAR* INSTID="INST"; | ||
94 | static CHAR* PATTID="PATT"; | ||
95 | |||
96 | static UBYTE blockid[4]; | ||
97 | static ULONG blockln; | ||
98 | static ULONG blocklp; | ||
99 | static DSMSONG* mh=NULL; | ||
100 | static DSMNOTE* dsmbuf=NULL; | ||
101 | |||
102 | static CHAR DSM_Version[]="DSIK DSM-format"; | ||
103 | |||
104 | static unsigned char DSMSIG[4+4]={'R','I','F','F','D','S','M','F'}; | ||
105 | |||
106 | /*========== Loader code */ | ||
107 | |||
108 | int DSM_Test(void) | ||
109 | { | ||
110 | UBYTE id[12]; | ||
111 | |||
112 | if(!_mm_read_UBYTES(id,12,modreader)) return 0; | ||
113 | if(!memcmp(id,DSMSIG,4) && !memcmp(id+8,DSMSIG+4,4)) return 1; | ||
114 | |||
115 | return 0; | ||
116 | } | ||
117 | |||
118 | int DSM_Init(void) | ||
119 | { | ||
120 | if(!(dsmbuf=(DSMNOTE *)MikMod_malloc(DSM_MAXCHAN*64*sizeof(DSMNOTE)))) return 0; | ||
121 | if(!(mh=(DSMSONG *)MikMod_calloc(1,sizeof(DSMSONG)))) return 0; | ||
122 | return 1; | ||
123 | } | ||
124 | |||
125 | void DSM_Cleanup(void) | ||
126 | { | ||
127 | MikMod_free(dsmbuf); | ||
128 | MikMod_free(mh); | ||
129 | } | ||
130 | |||
131 | static int GetBlockHeader(void) | ||
132 | { | ||
133 | /* make sure we're at the right position for reading the | ||
134 | next riff block, no matter how many bytes read */ | ||
135 | _mm_fseek(modreader, blocklp+blockln, SEEK_SET); | ||
136 | |||
137 | while(1) { | ||
138 | _mm_read_UBYTES(blockid,4,modreader); | ||
139 | blockln=_mm_read_I_ULONG(modreader); | ||
140 | if(_mm_eof(modreader)) { | ||
141 | _mm_errno = MMERR_LOADING_HEADER; | ||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | if(memcmp(blockid,SONGID,4) && memcmp(blockid,INSTID,4) && | ||
146 | memcmp(blockid,PATTID,4)) { | ||
147 | #ifdef MIKMOD_DEBUG | ||
148 | fprintf(stderr,"\rDSM: Skipping unknown block type %4.4s\n",blockid); | ||
149 | #endif | ||
150 | _mm_fseek(modreader, blockln, SEEK_CUR); | ||
151 | } else | ||
152 | break; | ||
153 | } | ||
154 | |||
155 | blocklp = _mm_ftell(modreader); | ||
156 | |||
157 | return 1; | ||
158 | } | ||
159 | |||
160 | static int DSM_ReadPattern(void) | ||
161 | { | ||
162 | int flag,row=0; | ||
163 | SWORD length; | ||
164 | DSMNOTE *n; | ||
165 | |||
166 | /* clear pattern data */ | ||
167 | memset(dsmbuf,255,DSM_MAXCHAN*64*sizeof(DSMNOTE)); | ||
168 | length=_mm_read_I_SWORD(modreader); | ||
169 | |||
170 | while(row<64) { | ||
171 | flag=_mm_read_UBYTE(modreader); | ||
172 | if((_mm_eof(modreader))||(--length<0)) { | ||
173 | _mm_errno = MMERR_LOADING_PATTERN; | ||
174 | return 0; | ||
175 | } | ||
176 | |||
177 | if(flag) { | ||
178 | n=&dsmbuf[((flag&0xf)*64)+row]; | ||
179 | if(flag&0x80) n->note=_mm_read_UBYTE(modreader); | ||
180 | if(flag&0x40) n->ins=_mm_read_UBYTE(modreader); | ||
181 | if(flag&0x20) n->vol=_mm_read_UBYTE(modreader); | ||
182 | if(flag&0x10) { | ||
183 | n->cmd=_mm_read_UBYTE(modreader); | ||
184 | n->inf=_mm_read_UBYTE(modreader); | ||
185 | } | ||
186 | } else | ||
187 | row++; | ||
188 | } | ||
189 | |||
190 | return 1; | ||
191 | } | ||
192 | |||
193 | static UBYTE *DSM_ConvertTrack(DSMNOTE *tr) | ||
194 | { | ||
195 | int t; | ||
196 | UBYTE note,ins,vol,cmd,inf; | ||
197 | |||
198 | UniReset(); | ||
199 | for(t=0;t<64;t++) { | ||
200 | note=tr[t].note; | ||
201 | ins=tr[t].ins; | ||
202 | vol=tr[t].vol; | ||
203 | cmd=tr[t].cmd; | ||
204 | inf=tr[t].inf; | ||
205 | |||
206 | if(ins!=0 && ins!=255) UniInstrument(ins-1); | ||
207 | if(note!=255) UniNote(note-1); /* normal note */ | ||
208 | if(vol<65) UniPTEffect(0xc,vol); | ||
209 | |||
210 | if(cmd!=255) { | ||
211 | if(cmd==0x8) { | ||
212 | if(inf==DSM_SURROUND) | ||
213 | UniEffect(UNI_ITEFFECTS0,0x91); | ||
214 | else | ||
215 | if(inf<=0x80) { | ||
216 | inf=(inf<0x80)?inf<<1:255; | ||
217 | UniPTEffect(cmd,inf); | ||
218 | } | ||
219 | } else | ||
220 | if(cmd==0xb) { | ||
221 | if(inf<=0x7f) UniPTEffect(cmd,inf); | ||
222 | } else { | ||
223 | /* Convert pattern jump from Dec to Hex */ | ||
224 | if(cmd == 0xd) | ||
225 | inf = (((inf&0xf0)>>4)*10)+(inf&0xf); | ||
226 | UniPTEffect(cmd,inf); | ||
227 | } | ||
228 | } | ||
229 | UniNewline(); | ||
230 | } | ||
231 | return UniDup(); | ||
232 | } | ||
233 | |||
234 | int DSM_Load(int curious) | ||
235 | { | ||
236 | int t; | ||
237 | DSMINST s; | ||
238 | SAMPLE *q; | ||
239 | int cursmp=0,curpat=0,track=0; | ||
240 | |||
241 | blocklp=0; | ||
242 | blockln=12; | ||
243 | |||
244 | if(!GetBlockHeader()) return 0; | ||
245 | if(memcmp(blockid,SONGID,4)) { | ||
246 | _mm_errno = MMERR_LOADING_HEADER; | ||
247 | return 0; | ||
248 | } | ||
249 | |||
250 | _mm_read_UBYTES(mh->songname,28,modreader); | ||
251 | mh->version=_mm_read_I_UWORD(modreader); | ||
252 | mh->flags=_mm_read_I_UWORD(modreader); | ||
253 | mh->reserved2=_mm_read_I_ULONG(modreader); | ||
254 | mh->numord=_mm_read_I_UWORD(modreader); | ||
255 | mh->numsmp=_mm_read_I_UWORD(modreader); | ||
256 | mh->numpat=_mm_read_I_UWORD(modreader); | ||
257 | mh->numtrk=_mm_read_I_UWORD(modreader); | ||
258 | mh->globalvol=_mm_read_UBYTE(modreader); | ||
259 | mh->mastervol=_mm_read_UBYTE(modreader); | ||
260 | mh->speed=_mm_read_UBYTE(modreader); | ||
261 | mh->bpm=_mm_read_UBYTE(modreader); | ||
262 | _mm_read_UBYTES(mh->panpos,DSM_MAXCHAN,modreader); | ||
263 | _mm_read_UBYTES(mh->orders,DSM_MAXORDERS,modreader); | ||
264 | |||
265 | /* set module variables */ | ||
266 | of.initspeed=mh->speed; | ||
267 | of.inittempo=mh->bpm; | ||
268 | of.modtype=StrDup(DSM_Version); | ||
269 | of.numchn=mh->numtrk; | ||
270 | of.numpat=mh->numpat; | ||
271 | of.numtrk=of.numchn*of.numpat; | ||
272 | of.songname=DupStr(mh->songname,28,1); /* make a cstr of songname */ | ||
273 | of.reppos=0; | ||
274 | of.flags |= UF_PANNING; | ||
275 | /* XXX whenever possible, we should try to determine the original format. | ||
276 | Here we assume it was S3M-style wrt bpmlimit... */ | ||
277 | of.bpmlimit = 32; | ||
278 | |||
279 | for(t=0;t<DSM_MAXCHAN;t++) | ||
280 | of.panning[t]=mh->panpos[t]==DSM_SURROUND?PAN_SURROUND: | ||
281 | mh->panpos[t]<0x80?(mh->panpos[t]<<1):255; | ||
282 | |||
283 | if(!AllocPositions(mh->numord)) return 0; | ||
284 | of.numpos=0; | ||
285 | for(t=0;t<mh->numord;t++) { | ||
286 | int order=mh->orders[t]; | ||
287 | if(order==255) order=LAST_PATTERN; | ||
288 | of.positions[of.numpos]=order; | ||
289 | if(mh->orders[t]<254) of.numpos++; | ||
290 | } | ||
291 | |||
292 | of.numins=of.numsmp=mh->numsmp; | ||
293 | |||
294 | if(!AllocSamples()) return 0; | ||
295 | if(!AllocTracks()) return 0; | ||
296 | if(!AllocPatterns()) return 0; | ||
297 | |||
298 | while(cursmp<of.numins||curpat<of.numpat) { | ||
299 | if(!GetBlockHeader()) return 0; | ||
300 | if(!memcmp(blockid,INSTID,4) && cursmp<of.numins) { | ||
301 | q=&of.samples[cursmp]; | ||
302 | |||
303 | /* try to read sample info */ | ||
304 | _mm_read_UBYTES(s.filename,13,modreader); | ||
305 | s.flags=_mm_read_I_UWORD(modreader); | ||
306 | s.volume=_mm_read_UBYTE(modreader); | ||
307 | s.length=_mm_read_I_ULONG(modreader); | ||
308 | s.loopstart=_mm_read_I_ULONG(modreader); | ||
309 | s.loopend=_mm_read_I_ULONG(modreader); | ||
310 | s.reserved1=_mm_read_I_ULONG(modreader); | ||
311 | s.c2spd=_mm_read_I_UWORD(modreader); | ||
312 | s.period=_mm_read_I_UWORD(modreader); | ||
313 | _mm_read_UBYTES(s.samplename,28,modreader); | ||
314 | |||
315 | q->samplename=DupStr(s.samplename,28,1); | ||
316 | q->seekpos=_mm_ftell(modreader); | ||
317 | q->speed=s.c2spd; | ||
318 | q->length=s.length; | ||
319 | q->loopstart=s.loopstart; | ||
320 | q->loopend=s.loopend; | ||
321 | q->volume=s.volume; | ||
322 | |||
323 | if(s.flags&1) q->flags|=SF_LOOP; | ||
324 | if(s.flags&2) q->flags|=SF_SIGNED; | ||
325 | /* (s.flags&4) means packed sample, | ||
326 | but did they really exist in dsm ?*/ | ||
327 | cursmp++; | ||
328 | } else | ||
329 | if(!memcmp(blockid,PATTID,4) && curpat<of.numpat) { | ||
330 | DSM_ReadPattern(); | ||
331 | for(t=0;t<of.numchn;t++) | ||
332 | if(!(of.tracks[track++]=DSM_ConvertTrack(&dsmbuf[t*64]))) return 0; | ||
333 | curpat++; | ||
334 | } | ||
335 | } | ||
336 | |||
337 | return 1; | ||
338 | } | ||
339 | |||
340 | CHAR *DSM_LoadTitle(void) | ||
341 | { | ||
342 | CHAR s[28]; | ||
343 | |||
344 | _mm_fseek(modreader,12,SEEK_SET); | ||
345 | if(!_mm_read_UBYTES(s,28,modreader)) return NULL; | ||
346 | |||
347 | return(DupStr(s,28,1)); | ||
348 | } | ||
349 | |||
350 | /*========== Loader information */ | ||
351 | |||
352 | MIKMODAPI MLOADER load_dsm={ | ||
353 | NULL, | ||
354 | "DSM", | ||
355 | "DSM (DSIK internal format)", | ||
356 | DSM_Init, | ||
357 | DSM_Test, | ||
358 | DSM_Load, | ||
359 | DSM_Cleanup, | ||
360 | DSM_LoadTitle | ||
361 | }; | ||
362 | |||
363 | |||
364 | /* ex:set ts=4: */ | ||
diff --git a/apps/plugins/mikmod/load_far.c b/apps/plugins/mikmod/load_far.c new file mode 100644 index 0000000000..69d48d6b96 --- /dev/null +++ b/apps/plugins/mikmod/load_far.c | |||
@@ -0,0 +1,346 @@ | |||
1 | /* MikMod sound library | ||
2 | (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file | ||
3 | AUTHORS 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: load_far.c,v 1.3 2005/04/07 19:57:38 realtech Exp $ | ||
24 | |||
25 | Farandole (FAR) module loader | ||
26 | |||
27 | ==============================================================================*/ | ||
28 | |||
29 | #ifdef HAVE_CONFIG_H | ||
30 | #include "config.h" | ||
31 | #endif | ||
32 | |||
33 | #ifdef HAVE_UNISTD_H | ||
34 | #include <unistd.h> | ||
35 | #endif | ||
36 | |||
37 | #include <stdio.h> | ||
38 | #ifdef HAVE_MEMORY_H | ||
39 | #include <memory.h> | ||
40 | #endif | ||
41 | #include <string.h> | ||
42 | |||
43 | #include "mikmod_internals.h" | ||
44 | |||
45 | #ifdef SUNOS | ||
46 | extern int fprintf(FILE *, const char *, ...); | ||
47 | #endif | ||
48 | |||
49 | /*========== Module structure */ | ||
50 | |||
51 | typedef struct FARHEADER1 { | ||
52 | UBYTE id[4]; /* file magic */ | ||
53 | CHAR songname[40]; /* songname */ | ||
54 | CHAR blah[3]; /* 13,10,26 */ | ||
55 | UWORD headerlen; /* remaining length of header in bytes */ | ||
56 | UBYTE version; | ||
57 | UBYTE onoff[16]; | ||
58 | UBYTE edit1[9]; | ||
59 | UBYTE speed; | ||
60 | UBYTE panning[16]; | ||
61 | UBYTE edit2[4]; | ||
62 | UWORD stlen; | ||
63 | } FARHEADER1; | ||
64 | |||
65 | typedef struct FARHEADER2 { | ||
66 | UBYTE orders[256]; | ||
67 | UBYTE numpat; | ||
68 | UBYTE snglen; | ||
69 | UBYTE loopto; | ||
70 | UWORD patsiz[256]; | ||
71 | } FARHEADER2; | ||
72 | |||
73 | typedef struct FARSAMPLE { | ||
74 | CHAR samplename[32]; | ||
75 | ULONG length; | ||
76 | UBYTE finetune; | ||
77 | UBYTE volume; | ||
78 | ULONG reppos; | ||
79 | ULONG repend; | ||
80 | UBYTE type; | ||
81 | UBYTE loop; | ||
82 | } FARSAMPLE; | ||
83 | |||
84 | typedef struct FARNOTE { | ||
85 | UBYTE note,ins,vol,eff; | ||
86 | } FARNOTE; | ||
87 | |||
88 | /*========== Loader variables */ | ||
89 | |||
90 | static CHAR FAR_Version[] = "Farandole"; | ||
91 | static FARHEADER1 *mh1 = NULL; | ||
92 | static FARHEADER2 *mh2 = NULL; | ||
93 | static FARNOTE *pat = NULL; | ||
94 | |||
95 | static unsigned char FARSIG[4+3]={'F','A','R',0xfe,13,10,26}; | ||
96 | |||
97 | /*========== Loader code */ | ||
98 | |||
99 | int FAR_Test(void) | ||
100 | { | ||
101 | UBYTE id[47]; | ||
102 | |||
103 | if(!_mm_read_UBYTES(id,47,modreader)) return 0; | ||
104 | if((memcmp(id,FARSIG,4))||(memcmp(id+44,FARSIG+4,3))) return 0; | ||
105 | return 1; | ||
106 | } | ||
107 | |||
108 | int FAR_Init(void) | ||
109 | { | ||
110 | if(!(mh1 = (FARHEADER1*)MikMod_malloc(sizeof(FARHEADER1)))) return 0; | ||
111 | if(!(mh2 = (FARHEADER2*)MikMod_malloc(sizeof(FARHEADER2)))) return 0; | ||
112 | if(!(pat = (FARNOTE*)MikMod_malloc(256*16*4*sizeof(FARNOTE)))) return 0; | ||
113 | |||
114 | return 1; | ||
115 | } | ||
116 | |||
117 | void FAR_Cleanup(void) | ||
118 | { | ||
119 | MikMod_free(mh1); | ||
120 | MikMod_free(mh2); | ||
121 | MikMod_free(pat); | ||
122 | } | ||
123 | |||
124 | static UBYTE *FAR_ConvertTrack(FARNOTE* n,int rows) | ||
125 | { | ||
126 | int t,vibdepth=1; | ||
127 | |||
128 | UniReset(); | ||
129 | for(t=0;t<rows;t++) { | ||
130 | if(n->note) { | ||
131 | UniInstrument(n->ins); | ||
132 | UniNote(n->note+3*OCTAVE-1); | ||
133 | } | ||
134 | if (n->vol&0xf) UniPTEffect(0xc,(n->vol&0xf)<<2); | ||
135 | if (n->eff) | ||
136 | switch(n->eff>>4) { | ||
137 | case 0x3: /* porta to note */ | ||
138 | UniPTEffect(0x3,(n->eff&0xf)<<4); | ||
139 | break; | ||
140 | case 0x4: /* retrigger */ | ||
141 | UniPTEffect(0x0e, 0x90 | (n->eff & 0x0f)); | ||
142 | break; | ||
143 | case 0x5: /* set vibrato depth */ | ||
144 | vibdepth=n->eff&0xf; | ||
145 | break; | ||
146 | case 0x6: /* vibrato */ | ||
147 | UniPTEffect(0x4,((n->eff&0xf)<<4)|vibdepth); | ||
148 | break; | ||
149 | case 0x7: /* volume slide up */ | ||
150 | UniPTEffect(0xa,(n->eff&0xf)<<4); | ||
151 | break; | ||
152 | case 0x8: /* volume slide down */ | ||
153 | UniPTEffect(0xa,n->eff&0xf); | ||
154 | break; | ||
155 | case 0xb: /* panning */ | ||
156 | UniPTEffect(0xe,0x80|(n->eff&0xf)); | ||
157 | break; | ||
158 | case 0xf: /* set speed */ | ||
159 | UniPTEffect(0xf,n->eff&0xf); | ||
160 | break; | ||
161 | |||
162 | /* others not yet implemented */ | ||
163 | default: | ||
164 | #ifdef MIKMOD_DEBUG | ||
165 | fprintf(stderr,"\rFAR: unsupported effect %02X\n",n->eff); | ||
166 | #endif | ||
167 | break; | ||
168 | } | ||
169 | |||
170 | UniNewline(); | ||
171 | n+=16; | ||
172 | } | ||
173 | return UniDup(); | ||
174 | } | ||
175 | |||
176 | int FAR_Load(int curious) | ||
177 | { | ||
178 | int t,u,tracks=0; | ||
179 | SAMPLE *q; | ||
180 | FARSAMPLE s; | ||
181 | FARNOTE *crow; | ||
182 | UBYTE smap[8]; | ||
183 | |||
184 | /* try to read module header (first part) */ | ||
185 | _mm_read_UBYTES(mh1->id,4,modreader); | ||
186 | _mm_read_SBYTES(mh1->songname,40,modreader); | ||
187 | _mm_read_SBYTES(mh1->blah,3,modreader); | ||
188 | mh1->headerlen = _mm_read_I_UWORD (modreader); | ||
189 | mh1->version = _mm_read_UBYTE (modreader); | ||
190 | _mm_read_UBYTES(mh1->onoff,16,modreader); | ||
191 | _mm_read_UBYTES(mh1->edit1,9,modreader); | ||
192 | mh1->speed = _mm_read_UBYTE(modreader); | ||
193 | _mm_read_UBYTES(mh1->panning,16,modreader); | ||
194 | _mm_read_UBYTES(mh1->edit2,4,modreader); | ||
195 | mh1->stlen = _mm_read_I_UWORD (modreader); | ||
196 | |||
197 | /* init modfile data */ | ||
198 | of.modtype = StrDup(FAR_Version); | ||
199 | of.songname = DupStr(mh1->songname,40,1); | ||
200 | of.numchn = 16; | ||
201 | of.initspeed = mh1->speed; | ||
202 | of.inittempo = 80; | ||
203 | of.reppos = 0; | ||
204 | of.flags |= UF_PANNING; | ||
205 | for(t=0;t<16;t++) of.panning[t]=mh1->panning[t]<<4; | ||
206 | |||
207 | /* read songtext into comment field */ | ||
208 | if(mh1->stlen) | ||
209 | if (!ReadLinedComment(mh1->stlen, 66)) return 0; | ||
210 | |||
211 | /* try to read module header (second part) */ | ||
212 | _mm_read_UBYTES(mh2->orders,256,modreader); | ||
213 | mh2->numpat = _mm_read_UBYTE(modreader); | ||
214 | mh2->snglen = _mm_read_UBYTE(modreader); | ||
215 | mh2->loopto = _mm_read_UBYTE(modreader); | ||
216 | _mm_read_I_UWORDS(mh2->patsiz,256,modreader); | ||
217 | |||
218 | of.numpos = mh2->snglen; | ||
219 | if(!AllocPositions(of.numpos)) return 0; | ||
220 | for(t=0;t<of.numpos;t++) { | ||
221 | if(mh2->orders[t]==0xff) break; | ||
222 | of.positions[t] = mh2->orders[t]; | ||
223 | } | ||
224 | |||
225 | /* count number of patterns stored in file */ | ||
226 | of.numpat = 0; | ||
227 | for(t=0;t<256;t++) | ||
228 | if(mh2->patsiz[t]) | ||
229 | if((t+1)>of.numpat) of.numpat=t+1; | ||
230 | of.numtrk = of.numpat*of.numchn; | ||
231 | |||
232 | /* seek across eventual new data */ | ||
233 | _mm_fseek(modreader,mh1->headerlen-(869+mh1->stlen),SEEK_CUR); | ||
234 | |||
235 | /* alloc track and pattern structures */ | ||
236 | if(!AllocTracks()) return 0; | ||
237 | if(!AllocPatterns()) return 0; | ||
238 | |||
239 | for(t=0;t<of.numpat;t++) { | ||
240 | UBYTE rows=0,tempo; | ||
241 | |||
242 | memset(pat,0,256*16*4*sizeof(FARNOTE)); | ||
243 | if(mh2->patsiz[t]) { | ||
244 | rows = _mm_read_UBYTE(modreader); | ||
245 | tempo = _mm_read_UBYTE(modreader); | ||
246 | |||
247 | crow = pat; | ||
248 | /* file often allocates 64 rows even if there are less in pattern */ | ||
249 | if (mh2->patsiz[t]<2+(rows*16*4)) { | ||
250 | _mm_errno = MMERR_LOADING_PATTERN; | ||
251 | return 0; | ||
252 | } | ||
253 | for(u=(mh2->patsiz[t]-2)/4;u;u--,crow++) { | ||
254 | crow->note = _mm_read_UBYTE(modreader); | ||
255 | crow->ins = _mm_read_UBYTE(modreader); | ||
256 | crow->vol = _mm_read_UBYTE(modreader); | ||
257 | crow->eff = _mm_read_UBYTE(modreader); | ||
258 | } | ||
259 | |||
260 | if(_mm_eof(modreader)) { | ||
261 | _mm_errno = MMERR_LOADING_PATTERN; | ||
262 | return 0; | ||
263 | } | ||
264 | |||
265 | crow=pat; | ||
266 | of.pattrows[t] = rows; | ||
267 | for(u=16;u;u--,crow++) | ||
268 | if(!(of.tracks[tracks++]=FAR_ConvertTrack(crow,rows))) { | ||
269 | _mm_errno=MMERR_LOADING_PATTERN; | ||
270 | return 0; | ||
271 | } | ||
272 | } else | ||
273 | tracks+=16; | ||
274 | } | ||
275 | |||
276 | /* read sample map */ | ||
277 | if(!_mm_read_UBYTES(smap,8,modreader)) { | ||
278 | _mm_errno = MMERR_LOADING_HEADER; | ||
279 | return 0; | ||
280 | } | ||
281 | |||
282 | /* count number of samples used */ | ||
283 | of.numins = 0; | ||
284 | for(t=0;t<64;t++) | ||
285 | if(smap[t>>3]&(1<<(t&7))) of.numins=t+1; | ||
286 | of.numsmp = of.numins; | ||
287 | |||
288 | /* alloc sample structs */ | ||
289 | if(!AllocSamples()) return 0; | ||
290 | |||
291 | q = of.samples; | ||
292 | for(t=0;t<of.numsmp;t++) { | ||
293 | q->speed = 8363; | ||
294 | q->flags = SF_SIGNED; | ||
295 | if(smap[t>>3]&(1<<(t&7))) { | ||
296 | _mm_read_SBYTES(s.samplename,32,modreader); | ||
297 | s.length = _mm_read_I_ULONG(modreader); | ||
298 | s.finetune = _mm_read_UBYTE(modreader); | ||
299 | s.volume = _mm_read_UBYTE(modreader); | ||
300 | s.reppos = _mm_read_I_ULONG(modreader); | ||
301 | s.repend = _mm_read_I_ULONG(modreader); | ||
302 | s.type = _mm_read_UBYTE(modreader); | ||
303 | s.loop = _mm_read_UBYTE(modreader); | ||
304 | |||
305 | q->samplename = DupStr(s.samplename,32,1); | ||
306 | q->length = s.length; | ||
307 | q->loopstart = s.reppos; | ||
308 | q->loopend = s.repend; | ||
309 | q->volume = s.volume<<2; | ||
310 | |||
311 | if(s.type&1) q->flags|=SF_16BITS; | ||
312 | if(s.loop&8) q->flags|=SF_LOOP; | ||
313 | |||
314 | q->seekpos = _mm_ftell(modreader); | ||
315 | _mm_fseek(modreader,q->length,SEEK_CUR); | ||
316 | } else | ||
317 | q->samplename = DupStr(NULL,0,0); | ||
318 | q++; | ||
319 | } | ||
320 | return 1; | ||
321 | } | ||
322 | |||
323 | CHAR *FAR_LoadTitle(void) | ||
324 | { | ||
325 | CHAR s[40]; | ||
326 | |||
327 | _mm_fseek(modreader,4,SEEK_SET); | ||
328 | if(!_mm_read_UBYTES(s,40,modreader)) return NULL; | ||
329 | |||
330 | return(DupStr(s,40,1)); | ||
331 | } | ||
332 | |||
333 | /*========== Loader information */ | ||
334 | |||
335 | MIKMODAPI MLOADER load_far={ | ||
336 | NULL, | ||
337 | "FAR", | ||
338 | "FAR (Farandole Composer)", | ||
339 | FAR_Init, | ||
340 | FAR_Test, | ||
341 | FAR_Load, | ||
342 | FAR_Cleanup, | ||
343 | FAR_LoadTitle | ||
344 | }; | ||
345 | |||
346 | /* ex:set ts=4: */ | ||
diff --git a/apps/plugins/mikmod/load_gdm.c b/apps/plugins/mikmod/load_gdm.c new file mode 100644 index 0000000000..616a2b56a3 --- /dev/null +++ b/apps/plugins/mikmod/load_gdm.c | |||
@@ -0,0 +1,558 @@ | |||
1 | /* MikMod sound library | ||
2 | (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file | ||
3 | AUTHORS 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: load_gdm.c,v 1.3 2005/04/07 19:57:38 realtech Exp $ | ||
24 | |||
25 | General DigiMusic (GDM) module loader | ||
26 | |||
27 | ==============================================================================*/ | ||
28 | |||
29 | /* | ||
30 | |||
31 | Written by Kev Vance<kvance@zeux.org> | ||
32 | based on the file format description written by 'MenTaLguY' | ||
33 | <mental@kludge.org> | ||
34 | |||
35 | */ | ||
36 | |||
37 | #ifdef HAVE_CONFIG_H | ||
38 | #include "config.h" | ||
39 | #endif | ||
40 | |||
41 | #ifdef HAVE_UNISTD_H | ||
42 | #include <unistd.h> | ||
43 | #endif | ||
44 | |||
45 | #include <stdio.h> | ||
46 | #ifdef HAVE_MEMORY_H | ||
47 | #include <memory.h> | ||
48 | #endif | ||
49 | #include <string.h> | ||
50 | |||
51 | #include "mikmod_internals.h" | ||
52 | |||
53 | #ifdef SUNOS | ||
54 | extern int fprintf(FILE *, const char *, ...); | ||
55 | #endif | ||
56 | |||
57 | typedef struct GDMNOTE { | ||
58 | UBYTE note; | ||
59 | UBYTE samp; | ||
60 | struct { | ||
61 | UBYTE effect; | ||
62 | UBYTE param; | ||
63 | } effect[4]; | ||
64 | } GDMNOTE; | ||
65 | |||
66 | typedef GDMNOTE GDMTRACK[64]; | ||
67 | |||
68 | typedef struct GDMHEADER { | ||
69 | CHAR id1[4]; | ||
70 | CHAR songname[32]; | ||
71 | CHAR author[32]; | ||
72 | CHAR eofmarker[3]; | ||
73 | CHAR id2[4]; | ||
74 | |||
75 | UBYTE majorver; | ||
76 | UBYTE minorver; | ||
77 | UWORD trackerid; | ||
78 | UBYTE t_majorver; | ||
79 | UBYTE t_minorver; | ||
80 | UBYTE pantable[32]; | ||
81 | UBYTE mastervol; | ||
82 | UBYTE mastertempo; | ||
83 | UBYTE masterbpm; | ||
84 | UWORD flags; | ||
85 | |||
86 | ULONG orderloc; | ||
87 | UBYTE ordernum; | ||
88 | ULONG patternloc; | ||
89 | UBYTE patternnum; | ||
90 | ULONG samhead; | ||
91 | ULONG samdata; | ||
92 | UBYTE samnum; | ||
93 | ULONG messageloc; | ||
94 | ULONG messagelen; | ||
95 | ULONG scrollyloc; | ||
96 | UWORD scrollylen; | ||
97 | ULONG graphicloc; | ||
98 | UWORD graphiclen; | ||
99 | } GDMHEADER; | ||
100 | |||
101 | typedef struct GDMSAMPLE { | ||
102 | CHAR sampname[32]; | ||
103 | CHAR filename[13]; | ||
104 | UBYTE ems; | ||
105 | ULONG length; | ||
106 | ULONG loopbeg; | ||
107 | ULONG loopend; | ||
108 | UBYTE flags; | ||
109 | UWORD c4spd; | ||
110 | UBYTE vol; | ||
111 | UBYTE pan; | ||
112 | } GDMSAMPLE; | ||
113 | |||
114 | static GDMHEADER *mh=NULL; /* pointer to GDM header */ | ||
115 | static GDMNOTE *gdmbuf=NULL; /* pointer to a complete GDM pattern */ | ||
116 | |||
117 | CHAR GDM_Version[]="General DigiMusic 1.xx"; | ||
118 | |||
119 | int GDM_Test(void) | ||
120 | { | ||
121 | /* test for gdm magic numbers */ | ||
122 | UBYTE id[4]; | ||
123 | |||
124 | _mm_fseek(modreader,0x00,SEEK_SET); | ||
125 | if (!_mm_read_UBYTES(id,4,modreader)) | ||
126 | return 0; | ||
127 | if (!memcmp(id,"GDM\xfe",4)) { | ||
128 | _mm_fseek(modreader,71,SEEK_SET); | ||
129 | if (!_mm_read_UBYTES(id,4,modreader)) | ||
130 | return 0; | ||
131 | if (!memcmp(id,"GMFS",4)) | ||
132 | return 1; | ||
133 | } | ||
134 | return 0; | ||
135 | } | ||
136 | |||
137 | int GDM_Init(void) | ||
138 | { | ||
139 | if (!(gdmbuf=(GDMNOTE*)MikMod_malloc(32*64*sizeof(GDMNOTE)))) return 0; | ||
140 | if (!(mh=(GDMHEADER*)MikMod_malloc(sizeof(GDMHEADER)))) return 0; | ||
141 | |||
142 | return 1; | ||
143 | } | ||
144 | |||
145 | void GDM_Cleanup(void) | ||
146 | { | ||
147 | MikMod_free(mh); | ||
148 | MikMod_free(gdmbuf); | ||
149 | } | ||
150 | |||
151 | int GDM_ReadPattern(void) | ||
152 | { | ||
153 | int pos,flag,ch,i,maxch; | ||
154 | GDMNOTE n; | ||
155 | UWORD length,x=0; | ||
156 | |||
157 | /* get pattern length */ | ||
158 | length=_mm_read_I_UWORD(modreader)-2; | ||
159 | |||
160 | /* clear pattern data */ | ||
161 | memset(gdmbuf,255,32*64*sizeof(GDMNOTE)); | ||
162 | pos=0; | ||
163 | maxch=0; | ||
164 | |||
165 | while (x<length) { | ||
166 | memset(&n,255,sizeof(GDMNOTE)); | ||
167 | flag=_mm_read_UBYTE(modreader); | ||
168 | x++; | ||
169 | |||
170 | if (_mm_eof(modreader)) { | ||
171 | _mm_errno=MMERR_LOADING_PATTERN; | ||
172 | return 0; | ||
173 | } | ||
174 | |||
175 | ch=flag&31; | ||
176 | if (ch>maxch) maxch=ch; | ||
177 | if (!flag) { | ||
178 | pos++; | ||
179 | continue; | ||
180 | } | ||
181 | if (flag&0x60) { | ||
182 | if (flag&0x20) { | ||
183 | /* new note */ | ||
184 | n.note=_mm_read_UBYTE(modreader)&127; | ||
185 | n.samp=_mm_read_UBYTE(modreader); | ||
186 | x +=2; | ||
187 | } | ||
188 | if (flag&0x40) { | ||
189 | do { | ||
190 | /* effect channel set */ | ||
191 | i=_mm_read_UBYTE(modreader); | ||
192 | n.effect[i>>6].effect=i&31; | ||
193 | n.effect[i>>6].param=_mm_read_UBYTE(modreader); | ||
194 | x +=2; | ||
195 | } while (i&32); | ||
196 | } | ||
197 | memcpy(gdmbuf+(64U*ch)+pos,&n,sizeof(GDMNOTE)); | ||
198 | } | ||
199 | } | ||
200 | return 1; | ||
201 | } | ||
202 | |||
203 | UBYTE *GDM_ConvertTrack(GDMNOTE*tr) | ||
204 | { | ||
205 | int t,i=0; | ||
206 | UBYTE note,ins,inf; | ||
207 | |||
208 | UniReset(); | ||
209 | for (t=0;t<64;t++) { | ||
210 | note=tr[t].note; | ||
211 | ins=tr[t].samp; | ||
212 | |||
213 | if ((ins)&&(ins!=255)) | ||
214 | UniInstrument(ins-1); | ||
215 | if (note!=255) { | ||
216 | UniNote(((note>>4)*OCTAVE)+(note&0xf)-1); | ||
217 | } | ||
218 | for (i=0;i<4;i++) { | ||
219 | inf = tr[t].effect[i].param; | ||
220 | switch (tr[t].effect[i].effect) { | ||
221 | case 1: /* toneslide up */ | ||
222 | UniEffect(UNI_S3MEFFECTF,inf); | ||
223 | break; | ||
224 | case 2: /* toneslide down */ | ||
225 | UniEffect(UNI_S3MEFFECTE,inf); | ||
226 | break; | ||
227 | case 3: /* glissando to note */ | ||
228 | UniEffect(UNI_ITEFFECTG,inf); | ||
229 | break; | ||
230 | case 4: /* vibrato */ | ||
231 | UniEffect(UNI_ITEFFECTH,inf); | ||
232 | break; | ||
233 | case 5: /* portamento+volslide */ | ||
234 | UniEffect(UNI_ITEFFECTG,0); | ||
235 | UniEffect(UNI_S3MEFFECTD,inf); | ||
236 | break; | ||
237 | case 6: /* vibrato+volslide */ | ||
238 | UniEffect(UNI_ITEFFECTH,0); | ||
239 | UniEffect(UNI_S3MEFFECTD,inf); | ||
240 | break; | ||
241 | case 7: /* tremolo */ | ||
242 | UniEffect(UNI_S3MEFFECTR,inf); | ||
243 | break; | ||
244 | case 8: /* tremor */ | ||
245 | UniEffect(UNI_S3MEFFECTI,inf); | ||
246 | break; | ||
247 | case 9: /* offset */ | ||
248 | UniPTEffect(0x09,inf); | ||
249 | break; | ||
250 | case 0x0a: /* volslide */ | ||
251 | UniEffect(UNI_S3MEFFECTD,inf); | ||
252 | break; | ||
253 | case 0x0b: /* jump to order */ | ||
254 | UniPTEffect(0x0b,inf); | ||
255 | break; | ||
256 | case 0x0c: /* volume set */ | ||
257 | UniPTEffect(0x0c,inf); | ||
258 | break; | ||
259 | case 0x0d: /* pattern break */ | ||
260 | UniPTEffect(0x0d,inf); | ||
261 | break; | ||
262 | case 0x0e: /* extended */ | ||
263 | switch (inf&0xf0) { | ||
264 | case 0x10: /* fine portamento up */ | ||
265 | UniEffect(UNI_S3MEFFECTF, 0x0f|((inf<<4)&0x0f)); | ||
266 | break; | ||
267 | case 0x20: /* fine portamento down */ | ||
268 | UniEffect(UNI_S3MEFFECTE, 0xf0|(inf&0x0f)); | ||
269 | break; | ||
270 | case 0x30: /* glissando control */ | ||
271 | UniEffect(SS_GLISSANDO, inf&0x0f); | ||
272 | break; | ||
273 | case 0x40: /* vibrato waveform */ | ||
274 | UniEffect(SS_VIBWAVE, inf&0x0f); | ||
275 | break; | ||
276 | case 0x50: /* set c4spd */ | ||
277 | UniEffect(SS_FINETUNE, inf&0x0f); | ||
278 | break; | ||
279 | case 0x60: /* loop fun */ | ||
280 | UniEffect(UNI_ITEFFECTS0, (inf&0x0f)|0xb0); | ||
281 | break; | ||
282 | case 0x70: /* tremolo waveform */ | ||
283 | UniEffect(SS_TREMWAVE, inf&0x0f); | ||
284 | break; | ||
285 | case 0x80: /* extra fine porta up */ | ||
286 | UniEffect(UNI_S3MEFFECTF, 0x0e|((inf<<4)&0x0f)); | ||
287 | break; | ||
288 | case 0x90: /* extra fine porta down */ | ||
289 | UniEffect(UNI_S3MEFFECTE, 0xe0|(inf&0x0f)); | ||
290 | break; | ||
291 | case 0xa0: /* fine volslide up */ | ||
292 | UniEffect(UNI_S3MEFFECTD, 0x0f|((inf<<4)&0x0f)); | ||
293 | break; | ||
294 | case 0xb0: /* fine volslide down */ | ||
295 | UniEffect(UNI_S3MEFFECTE, 0xf0|(inf&0x0f)); | ||
296 | break; | ||
297 | case 0xc0: /* note cut */ | ||
298 | case 0xd0: /* note delay */ | ||
299 | case 0xe0: /* extend row */ | ||
300 | UniPTEffect(0xe,inf); | ||
301 | break; | ||
302 | } | ||
303 | break; | ||
304 | case 0x0f: /* set tempo */ | ||
305 | UniEffect(UNI_S3MEFFECTA,inf); | ||
306 | break; | ||
307 | case 0x10: /* arpeggio */ | ||
308 | UniPTEffect(0x0,inf); | ||
309 | break; | ||
310 | case 0x12: /* retrigger */ | ||
311 | UniEffect(UNI_S3MEFFECTQ,inf); | ||
312 | break; | ||
313 | case 0x13: /* set global volume */ | ||
314 | UniEffect(UNI_XMEFFECTG,inf<<1); | ||
315 | break; | ||
316 | case 0x14: /* fine vibrato */ | ||
317 | UniEffect(UNI_ITEFFECTU,inf); | ||
318 | break; | ||
319 | case 0x1e: /* special */ | ||
320 | switch (inf&0xf0) { | ||
321 | case 8: /* set pan position */ | ||
322 | if (inf >=128) | ||
323 | UniPTEffect(0x08,255); | ||
324 | else | ||
325 | UniPTEffect(0x08,inf<<1); | ||
326 | break; | ||
327 | } | ||
328 | break; | ||
329 | case 0x1f: /* set bpm */ | ||
330 | if (inf >=0x20) | ||
331 | UniEffect(UNI_S3MEFFECTT,inf); | ||
332 | break; | ||
333 | } | ||
334 | } | ||
335 | UniNewline(); | ||
336 | } | ||
337 | return UniDup(); | ||
338 | } | ||
339 | |||
340 | int GDM_Load(int curious) | ||
341 | { | ||
342 | int i,x,u,track; | ||
343 | SAMPLE *q; | ||
344 | GDMSAMPLE s; | ||
345 | ULONG position; | ||
346 | |||
347 | /* read header */ | ||
348 | _mm_read_string(mh->id1,4,modreader); | ||
349 | _mm_read_string(mh->songname,32,modreader); | ||
350 | _mm_read_string(mh->author,32,modreader); | ||
351 | _mm_read_string(mh->eofmarker,3,modreader); | ||
352 | _mm_read_string(mh->id2,4,modreader); | ||
353 | |||
354 | mh->majorver=_mm_read_UBYTE(modreader); | ||
355 | mh->minorver=_mm_read_UBYTE(modreader); | ||
356 | mh->trackerid=_mm_read_I_UWORD(modreader); | ||
357 | mh->t_majorver=_mm_read_UBYTE(modreader); | ||
358 | mh->t_minorver=_mm_read_UBYTE(modreader); | ||
359 | _mm_read_UBYTES(mh->pantable,32,modreader); | ||
360 | mh->mastervol=_mm_read_UBYTE(modreader); | ||
361 | mh->mastertempo=_mm_read_UBYTE(modreader); | ||
362 | mh->masterbpm=_mm_read_UBYTE(modreader); | ||
363 | mh->flags=_mm_read_I_UWORD(modreader); | ||
364 | |||
365 | mh->orderloc=_mm_read_I_ULONG(modreader); | ||
366 | mh->ordernum=_mm_read_UBYTE(modreader); | ||
367 | mh->patternloc=_mm_read_I_ULONG(modreader); | ||
368 | mh->patternnum=_mm_read_UBYTE(modreader); | ||
369 | mh->samhead=_mm_read_I_ULONG(modreader); | ||
370 | mh->samdata=_mm_read_I_ULONG(modreader); | ||
371 | mh->samnum=_mm_read_UBYTE(modreader); | ||
372 | mh->messageloc=_mm_read_I_ULONG(modreader); | ||
373 | mh->messagelen=_mm_read_I_ULONG(modreader); | ||
374 | mh->scrollyloc=_mm_read_I_ULONG(modreader); | ||
375 | mh->scrollylen=_mm_read_I_UWORD(modreader); | ||
376 | mh->graphicloc=_mm_read_I_ULONG(modreader); | ||
377 | mh->graphiclen=_mm_read_I_UWORD(modreader); | ||
378 | |||
379 | /* have we ended abruptly? */ | ||
380 | if (_mm_eof(modreader)) { | ||
381 | _mm_errno=MMERR_LOADING_HEADER; | ||
382 | return 0; | ||
383 | } | ||
384 | |||
385 | /* any orders? */ | ||
386 | if(mh->ordernum==255) { | ||
387 | _mm_errno=MMERR_LOADING_PATTERN; | ||
388 | return 0; | ||
389 | } | ||
390 | |||
391 | /* now we fill */ | ||
392 | of.modtype=StrDup(GDM_Version); | ||
393 | of.modtype[18]=mh->majorver+'0'; | ||
394 | of.modtype[20]=mh->minorver/10+'0'; | ||
395 | of.modtype[21]=mh->minorver%10+'0'; | ||
396 | of.songname=DupStr(mh->songname,32,0); | ||
397 | of.numpat=mh->patternnum+1; | ||
398 | of.reppos=0; | ||
399 | of.numins=of.numsmp=mh->samnum+1; | ||
400 | of.initspeed=mh->mastertempo; | ||
401 | of.inittempo=mh->masterbpm; | ||
402 | of.initvolume=mh->mastervol<<1; | ||
403 | of.flags|=UF_S3MSLIDES | UF_PANNING; | ||
404 | /* XXX whenever possible, we should try to determine the original format. | ||
405 | Here we assume it was S3M-style wrt bpmlimit... */ | ||
406 | of.bpmlimit = 32; | ||
407 | |||
408 | /* read the order data */ | ||
409 | if (!AllocPositions(mh->ordernum+1)) { | ||
410 | _mm_errno=MMERR_OUT_OF_MEMORY; | ||
411 | return 0; | ||
412 | } | ||
413 | |||
414 | _mm_fseek(modreader,mh->orderloc,SEEK_SET); | ||
415 | for (i=0;i<mh->ordernum+1;i++) | ||
416 | of.positions[i]=_mm_read_UBYTE(modreader); | ||
417 | |||
418 | of.numpos=0; | ||
419 | for (i=0;i<mh->ordernum+1;i++) { | ||
420 | int order=of.positions[i]; | ||
421 | if(order==255) order=LAST_PATTERN; | ||
422 | of.positions[of.numpos]=order; | ||
423 | if (of.positions[i]<254) of.numpos++; | ||
424 | } | ||
425 | |||
426 | /* have we ended abruptly yet? */ | ||
427 | if (_mm_eof(modreader)) { | ||
428 | _mm_errno=MMERR_LOADING_HEADER; | ||
429 | return 0; | ||
430 | } | ||
431 | |||
432 | /* time to load the samples */ | ||
433 | if (!AllocSamples()) { | ||
434 | _mm_errno=MMERR_OUT_OF_MEMORY; | ||
435 | return 0; | ||
436 | } | ||
437 | |||
438 | q=of.samples; | ||
439 | position=mh->samdata; | ||
440 | |||
441 | /* seek to instrument position */ | ||
442 | _mm_fseek(modreader,mh->samhead,SEEK_SET); | ||
443 | |||
444 | for (i=0;i<of.numins;i++) { | ||
445 | /* load sample info */ | ||
446 | _mm_read_UBYTES(s.sampname,32,modreader); | ||
447 | _mm_read_UBYTES(s.filename,12,modreader); | ||
448 | s.ems=_mm_read_UBYTE(modreader); | ||
449 | s.length=_mm_read_I_ULONG(modreader); | ||
450 | s.loopbeg=_mm_read_I_ULONG(modreader); | ||
451 | s.loopend=_mm_read_I_ULONG(modreader); | ||
452 | s.flags=_mm_read_UBYTE(modreader); | ||
453 | s.c4spd=_mm_read_I_UWORD(modreader); | ||
454 | s.vol=_mm_read_UBYTE(modreader); | ||
455 | s.pan=_mm_read_UBYTE(modreader); | ||
456 | |||
457 | if (_mm_eof(modreader)) { | ||
458 | _mm_errno=MMERR_LOADING_SAMPLEINFO; | ||
459 | return 0; | ||
460 | } | ||
461 | q->samplename=DupStr(s.sampname,32,0); | ||
462 | q->speed=s.c4spd; | ||
463 | q->length=s.length; | ||
464 | q->loopstart=s.loopbeg; | ||
465 | q->loopend=s.loopend; | ||
466 | q->volume=s.vol; | ||
467 | q->panning=s.pan; | ||
468 | q->seekpos=position; | ||
469 | |||
470 | position +=s.length; | ||
471 | |||
472 | if (s.flags&1) | ||
473 | q->flags |=SF_LOOP; | ||
474 | if (s.flags&2) | ||
475 | q->flags |=SF_16BITS; | ||
476 | if (s.flags&16) | ||
477 | q->flags |=SF_STEREO; | ||
478 | q++; | ||
479 | } | ||
480 | |||
481 | /* set the panning */ | ||
482 | for (i=x=0;i<32;i++) { | ||
483 | of.panning[i]=mh->pantable[i]; | ||
484 | if (!of.panning[i]) | ||
485 | of.panning[i]=PAN_LEFT; | ||
486 | else if (of.panning[i]==8) | ||
487 | of.panning[i]=PAN_CENTER; | ||
488 | else if (of.panning[i]==15) | ||
489 | of.panning[i]=PAN_RIGHT; | ||
490 | else if (of.panning[i]==16) | ||
491 | of.panning[i]=PAN_SURROUND; | ||
492 | else if (of.panning[i]==255) | ||
493 | of.panning[i]=128; | ||
494 | else | ||
495 | of.panning[i]<<=3; | ||
496 | if (mh->pantable[i]!=255) | ||
497 | x=i; | ||
498 | } | ||
499 | |||
500 | of.numchn=x+1; | ||
501 | if (of.numchn<1) | ||
502 | of.numchn=1; /* for broken counts */ | ||
503 | |||
504 | /* load the pattern info */ | ||
505 | of.numtrk=of.numpat*of.numchn; | ||
506 | |||
507 | /* jump to patterns */ | ||
508 | _mm_fseek(modreader,mh->patternloc,SEEK_SET); | ||
509 | |||
510 | if (!AllocTracks()) { | ||
511 | _mm_errno=MMERR_OUT_OF_MEMORY; | ||
512 | return 0; | ||
513 | } | ||
514 | |||
515 | if (!AllocPatterns()) { | ||
516 | _mm_errno=MMERR_OUT_OF_MEMORY; | ||
517 | return 0; | ||
518 | } | ||
519 | |||
520 | for (i=track=0;i<of.numpat;i++) { | ||
521 | if (!GDM_ReadPattern()) { | ||
522 | _mm_errno=MMERR_LOADING_PATTERN; | ||
523 | return 0; | ||
524 | } | ||
525 | for (u=0;u<of.numchn;u++,track++) { | ||
526 | of.tracks[track]=GDM_ConvertTrack(&gdmbuf[u<<6]); | ||
527 | if (!of.tracks[track]) { | ||
528 | _mm_errno=MMERR_LOADING_TRACK; | ||
529 | return 0; | ||
530 | } | ||
531 | } | ||
532 | } | ||
533 | return 1; | ||
534 | } | ||
535 | |||
536 | CHAR *GDM_LoadTitle(void) | ||
537 | { | ||
538 | CHAR s[32]; | ||
539 | |||
540 | _mm_fseek(modreader,4,SEEK_SET); | ||
541 | if (!_mm_read_UBYTES(s,32,modreader)) return NULL; | ||
542 | |||
543 | return DupStr(s,28,0); | ||
544 | } | ||
545 | |||
546 | MIKMODAPI MLOADER load_gdm= | ||
547 | { | ||
548 | NULL, | ||
549 | "GDM", | ||
550 | "GDM (General DigiMusic)", | ||
551 | GDM_Init, | ||
552 | GDM_Test, | ||
553 | GDM_Load, | ||
554 | GDM_Cleanup, | ||
555 | GDM_LoadTitle | ||
556 | }; | ||
557 | |||
558 | /* ex:set ts=4: */ | ||
diff --git a/apps/plugins/mikmod/load_gt2.c b/apps/plugins/mikmod/load_gt2.c new file mode 100644 index 0000000000..996de0e61e --- /dev/null +++ b/apps/plugins/mikmod/load_gt2.c | |||
@@ -0,0 +1,374 @@ | |||
1 | /* MikMod sound library | ||
2 | (c) 2003-2004 Raphael Assenat and others - see file | ||
3 | AUTHORS 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: load_gt2.c,v 1.2 2005/03/30 19:09:35 realtech Exp $ | ||
24 | |||
25 | Graoumf tracker format (.GT2) | ||
26 | |||
27 | ==============================================================================*/ | ||
28 | |||
29 | #ifdef HAVE_CONFIG_H | ||
30 | #include "config.h" | ||
31 | #endif | ||
32 | |||
33 | #ifdef HAVE_UNISTD_H | ||
34 | #include <unistd.h> | ||
35 | #endif | ||
36 | |||
37 | #include <ctype.h> | ||
38 | #include <stdio.h> | ||
39 | #ifdef HAVE_MEMORY_H | ||
40 | #include <memory.h> | ||
41 | #endif | ||
42 | #include <string.h> | ||
43 | |||
44 | #include "mikmod_internals.h" | ||
45 | |||
46 | typedef struct GT_NOTE { | ||
47 | UBYTE note; /* 24-127, 48 is middle C-2. 0 for no note */ | ||
48 | UBYTE inst; /* instrument, 1-255, 0 for none */ | ||
49 | UWORD effect; /* 0 for no FX */ | ||
50 | UBYTE vv; /* volume, 1-255, 0 for no volume */ | ||
51 | } GT_NOTE; | ||
52 | |||
53 | /* general info chunk */ | ||
54 | typedef struct GT2_CHUNK { | ||
55 | UBYTE magic[4]; /* must be 'GT2' */ | ||
56 | UBYTE version; /* 01 = v0.7, 02=v0.726, 03=v0.731 */ | ||
57 | ULONG chunk_size; | ||
58 | CHAR module_name[33]; /* 32 bytes in file */ | ||
59 | CHAR comments_author[161]; /* 160 bytes in file */ | ||
60 | UBYTE date_day; | ||
61 | UBYTE date_month; | ||
62 | UWORD date_year; | ||
63 | CHAR tracker_name[25]; /* 24 in file */ | ||
64 | UWORD initial_speed; | ||
65 | UWORD initial_tempo; | ||
66 | UWORD initial_master_volume; /* 000 - fff */ | ||
67 | UWORD num_voices; /* for the following panning section */ | ||
68 | UWORD *voice_pannings; /* 000 - 800 - fff */ | ||
69 | } GT2_CHUNK; | ||
70 | |||
71 | /* track volume chunk */ | ||
72 | typedef struct TVOL_CHUNK { | ||
73 | UBYTE id[4]; /* must be TVOL */ | ||
74 | ULONG chunk_size; | ||
75 | UWORD num_tracks; /* for the following array */ | ||
76 | UWORD *track_volumes; /* 0000 - 1000 - FFFF */ | ||
77 | } TVOL_CHUNK; | ||
78 | |||
79 | /* extra-comment chunk */ | ||
80 | typedef struct XCOM_CHUNK { | ||
81 | UBYTE id[4]; /* must be XCOM */ | ||
82 | ULONG chunk_size; | ||
83 | ULONG comment_len; | ||
84 | CHAR *comment; /* comment_len + 1 allocated */ | ||
85 | } XCOM_CHUNK; | ||
86 | |||
87 | /* song chunk */ | ||
88 | typedef struct SONG_CHUNK { | ||
89 | UBYTE id[4]; /* must be SONG */ | ||
90 | ULONG chunk_size; | ||
91 | UWORD song_length; | ||
92 | UWORD song_repeat_point; | ||
93 | UWORD *patterns; /* pattern numbers */ | ||
94 | } SONG_CHUNK; | ||
95 | |||
96 | /* pattern set chunk */ | ||
97 | typedef struct PATS_CHUNK { | ||
98 | UBYTE id[4]; /* must be PATS */ | ||
99 | ULONG chunk_size; | ||
100 | UWORD num_tracks; /* total number of tracks for the song */ | ||
101 | UWORD num_patterns; /* number of patterns saved */ | ||
102 | } PATS_CHUNK; | ||
103 | |||
104 | /* pattern chunk */ | ||
105 | typedef struct PATD_CHUNK { | ||
106 | UBYTE id[4]; /* must be PATD */ | ||
107 | ULONG chunk_size; | ||
108 | UWORD pattern_number; | ||
109 | CHAR pattern_name[17]; /* 16 in file */ | ||
110 | UWORD codage_version; /* only 0 expected for now */ | ||
111 | /* version 0 (full pattern) */ | ||
112 | UWORD num_lines; | ||
113 | UWORD num_tracks; | ||
114 | GT_NOTE *notes; /* sizeof(GT_NOTE) * num_lines * num_tracks */ | ||
115 | } PATD_CHUNK; | ||
116 | |||
117 | /* instrument set chunk */ | ||
118 | typedef struct ORCH_CHUNK { | ||
119 | UBYTE id[4]; /* must be ORCH */ | ||
120 | ULONG chunk_size; | ||
121 | UWORD num_instruments; /* number of instruments saved */ | ||
122 | } ORCH_CHUNK; | ||
123 | |||
124 | typedef struct INST_NOTE { | ||
125 | UBYTE samp_number;/* sample number for midi note */ | ||
126 | CHAR tranp; /* transposition for note */ | ||
127 | } INST_NOTE; | ||
128 | |||
129 | /* instrument chunk */ | ||
130 | typedef struct INST_CHUNK { | ||
131 | UBYTE id[4]; /* must be INST */ | ||
132 | ULONG chunk_size; | ||
133 | UWORD instrument_number; | ||
134 | CHAR name[29]; /* 28 in file */ | ||
135 | UWORD type; /* 0 = sample */ | ||
136 | UWORD volume; /* volume, 0-255 */ | ||
137 | UWORD auto_panning; /* autopanning, 000 - 800 - fff, -1 no autopanning */ | ||
138 | UWORD volume_enveloppe_number; | ||
139 | UWORD tone_enveloppe_number; | ||
140 | UWORD pan_enveloppe_number; | ||
141 | UBYTE reserved[10]; | ||
142 | INST_NOTE note[128]; | ||
143 | } INST_CHUNK; | ||
144 | |||
145 | typedef struct SAMP_CHUNK { | ||
146 | UBYTE id[4]; /* must be SAMP */ | ||
147 | ULONG chunk_size; | ||
148 | UWORD sample_number; | ||
149 | CHAR name[29]; /* 28 in file */ | ||
150 | UWORD flags; /* bit0: 0 = mono, 1 = stereo bit1: 0 normal loop, bit2: ping pong loop */ | ||
151 | UWORD autopanning; /* 000 - 800 - fff */ | ||
152 | UWORD num_bits; /* 8 or 16 */ | ||
153 | UWORD rate; /* between 2000 and 65000 */ | ||
154 | ULONG length; /* bytes */ | ||
155 | ULONG loop_start; /* bytes */ | ||
156 | ULONG loop_len; /* bytes */ | ||
157 | UWORD volume; /* 0 - 255 */ | ||
158 | UWORD finetune; /* (-8..+7 -> -1..+7/8 halftone) */ | ||
159 | UWORD codage; /* 0 */ | ||
160 | UBYTE *data; | ||
161 | } SAMP_CHUNK; | ||
162 | |||
163 | typedef struct xENV_CHUNK { | ||
164 | UBYTE id[4]; /* must be VENV, TENV or PENV */ | ||
165 | ULONG chunk_size; | ||
166 | UWORD envelope_number; | ||
167 | CHAR name[21]; /* 20 in file */ | ||
168 | UWORD keyoff_offset; | ||
169 | UBYTE *data; | ||
170 | } xENV_CHUNK; | ||
171 | |||
172 | typedef struct ENDC_CHUNK { | ||
173 | UBYTE id[4]; /* must be ENDC */ | ||
174 | ULONG chunk_size; | ||
175 | ULONG total_module_size; | ||
176 | } ENDC_CHUNK; | ||
177 | |||
178 | |||
179 | typedef union GT_CHUNK | ||
180 | { | ||
181 | UBYTE id[4]; /* must be TVOL */ | ||
182 | GT2_CHUNK gt2; | ||
183 | TVOL_CHUNK tvol; | ||
184 | XCOM_CHUNK xcom; | ||
185 | SONG_CHUNK song; | ||
186 | PATS_CHUNK pats; | ||
187 | PATD_CHUNK patd; | ||
188 | ORCH_CHUNK orch; | ||
189 | INST_CHUNK inst; | ||
190 | SAMP_CHUNK samp; | ||
191 | xENV_CHUNK xenv; | ||
192 | ENDC_CHUNK endc; | ||
193 | } GT_CHUNK; | ||
194 | |||
195 | GT_CHUNK *loadChunk(void) | ||
196 | { | ||
197 | GT_CHUNK *new_chunk = MikMod_malloc(sizeof(GT_CHUNK)); | ||
198 | |||
199 | /* the file chunk id only use 3 bytes, others 4 */ | ||
200 | _mm_read_UBYTES(new_chunk->id, 3, modreader); | ||
201 | if (! (new_chunk->id[0]=='G' && | ||
202 | new_chunk->id[1]=='T' && | ||
203 | new_chunk->id[2]=='2') | ||
204 | ) | ||
205 | { | ||
206 | _mm_read_UBYTES(&new_chunk->id[3], 1, modreader); | ||
207 | } | ||
208 | else | ||
209 | { | ||
210 | new_chunk->id[3] = ' '; | ||
211 | } | ||
212 | |||
213 | printf(">> %c%c%c%c\n", new_chunk->id[0], new_chunk->id[1], new_chunk->id[2], new_chunk->id[3]); | ||
214 | |||
215 | if (!memcmp(new_chunk, "GT2", 3)) { | ||
216 | _mm_read_UBYTES(&new_chunk->gt2.version, 1, modreader); | ||
217 | _mm_read_M_ULONGS(&new_chunk->gt2.chunk_size, 1, modreader); | ||
218 | new_chunk->gt2.module_name[32] = 0; | ||
219 | _mm_read_UBYTES(&new_chunk->gt2.module_name, 32, modreader); | ||
220 | new_chunk->gt2.module_name[160] = 0; | ||
221 | _mm_read_UBYTES(&new_chunk->gt2.comments_author, 160, modreader); | ||
222 | _mm_read_UBYTES(&new_chunk->gt2.date_day, 1, modreader); | ||
223 | _mm_read_UBYTES(&new_chunk->gt2.date_month, 1, modreader); | ||
224 | _mm_read_M_UWORDS(&new_chunk->gt2.date_year, 1, modreader); | ||
225 | new_chunk->gt2.tracker_name[24] = 0; | ||
226 | _mm_read_UBYTES(&new_chunk->gt2.tracker_name, 24, modreader); | ||
227 | _mm_read_M_UWORDS(&new_chunk->gt2.initial_speed, 1, modreader); | ||
228 | _mm_read_M_UWORDS(&new_chunk->gt2.initial_tempo, 1, modreader); | ||
229 | _mm_read_M_UWORDS(&new_chunk->gt2.initial_master_volume, 1, modreader); | ||
230 | _mm_read_M_UWORDS(&new_chunk->gt2.num_voices, 1, modreader); | ||
231 | new_chunk->gt2.voice_pannings = MikMod_malloc(2*new_chunk->gt2.num_voices); | ||
232 | _mm_read_M_UWORDS(new_chunk->gt2.voice_pannings, new_chunk->gt2.num_voices, modreader); | ||
233 | return new_chunk; | ||
234 | } | ||
235 | |||
236 | if (!memcmp(new_chunk, "TVOL", 4)) { | ||
237 | new_chunk->tvol.chunk_size = _mm_read_M_ULONG(modreader); | ||
238 | new_chunk->tvol.num_tracks = _mm_read_M_UWORD(modreader); | ||
239 | new_chunk->tvol.track_volumes = MikMod_malloc(new_chunk->tvol.num_tracks * 2); | ||
240 | _mm_read_M_UWORDS(new_chunk->tvol.track_volumes, new_chunk->tvol.num_tracks, modreader); | ||
241 | return new_chunk; | ||
242 | } | ||
243 | |||
244 | if (!memcmp(new_chunk, "XCOM", 4)) { | ||
245 | new_chunk->xcom.chunk_size = _mm_read_M_ULONG(modreader); | ||
246 | new_chunk->xcom.comment_len = _mm_read_M_ULONG(modreader); | ||
247 | new_chunk->xcom.comment = MikMod_malloc(new_chunk->xcom.comment_len + 1); | ||
248 | _mm_read_UBYTES(new_chunk->xcom.comment, new_chunk->xcom.comment_len, modreader); | ||
249 | return new_chunk; | ||
250 | } | ||
251 | |||
252 | if (!memcmp(new_chunk, "SONG", 4)) { | ||
253 | new_chunk->song.chunk_size = _mm_read_M_ULONG(modreader); | ||
254 | new_chunk->song.song_length = _mm_read_M_UWORD(modreader); | ||
255 | new_chunk->song.song_repeat_point = _mm_read_M_UWORD(modreader); | ||
256 | new_chunk->song.patterns = MikMod_malloc(2*new_chunk->song.song_length); | ||
257 | _mm_read_M_UWORDS(new_chunk->song.patterns, new_chunk->song.song_length, modreader); | ||
258 | return new_chunk; | ||
259 | } | ||
260 | |||
261 | if (!memcmp(new_chunk, "PATS", 4)) { | ||
262 | new_chunk->pats.chunk_size = _mm_read_M_ULONG(modreader); | ||
263 | new_chunk->pats.num_tracks = _mm_read_M_UWORD(modreader); | ||
264 | new_chunk->pats.num_patterns = _mm_read_M_UWORD(modreader); | ||
265 | return new_chunk; | ||
266 | } | ||
267 | |||
268 | if (!memcmp(new_chunk, "PATD", 4)) { | ||
269 | new_chunk->patd.chunk_size = _mm_read_M_ULONG(modreader); | ||
270 | new_chunk->patd.pattern_number = _mm_read_M_UWORD(modreader); | ||
271 | new_chunk->patd.pattern_name[16] = 0; | ||
272 | _mm_read_UBYTES(new_chunk->patd.pattern_name, 16, modreader); | ||
273 | new_chunk->patd.codage_version = _mm_read_M_UWORD(modreader); | ||
274 | new_chunk->patd.num_lines = _mm_read_M_UWORD(modreader); | ||
275 | new_chunk->patd.num_tracks = _mm_read_M_UWORD(modreader); | ||
276 | new_chunk->patd.notes = MikMod_malloc(5 * | ||
277 | new_chunk->patd.num_lines * | ||
278 | new_chunk->patd.num_tracks); | ||
279 | _mm_read_UBYTES(new_chunk->patd.notes, | ||
280 | new_chunk->patd.num_lines * new_chunk->patd.num_tracks * 5, | ||
281 | modreader); | ||
282 | return new_chunk; | ||
283 | } | ||
284 | |||
285 | if (!memcmp(new_chunk, "ORCH", 4)) { | ||
286 | new_chunk->orch.chunk_size = _mm_read_M_ULONG(modreader); | ||
287 | new_chunk->orch.num_instruments = _mm_read_M_UWORD(modreader); | ||
288 | return new_chunk; | ||
289 | } | ||
290 | if (!memcmp(new_chunk, "INST", 4)) { | ||
291 | return new_chunk; | ||
292 | } | ||
293 | if (!memcmp(new_chunk, "SAMP", 4)) { | ||
294 | return new_chunk; | ||
295 | } | ||
296 | if (!memcmp(new_chunk, "VENV", 4)) { | ||
297 | return new_chunk; | ||
298 | } | ||
299 | if (!memcmp(new_chunk, "TENV", 4)) { | ||
300 | return new_chunk; | ||
301 | } | ||
302 | if (!memcmp(new_chunk, "PENV", 4)) { | ||
303 | return new_chunk; | ||
304 | } | ||
305 | if (!memcmp(new_chunk, "ENDC", 4)) { | ||
306 | return new_chunk; | ||
307 | } | ||
308 | |||
309 | printf("?? %c%c%c%c\n", new_chunk->id[0], new_chunk->id[1], new_chunk->id[2], new_chunk->id[3]); | ||
310 | |||
311 | MikMod_free(new_chunk); | ||
312 | return NULL; // unknown chunk | ||
313 | } | ||
314 | |||
315 | int GT2_Init(void) | ||
316 | { | ||
317 | return 1; | ||
318 | } | ||
319 | |||
320 | int GT2_Test(void) | ||
321 | { | ||
322 | UBYTE magic[3]; | ||
323 | _mm_fseek(modreader, 0, SEEK_SET); | ||
324 | |||
325 | _mm_read_UBYTES(magic, 3, modreader); | ||
326 | |||
327 | if (magic[0] == 'G' && magic[1] == 'T' && magic[2] == '2') { return 1; } | ||
328 | |||
329 | return 0; | ||
330 | } | ||
331 | |||
332 | int GT2_Load(int curious) | ||
333 | { | ||
334 | GT_CHUNK *tmp; | ||
335 | |||
336 | _mm_fseek(modreader, 0, SEEK_SET); | ||
337 | while ( (tmp = loadChunk() )) | ||
338 | { | ||
339 | printf("%c%c%c%c\n", tmp->id[0], tmp->id[1], tmp->id[2], tmp->id[3]); | ||
340 | |||
341 | } | ||
342 | |||
343 | return 0; | ||
344 | } | ||
345 | |||
346 | void GT2_Cleanup(void) | ||
347 | { | ||
348 | } | ||
349 | |||
350 | CHAR *GT2_LoadTitle(void) | ||
351 | { | ||
352 | CHAR title[33]; | ||
353 | _mm_fseek(modreader, 8, SEEK_SET); | ||
354 | |||
355 | _mm_read_UBYTES(title, 32, modreader); | ||
356 | title[32]=0; | ||
357 | |||
358 | return (DupStr(title, 32, 1)); | ||
359 | } | ||
360 | |||
361 | |||
362 | MIKMODAPI MLOADER load_gt2 = { | ||
363 | NULL, | ||
364 | "Graoumf Tracker 2 module", | ||
365 | "Graoumf Tracker 2", | ||
366 | GT2_Init, | ||
367 | GT2_Test, | ||
368 | GT2_Load, | ||
369 | GT2_Cleanup, | ||
370 | GT2_LoadTitle | ||
371 | }; | ||
372 | |||
373 | |||
374 | |||
diff --git a/apps/plugins/mikmod/load_imf.c b/apps/plugins/mikmod/load_imf.c new file mode 100644 index 0000000000..0b85c0ecc3 --- /dev/null +++ b/apps/plugins/mikmod/load_imf.c | |||
@@ -0,0 +1,738 @@ | |||
1 | /* MikMod sound library | ||
2 | (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file | ||
3 | AUTHORS 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: load_imf.c,v 1.3 2005/04/07 19:57:38 realtech Exp $ | ||
24 | |||
25 | Imago Orpheus (IMF) module loader | ||
26 | |||
27 | ==============================================================================*/ | ||
28 | |||
29 | #ifdef HAVE_CONFIG_H | ||
30 | #include "config.h" | ||
31 | #endif | ||
32 | |||
33 | #ifdef HAVE_UNISTD_H | ||
34 | #include <unistd.h> | ||
35 | #endif | ||
36 | |||
37 | #include <stdio.h> | ||
38 | #ifdef HAVE_MEMORY_H | ||
39 | #include <memory.h> | ||
40 | #endif | ||
41 | #include <string.h> | ||
42 | |||
43 | #include "mikmod_internals.h" | ||
44 | |||
45 | #ifdef SUNOS | ||
46 | extern int fprintf(FILE *, const char *, ...); | ||
47 | #endif | ||
48 | |||
49 | /*========== Module structure */ | ||
50 | |||
51 | /* module header */ | ||
52 | typedef struct IMFHEADER { | ||
53 | CHAR songname[32]; | ||
54 | UWORD ordnum; | ||
55 | UWORD patnum; | ||
56 | UWORD insnum; | ||
57 | UWORD flags; | ||
58 | UBYTE initspeed; | ||
59 | UBYTE inittempo; | ||
60 | UBYTE mastervol; | ||
61 | UBYTE mastermult; | ||
62 | UBYTE orders[256]; | ||
63 | } IMFHEADER; | ||
64 | |||
65 | /* channel settings */ | ||
66 | typedef struct IMFCHANNEL { | ||
67 | CHAR name[12]; | ||
68 | UBYTE chorus; | ||
69 | UBYTE reverb; | ||
70 | UBYTE pan; | ||
71 | UBYTE status; | ||
72 | } IMFCHANNEL; | ||
73 | |||
74 | /* instrument header */ | ||
75 | #define IMFNOTECNT (10*OCTAVE) | ||
76 | #define IMFENVCNT (16*2) | ||
77 | typedef struct IMFINSTHEADER { | ||
78 | CHAR name[32]; | ||
79 | UBYTE what[IMFNOTECNT]; | ||
80 | UWORD volenv[IMFENVCNT]; | ||
81 | UWORD panenv[IMFENVCNT]; | ||
82 | UWORD pitenv[IMFENVCNT]; | ||
83 | UBYTE volpts; | ||
84 | UBYTE volsus; | ||
85 | UBYTE volbeg; | ||
86 | UBYTE volend; | ||
87 | UBYTE volflg; | ||
88 | UBYTE panpts; | ||
89 | UBYTE pansus; | ||
90 | UBYTE panbeg; | ||
91 | UBYTE panend; | ||
92 | UBYTE panflg; | ||
93 | UBYTE pitpts; | ||
94 | UBYTE pitsus; | ||
95 | UBYTE pitbeg; | ||
96 | UBYTE pitend; | ||
97 | UBYTE pitflg; | ||
98 | UWORD volfade; | ||
99 | UWORD numsmp; | ||
100 | ULONG signature; | ||
101 | } IMFINSTHEADER; | ||
102 | |||
103 | /* sample header */ | ||
104 | typedef struct IMFWAVHEADER { | ||
105 | CHAR samplename[13]; | ||
106 | ULONG length; | ||
107 | ULONG loopstart; | ||
108 | ULONG loopend; | ||
109 | ULONG samplerate; | ||
110 | UBYTE volume; | ||
111 | UBYTE pan; | ||
112 | UBYTE flags; | ||
113 | } IMFWAVHEADER; | ||
114 | |||
115 | typedef struct IMFNOTE { | ||
116 | UBYTE note,ins,eff1,dat1,eff2,dat2; | ||
117 | } IMFNOTE; | ||
118 | |||
119 | /*========== Loader variables */ | ||
120 | |||
121 | static CHAR IMF_Version[]="Imago Orpheus"; | ||
122 | |||
123 | static IMFNOTE *imfpat=NULL; | ||
124 | static IMFHEADER *mh=NULL; | ||
125 | |||
126 | /*========== Loader code */ | ||
127 | |||
128 | int IMF_Test(void) | ||
129 | { | ||
130 | UBYTE id[4]; | ||
131 | |||
132 | _mm_fseek(modreader,0x3c,SEEK_SET); | ||
133 | if(!_mm_read_UBYTES(id,4,modreader)) return 0; | ||
134 | if(!memcmp(id,"IM10",4)) return 1; | ||
135 | return 0; | ||
136 | } | ||
137 | |||
138 | int IMF_Init(void) | ||
139 | { | ||
140 | if(!(imfpat=(IMFNOTE*)MikMod_malloc(32*256*sizeof(IMFNOTE)))) return 0; | ||
141 | if(!(mh=(IMFHEADER*)MikMod_malloc(sizeof(IMFHEADER)))) return 0; | ||
142 | |||
143 | return 1; | ||
144 | } | ||
145 | |||
146 | void IMF_Cleanup(void) | ||
147 | { | ||
148 | FreeLinear(); | ||
149 | |||
150 | MikMod_free(imfpat); | ||
151 | MikMod_free(mh); | ||
152 | } | ||
153 | |||
154 | static int IMF_ReadPattern(SLONG size,UWORD rows) | ||
155 | { | ||
156 | int row=0,flag,ch; | ||
157 | IMFNOTE *n,dummy; | ||
158 | |||
159 | /* clear pattern data */ | ||
160 | memset(imfpat,255,32*256*sizeof(IMFNOTE)); | ||
161 | |||
162 | while((size>0)&&(row<rows)) { | ||
163 | flag=_mm_read_UBYTE(modreader);size--; | ||
164 | |||
165 | if(_mm_eof(modreader)) { | ||
166 | _mm_errno=MMERR_LOADING_PATTERN; | ||
167 | return 0; | ||
168 | } | ||
169 | |||
170 | if(flag) { | ||
171 | ch=remap[flag&31]; | ||
172 | |||
173 | if(ch!=-1) | ||
174 | n=&imfpat[256*ch+row]; | ||
175 | else | ||
176 | n=&dummy; | ||
177 | |||
178 | if(flag&32) { | ||
179 | n->note=_mm_read_UBYTE(modreader); | ||
180 | if(n->note>=0xa0) n->note=0xa0; /* note off */ | ||
181 | n->ins =_mm_read_UBYTE(modreader); | ||
182 | size-=2; | ||
183 | } | ||
184 | if(flag&64) { | ||
185 | size-=2; | ||
186 | n->eff2=_mm_read_UBYTE(modreader); | ||
187 | n->dat2=_mm_read_UBYTE(modreader); | ||
188 | } | ||
189 | if(flag&128) { | ||
190 | n->eff1=_mm_read_UBYTE(modreader); | ||
191 | n->dat1=_mm_read_UBYTE(modreader); | ||
192 | size-=2; | ||
193 | } | ||
194 | } else row++; | ||
195 | } | ||
196 | if((size)||(row!=rows)) { | ||
197 | _mm_errno=MMERR_LOADING_PATTERN; | ||
198 | return 0; | ||
199 | } | ||
200 | return 1; | ||
201 | } | ||
202 | |||
203 | static void IMF_ProcessCmd(UBYTE eff,UBYTE inf) | ||
204 | { | ||
205 | if((eff)&&(eff!=255)) | ||
206 | switch (eff) { | ||
207 | case 0x01: /* set tempo */ | ||
208 | UniEffect(UNI_S3MEFFECTA,inf); | ||
209 | break; | ||
210 | case 0x02: /* set BPM */ | ||
211 | if(inf>=0x20) UniEffect(UNI_S3MEFFECTT,inf); | ||
212 | break; | ||
213 | case 0x03: /* tone portamento */ | ||
214 | UniEffect(UNI_ITEFFECTG,inf); | ||
215 | break; | ||
216 | case 0x04: /* porta + volslide */ | ||
217 | UniEffect(UNI_ITEFFECTG,inf); | ||
218 | UniEffect(UNI_S3MEFFECTD,0); | ||
219 | break; | ||
220 | case 0x05: /* vibrato */ | ||
221 | UniEffect(UNI_XMEFFECT4,inf); | ||
222 | break; | ||
223 | case 0x06: /* vibrato + volslide */ | ||
224 | UniEffect(UNI_XMEFFECT6,inf); | ||
225 | break; | ||
226 | case 0x07: /* fine vibrato */ | ||
227 | UniEffect(UNI_ITEFFECTU,inf); | ||
228 | break; | ||
229 | case 0x08: /* tremolo */ | ||
230 | UniEffect(UNI_S3MEFFECTR,inf); | ||
231 | break; | ||
232 | case 0x09: /* arpeggio */ | ||
233 | UniPTEffect(0x0,inf); | ||
234 | break; | ||
235 | case 0x0a: /* panning */ | ||
236 | UniPTEffect(0x8,(inf>=128)?255:(inf<<1)); | ||
237 | break; | ||
238 | case 0x0b: /* pan slide */ | ||
239 | UniEffect(UNI_XMEFFECTP,inf); | ||
240 | break; | ||
241 | case 0x0c: /* set channel volume */ | ||
242 | if(inf<=64) UniPTEffect(0xc,inf); | ||
243 | break; | ||
244 | case 0x0d: /* volume slide */ | ||
245 | UniEffect(UNI_S3MEFFECTD,inf); | ||
246 | break; | ||
247 | case 0x0e: /* fine volume slide */ | ||
248 | if(inf) { | ||
249 | if(inf>>4) | ||
250 | UniEffect(UNI_S3MEFFECTD,0x0f|inf); | ||
251 | else | ||
252 | UniEffect(UNI_S3MEFFECTD,0xf0|inf); | ||
253 | } else | ||
254 | UniEffect(UNI_S3MEFFECTD,0); | ||
255 | break; | ||
256 | case 0x0f: /* set finetune */ | ||
257 | UniPTEffect(0xe,0x50|(inf>>4)); | ||
258 | break; | ||
259 | #ifdef MIKMOD_DEBUG | ||
260 | case 0x10: /* note slide up */ | ||
261 | case 0x11: /* not slide down */ | ||
262 | fprintf(stderr,"\rIMF effect 0x10/0x11 (note slide)" | ||
263 | " not implemented (eff=%2X inf=%2X)\n",eff,inf); | ||
264 | break; | ||
265 | #endif | ||
266 | case 0x12: /* slide up */ | ||
267 | UniEffect(UNI_S3MEFFECTF,inf); | ||
268 | break; | ||
269 | case 0x13: /* slide down */ | ||
270 | UniEffect(UNI_S3MEFFECTE,inf); | ||
271 | break; | ||
272 | case 0x14: /* fine slide up */ | ||
273 | if (inf) { | ||
274 | if (inf<0x40) | ||
275 | UniEffect(UNI_S3MEFFECTF,0xe0|(inf>>2)); | ||
276 | else | ||
277 | UniEffect(UNI_S3MEFFECTF,0xf0|(inf>>4)); | ||
278 | } else | ||
279 | UniEffect(UNI_S3MEFFECTF,0); | ||
280 | break; | ||
281 | case 0x15: /* fine slide down */ | ||
282 | if (inf) { | ||
283 | if (inf<0x40) | ||
284 | UniEffect(UNI_S3MEFFECTE,0xe0|(inf>>2)); | ||
285 | else | ||
286 | UniEffect(UNI_S3MEFFECTE,0xf0|(inf>>4)); | ||
287 | } else | ||
288 | UniEffect(UNI_S3MEFFECTE,0); | ||
289 | break; | ||
290 | /* 0x16 set filter cutoff (awe32) */ | ||
291 | /* 0x17 filter side + resonance (awe32) */ | ||
292 | case 0x18: /* sample offset */ | ||
293 | UniPTEffect(0x9,inf); | ||
294 | break; | ||
295 | #ifdef MIKMOD_DEBUG | ||
296 | case 0x19: /* set fine sample offset */ | ||
297 | fprintf(stderr,"\rIMF effect 0x19 (fine sample offset)" | ||
298 | " not implemented (inf=%2X)\n",inf); | ||
299 | break; | ||
300 | #endif | ||
301 | case 0x1a: /* keyoff */ | ||
302 | UniWriteByte(UNI_KEYOFF); | ||
303 | break; | ||
304 | case 0x1b: /* retrig */ | ||
305 | UniEffect(UNI_S3MEFFECTQ,inf); | ||
306 | break; | ||
307 | case 0x1c: /* tremor */ | ||
308 | UniEffect(UNI_S3MEFFECTI,inf); | ||
309 | break; | ||
310 | case 0x1d: /* position jump */ | ||
311 | UniPTEffect(0xb,inf); | ||
312 | break; | ||
313 | case 0x1e: /* pattern break */ | ||
314 | UniPTEffect(0xd,(inf>>4)*10+(inf&0xf)); | ||
315 | break; | ||
316 | case 0x1f: /* set master volume */ | ||
317 | if(inf<=64) UniEffect(UNI_XMEFFECTG,inf<<1); | ||
318 | break; | ||
319 | case 0x20: /* master volume slide */ | ||
320 | UniEffect(UNI_XMEFFECTH,inf); | ||
321 | break; | ||
322 | case 0x21: /* extended effects */ | ||
323 | switch(inf>>4) { | ||
324 | case 0x1: /* set filter */ | ||
325 | case 0x5: /* vibrato waveform */ | ||
326 | case 0x8: /* tremolo waveform */ | ||
327 | UniPTEffect(0xe,inf-0x10); | ||
328 | break; | ||
329 | case 0xa: /* pattern loop */ | ||
330 | UniPTEffect(0xe,0x60|(inf&0xf)); | ||
331 | break; | ||
332 | case 0xb: /* pattern delay */ | ||
333 | UniPTEffect(0xe,0xe0|(inf&0xf)); | ||
334 | break; | ||
335 | case 0x3: /* glissando */ | ||
336 | case 0xc: /* note cut */ | ||
337 | case 0xd: /* note delay */ | ||
338 | case 0xf: /* invert loop */ | ||
339 | UniPTEffect(0xe,inf); | ||
340 | break; | ||
341 | case 0xe: /* ignore envelope */ | ||
342 | UniEffect(UNI_ITEFFECTS0, 0x77); /* vol */ | ||
343 | UniEffect(UNI_ITEFFECTS0, 0x79); /* pan */ | ||
344 | UniEffect(UNI_ITEFFECTS0, 0x7b); /* pit */ | ||
345 | break; | ||
346 | } | ||
347 | break; | ||
348 | /* 0x22 chorus (awe32) */ | ||
349 | /* 0x23 reverb (awe32) */ | ||
350 | } | ||
351 | } | ||
352 | |||
353 | static UBYTE* IMF_ConvertTrack(IMFNOTE* tr,UWORD rows) | ||
354 | { | ||
355 | int t; | ||
356 | UBYTE note,ins; | ||
357 | |||
358 | UniReset(); | ||
359 | for(t=0;t<rows;t++) { | ||
360 | note=tr[t].note; | ||
361 | ins=tr[t].ins; | ||
362 | |||
363 | if((ins)&&(ins!=255)) UniInstrument(ins-1); | ||
364 | if(note!=255) { | ||
365 | if(note==0xa0) { | ||
366 | UniPTEffect(0xc,0); /* Note cut */ | ||
367 | if(tr[t].eff1==0x0c) tr[t].eff1=0; | ||
368 | if(tr[t].eff2==0x0c) tr[t].eff2=0; | ||
369 | } else | ||
370 | UniNote(((note>>4)*OCTAVE)+(note&0xf)); | ||
371 | } | ||
372 | |||
373 | IMF_ProcessCmd(tr[t].eff1,tr[t].dat1); | ||
374 | IMF_ProcessCmd(tr[t].eff2,tr[t].dat2); | ||
375 | UniNewline(); | ||
376 | } | ||
377 | return UniDup(); | ||
378 | } | ||
379 | |||
380 | int IMF_Load(int curious) | ||
381 | { | ||
382 | #define IMF_SMPINCR 64 | ||
383 | int t,u,track=0,oldnumsmp; | ||
384 | IMFCHANNEL channels[32]; | ||
385 | INSTRUMENT *d; | ||
386 | SAMPLE *q; | ||
387 | IMFWAVHEADER *wh=NULL,*s=NULL; | ||
388 | ULONG *nextwav=NULL; | ||
389 | UWORD wavcnt=0; | ||
390 | UBYTE id[4]; | ||
391 | |||
392 | /* try to read the module header */ | ||
393 | _mm_read_string(mh->songname,32,modreader); | ||
394 | mh->ordnum=_mm_read_I_UWORD(modreader); | ||
395 | mh->patnum=_mm_read_I_UWORD(modreader); | ||
396 | mh->insnum=_mm_read_I_UWORD(modreader); | ||
397 | mh->flags =_mm_read_I_UWORD(modreader); | ||
398 | _mm_fseek(modreader,8,SEEK_CUR); | ||
399 | mh->initspeed =_mm_read_UBYTE(modreader); | ||
400 | mh->inittempo =_mm_read_UBYTE(modreader); | ||
401 | mh->mastervol =_mm_read_UBYTE(modreader); | ||
402 | mh->mastermult=_mm_read_UBYTE(modreader); | ||
403 | _mm_fseek(modreader,64,SEEK_SET); | ||
404 | |||
405 | if(_mm_eof(modreader)) { | ||
406 | _mm_errno = MMERR_LOADING_HEADER; | ||
407 | return 0; | ||
408 | } | ||
409 | |||
410 | /* set module variables */ | ||
411 | of.songname=DupStr(mh->songname,31,1); | ||
412 | of.modtype=StrDup(IMF_Version); | ||
413 | of.numpat=mh->patnum; | ||
414 | of.numins=mh->insnum; | ||
415 | of.reppos=0; | ||
416 | of.initspeed=mh->initspeed; | ||
417 | of.inittempo=mh->inittempo; | ||
418 | of.initvolume=mh->mastervol<<1; | ||
419 | of.flags |= UF_INST | UF_ARPMEM | UF_PANNING; | ||
420 | if(mh->flags&1) of.flags |= UF_LINEAR; | ||
421 | of.bpmlimit=32; | ||
422 | |||
423 | /* read channel information */ | ||
424 | of.numchn=0; | ||
425 | memset(remap,-1,32*sizeof(UBYTE)); | ||
426 | for(t=0;t<32;t++) { | ||
427 | _mm_read_string(channels[t].name,12,modreader); | ||
428 | channels[t].chorus=_mm_read_UBYTE(modreader); | ||
429 | channels[t].reverb=_mm_read_UBYTE(modreader); | ||
430 | channels[t].pan =_mm_read_UBYTE(modreader); | ||
431 | channels[t].status=_mm_read_UBYTE(modreader); | ||
432 | } | ||
433 | /* bug in Imago Orpheus ? If only channel 1 is enabled, in fact we have to | ||
434 | enable 16 channels */ | ||
435 | if(!channels[0].status) { | ||
436 | for(t=1;t<16;t++) if(channels[t].status!=1) break; | ||
437 | if(t==16) for(t=1;t<16;t++) channels[t].status=0; | ||
438 | } | ||
439 | for(t=0;t<32;t++) { | ||
440 | if(channels[t].status!=2) | ||
441 | remap[t]=of.numchn++; | ||
442 | else | ||
443 | remap[t]=-1; | ||
444 | } | ||
445 | for(t=0;t<32;t++) | ||
446 | if(remap[t]!=-1) { | ||
447 | of.panning[remap[t]]=channels[t].pan; | ||
448 | of.chanvol[remap[t]]=channels[t].status?0:64; | ||
449 | } | ||
450 | |||
451 | if(_mm_eof(modreader)) { | ||
452 | _mm_errno = MMERR_LOADING_HEADER; | ||
453 | return 0; | ||
454 | } | ||
455 | |||
456 | /* read order list */ | ||
457 | _mm_read_UBYTES(mh->orders,256,modreader); | ||
458 | if(_mm_eof(modreader)) { | ||
459 | _mm_errno = MMERR_LOADING_HEADER; | ||
460 | return 0; | ||
461 | } | ||
462 | |||
463 | of.numpos=0; | ||
464 | for(t=0;t<mh->ordnum;t++) | ||
465 | if(mh->orders[t]!=0xff) of.numpos++; | ||
466 | if(!AllocPositions(of.numpos)) return 0; | ||
467 | for(t=u=0;t<mh->ordnum;t++) | ||
468 | if(mh->orders[t]!=0xff) of.positions[u++]=mh->orders[t]; | ||
469 | |||
470 | /* load pattern info */ | ||
471 | of.numtrk=of.numpat*of.numchn; | ||
472 | if(!AllocTracks()) return 0; | ||
473 | if(!AllocPatterns()) return 0; | ||
474 | |||
475 | for(t=0;t<of.numpat;t++) { | ||
476 | SLONG size; | ||
477 | UWORD rows; | ||
478 | |||
479 | size=(SLONG)_mm_read_I_UWORD(modreader); | ||
480 | rows=_mm_read_I_UWORD(modreader); | ||
481 | if((rows>256)||(size<4)) { | ||
482 | _mm_errno=MMERR_LOADING_PATTERN; | ||
483 | return 0; | ||
484 | } | ||
485 | |||
486 | of.pattrows[t]=rows; | ||
487 | if(!IMF_ReadPattern(size-4,rows)) return 0; | ||
488 | for(u=0;u<of.numchn;u++) | ||
489 | if(!(of.tracks[track++]=IMF_ConvertTrack(&imfpat[u*256],rows))) | ||
490 | return 0; | ||
491 | } | ||
492 | |||
493 | /* load instruments */ | ||
494 | if(!AllocInstruments()) return 0; | ||
495 | d=of.instruments; | ||
496 | |||
497 | for(oldnumsmp=t=0;t<of.numins;t++) { | ||
498 | IMFINSTHEADER ih; | ||
499 | |||
500 | memset(d->samplenumber,0xff,INSTNOTES*sizeof(UWORD)); | ||
501 | |||
502 | /* read instrument header */ | ||
503 | _mm_read_string(ih.name,32,modreader); | ||
504 | d->insname=DupStr(ih.name,31,1); | ||
505 | _mm_read_UBYTES(ih.what,IMFNOTECNT,modreader); | ||
506 | _mm_fseek(modreader,8,SEEK_CUR); | ||
507 | _mm_read_I_UWORDS(ih.volenv,IMFENVCNT,modreader); | ||
508 | _mm_read_I_UWORDS(ih.panenv,IMFENVCNT,modreader); | ||
509 | _mm_read_I_UWORDS(ih.pitenv,IMFENVCNT,modreader); | ||
510 | |||
511 | #if defined __STDC__ || defined _MSC_VER || defined MPW_C | ||
512 | #define IMF_FinishLoadingEnvelope(name) \ | ||
513 | ih. name##pts=_mm_read_UBYTE(modreader); \ | ||
514 | ih. name##sus=_mm_read_UBYTE(modreader); \ | ||
515 | ih. name##beg=_mm_read_UBYTE(modreader); \ | ||
516 | ih. name##end=_mm_read_UBYTE(modreader); \ | ||
517 | ih. name##flg=_mm_read_UBYTE(modreader); \ | ||
518 | _mm_read_UBYTE(modreader); \ | ||
519 | _mm_read_UBYTE(modreader); \ | ||
520 | _mm_read_UBYTE(modreader) | ||
521 | #else | ||
522 | #define IMF_FinishLoadingEnvelope(name) \ | ||
523 | ih. name/**/pts=_mm_read_UBYTE(modreader); \ | ||
524 | ih. name/**/sus=_mm_read_UBYTE(modreader); \ | ||
525 | ih. name/**/beg=_mm_read_UBYTE(modreader); \ | ||
526 | ih. name/**/end=_mm_read_UBYTE(modreader); \ | ||
527 | ih. name/**/flg=_mm_read_UBYTE(modreader); \ | ||
528 | _mm_read_UBYTE(modreader); \ | ||
529 | _mm_read_UBYTE(modreader); \ | ||
530 | _mm_read_UBYTE(modreader) | ||
531 | #endif | ||
532 | |||
533 | IMF_FinishLoadingEnvelope(vol); | ||
534 | IMF_FinishLoadingEnvelope(pan); | ||
535 | IMF_FinishLoadingEnvelope(pit); | ||
536 | |||
537 | ih.volfade=_mm_read_I_UWORD(modreader); | ||
538 | ih.numsmp =_mm_read_I_UWORD(modreader); | ||
539 | |||
540 | _mm_read_UBYTES(id,4,modreader); | ||
541 | /* Looks like Imago Orpheus forgets the signature for empty | ||
542 | instruments following a multi-sample instrument... */ | ||
543 | if(memcmp(id,"II10",4) && | ||
544 | (oldnumsmp && memcmp(id,"\x0\x0\x0\x0",4))) { | ||
545 | if(nextwav) MikMod_free(nextwav); | ||
546 | if(wh) MikMod_free(wh); | ||
547 | _mm_errno=MMERR_LOADING_SAMPLEINFO; | ||
548 | return 0; | ||
549 | } | ||
550 | oldnumsmp=ih.numsmp; | ||
551 | |||
552 | if((ih.numsmp>16)||(ih.volpts>IMFENVCNT/2)||(ih.panpts>IMFENVCNT/2)|| | ||
553 | (ih.pitpts>IMFENVCNT/2)||(_mm_eof(modreader))) { | ||
554 | if(nextwav) MikMod_free(nextwav); | ||
555 | if(wh) MikMod_free(wh); | ||
556 | _mm_errno=MMERR_LOADING_SAMPLEINFO; | ||
557 | return 0; | ||
558 | } | ||
559 | |||
560 | for(u=0;u<IMFNOTECNT;u++) | ||
561 | d->samplenumber[u]=ih.what[u]>ih.numsmp?0xffff:ih.what[u]+of.numsmp; | ||
562 | d->volfade=ih.volfade; | ||
563 | |||
564 | #if defined __STDC__ || defined _MSC_VER || defined MPW_C | ||
565 | #define IMF_ProcessEnvelope(name) \ | ||
566 | for (u = 0; u < (IMFENVCNT >> 1); u++) { \ | ||
567 | d-> name##env[u].pos = ih. name##env[u << 1]; \ | ||
568 | d-> name##env[u].val = ih. name##env[(u << 1)+ 1]; \ | ||
569 | } \ | ||
570 | if (ih. name##flg&1) d-> name##flg|=EF_ON; \ | ||
571 | if (ih. name##flg&2) d-> name##flg|=EF_SUSTAIN; \ | ||
572 | if (ih. name##flg&4) d-> name##flg|=EF_LOOP; \ | ||
573 | d-> name##susbeg=d-> name##susend=ih. name##sus; \ | ||
574 | d-> name##beg=ih. name##beg; \ | ||
575 | d-> name##end=ih. name##end; \ | ||
576 | d-> name##pts=ih. name##pts; \ | ||
577 | \ | ||
578 | if ((d-> name##flg&EF_ON)&&(d-> name##pts<2)) \ | ||
579 | d-> name##flg&=~EF_ON | ||
580 | #else | ||
581 | #define IMF_ProcessEnvelope(name) \ | ||
582 | for (u = 0; u < (IMFENVCNT >> 1); u++) { \ | ||
583 | d-> name/**/env[u].pos = ih. name/**/env[u << 1]; \ | ||
584 | d-> name/**/env[u].val = ih. name/**/env[(u << 1)+ 1]; \ | ||
585 | } \ | ||
586 | if (ih. name/**/flg&1) d-> name/**/flg|=EF_ON; \ | ||
587 | if (ih. name/**/flg&2) d-> name/**/flg|=EF_SUSTAIN; \ | ||
588 | if (ih. name/**/flg&4) d-> name/**/flg|=EF_LOOP; \ | ||
589 | d-> name/**/susbeg=d-> name/**/susend=ih. name/**/sus; \ | ||
590 | d-> name/**/beg=ih. name/**/beg; \ | ||
591 | d-> name/**/end=ih. name/**/end; \ | ||
592 | d-> name/**/pts=ih. name/**/pts; \ | ||
593 | \ | ||
594 | if ((d-> name/**/flg&EF_ON)&&(d-> name/**/pts<2)) \ | ||
595 | d-> name/**/flg&=~EF_ON | ||
596 | #endif | ||
597 | |||
598 | IMF_ProcessEnvelope(vol); | ||
599 | IMF_ProcessEnvelope(pan); | ||
600 | IMF_ProcessEnvelope(pit); | ||
601 | #undef IMF_ProcessEnvelope | ||
602 | |||
603 | if(ih.pitflg&1) { | ||
604 | d->pitflg&=~EF_ON; | ||
605 | #ifdef MIKMOD_DEBUG | ||
606 | fprintf(stderr, "\rFilter envelopes not supported yet\n"); | ||
607 | #endif | ||
608 | } | ||
609 | |||
610 | /* gather sample information */ | ||
611 | for(u=0;u<ih.numsmp;u++,s++) { | ||
612 | /* allocate more room for sample information if necessary */ | ||
613 | if(of.numsmp+u==wavcnt) { | ||
614 | wavcnt+=IMF_SMPINCR; | ||
615 | if(!(nextwav=MikMod_realloc(nextwav,wavcnt*sizeof(ULONG)))) { | ||
616 | if(wh) MikMod_free(wh); | ||
617 | _mm_errno=MMERR_OUT_OF_MEMORY; | ||
618 | return 0; | ||
619 | } | ||
620 | if(!(wh=MikMod_realloc(wh,wavcnt*sizeof(IMFWAVHEADER)))) { | ||
621 | MikMod_free(nextwav); | ||
622 | _mm_errno=MMERR_OUT_OF_MEMORY; | ||
623 | return 0; | ||
624 | } | ||
625 | s=wh+(wavcnt-IMF_SMPINCR); | ||
626 | } | ||
627 | |||
628 | _mm_read_string(s->samplename,13,modreader); | ||
629 | _mm_read_UBYTE(modreader);_mm_read_UBYTE(modreader);_mm_read_UBYTE(modreader); | ||
630 | s->length =_mm_read_I_ULONG(modreader); | ||
631 | s->loopstart =_mm_read_I_ULONG(modreader); | ||
632 | s->loopend =_mm_read_I_ULONG(modreader); | ||
633 | s->samplerate=_mm_read_I_ULONG(modreader); | ||
634 | s->volume =_mm_read_UBYTE(modreader)&0x7f; | ||
635 | s->pan =_mm_read_UBYTE(modreader); | ||
636 | _mm_fseek(modreader,14,SEEK_CUR); | ||
637 | s->flags =_mm_read_UBYTE(modreader); | ||
638 | _mm_fseek(modreader,11,SEEK_CUR); | ||
639 | _mm_read_UBYTES(id,4,modreader); | ||
640 | if(((memcmp(id,"IS10",4))&&(memcmp(id,"IW10",4)))|| | ||
641 | (_mm_eof(modreader))) { | ||
642 | MikMod_free(nextwav);MikMod_free(wh); | ||
643 | _mm_errno=MMERR_LOADING_SAMPLEINFO; | ||
644 | return 0; | ||
645 | } | ||
646 | nextwav[of.numsmp+u]=_mm_ftell(modreader); | ||
647 | _mm_fseek(modreader,s->length,SEEK_CUR); | ||
648 | } | ||
649 | |||
650 | of.numsmp+=ih.numsmp; | ||
651 | d++; | ||
652 | } | ||
653 | |||
654 | /* sanity check */ | ||
655 | if(!of.numsmp) { | ||
656 | if(nextwav) MikMod_free(nextwav); | ||
657 | if(wh) MikMod_free(wh); | ||
658 | _mm_errno=MMERR_LOADING_SAMPLEINFO; | ||
659 | return 0; | ||
660 | } | ||
661 | |||
662 | /* load samples */ | ||
663 | if(!AllocSamples()) { | ||
664 | MikMod_free(nextwav);MikMod_free(wh); | ||
665 | return 0; | ||
666 | } | ||
667 | if(!AllocLinear()) { | ||
668 | MikMod_free(nextwav);MikMod_free(wh); | ||
669 | return 0; | ||
670 | } | ||
671 | q=of.samples; | ||
672 | s=wh; | ||
673 | for(u=0;u<of.numsmp;u++,s++,q++) { | ||
674 | q->samplename=DupStr(s->samplename,12,1); | ||
675 | q->length =s->length; | ||
676 | q->loopstart=s->loopstart; | ||
677 | q->loopend =s->loopend; | ||
678 | q->volume =s->volume; | ||
679 | q->speed =s->samplerate; | ||
680 | if(of.flags&UF_LINEAR) | ||
681 | q->speed=speed_to_finetune(s->samplerate<<1,u); | ||
682 | q->panning =s->pan; | ||
683 | q->seekpos =nextwav[u]; | ||
684 | |||
685 | q->flags|=SF_SIGNED; | ||
686 | if(s->flags&0x1) q->flags|=SF_LOOP; | ||
687 | if(s->flags&0x2) q->flags|=SF_BIDI; | ||
688 | if(s->flags&0x8) q->flags|=SF_OWNPAN; | ||
689 | if(s->flags&0x4) { | ||
690 | q->flags|=SF_16BITS; | ||
691 | q->length >>=1; | ||
692 | q->loopstart>>=1; | ||
693 | q->loopend >>=1; | ||
694 | } | ||
695 | } | ||
696 | |||
697 | d=of.instruments; | ||
698 | s=wh; | ||
699 | for(u=0;u<of.numins;u++,d++) { | ||
700 | for(t=0;t<IMFNOTECNT;t++) { | ||
701 | if(d->samplenumber[t]>=of.numsmp) | ||
702 | d->samplenote[t]=255; | ||
703 | else if (of.flags&UF_LINEAR) { | ||
704 | int note=(int)d->samplenote[u]+noteindex[d->samplenumber[u]]; | ||
705 | d->samplenote[u]=(note<0)?0:(note>255?255:note); | ||
706 | } else | ||
707 | d->samplenote[t]=t; | ||
708 | } | ||
709 | } | ||
710 | |||
711 | MikMod_free(wh);MikMod_free(nextwav); | ||
712 | return 1; | ||
713 | } | ||
714 | |||
715 | CHAR *IMF_LoadTitle(void) | ||
716 | { | ||
717 | CHAR s[31]; | ||
718 | |||
719 | _mm_fseek(modreader,0,SEEK_SET); | ||
720 | if(!_mm_read_UBYTES(s,31,modreader)) return NULL; | ||
721 | |||
722 | return(DupStr(s,31,1)); | ||
723 | } | ||
724 | |||
725 | /*========== Loader information */ | ||
726 | |||
727 | MIKMODAPI MLOADER load_imf={ | ||
728 | NULL, | ||
729 | "IMF", | ||
730 | "IMF (Imago Orpheus)", | ||
731 | IMF_Init, | ||
732 | IMF_Test, | ||
733 | IMF_Load, | ||
734 | IMF_Cleanup, | ||
735 | IMF_LoadTitle | ||
736 | }; | ||
737 | |||
738 | /* ex:set ts=4: */ | ||
diff --git a/apps/plugins/mikmod/load_it.c b/apps/plugins/mikmod/load_it.c new file mode 100644 index 0000000000..6ce3a1ce65 --- /dev/null +++ b/apps/plugins/mikmod/load_it.c | |||
@@ -0,0 +1,1013 @@ | |||
1 | /* MikMod sound library | ||
2 | (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file | ||
3 | AUTHORS 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: load_it.c,v 1.4 2010/01/12 03:30:32 realtech Exp $ | ||
24 | |||
25 | Impulse tracker (IT) module loader | ||
26 | |||
27 | ==============================================================================*/ | ||
28 | |||
29 | #ifdef HAVE_CONFIG_H | ||
30 | #include "config.h" | ||
31 | #endif | ||
32 | |||
33 | #ifdef HAVE_UNISTD_H | ||
34 | #include <unistd.h> | ||
35 | #endif | ||
36 | |||
37 | #include <ctype.h> | ||
38 | #include <stdio.h> | ||
39 | #ifdef HAVE_MEMORY_H | ||
40 | #include <memory.h> | ||
41 | #endif | ||
42 | #include <string.h> | ||
43 | |||
44 | #include "mikmod_internals.h" | ||
45 | |||
46 | #ifdef SUNOS | ||
47 | extern int fprintf(FILE *, const char *, ...); | ||
48 | extern int toupper(int); | ||
49 | #endif | ||
50 | |||
51 | /*========== Module structure */ | ||
52 | |||
53 | /* header */ | ||
54 | typedef struct ITHEADER { | ||
55 | CHAR songname[26]; | ||
56 | UBYTE blank01[2]; | ||
57 | UWORD ordnum; | ||
58 | UWORD insnum; | ||
59 | UWORD smpnum; | ||
60 | UWORD patnum; | ||
61 | UWORD cwt; /* Created with tracker (y.xx = 0x0yxx) */ | ||
62 | UWORD cmwt; /* Compatible with tracker ver > than val. */ | ||
63 | UWORD flags; | ||
64 | UWORD special; /* bit 0 set = song message attached */ | ||
65 | UBYTE globvol; | ||
66 | UBYTE mixvol; /* mixing volume [ignored] */ | ||
67 | UBYTE initspeed; | ||
68 | UBYTE inittempo; | ||
69 | UBYTE pansep; /* panning separation between channels */ | ||
70 | UBYTE zerobyte; | ||
71 | UWORD msglength; | ||
72 | ULONG msgoffset; | ||
73 | UBYTE blank02[4]; | ||
74 | UBYTE pantable[64]; | ||
75 | UBYTE voltable[64]; | ||
76 | } ITHEADER; | ||
77 | |||
78 | /* sample information */ | ||
79 | typedef struct ITSAMPLE { | ||
80 | CHAR filename[12]; | ||
81 | UBYTE zerobyte; | ||
82 | UBYTE globvol; | ||
83 | UBYTE flag; | ||
84 | UBYTE volume; | ||
85 | UBYTE panning; | ||
86 | CHAR sampname[28]; | ||
87 | UWORD convert; /* sample conversion flag */ | ||
88 | ULONG length; | ||
89 | ULONG loopbeg; | ||
90 | ULONG loopend; | ||
91 | ULONG c5spd; | ||
92 | ULONG susbegin; | ||
93 | ULONG susend; | ||
94 | ULONG sampoffset; | ||
95 | UBYTE vibspeed; | ||
96 | UBYTE vibdepth; | ||
97 | UBYTE vibrate; | ||
98 | UBYTE vibwave; /* 0=sine, 1=rampdown, 2=square, 3=random (speed ignored) */ | ||
99 | } ITSAMPLE; | ||
100 | |||
101 | /* instrument information */ | ||
102 | |||
103 | #define ITENVCNT 25 | ||
104 | #define ITNOTECNT 120 | ||
105 | typedef struct ITINSTHEADER { | ||
106 | ULONG size; /* (dword) Instrument size */ | ||
107 | CHAR filename[12]; /* (char) Instrument filename */ | ||
108 | UBYTE zerobyte; /* (byte) Instrument type (always 0) */ | ||
109 | UBYTE volflg; | ||
110 | UBYTE volpts; | ||
111 | UBYTE volbeg; /* (byte) Volume loop start (node) */ | ||
112 | UBYTE volend; /* (byte) Volume loop end (node) */ | ||
113 | UBYTE volsusbeg; /* (byte) Volume sustain begin (node) */ | ||
114 | UBYTE volsusend; /* (byte) Volume Sustain end (node) */ | ||
115 | UBYTE panflg; | ||
116 | UBYTE panpts; | ||
117 | UBYTE panbeg; /* (byte) channel loop start (node) */ | ||
118 | UBYTE panend; /* (byte) channel loop end (node) */ | ||
119 | UBYTE pansusbeg; /* (byte) channel sustain begin (node) */ | ||
120 | UBYTE pansusend; /* (byte) channel Sustain end (node) */ | ||
121 | UBYTE pitflg; | ||
122 | UBYTE pitpts; | ||
123 | UBYTE pitbeg; /* (byte) pitch loop start (node) */ | ||
124 | UBYTE pitend; /* (byte) pitch loop end (node) */ | ||
125 | UBYTE pitsusbeg; /* (byte) pitch sustain begin (node) */ | ||
126 | UBYTE pitsusend; /* (byte) pitch Sustain end (node) */ | ||
127 | UWORD blank; | ||
128 | UBYTE globvol; | ||
129 | UBYTE chanpan; | ||
130 | UWORD fadeout; /* Envelope end / NNA volume fadeout */ | ||
131 | UBYTE dnc; /* Duplicate note check */ | ||
132 | UBYTE dca; /* Duplicate check action */ | ||
133 | UBYTE dct; /* Duplicate check type */ | ||
134 | UBYTE nna; /* New Note Action [0,1,2,3] */ | ||
135 | UWORD trkvers; /* tracker version used to save [files only] */ | ||
136 | UBYTE ppsep; /* Pitch-pan Separation */ | ||
137 | UBYTE ppcenter; /* Pitch-pan Center */ | ||
138 | UBYTE rvolvar; /* random volume varations */ | ||
139 | UBYTE rpanvar; /* random panning varations */ | ||
140 | UWORD numsmp; /* Number of samples in instrument [files only] */ | ||
141 | CHAR name[26]; /* Instrument name */ | ||
142 | UBYTE blank01[6]; | ||
143 | UWORD samptable[ITNOTECNT];/* sample for each note [note / samp pairs] */ | ||
144 | UBYTE volenv[200]; /* volume envelope (IT 1.x stuff) */ | ||
145 | UBYTE oldvoltick[ITENVCNT];/* volume tick position (IT 1.x stuff) */ | ||
146 | UBYTE volnode[ITENVCNT]; /* amplitude of volume nodes */ | ||
147 | UWORD voltick[ITENVCNT]; /* tick value of volume nodes */ | ||
148 | SBYTE pannode[ITENVCNT]; /* panenv - node points */ | ||
149 | UWORD pantick[ITENVCNT]; /* tick value of panning nodes */ | ||
150 | SBYTE pitnode[ITENVCNT]; /* pitchenv - node points */ | ||
151 | UWORD pittick[ITENVCNT]; /* tick value of pitch nodes */ | ||
152 | } ITINSTHEADER; | ||
153 | |||
154 | /* unpacked note */ | ||
155 | |||
156 | typedef struct ITNOTE { | ||
157 | UBYTE note,ins,volpan,cmd,inf; | ||
158 | } ITNOTE; | ||
159 | |||
160 | /*========== Loader data */ | ||
161 | |||
162 | static ULONG *paraptr=NULL; /* parapointer array (see IT docs) */ | ||
163 | static ITHEADER *mh=NULL; | ||
164 | static ITNOTE *itpat=NULL; /* allocate to space for one full pattern */ | ||
165 | static UBYTE *mask=NULL; /* arrays allocated to 64 elements and used for */ | ||
166 | static ITNOTE *last=NULL; /* uncompressing IT's pattern information */ | ||
167 | static int numtrk=0; | ||
168 | static unsigned int old_effect; /* if set, use S3M old-effects stuffs */ | ||
169 | |||
170 | static CHAR* IT_Version[]={ | ||
171 | "ImpulseTracker . ", | ||
172 | "Compressed ImpulseTracker . ", | ||
173 | "ImpulseTracker 2.14p3", | ||
174 | "Compressed ImpulseTracker 2.14p3", | ||
175 | "ImpulseTracker 2.14p4", | ||
176 | "Compressed ImpulseTracker 2.14p4", | ||
177 | }; | ||
178 | |||
179 | /* table for porta-to-note command within volume/panning column */ | ||
180 | static UBYTE portatable[10]= {0,1,4,8,16,32,64,96,128,255}; | ||
181 | |||
182 | /*========== Loader code */ | ||
183 | |||
184 | int IT_Test(void) | ||
185 | { | ||
186 | UBYTE id[4]; | ||
187 | |||
188 | if(!_mm_read_UBYTES(id,4,modreader)) return 0; | ||
189 | if(!memcmp(id,"IMPM",4)) return 1; | ||
190 | return 0; | ||
191 | } | ||
192 | |||
193 | int IT_Init(void) | ||
194 | { | ||
195 | if(!(mh=(ITHEADER*)MikMod_malloc(sizeof(ITHEADER)))) return 0; | ||
196 | if(!(poslookup=(UBYTE*)MikMod_malloc(256*sizeof(UBYTE)))) return 0; | ||
197 | if(!(itpat=(ITNOTE*)MikMod_malloc(200*64*sizeof(ITNOTE)))) return 0; | ||
198 | if(!(mask=(UBYTE*)MikMod_malloc(64*sizeof(UBYTE)))) return 0; | ||
199 | if(!(last=(ITNOTE*)MikMod_malloc(64*sizeof(ITNOTE)))) return 0; | ||
200 | |||
201 | return 1; | ||
202 | } | ||
203 | |||
204 | void IT_Cleanup(void) | ||
205 | { | ||
206 | FreeLinear(); | ||
207 | |||
208 | MikMod_free(mh); | ||
209 | MikMod_free(poslookup); | ||
210 | MikMod_free(itpat); | ||
211 | MikMod_free(mask); | ||
212 | MikMod_free(last); | ||
213 | MikMod_free(paraptr); | ||
214 | MikMod_free(origpositions); | ||
215 | } | ||
216 | |||
217 | /* Because so many IT files have 64 channels as the set number used, but really | ||
218 | only use far less (usually from 8 to 24 still), I had to make this function, | ||
219 | which determines the number of channels that are actually USED by a pattern. | ||
220 | |||
221 | NOTE: You must first seek to the file location of the pattern before calling | ||
222 | this procedure. | ||
223 | |||
224 | Returns 1 on error | ||
225 | */ | ||
226 | static int IT_GetNumChannels(UWORD patrows) | ||
227 | { | ||
228 | int row=0,flag,ch; | ||
229 | |||
230 | do { | ||
231 | if((flag=_mm_read_UBYTE(modreader))==EOF) { | ||
232 | _mm_errno=MMERR_LOADING_PATTERN; | ||
233 | return 1; | ||
234 | } | ||
235 | if(!flag) | ||
236 | row++; | ||
237 | else { | ||
238 | ch=(flag-1)&63; | ||
239 | remap[ch]=0; | ||
240 | if(flag & 128) mask[ch]=_mm_read_UBYTE(modreader); | ||
241 | if(mask[ch]&1) _mm_read_UBYTE(modreader); | ||
242 | if(mask[ch]&2) _mm_read_UBYTE(modreader); | ||
243 | if(mask[ch]&4) _mm_read_UBYTE(modreader); | ||
244 | if(mask[ch]&8) { _mm_read_UBYTE(modreader);_mm_read_UBYTE(modreader); } | ||
245 | } | ||
246 | } while(row<patrows); | ||
247 | |||
248 | return 0; | ||
249 | } | ||
250 | |||
251 | static UBYTE* IT_ConvertTrack(ITNOTE* tr,UWORD numrows) | ||
252 | { | ||
253 | int t; | ||
254 | UBYTE note,ins,volpan; | ||
255 | |||
256 | UniReset(); | ||
257 | |||
258 | for(t=0;t<numrows;t++) { | ||
259 | note=tr[t*of.numchn].note; | ||
260 | ins=tr[t*of.numchn].ins; | ||
261 | volpan=tr[t*of.numchn].volpan; | ||
262 | |||
263 | if(note!=255) { | ||
264 | if(note==253) | ||
265 | UniWriteByte(UNI_KEYOFF); | ||
266 | else if(note==254) { | ||
267 | UniPTEffect(0xc,-1); /* note cut command */ | ||
268 | volpan=255; | ||
269 | } else | ||
270 | UniNote(note); | ||
271 | } | ||
272 | |||
273 | if((ins)&&(ins<100)) | ||
274 | UniInstrument(ins-1); | ||
275 | else if(ins==253) | ||
276 | UniWriteByte(UNI_KEYOFF); | ||
277 | else if(ins!=255) { /* crap */ | ||
278 | _mm_errno=MMERR_LOADING_PATTERN; | ||
279 | return NULL; | ||
280 | } | ||
281 | |||
282 | /* process volume / panning column | ||
283 | volume / panning effects do NOT all share the same memory address | ||
284 | yet. */ | ||
285 | if(volpan<=64) | ||
286 | UniVolEffect(VOL_VOLUME,volpan); | ||
287 | else if(volpan==65) /* fine volume slide up (65-74) - A0 case */ | ||
288 | UniVolEffect(VOL_VOLSLIDE,0); | ||
289 | else if(volpan<=74) { /* fine volume slide up (65-74) - general case */ | ||
290 | UniVolEffect(VOL_VOLSLIDE,0x0f+((volpan-65)<<4)); | ||
291 | } else if(volpan==75) /* fine volume slide down (75-84) - B0 case */ | ||
292 | UniVolEffect(VOL_VOLSLIDE,0); | ||
293 | else if(volpan<=84) { /* fine volume slide down (75-84) - general case*/ | ||
294 | UniVolEffect(VOL_VOLSLIDE,0xf0+(volpan-75)); | ||
295 | } else if(volpan<=94) /* volume slide up (85-94) */ | ||
296 | UniVolEffect(VOL_VOLSLIDE,((volpan-85)<<4)); | ||
297 | else if(volpan<=104)/* volume slide down (95-104) */ | ||
298 | UniVolEffect(VOL_VOLSLIDE,(volpan-95)); | ||
299 | else if(volpan<=114)/* pitch slide down (105-114) */ | ||
300 | UniVolEffect(VOL_PITCHSLIDEDN,(volpan-105)); | ||
301 | else if(volpan<=124)/* pitch slide up (115-124) */ | ||
302 | UniVolEffect(VOL_PITCHSLIDEUP,(volpan-115)); | ||
303 | else if(volpan<=127) { /* crap */ | ||
304 | _mm_errno=MMERR_LOADING_PATTERN; | ||
305 | return NULL; | ||
306 | } else if(volpan<=192) | ||
307 | UniVolEffect(VOL_PANNING,((volpan-128)==64)?255:((volpan-128)<<2)); | ||
308 | else if(volpan<=202)/* portamento to note */ | ||
309 | UniVolEffect(VOL_PORTAMENTO,portatable[volpan-193]); | ||
310 | else if(volpan<=212)/* vibrato */ | ||
311 | UniVolEffect(VOL_VIBRATO,(volpan-203)); | ||
312 | else if((volpan!=239)&&(volpan!=255)) { /* crap */ | ||
313 | _mm_errno=MMERR_LOADING_PATTERN; | ||
314 | return NULL; | ||
315 | } | ||
316 | |||
317 | S3MIT_ProcessCmd(tr[t*of.numchn].cmd,tr[t*of.numchn].inf, | ||
318 | old_effect|S3MIT_IT); | ||
319 | |||
320 | UniNewline(); | ||
321 | } | ||
322 | return UniDup(); | ||
323 | } | ||
324 | |||
325 | static int IT_ReadPattern(UWORD patrows) | ||
326 | { | ||
327 | int row=0,flag,ch,blah; | ||
328 | ITNOTE *itt=itpat,dummy,*n,*l; | ||
329 | |||
330 | memset(itt,255,200*64*sizeof(ITNOTE)); | ||
331 | |||
332 | do { | ||
333 | if((flag=_mm_read_UBYTE(modreader))==EOF) { | ||
334 | _mm_errno = MMERR_LOADING_PATTERN; | ||
335 | return 0; | ||
336 | } | ||
337 | if(!flag) { | ||
338 | itt=&itt[of.numchn]; | ||
339 | row++; | ||
340 | } else { | ||
341 | ch=remap[(flag-1)&63]; | ||
342 | if(ch!=-1) { | ||
343 | n=&itt[ch]; | ||
344 | l=&last[ch]; | ||
345 | } else | ||
346 | n=l=&dummy; | ||
347 | |||
348 | if(flag&128) mask[ch]=_mm_read_UBYTE(modreader); | ||
349 | if(mask[ch]&1) | ||
350 | /* convert IT note off to internal note off */ | ||
351 | if((l->note=n->note=_mm_read_UBYTE(modreader))==255) | ||
352 | l->note=n->note=253; | ||
353 | if(mask[ch]&2) | ||
354 | l->ins=n->ins=_mm_read_UBYTE(modreader); | ||
355 | if(mask[ch]&4) | ||
356 | l->volpan=n->volpan=_mm_read_UBYTE(modreader); | ||
357 | if(mask[ch]&8) { | ||
358 | l->cmd=n->cmd=_mm_read_UBYTE(modreader); | ||
359 | l->inf=n->inf=_mm_read_UBYTE(modreader); | ||
360 | } | ||
361 | if(mask[ch]&16) | ||
362 | n->note=l->note; | ||
363 | if(mask[ch]&32) | ||
364 | n->ins=l->ins; | ||
365 | if(mask[ch]&64) | ||
366 | n->volpan=l->volpan; | ||
367 | if(mask[ch]&128) { | ||
368 | n->cmd=l->cmd; | ||
369 | n->inf=l->inf; | ||
370 | } | ||
371 | } | ||
372 | } while(row<patrows); | ||
373 | |||
374 | for(blah=0;blah<of.numchn;blah++) { | ||
375 | if(!(of.tracks[numtrk++]=IT_ConvertTrack(&itpat[blah],patrows))) | ||
376 | return 0; | ||
377 | } | ||
378 | |||
379 | return 1; | ||
380 | } | ||
381 | |||
382 | static void LoadMidiString(MREADER* modreader,CHAR* dest) | ||
383 | { | ||
384 | CHAR *cur,*last; | ||
385 | |||
386 | _mm_read_UBYTES(dest,32,modreader); | ||
387 | cur=last=dest; | ||
388 | /* remove blanks and uppercase all */ | ||
389 | while(*last) { | ||
390 | if(isalnum((int)*last)) *(cur++)=toupper((int)*last); | ||
391 | last++; | ||
392 | } | ||
393 | *cur=0; | ||
394 | } | ||
395 | |||
396 | /* Load embedded midi information for resonant filters */ | ||
397 | static void IT_LoadMidiConfiguration(MREADER* modreader) | ||
398 | { | ||
399 | int i; | ||
400 | |||
401 | memset(filtermacros,0,sizeof(filtermacros)); | ||
402 | memset(filtersettings,0,sizeof(filtersettings)); | ||
403 | |||
404 | if (modreader) { /* information is embedded in file */ | ||
405 | UWORD dat; | ||
406 | CHAR midiline[33]; | ||
407 | |||
408 | dat=_mm_read_I_UWORD(modreader); | ||
409 | _mm_fseek(modreader,8*dat+0x120,SEEK_CUR); | ||
410 | |||
411 | /* read midi macros */ | ||
412 | for(i=0;i<UF_MAXMACRO;i++) { | ||
413 | LoadMidiString(modreader,midiline); | ||
414 | if((!strncmp(midiline,"F0F00",5))&& | ||
415 | ((midiline[5]=='0')||(midiline[5]=='1'))) | ||
416 | filtermacros[i]=(midiline[5]-'0')|0x80; | ||
417 | } | ||
418 | |||
419 | /* read standalone filters */ | ||
420 | for(i=0x80;i<0x100;i++) { | ||
421 | LoadMidiString(modreader,midiline); | ||
422 | if((!strncmp(midiline,"F0F00",5))&& | ||
423 | ((midiline[5]=='0')||(midiline[5]=='1'))) { | ||
424 | filtersettings[i].filter=(midiline[5]-'0')|0x80; | ||
425 | dat=(midiline[6])?(midiline[6]-'0'):0; | ||
426 | if(midiline[7])dat=(dat<<4)|(midiline[7]-'0'); | ||
427 | filtersettings[i].inf=dat; | ||
428 | } | ||
429 | } | ||
430 | } else { /* use default information */ | ||
431 | filtermacros[0]=FILT_CUT; | ||
432 | for(i=0x80;i<0x90;i++) { | ||
433 | filtersettings[i].filter=FILT_RESONANT; | ||
434 | filtersettings[i].inf=(i&0x7f)<<3; | ||
435 | } | ||
436 | } | ||
437 | activemacro=0; | ||
438 | for(i=0;i<0x80;i++) { | ||
439 | filtersettings[i].filter=filtermacros[0]; | ||
440 | filtersettings[i].inf=i; | ||
441 | } | ||
442 | } | ||
443 | |||
444 | int IT_Load(int curious) | ||
445 | { | ||
446 | int t,u,lp; | ||
447 | INSTRUMENT *d; | ||
448 | SAMPLE *q; | ||
449 | int compressed=0; | ||
450 | |||
451 | numtrk=0; | ||
452 | filters=0; | ||
453 | |||
454 | /* try to read module header */ | ||
455 | _mm_read_I_ULONG(modreader); /* kill the 4 byte header */ | ||
456 | _mm_read_string(mh->songname,26,modreader); | ||
457 | _mm_read_UBYTES(mh->blank01,2,modreader); | ||
458 | mh->ordnum =_mm_read_I_UWORD(modreader); | ||
459 | mh->insnum =_mm_read_I_UWORD(modreader); | ||
460 | mh->smpnum =_mm_read_I_UWORD(modreader); | ||
461 | mh->patnum =_mm_read_I_UWORD(modreader); | ||
462 | mh->cwt =_mm_read_I_UWORD(modreader); | ||
463 | mh->cmwt =_mm_read_I_UWORD(modreader); | ||
464 | mh->flags =_mm_read_I_UWORD(modreader); | ||
465 | mh->special =_mm_read_I_UWORD(modreader); | ||
466 | mh->globvol =_mm_read_UBYTE(modreader); | ||
467 | mh->mixvol =_mm_read_UBYTE(modreader); | ||
468 | mh->initspeed =_mm_read_UBYTE(modreader); | ||
469 | mh->inittempo =_mm_read_UBYTE(modreader); | ||
470 | mh->pansep =_mm_read_UBYTE(modreader); | ||
471 | mh->zerobyte =_mm_read_UBYTE(modreader); | ||
472 | mh->msglength =_mm_read_I_UWORD(modreader); | ||
473 | mh->msgoffset =_mm_read_I_ULONG(modreader); | ||
474 | _mm_read_UBYTES(mh->blank02,4,modreader); | ||
475 | _mm_read_UBYTES(mh->pantable,64,modreader); | ||
476 | _mm_read_UBYTES(mh->voltable,64,modreader); | ||
477 | |||
478 | if(_mm_eof(modreader)) { | ||
479 | _mm_errno=MMERR_LOADING_HEADER; | ||
480 | return 0; | ||
481 | } | ||
482 | |||
483 | /* set module variables */ | ||
484 | of.songname = DupStr(mh->songname,26,0); /* make a cstr of songname */ | ||
485 | of.reppos = 0; | ||
486 | of.numpat = mh->patnum; | ||
487 | of.numins = mh->insnum; | ||
488 | of.numsmp = mh->smpnum; | ||
489 | of.initspeed = mh->initspeed; | ||
490 | of.inittempo = mh->inittempo; | ||
491 | of.initvolume = mh->globvol; | ||
492 | of.flags |= UF_BGSLIDES | UF_ARPMEM; | ||
493 | if (!(mh->flags & 1)) | ||
494 | of.flags |= UF_PANNING; | ||
495 | of.bpmlimit=32; | ||
496 | |||
497 | if(mh->songname[25]) { | ||
498 | of.numvoices=1+mh->songname[25]; | ||
499 | #ifdef MIKMOD_DEBUG | ||
500 | fprintf(stderr,"Embedded IT limitation to %d voices\n",of.numvoices); | ||
501 | #endif | ||
502 | } | ||
503 | |||
504 | /* set the module type */ | ||
505 | /* 2.17 : IT 2.14p4 */ | ||
506 | /* 2.16 : IT 2.14p3 with resonant filters */ | ||
507 | /* 2.15 : IT 2.14p3 (improved compression) */ | ||
508 | if((mh->cwt<=0x219)&&(mh->cwt>=0x217)) | ||
509 | of.modtype=StrDup(IT_Version[mh->cmwt<0x214?4:5]); | ||
510 | else if (mh->cwt>=0x215) | ||
511 | of.modtype=StrDup(IT_Version[mh->cmwt<0x214?2:3]); | ||
512 | else { | ||
513 | of.modtype = StrDup(IT_Version[mh->cmwt<0x214?0:1]); | ||
514 | of.modtype[mh->cmwt<0x214?15:26] = (mh->cwt>>8)+'0'; | ||
515 | of.modtype[mh->cmwt<0x214?17:28] = ((mh->cwt>>4)&0xf)+'0'; | ||
516 | of.modtype[mh->cmwt<0x214?18:29] = ((mh->cwt)&0xf)+'0'; | ||
517 | } | ||
518 | |||
519 | if(mh->flags&8) | ||
520 | of.flags |= UF_XMPERIODS | UF_LINEAR; | ||
521 | |||
522 | if((mh->cwt>=0x106)&&(mh->flags&16)) | ||
523 | old_effect=S3MIT_OLDSTYLE; | ||
524 | else | ||
525 | old_effect=0; | ||
526 | |||
527 | /* set panning positions */ | ||
528 | if (mh->flags & 1) | ||
529 | for(t=0;t<64;t++) { | ||
530 | mh->pantable[t]&=0x7f; | ||
531 | if(mh->pantable[t]<64) | ||
532 | of.panning[t]=mh->pantable[t]<<2; | ||
533 | else if(mh->pantable[t]==64) | ||
534 | of.panning[t]=255; | ||
535 | else if(mh->pantable[t]==100) | ||
536 | of.panning[t]=PAN_SURROUND; | ||
537 | else if(mh->pantable[t]==127) | ||
538 | of.panning[t]=PAN_CENTER; | ||
539 | else { | ||
540 | _mm_errno=MMERR_LOADING_HEADER; | ||
541 | return 0; | ||
542 | } | ||
543 | } | ||
544 | else | ||
545 | for(t=0;t<64;t++) | ||
546 | of.panning[t]=PAN_CENTER; | ||
547 | |||
548 | /* set channel volumes */ | ||
549 | memcpy(of.chanvol,mh->voltable,64); | ||
550 | |||
551 | /* read the order data */ | ||
552 | if(!AllocPositions(mh->ordnum)) return 0; | ||
553 | if(!(origpositions=MikMod_calloc(mh->ordnum,sizeof(UWORD)))) return 0; | ||
554 | |||
555 | for(t=0;t<mh->ordnum;t++) { | ||
556 | origpositions[t]=_mm_read_UBYTE(modreader); | ||
557 | if((origpositions[t]>mh->patnum)&&(origpositions[t]<254)) | ||
558 | origpositions[t]=255; | ||
559 | } | ||
560 | |||
561 | if(_mm_eof(modreader)) { | ||
562 | _mm_errno = MMERR_LOADING_HEADER; | ||
563 | return 0; | ||
564 | } | ||
565 | |||
566 | poslookupcnt=mh->ordnum; | ||
567 | S3MIT_CreateOrders(curious); | ||
568 | |||
569 | if(!(paraptr=(ULONG*)MikMod_malloc((mh->insnum+mh->smpnum+of.numpat)* | ||
570 | sizeof(ULONG)))) return 0; | ||
571 | |||
572 | /* read the instrument, sample, and pattern parapointers */ | ||
573 | _mm_read_I_ULONGS(paraptr,mh->insnum+mh->smpnum+of.numpat,modreader); | ||
574 | |||
575 | if(_mm_eof(modreader)) { | ||
576 | _mm_errno = MMERR_LOADING_HEADER; | ||
577 | return 0; | ||
578 | } | ||
579 | |||
580 | /* Check for and load midi information for resonant filters */ | ||
581 | if(mh->cmwt>=0x216) { | ||
582 | if(mh->special&8) { | ||
583 | IT_LoadMidiConfiguration(modreader); | ||
584 | if(_mm_eof(modreader)) { | ||
585 | _mm_errno = MMERR_LOADING_HEADER; | ||
586 | return 0; | ||
587 | } | ||
588 | } else | ||
589 | IT_LoadMidiConfiguration(NULL); | ||
590 | filters=1; | ||
591 | } | ||
592 | |||
593 | /* Check for and load song comment */ | ||
594 | if((mh->special&1)&&(mh->cwt>=0x104)&&(mh->msglength)) { | ||
595 | _mm_fseek(modreader,(long)(mh->msgoffset),SEEK_SET); | ||
596 | if(!ReadComment(mh->msglength)) return 0; | ||
597 | } | ||
598 | |||
599 | if(!(mh->flags&4)) of.numins=of.numsmp; | ||
600 | if(!AllocSamples()) return 0; | ||
601 | |||
602 | if(!AllocLinear()) return 0; | ||
603 | |||
604 | /* Load all samples */ | ||
605 | q = of.samples; | ||
606 | for(t=0;t<mh->smpnum;t++) { | ||
607 | ITSAMPLE s; | ||
608 | |||
609 | /* seek to sample position */ | ||
610 | _mm_fseek(modreader,(long)(paraptr[mh->insnum+t]+4),SEEK_SET); | ||
611 | |||
612 | /* load sample info */ | ||
613 | _mm_read_string(s.filename,12,modreader); | ||
614 | s.zerobyte = _mm_read_UBYTE(modreader); | ||
615 | s.globvol = _mm_read_UBYTE(modreader); | ||
616 | s.flag = _mm_read_UBYTE(modreader); | ||
617 | s.volume = _mm_read_UBYTE(modreader); | ||
618 | _mm_read_string(s.sampname,26,modreader); | ||
619 | s.convert = _mm_read_UBYTE(modreader); | ||
620 | s.panning = _mm_read_UBYTE(modreader); | ||
621 | s.length = _mm_read_I_ULONG(modreader); | ||
622 | s.loopbeg = _mm_read_I_ULONG(modreader); | ||
623 | s.loopend = _mm_read_I_ULONG(modreader); | ||
624 | s.c5spd = _mm_read_I_ULONG(modreader); | ||
625 | s.susbegin = _mm_read_I_ULONG(modreader); | ||
626 | s.susend = _mm_read_I_ULONG(modreader); | ||
627 | s.sampoffset = _mm_read_I_ULONG(modreader); | ||
628 | s.vibspeed = _mm_read_UBYTE(modreader); | ||
629 | s.vibdepth = _mm_read_UBYTE(modreader); | ||
630 | s.vibrate = _mm_read_UBYTE(modreader); | ||
631 | s.vibwave = _mm_read_UBYTE(modreader); | ||
632 | |||
633 | /* Generate an error if c5spd is > 512k, or samplelength > 256 megs | ||
634 | (nothing would EVER be that high) */ | ||
635 | |||
636 | if(_mm_eof(modreader)||(s.c5spd>0x7ffffL)||(s.length>0xfffffffUL)) { | ||
637 | _mm_errno = MMERR_LOADING_SAMPLEINFO; | ||
638 | return 0; | ||
639 | } | ||
640 | |||
641 | /* Reality check for sample loop information */ | ||
642 | if((s.flag&16)&& | ||
643 | ((s.loopbeg>0xfffffffUL)||(s.loopend>0xfffffffUL))) { | ||
644 | _mm_errno = MMERR_LOADING_SAMPLEINFO; | ||
645 | return 0; | ||
646 | } | ||
647 | |||
648 | q->samplename = DupStr(s.sampname,26,0); | ||
649 | q->speed = s.c5spd / 2; | ||
650 | q->panning = ((s.panning&127)==64)?255:(s.panning&127)<<2; | ||
651 | q->length = s.length; | ||
652 | q->loopstart = s.loopbeg; | ||
653 | q->loopend = s.loopend; | ||
654 | q->volume = s.volume; | ||
655 | q->globvol = s.globvol; | ||
656 | q->seekpos = s.sampoffset; | ||
657 | |||
658 | /* Convert speed to XM linear finetune */ | ||
659 | if(of.flags&UF_LINEAR) | ||
660 | q->speed=speed_to_finetune(s.c5spd,t); | ||
661 | |||
662 | if(s.panning&128) q->flags|=SF_OWNPAN; | ||
663 | |||
664 | if(s.vibrate) { | ||
665 | q->vibflags |= AV_IT; | ||
666 | q->vibtype = s.vibwave; | ||
667 | q->vibsweep = s.vibrate * 2; | ||
668 | q->vibdepth = s.vibdepth; | ||
669 | q->vibrate = s.vibspeed; | ||
670 | } | ||
671 | |||
672 | if(s.flag&2) q->flags|=SF_16BITS; | ||
673 | if((s.flag&8)&&(mh->cwt>=0x214)) { | ||
674 | q->flags|=SF_ITPACKED; | ||
675 | compressed=1; | ||
676 | } | ||
677 | if(s.flag&16) q->flags|=SF_LOOP; | ||
678 | if(s.flag&64) q->flags|=SF_BIDI; | ||
679 | |||
680 | if(mh->cwt>=0x200) { | ||
681 | if(s.convert&1) q->flags|=SF_SIGNED; | ||
682 | if(s.convert&4) q->flags|=SF_DELTA; | ||
683 | } | ||
684 | q++; | ||
685 | } | ||
686 | |||
687 | /* Load instruments if instrument mode flag enabled */ | ||
688 | if(mh->flags&4) { | ||
689 | if(!AllocInstruments()) return 0; | ||
690 | d=of.instruments; | ||
691 | of.flags|=UF_NNA|UF_INST; | ||
692 | |||
693 | for(t=0;t<mh->insnum;t++) { | ||
694 | ITINSTHEADER ih; | ||
695 | |||
696 | /* seek to instrument position */ | ||
697 | _mm_fseek(modreader,paraptr[t]+4,SEEK_SET); | ||
698 | |||
699 | /* load instrument info */ | ||
700 | _mm_read_string(ih.filename,12,modreader); | ||
701 | ih.zerobyte = _mm_read_UBYTE(modreader); | ||
702 | if(mh->cwt<0x200) { | ||
703 | /* load IT 1.xx inst header */ | ||
704 | ih.volflg = _mm_read_UBYTE(modreader); | ||
705 | ih.volbeg = _mm_read_UBYTE(modreader); | ||
706 | ih.volend = _mm_read_UBYTE(modreader); | ||
707 | ih.volsusbeg = _mm_read_UBYTE(modreader); | ||
708 | ih.volsusend = _mm_read_UBYTE(modreader); | ||
709 | _mm_read_I_UWORD(modreader); | ||
710 | ih.fadeout = _mm_read_I_UWORD(modreader); | ||
711 | ih.nna = _mm_read_UBYTE(modreader); | ||
712 | ih.dnc = _mm_read_UBYTE(modreader); | ||
713 | } else { | ||
714 | /* Read IT200+ header */ | ||
715 | ih.nna = _mm_read_UBYTE(modreader); | ||
716 | ih.dct = _mm_read_UBYTE(modreader); | ||
717 | ih.dca = _mm_read_UBYTE(modreader); | ||
718 | ih.fadeout = _mm_read_I_UWORD(modreader); | ||
719 | ih.ppsep = _mm_read_UBYTE(modreader); | ||
720 | ih.ppcenter = _mm_read_UBYTE(modreader); | ||
721 | ih.globvol = _mm_read_UBYTE(modreader); | ||
722 | ih.chanpan = _mm_read_UBYTE(modreader); | ||
723 | ih.rvolvar = _mm_read_UBYTE(modreader); | ||
724 | ih.rpanvar = _mm_read_UBYTE(modreader); | ||
725 | } | ||
726 | |||
727 | ih.trkvers = _mm_read_I_UWORD(modreader); | ||
728 | ih.numsmp = _mm_read_UBYTE(modreader); | ||
729 | _mm_read_UBYTE(modreader); | ||
730 | _mm_read_string(ih.name,26,modreader); | ||
731 | _mm_read_UBYTES(ih.blank01,6,modreader); | ||
732 | _mm_read_I_UWORDS(ih.samptable,ITNOTECNT,modreader); | ||
733 | if(mh->cwt<0x200) { | ||
734 | /* load IT 1xx volume envelope */ | ||
735 | _mm_read_UBYTES(ih.volenv,200,modreader); | ||
736 | for(lp=0;lp<ITENVCNT;lp++) { | ||
737 | ih.oldvoltick[lp] = _mm_read_UBYTE(modreader); | ||
738 | ih.volnode[lp] = _mm_read_UBYTE(modreader); | ||
739 | } | ||
740 | } else { | ||
741 | /* load IT 2xx volume, pan and pitch envelopes */ | ||
742 | #if defined __STDC__ || defined _MSC_VER || defined MPW_C | ||
743 | #define IT_LoadEnvelope(name,type) \ | ||
744 | ih. name##flg =_mm_read_UBYTE(modreader); \ | ||
745 | ih. name##pts =_mm_read_UBYTE(modreader); \ | ||
746 | ih. name##beg =_mm_read_UBYTE(modreader); \ | ||
747 | ih. name##end =_mm_read_UBYTE(modreader); \ | ||
748 | ih. name##susbeg=_mm_read_UBYTE(modreader); \ | ||
749 | ih. name##susend=_mm_read_UBYTE(modreader); \ | ||
750 | for(lp=0;lp<ITENVCNT;lp++) { \ | ||
751 | ih. name##node[lp]=_mm_read_##type (modreader); \ | ||
752 | ih. name##tick[lp]=_mm_read_I_UWORD(modreader); \ | ||
753 | } \ | ||
754 | _mm_read_UBYTE(modreader) | ||
755 | #else | ||
756 | #define IT_LoadEnvelope(name,type) \ | ||
757 | ih. name/**/flg =_mm_read_UBYTE(modreader); \ | ||
758 | ih. name/**/pts =_mm_read_UBYTE(modreader); \ | ||
759 | ih. name/**/beg =_mm_read_UBYTE(modreader); \ | ||
760 | ih. name/**/end =_mm_read_UBYTE(modreader); \ | ||
761 | ih. name/**/susbeg=_mm_read_UBYTE(modreader); \ | ||
762 | ih. name/**/susend=_mm_read_UBYTE(modreader); \ | ||
763 | for(lp=0;lp<ITENVCNT;lp++) { \ | ||
764 | ih. name/**/node[lp]=_mm_read_/**/type (modreader); \ | ||
765 | ih. name/**/tick[lp]=_mm_read_I_UWORD(modreader); \ | ||
766 | } \ | ||
767 | _mm_read_UBYTE(modreader) | ||
768 | #endif | ||
769 | |||
770 | IT_LoadEnvelope(vol,UBYTE); | ||
771 | IT_LoadEnvelope(pan,SBYTE); | ||
772 | IT_LoadEnvelope(pit,SBYTE); | ||
773 | #undef IT_LoadEnvelope | ||
774 | } | ||
775 | |||
776 | if(_mm_eof(modreader)) { | ||
777 | _mm_errno = MMERR_LOADING_SAMPLEINFO; | ||
778 | return 0; | ||
779 | } | ||
780 | |||
781 | d->volflg|=EF_VOLENV; | ||
782 | d->insname = DupStr(ih.name,26,0); | ||
783 | d->nnatype = ih.nna & NNA_MASK; | ||
784 | |||
785 | if(mh->cwt<0x200) { | ||
786 | d->volfade=ih.fadeout<< 6; | ||
787 | if(ih.dnc) { | ||
788 | d->dct=DCT_NOTE; | ||
789 | d->dca=DCA_CUT; | ||
790 | } | ||
791 | |||
792 | if(ih.volflg&1) d->volflg|=EF_ON; | ||
793 | if(ih.volflg&2) d->volflg|=EF_LOOP; | ||
794 | if(ih.volflg&4) d->volflg|=EF_SUSTAIN; | ||
795 | |||
796 | /* XM conversion of IT envelope Array */ | ||
797 | d->volbeg = ih.volbeg; | ||
798 | d->volend = ih.volend; | ||
799 | d->volsusbeg = ih.volsusbeg; | ||
800 | d->volsusend = ih.volsusend; | ||
801 | |||
802 | if(ih.volflg&1) { | ||
803 | for(u=0;u<ITENVCNT;u++) | ||
804 | if(ih.oldvoltick[d->volpts]!=0xff) { | ||
805 | d->volenv[d->volpts].val=(ih.volnode[d->volpts]<<2); | ||
806 | d->volenv[d->volpts].pos=ih.oldvoltick[d->volpts]; | ||
807 | d->volpts++; | ||
808 | } else | ||
809 | break; | ||
810 | } | ||
811 | } else { | ||
812 | d->panning=((ih.chanpan&127)==64)?255:(ih.chanpan&127)<<2; | ||
813 | if(!(ih.chanpan&128)) d->flags|=IF_OWNPAN; | ||
814 | |||
815 | if(!(ih.ppsep & 128)) { | ||
816 | d->pitpansep=ih.ppsep<<2; | ||
817 | d->pitpancenter=ih.ppcenter; | ||
818 | d->flags|=IF_PITCHPAN; | ||
819 | } | ||
820 | d->globvol=ih.globvol>>1; | ||
821 | d->volfade=ih.fadeout<<5; | ||
822 | d->dct =ih.dct; | ||
823 | d->dca =ih.dca; | ||
824 | |||
825 | if(mh->cwt>=0x204) { | ||
826 | d->rvolvar = ih.rvolvar; | ||
827 | d->rpanvar = ih.rpanvar; | ||
828 | } | ||
829 | |||
830 | #if defined __STDC__ || defined _MSC_VER || defined MPW_C | ||
831 | #define IT_ProcessEnvelope(name) \ | ||
832 | if(ih. name##flg&1) d-> name##flg|=EF_ON; \ | ||
833 | if(ih. name##flg&2) d-> name##flg|=EF_LOOP; \ | ||
834 | if(ih. name##flg&4) d-> name##flg|=EF_SUSTAIN; \ | ||
835 | d-> name##pts=ih. name##pts; \ | ||
836 | d-> name##beg=ih. name##beg; \ | ||
837 | d-> name##end=ih. name##end; \ | ||
838 | d-> name##susbeg=ih. name##susbeg; \ | ||
839 | d-> name##susend=ih. name##susend; \ | ||
840 | \ | ||
841 | for(u=0;u<ih. name##pts;u++) \ | ||
842 | d-> name##env[u].pos=ih. name##tick[u]; \ | ||
843 | \ | ||
844 | if((d-> name##flg&EF_ON)&&(d-> name##pts<2)) \ | ||
845 | d-> name##flg&=~EF_ON | ||
846 | #else | ||
847 | #define IT_ProcessEnvelope(name) \ | ||
848 | if(ih. name/**/flg&1) d-> name/**/flg|=EF_ON; \ | ||
849 | if(ih. name/**/flg&2) d-> name/**/flg|=EF_LOOP; \ | ||
850 | if(ih. name/**/flg&4) d-> name/**/flg|=EF_SUSTAIN; \ | ||
851 | d-> name/**/pts=ih. name/**/pts; \ | ||
852 | d-> name/**/beg=ih. name/**/beg; \ | ||
853 | d-> name/**/end=ih. name/**/end; \ | ||
854 | d-> name/**/susbeg=ih. name/**/susbeg; \ | ||
855 | d-> name/**/susend=ih. name/**/susend; \ | ||
856 | \ | ||
857 | for(u=0;u<ih. name/**/pts;u++) \ | ||
858 | d-> name/**/env[u].pos=ih. name/**/tick[u]; \ | ||
859 | \ | ||
860 | if((d-> name/**/flg&EF_ON)&&(d-> name/**/pts<2)) \ | ||
861 | d-> name/**/flg&=~EF_ON | ||
862 | #endif | ||
863 | |||
864 | IT_ProcessEnvelope(vol); | ||
865 | |||
866 | // Secunia SA37775 | ||
867 | if (ih.volpts>= ENVPOINTS) | ||
868 | ih.volpts = ENVPOINTS-1; | ||
869 | |||
870 | for(u=0;u<ih.volpts;u++) | ||
871 | d->volenv[u].val=(ih.volnode[u]<<2); | ||
872 | |||
873 | IT_ProcessEnvelope(pan); | ||
874 | for(u=0;u<ih.panpts;u++) | ||
875 | d->panenv[u].val= | ||
876 | ih.pannode[u]==32?255:(ih.pannode[u]+32)<<2; | ||
877 | |||
878 | IT_ProcessEnvelope(pit); | ||
879 | for(u=0;u<ih.pitpts;u++) | ||
880 | d->pitenv[u].val=ih.pitnode[u]+32; | ||
881 | #undef IT_ProcessEnvelope | ||
882 | |||
883 | if(ih.pitflg&0x80) { | ||
884 | /* filter envelopes not supported yet */ | ||
885 | d->pitflg&=~EF_ON; | ||
886 | ih.pitpts=ih.pitbeg=ih.pitend=0; | ||
887 | #ifdef MIKMOD_DEBUG | ||
888 | { | ||
889 | static int warn=0; | ||
890 | |||
891 | if(!warn) | ||
892 | fprintf(stderr, "\rFilter envelopes not supported yet\n"); | ||
893 | warn=1; | ||
894 | } | ||
895 | #endif | ||
896 | } | ||
897 | } | ||
898 | |||
899 | for(u=0;u<ITNOTECNT;u++) { | ||
900 | d->samplenote[u]=(ih.samptable[u]&255); | ||
901 | d->samplenumber[u]= | ||
902 | (ih.samptable[u]>>8)?((ih.samptable[u]>>8)-1):0xffff; | ||
903 | if(d->samplenumber[u]>=of.numsmp) | ||
904 | d->samplenote[u]=255; | ||
905 | else if (of.flags&UF_LINEAR) { | ||
906 | int note=(int)d->samplenote[u]+noteindex[d->samplenumber[u]]; | ||
907 | d->samplenote[u]=(note<0)?0:(note>255?255:note); | ||
908 | } | ||
909 | } | ||
910 | |||
911 | d++; | ||
912 | } | ||
913 | } else if(of.flags & UF_LINEAR) { | ||
914 | if(!AllocInstruments()) return 0; | ||
915 | d=of.instruments; | ||
916 | of.flags|=UF_INST; | ||
917 | |||
918 | for(t=0;t<mh->smpnum;t++,d++) | ||
919 | for(u=0;u<ITNOTECNT;u++) { | ||
920 | if(d->samplenumber[u]>=of.numsmp) | ||
921 | d->samplenote[u]=255; | ||
922 | else { | ||
923 | int note=(int)d->samplenote[u]+noteindex[d->samplenumber[u]]; | ||
924 | d->samplenote[u]=(note<0)?0:(note>255?255:note); | ||
925 | } | ||
926 | } | ||
927 | } | ||
928 | |||
929 | /* Figure out how many channels this song actually uses */ | ||
930 | of.numchn=0; | ||
931 | memset(remap,-1,UF_MAXCHAN*sizeof(UBYTE)); | ||
932 | for(t=0;t<of.numpat;t++) { | ||
933 | UWORD packlen; | ||
934 | |||
935 | /* seek to pattern position */ | ||
936 | if(paraptr[mh->insnum+mh->smpnum+t]) { /* 0 -> empty 64 row pattern */ | ||
937 | _mm_fseek(modreader,((long)paraptr[mh->insnum+mh->smpnum+t]),SEEK_SET); | ||
938 | _mm_read_I_UWORD(modreader); | ||
939 | /* read pattern length (# of rows) | ||
940 | Impulse Tracker never creates patterns with less than 32 rows, | ||
941 | but some other trackers do, so we only check for more than 256 | ||
942 | rows */ | ||
943 | packlen=_mm_read_I_UWORD(modreader); | ||
944 | if(packlen>256) { | ||
945 | _mm_errno=MMERR_LOADING_PATTERN; | ||
946 | return 0; | ||
947 | } | ||
948 | _mm_read_I_ULONG(modreader); | ||
949 | if(IT_GetNumChannels(packlen)) return 0; | ||
950 | } | ||
951 | } | ||
952 | |||
953 | /* give each of them a different number */ | ||
954 | for(t=0;t<UF_MAXCHAN;t++) | ||
955 | if(!remap[t]) | ||
956 | remap[t]=of.numchn++; | ||
957 | |||
958 | of.numtrk = of.numpat*of.numchn; | ||
959 | if(of.numvoices) | ||
960 | if (of.numvoices<of.numchn) of.numvoices=of.numchn; | ||
961 | |||
962 | if(!AllocPatterns()) return 0; | ||
963 | if(!AllocTracks()) return 0; | ||
964 | |||
965 | for(t=0;t<of.numpat;t++) { | ||
966 | UWORD packlen; | ||
967 | |||
968 | /* seek to pattern position */ | ||
969 | if(!paraptr[mh->insnum+mh->smpnum+t]) { /* 0 -> empty 64 row pattern */ | ||
970 | of.pattrows[t]=64; | ||
971 | for(u=0;u<of.numchn;u++) { | ||
972 | int k; | ||
973 | |||
974 | UniReset(); | ||
975 | for(k=0;k<64;k++) UniNewline(); | ||
976 | of.tracks[numtrk++]=UniDup(); | ||
977 | } | ||
978 | } else { | ||
979 | _mm_fseek(modreader,((long)paraptr[mh->insnum+mh->smpnum+t]),SEEK_SET); | ||
980 | packlen=_mm_read_I_UWORD(modreader); | ||
981 | of.pattrows[t]=_mm_read_I_UWORD(modreader); | ||
982 | _mm_read_I_ULONG(modreader); | ||
983 | if(!IT_ReadPattern(of.pattrows[t])) return 0; | ||
984 | } | ||
985 | } | ||
986 | |||
987 | return 1; | ||
988 | } | ||
989 | |||
990 | CHAR *IT_LoadTitle(void) | ||
991 | { | ||
992 | CHAR s[26]; | ||
993 | |||
994 | _mm_fseek(modreader,4,SEEK_SET); | ||
995 | if(!_mm_read_UBYTES(s,26,modreader)) return NULL; | ||
996 | |||
997 | return(DupStr(s,26,0)); | ||
998 | } | ||
999 | |||
1000 | /*========== Loader information */ | ||
1001 | |||
1002 | MIKMODAPI MLOADER load_it={ | ||
1003 | NULL, | ||
1004 | "IT", | ||
1005 | "IT (Impulse Tracker)", | ||
1006 | IT_Init, | ||
1007 | IT_Test, | ||
1008 | IT_Load, | ||
1009 | IT_Cleanup, | ||
1010 | IT_LoadTitle | ||
1011 | }; | ||
1012 | |||
1013 | /* ex:set ts=4: */ | ||
diff --git a/apps/plugins/mikmod/load_m15.c b/apps/plugins/mikmod/load_m15.c new file mode 100644 index 0000000000..d97378aab3 --- /dev/null +++ b/apps/plugins/mikmod/load_m15.c | |||
@@ -0,0 +1,505 @@ | |||
1 | /* MikMod sound library | ||
2 | (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file | ||
3 | AUTHORS 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: load_m15.c,v 1.3 2005/04/07 19:57:38 realtech Exp $ | ||
24 | |||
25 | 15 instrument MOD loader | ||
26 | Also supports Ultimate Sound Tracker (old M15 format) | ||
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 <ctype.h> | ||
39 | #include <stdio.h> | ||
40 | #ifdef HAVE_MEMORY_H | ||
41 | #include <memory.h> | ||
42 | #endif | ||
43 | #include <string.h> | ||
44 | |||
45 | #include "mikmod_internals.h" | ||
46 | |||
47 | #ifdef SUNOS | ||
48 | extern int fprintf(FILE *, const char *, ...); | ||
49 | #endif | ||
50 | |||
51 | /*========== Module Structure */ | ||
52 | |||
53 | typedef struct MSAMPINFO { | ||
54 | CHAR samplename[23]; /* 22 in module, 23 in memory */ | ||
55 | UWORD length; | ||
56 | UBYTE finetune; | ||
57 | UBYTE volume; | ||
58 | UWORD reppos; | ||
59 | UWORD replen; | ||
60 | } MSAMPINFO; | ||
61 | |||
62 | typedef struct MODULEHEADER { | ||
63 | CHAR songname[21]; /* the songname.., 20 in module, 21 in memory */ | ||
64 | MSAMPINFO samples[15]; /* all sampleinfo */ | ||
65 | UBYTE songlength; /* number of patterns used */ | ||
66 | UBYTE magic1; /* should be 127 */ | ||
67 | UBYTE positions[128]; /* which pattern to play at pos */ | ||
68 | } MODULEHEADER; | ||
69 | |||
70 | typedef struct MODNOTE { | ||
71 | UBYTE a,b,c,d; | ||
72 | } MODNOTE; | ||
73 | |||
74 | /*========== Loader variables */ | ||
75 | |||
76 | static MODULEHEADER *mh = NULL; | ||
77 | static MODNOTE *patbuf = NULL; | ||
78 | static int ust_loader = 0; /* if TRUE, load as an ust module. */ | ||
79 | |||
80 | /* known file formats which can confuse the loader */ | ||
81 | #define REJECT 2 | ||
82 | static char *signatures[REJECT]={ | ||
83 | "CAKEWALK", /* cakewalk midi files */ | ||
84 | "SZDD" /* Microsoft compressed files */ | ||
85 | }; | ||
86 | static int siglen[REJECT]={8,4}; | ||
87 | |||
88 | /*========== Loader code */ | ||
89 | |||
90 | static int LoadModuleHeader(MODULEHEADER *mh) | ||
91 | { | ||
92 | int t,u; | ||
93 | |||
94 | _mm_read_string(mh->songname,20,modreader); | ||
95 | mh->songname[20]=0; /* just in case */ | ||
96 | |||
97 | /* sanity check : title should contain printable characters and a bunch | ||
98 | of null chars */ | ||
99 | for(t=0;t<20;t++) | ||
100 | if((mh->songname[t])&&(mh->songname[t]<32)) return 0; | ||
101 | for(t=0;(mh->songname[t])&&(t<20);t++); | ||
102 | if(t<20) for(;t<20;t++) if(mh->songname[t]) return 0; | ||
103 | |||
104 | for(t=0;t<15;t++) { | ||
105 | MSAMPINFO *s=&mh->samples[t]; | ||
106 | |||
107 | _mm_read_string(s->samplename,22,modreader); | ||
108 | s->samplename[22]=0; /* just in case */ | ||
109 | s->length =_mm_read_M_UWORD(modreader); | ||
110 | s->finetune =_mm_read_UBYTE(modreader); | ||
111 | s->volume =_mm_read_UBYTE(modreader); | ||
112 | s->reppos =_mm_read_M_UWORD(modreader); | ||
113 | s->replen =_mm_read_M_UWORD(modreader); | ||
114 | |||
115 | /* sanity check : sample title should contain printable characters and | ||
116 | a bunch of null chars */ | ||
117 | for(u=0;u<20;u++) | ||
118 | if((s->samplename[u])&&(s->samplename[u]</*32*/14)) return 0; | ||
119 | for(u=0;(s->samplename[u])&&(u<20);u++); | ||
120 | if(u<20) for(;u<20;u++) if(s->samplename[u]) return 0; | ||
121 | |||
122 | /* sanity check : finetune values */ | ||
123 | if(s->finetune>>4) return 0; | ||
124 | } | ||
125 | |||
126 | mh->songlength =_mm_read_UBYTE(modreader); | ||
127 | mh->magic1 =_mm_read_UBYTE(modreader); /* should be 127 */ | ||
128 | |||
129 | /* sanity check : no more than 128 positions, restart position in range */ | ||
130 | if((!mh->songlength)||(mh->songlength>128)) return 0; | ||
131 | /* values encountered so far are 0x6a and 0x78 */ | ||
132 | if(((mh->magic1&0xf8)!=0x78)&&(mh->magic1!=0x6a)&&(mh->magic1>mh->songlength)) return 0; | ||
133 | |||
134 | _mm_read_UBYTES(mh->positions,128,modreader); | ||
135 | |||
136 | /* sanity check : pattern range is 0..63 */ | ||
137 | for(t=0;t<128;t++) | ||
138 | if(mh->positions[t]>63) return 0; | ||
139 | |||
140 | return(!_mm_eof(modreader)); | ||
141 | } | ||
142 | |||
143 | /* Checks the patterns in the modfile for UST / 15-inst indications. | ||
144 | For example, if an effect 3xx is found, it is assumed that the song | ||
145 | is 15-inst. If a 1xx effect has dat greater than 0x20, it is UST. | ||
146 | |||
147 | Returns: 0 indecisive; 1 = UST; 2 = 15-inst */ | ||
148 | static int CheckPatternType(int numpat) | ||
149 | { | ||
150 | int t; | ||
151 | UBYTE eff, dat; | ||
152 | |||
153 | for(t=0;t<numpat*(64U*4);t++) { | ||
154 | /* Load the pattern into the temp buffer and scan it */ | ||
155 | _mm_read_UBYTE(modreader);_mm_read_UBYTE(modreader); | ||
156 | eff = _mm_read_UBYTE(modreader); | ||
157 | dat = _mm_read_UBYTE(modreader); | ||
158 | |||
159 | switch(eff) { | ||
160 | case 1: | ||
161 | if(dat>0x1f) return 1; | ||
162 | if(dat<0x3) return 2; | ||
163 | break; | ||
164 | case 2: | ||
165 | if(dat>0x1f) return 1; | ||
166 | return 2; | ||
167 | case 3: | ||
168 | if (dat) return 2; | ||
169 | break; | ||
170 | default: | ||
171 | return 2; | ||
172 | } | ||
173 | } | ||
174 | return 0; | ||
175 | } | ||
176 | |||
177 | static int M15_Test(void) | ||
178 | { | ||
179 | int t, numpat; | ||
180 | MODULEHEADER mh; | ||
181 | |||
182 | ust_loader = 0; | ||
183 | if(!LoadModuleHeader(&mh)) return 0; | ||
184 | |||
185 | /* reject other file types */ | ||
186 | for(t=0;t<REJECT;t++) | ||
187 | if(!memcmp(mh.songname,signatures[t],siglen[t])) return 0; | ||
188 | |||
189 | if(mh.magic1>127) return 0; | ||
190 | if((!mh.songlength)||(mh.songlength>mh.magic1)) return 0; | ||
191 | |||
192 | for(t=0;t<15;t++) { | ||
193 | /* all finetunes should be zero */ | ||
194 | if(mh.samples[t].finetune) return 0; | ||
195 | |||
196 | /* all volumes should be <= 64 */ | ||
197 | if(mh.samples[t].volume>64) return 0; | ||
198 | |||
199 | /* all instrument names should begin with s, st-, or a number */ | ||
200 | if((mh.samples[t].samplename[0]=='s')|| | ||
201 | (mh.samples[t].samplename[0]=='S')) { | ||
202 | if((memcmp(mh.samples[t].samplename,"st-",3)) && | ||
203 | (memcmp(mh.samples[t].samplename,"ST-",3)) && | ||
204 | (*mh.samples[t].samplename)) | ||
205 | ust_loader = 1; | ||
206 | } else | ||
207 | if(!isdigit((int)mh.samples[t].samplename[0])) | ||
208 | ust_loader = 1; | ||
209 | |||
210 | if(mh.samples[t].length>4999||mh.samples[t].reppos>9999) { | ||
211 | ust_loader = 0; | ||
212 | if(mh.samples[t].length>32768) return 0; | ||
213 | } | ||
214 | |||
215 | /* if loop information is incorrect as words, but correct as bytes, | ||
216 | this is likely to be an ust-style module */ | ||
217 | if((mh.samples[t].reppos+mh.samples[t].replen>mh.samples[t].length)&& | ||
218 | (mh.samples[t].reppos+mh.samples[t].replen<(mh.samples[t].length<<1))){ | ||
219 | ust_loader = 1; | ||
220 | return 1; | ||
221 | } | ||
222 | |||
223 | if(!ust_loader) return 1; | ||
224 | } | ||
225 | |||
226 | for(numpat=0,t=0;t<mh.songlength;t++) | ||
227 | if(mh.positions[t]>numpat) | ||
228 | numpat = mh.positions[t]; | ||
229 | numpat++; | ||
230 | switch(CheckPatternType(numpat)) { | ||
231 | case 0: /* indecisive, so check more clues... */ | ||
232 | break; | ||
233 | case 1: | ||
234 | ust_loader = 1; | ||
235 | break; | ||
236 | case 2: | ||
237 | ust_loader = 0; | ||
238 | break; | ||
239 | } | ||
240 | return 1; | ||
241 | } | ||
242 | |||
243 | static int M15_Init(void) | ||
244 | { | ||
245 | if(!(mh=(MODULEHEADER*)MikMod_malloc(sizeof(MODULEHEADER)))) return 0; | ||
246 | return 1; | ||
247 | } | ||
248 | |||
249 | static void M15_Cleanup(void) | ||
250 | { | ||
251 | MikMod_free(mh); | ||
252 | MikMod_free(patbuf); | ||
253 | } | ||
254 | |||
255 | /* | ||
256 | Old (amiga) noteinfo: | ||
257 | |||
258 | _____byte 1_____ byte2_ _____byte 3_____ byte4_ | ||
259 | / \ / \ / \ / \ | ||
260 | 0000 0000-00000000 0000 0000-00000000 | ||
261 | |||
262 | Upper four 12 bits for Lower four Effect command. | ||
263 | bits of sam- note period. bits of sam- | ||
264 | ple number. ple number. | ||
265 | */ | ||
266 | |||
267 | static UBYTE M15_ConvertNote(MODNOTE* n, UBYTE lasteffect) | ||
268 | { | ||
269 | UBYTE instrument,effect,effdat,note; | ||
270 | UWORD period; | ||
271 | UBYTE lastnote=0; | ||
272 | |||
273 | /* decode the 4 bytes that make up a single note */ | ||
274 | instrument = n->c>>4; | ||
275 | period = (((UWORD)n->a&0xf)<<8)+n->b; | ||
276 | effect = n->c&0xf; | ||
277 | effdat = n->d; | ||
278 | |||
279 | /* Convert the period to a note number */ | ||
280 | note=0; | ||
281 | if(period) { | ||
282 | for(note=0;note<7*OCTAVE;note++) | ||
283 | if(period>=npertab[note]) break; | ||
284 | if(note==7*OCTAVE) note=0; | ||
285 | else note++; | ||
286 | } | ||
287 | |||
288 | if(instrument) { | ||
289 | /* if instrument does not exist, note cut */ | ||
290 | if((instrument>15)||(!mh->samples[instrument-1].length)) { | ||
291 | UniPTEffect(0xc,0); | ||
292 | if(effect==0xc) effect=effdat=0; | ||
293 | } else { | ||
294 | /* if we had a note, then change instrument... */ | ||
295 | if(note) | ||
296 | UniInstrument(instrument-1); | ||
297 | /* ...otherwise, only adjust volume... */ | ||
298 | else { | ||
299 | /* ...unless an effect was specified, which forces a new note | ||
300 | to be played */ | ||
301 | if(effect||effdat) { | ||
302 | UniInstrument(instrument-1); | ||
303 | note=lastnote; | ||
304 | } else | ||
305 | UniPTEffect(0xc,mh->samples[instrument-1].volume&0x7f); | ||
306 | } | ||
307 | } | ||
308 | } | ||
309 | if(note) { | ||
310 | UniNote(note+2*OCTAVE-1); | ||
311 | lastnote=note; | ||
312 | } | ||
313 | |||
314 | /* Convert pattern jump from Dec to Hex */ | ||
315 | if(effect == 0xd) | ||
316 | effdat=(((effdat&0xf0)>>4)*10)+(effdat&0xf); | ||
317 | |||
318 | /* Volume slide, up has priority */ | ||
319 | if((effect==0xa)&&(effdat&0xf)&&(effdat&0xf0)) | ||
320 | effdat&=0xf0; | ||
321 | |||
322 | /* Handle ``heavy'' volumes correctly */ | ||
323 | if ((effect == 0xc) && (effdat > 0x40)) | ||
324 | effdat = 0x40; | ||
325 | |||
326 | if(ust_loader) { | ||
327 | switch(effect) { | ||
328 | case 0: | ||
329 | case 3: | ||
330 | break; | ||
331 | case 1: | ||
332 | UniPTEffect(0,effdat); | ||
333 | break; | ||
334 | case 2: | ||
335 | if(effdat&0xf) UniPTEffect(1,effdat&0xf); | ||
336 | else if(effdat>>2) UniPTEffect(2,effdat>>2); | ||
337 | break; | ||
338 | default: | ||
339 | UniPTEffect(effect,effdat); | ||
340 | break; | ||
341 | } | ||
342 | } else { | ||
343 | /* An isolated 100, 200 or 300 effect should be ignored (no | ||
344 | "standalone" porta memory in mod files). However, a sequence | ||
345 | such as 1XX, 100, 100, 100 is fine. */ | ||
346 | if ((!effdat) && ((effect == 1)||(effect == 2)||(effect ==3)) && | ||
347 | (lasteffect < 0x10) && (effect != lasteffect)) | ||
348 | effect = 0; | ||
349 | |||
350 | UniPTEffect(effect,effdat); | ||
351 | } | ||
352 | if (effect == 8) | ||
353 | of.flags |= UF_PANNING; | ||
354 | |||
355 | return effect; | ||
356 | } | ||
357 | |||
358 | static UBYTE *M15_ConvertTrack(MODNOTE* n) | ||
359 | { | ||
360 | int t; | ||
361 | UBYTE lasteffect = 0x10; /* non existant effect */ | ||
362 | |||
363 | UniReset(); | ||
364 | for(t=0;t<64;t++) { | ||
365 | lasteffect = M15_ConvertNote(n,lasteffect); | ||
366 | UniNewline(); | ||
367 | n+=4; | ||
368 | } | ||
369 | return UniDup(); | ||
370 | } | ||
371 | |||
372 | /* Loads all patterns of a modfile and converts them into the 3 byte format. */ | ||
373 | static int M15_LoadPatterns(void) | ||
374 | { | ||
375 | int t,s,tracks=0; | ||
376 | |||
377 | if(!AllocPatterns()) return 0; | ||
378 | if(!AllocTracks()) return 0; | ||
379 | |||
380 | /* Allocate temporary buffer for loading and converting the patterns */ | ||
381 | if(!(patbuf=(MODNOTE*)MikMod_calloc(64U*4,sizeof(MODNOTE)))) return 0; | ||
382 | |||
383 | for(t=0;t<of.numpat;t++) { | ||
384 | /* Load the pattern into the temp buffer and convert it */ | ||
385 | for(s=0;s<(64U*4);s++) { | ||
386 | patbuf[s].a=_mm_read_UBYTE(modreader); | ||
387 | patbuf[s].b=_mm_read_UBYTE(modreader); | ||
388 | patbuf[s].c=_mm_read_UBYTE(modreader); | ||
389 | patbuf[s].d=_mm_read_UBYTE(modreader); | ||
390 | } | ||
391 | |||
392 | for(s=0;s<4;s++) | ||
393 | if(!(of.tracks[tracks++]=M15_ConvertTrack(patbuf+s))) return 0; | ||
394 | } | ||
395 | return 1; | ||
396 | } | ||
397 | |||
398 | static int M15_Load(int curious) | ||
399 | { | ||
400 | int t,scan; | ||
401 | SAMPLE *q; | ||
402 | MSAMPINFO *s; | ||
403 | |||
404 | /* try to read module header */ | ||
405 | if(!LoadModuleHeader(mh)) { | ||
406 | _mm_errno = MMERR_LOADING_HEADER; | ||
407 | return 0; | ||
408 | } | ||
409 | |||
410 | if(ust_loader) | ||
411 | of.modtype = StrDup("Ultimate Soundtracker"); | ||
412 | else | ||
413 | of.modtype = StrDup("Soundtracker"); | ||
414 | |||
415 | /* set module variables */ | ||
416 | of.initspeed = 6; | ||
417 | of.inittempo = 125; | ||
418 | of.numchn = 4; | ||
419 | of.songname = DupStr(mh->songname,21,1); | ||
420 | of.numpos = mh->songlength; | ||
421 | of.reppos = 0; | ||
422 | |||
423 | /* Count the number of patterns */ | ||
424 | of.numpat = 0; | ||
425 | for(t=0;t<of.numpos;t++) | ||
426 | if(mh->positions[t]>of.numpat) | ||
427 | of.numpat=mh->positions[t]; | ||
428 | /* since some old modules embed extra patterns, we have to check the | ||
429 | whole list to get the samples' file offsets right - however we can find | ||
430 | garbage here, so check carefully */ | ||
431 | scan=1; | ||
432 | for(t=of.numpos;t<128;t++) | ||
433 | if(mh->positions[t]>=0x80) scan=0; | ||
434 | if (scan) | ||
435 | for(t=of.numpos;t<128;t++) { | ||
436 | if(mh->positions[t]>of.numpat) | ||
437 | of.numpat=mh->positions[t]; | ||
438 | if((curious)&&(mh->positions[t])) of.numpos=t+1; | ||
439 | } | ||
440 | of.numpat++; | ||
441 | of.numtrk = of.numpat*of.numchn; | ||
442 | |||
443 | if(!AllocPositions(of.numpos)) return 0; | ||
444 | for(t=0;t<of.numpos;t++) | ||
445 | of.positions[t]=mh->positions[t]; | ||
446 | |||
447 | /* Finally, init the sampleinfo structures */ | ||
448 | of.numins=of.numsmp=15; | ||
449 | if(!AllocSamples()) return 0; | ||
450 | |||
451 | s = mh->samples; | ||
452 | q = of.samples; | ||
453 | |||
454 | for(t=0;t<of.numins;t++) { | ||
455 | /* convert the samplename */ | ||
456 | q->samplename = DupStr(s->samplename,23,1); | ||
457 | |||
458 | /* init the sampleinfo variables and convert the size pointers */ | ||
459 | q->speed = finetune[s->finetune&0xf]; | ||
460 | q->volume = s->volume; | ||
461 | if(ust_loader) | ||
462 | q->loopstart = s->reppos; | ||
463 | else | ||
464 | q->loopstart = s->reppos<<1; | ||
465 | q->loopend = q->loopstart+(s->replen<<1); | ||
466 | q->length = s->length<<1; | ||
467 | |||
468 | q->flags = SF_SIGNED; | ||
469 | if(ust_loader) q->flags |= SF_UST_LOOP; | ||
470 | if(s->replen>2) q->flags |= SF_LOOP; | ||
471 | |||
472 | s++; | ||
473 | q++; | ||
474 | } | ||
475 | |||
476 | if(!M15_LoadPatterns()) return 0; | ||
477 | ust_loader = 0; | ||
478 | |||
479 | return 1; | ||
480 | } | ||
481 | |||
482 | static CHAR *M15_LoadTitle(void) | ||
483 | { | ||
484 | CHAR s[21]; | ||
485 | |||
486 | _mm_fseek(modreader,0,SEEK_SET); | ||
487 | if(!_mm_read_UBYTES(s,20,modreader)) return NULL; | ||
488 | s[20]=0; /* just in case */ | ||
489 | return(DupStr(s,21,1)); | ||
490 | } | ||
491 | |||
492 | /*========== Loader information */ | ||
493 | |||
494 | MIKMODAPI MLOADER load_m15={ | ||
495 | NULL, | ||
496 | "15-instrument module", | ||
497 | "MOD (15 instrument)", | ||
498 | M15_Init, | ||
499 | M15_Test, | ||
500 | M15_Load, | ||
501 | M15_Cleanup, | ||
502 | M15_LoadTitle | ||
503 | }; | ||
504 | |||
505 | /* ex:set ts=4: */ | ||
diff --git a/apps/plugins/mikmod/load_med.c b/apps/plugins/mikmod/load_med.c new file mode 100644 index 0000000000..21a85b39a0 --- /dev/null +++ b/apps/plugins/mikmod/load_med.c | |||
@@ -0,0 +1,719 @@ | |||
1 | /* MikMod sound library | ||
2 | (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file | ||
3 | AUTHORS 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: load_med.c,v 1.3 2005/04/07 19:57:38 realtech Exp $ | ||
24 | |||
25 | Amiga MED module loader | ||
26 | |||
27 | ==============================================================================*/ | ||
28 | |||
29 | #ifdef HAVE_CONFIG_H | ||
30 | #include "config.h" | ||
31 | #endif | ||
32 | |||
33 | #ifdef HAVE_UNISTD_H | ||
34 | #include <unistd.h> | ||
35 | #endif | ||
36 | |||
37 | #include <stdio.h> | ||
38 | #ifdef HAVE_MEMORY_H | ||
39 | #include <memory.h> | ||
40 | #endif | ||
41 | #include <string.h> | ||
42 | |||
43 | #include "mikmod_internals.h" | ||
44 | |||
45 | #ifdef SUNOS | ||
46 | extern int fprintf(FILE *, const char *, ...); | ||
47 | #endif | ||
48 | |||
49 | /*========== Module information */ | ||
50 | |||
51 | typedef struct MEDHEADER { | ||
52 | ULONG id; | ||
53 | ULONG modlen; | ||
54 | ULONG MEDSONGP; /* struct MEDSONG *song; */ | ||
55 | UWORD psecnum; /* for the player routine, MMD2 only */ | ||
56 | UWORD pseq; /* " " " " */ | ||
57 | ULONG MEDBlockPP; /* struct MEDBlock **blockarr; */ | ||
58 | ULONG reserved1; | ||
59 | ULONG MEDINSTHEADERPP; /* struct MEDINSTHEADER **smplarr; */ | ||
60 | ULONG reserved2; | ||
61 | ULONG MEDEXPP; /* struct MEDEXP *expdata; */ | ||
62 | ULONG reserved3; | ||
63 | UWORD pstate; /* some data for the player routine */ | ||
64 | UWORD pblock; | ||
65 | UWORD pline; | ||
66 | UWORD pseqnum; | ||
67 | SWORD actplayline; | ||
68 | UBYTE counter; | ||
69 | UBYTE extra_songs; /* number of songs - 1 */ | ||
70 | } MEDHEADER; | ||
71 | |||
72 | typedef struct MEDSAMPLE { | ||
73 | UWORD rep, replen; /* offs: 0(s), 2(s) */ | ||
74 | UBYTE midich; /* offs: 4(s) */ | ||
75 | UBYTE midipreset; /* offs: 5(s) */ | ||
76 | UBYTE svol; /* offs: 6(s) */ | ||
77 | SBYTE strans; /* offs: 7(s) */ | ||
78 | } MEDSAMPLE; | ||
79 | |||
80 | typedef struct MEDSONG { | ||
81 | MEDSAMPLE sample[63]; /* 63 * 8 bytes = 504 bytes */ | ||
82 | UWORD numblocks; /* offs: 504 */ | ||
83 | UWORD songlen; /* offs: 506 */ | ||
84 | UBYTE playseq[256]; /* offs: 508 */ | ||
85 | UWORD deftempo; /* offs: 764 */ | ||
86 | SBYTE playtransp; /* offs: 766 */ | ||
87 | UBYTE flags; /* offs: 767 */ | ||
88 | UBYTE flags2; /* offs: 768 */ | ||
89 | UBYTE tempo2; /* offs: 769 */ | ||
90 | UBYTE trkvol[16]; /* offs: 770 */ | ||
91 | UBYTE mastervol; /* offs: 786 */ | ||
92 | UBYTE numsamples; /* offs: 787 */ | ||
93 | } MEDSONG; | ||
94 | |||
95 | typedef struct MEDEXP { | ||
96 | ULONG nextmod; /* pointer to next module */ | ||
97 | ULONG exp_smp; /* pointer to MEDINSTEXT array */ | ||
98 | UWORD s_ext_entries; | ||
99 | UWORD s_ext_entrsz; | ||
100 | ULONG annotxt; /* pointer to annotation text */ | ||
101 | ULONG annolen; | ||
102 | ULONG iinfo; /* pointer to MEDINSTINFO array */ | ||
103 | UWORD i_ext_entries; | ||
104 | UWORD i_ext_entrsz; | ||
105 | ULONG jumpmask; | ||
106 | ULONG rgbtable; | ||
107 | ULONG channelsplit; | ||
108 | ULONG n_info; | ||
109 | ULONG songname; /* pointer to songname */ | ||
110 | ULONG songnamelen; | ||
111 | ULONG dumps; | ||
112 | ULONG reserved2[7]; | ||
113 | } MEDEXP; | ||
114 | |||
115 | typedef struct MMD0NOTE { | ||
116 | UBYTE a, b, c; | ||
117 | } MMD0NOTE; | ||
118 | |||
119 | typedef struct MMD1NOTE { | ||
120 | UBYTE a, b, c, d; | ||
121 | } MMD1NOTE; | ||
122 | |||
123 | typedef struct MEDINSTHEADER { | ||
124 | ULONG length; | ||
125 | SWORD type; | ||
126 | /* Followed by actual data */ | ||
127 | } MEDINSTHEADER; | ||
128 | |||
129 | typedef struct MEDINSTEXT { | ||
130 | UBYTE hold; | ||
131 | UBYTE decay; | ||
132 | UBYTE suppress_midi_off; | ||
133 | SBYTE finetune; | ||
134 | } MEDINSTEXT; | ||
135 | |||
136 | typedef struct MEDINSTINFO { | ||
137 | UBYTE name[40]; | ||
138 | } MEDINSTINFO; | ||
139 | |||
140 | /*========== Loader variables */ | ||
141 | |||
142 | #define MMD0_string 0x4D4D4430 | ||
143 | #define MMD1_string 0x4D4D4431 | ||
144 | |||
145 | static MEDHEADER *mh = NULL; | ||
146 | static MEDSONG *ms = NULL; | ||
147 | static MEDEXP *me = NULL; | ||
148 | static ULONG *ba = NULL; | ||
149 | static MMD0NOTE *mmd0pat = NULL; | ||
150 | static MMD1NOTE *mmd1pat = NULL; | ||
151 | |||
152 | static int decimalvolumes; | ||
153 | static int bpmtempos; | ||
154 | |||
155 | #define d0note(row,col) mmd0pat[((row)*(UWORD)of.numchn)+(col)] | ||
156 | #define d1note(row,col) mmd1pat[((row)*(UWORD)of.numchn)+(col)] | ||
157 | |||
158 | static CHAR MED_Version[] = "OctaMED (MMDx)"; | ||
159 | |||
160 | /*========== Loader code */ | ||
161 | |||
162 | int MED_Test(void) | ||
163 | { | ||
164 | UBYTE id[4]; | ||
165 | |||
166 | if (!_mm_read_UBYTES(id, 4, modreader)) | ||
167 | return 0; | ||
168 | if ((!memcmp(id, "MMD0", 4)) || (!memcmp(id, "MMD1", 4))) | ||
169 | return 1; | ||
170 | return 0; | ||
171 | } | ||
172 | |||
173 | int MED_Init(void) | ||
174 | { | ||
175 | if (!(me = (MEDEXP *)MikMod_malloc(sizeof(MEDEXP)))) | ||
176 | return 0; | ||
177 | if (!(mh = (MEDHEADER *)MikMod_malloc(sizeof(MEDHEADER)))) | ||
178 | return 0; | ||
179 | if (!(ms = (MEDSONG *)MikMod_malloc(sizeof(MEDSONG)))) | ||
180 | return 0; | ||
181 | return 1; | ||
182 | } | ||
183 | |||
184 | void MED_Cleanup(void) | ||
185 | { | ||
186 | MikMod_free(me); | ||
187 | MikMod_free(mh); | ||
188 | MikMod_free(ms); | ||
189 | MikMod_free(ba); | ||
190 | MikMod_free(mmd0pat); | ||
191 | MikMod_free(mmd1pat); | ||
192 | } | ||
193 | |||
194 | static void EffectCvt(UBYTE eff, UBYTE dat) | ||
195 | { | ||
196 | switch (eff) { | ||
197 | /* 0x0 0x1 0x2 0x3 0x4 PT effects */ | ||
198 | case 0x5: /* PT vibrato with speed/depth nibbles swapped */ | ||
199 | UniPTEffect(0x4, (dat >> 4) | ((dat & 0xf) << 4)); | ||
200 | break; | ||
201 | /* 0x6 0x7 not used */ | ||
202 | case 0x6: | ||
203 | case 0x7: | ||
204 | break; | ||
205 | case 0x8: /* midi hold/decay */ | ||
206 | break; | ||
207 | case 0x9: | ||
208 | if (bpmtempos) { | ||
209 | if (!dat) | ||
210 | dat = of.initspeed; | ||
211 | UniEffect(UNI_S3MEFFECTA, dat); | ||
212 | } else { | ||
213 | if (dat <= 0x20) { | ||
214 | if (!dat) | ||
215 | dat = of.initspeed; | ||
216 | else | ||
217 | dat /= 4; | ||
218 | UniPTEffect(0xf, dat); | ||
219 | } else | ||
220 | UniEffect(UNI_MEDSPEED, ((UWORD)dat * 125) / (33 * 4)); | ||
221 | } | ||
222 | break; | ||
223 | /* 0xa 0xb PT effects */ | ||
224 | case 0xc: | ||
225 | if (decimalvolumes) | ||
226 | dat = (dat >> 4) * 10 + (dat & 0xf); | ||
227 | UniPTEffect(0xc, dat); | ||
228 | break; | ||
229 | case 0xd: /* same as PT volslide */ | ||
230 | UniPTEffect(0xa, dat); | ||
231 | break; | ||
232 | case 0xe: /* synth jmp - midi */ | ||
233 | break; | ||
234 | case 0xf: | ||
235 | switch (dat) { | ||
236 | case 0: /* patternbreak */ | ||
237 | UniPTEffect(0xd, 0); | ||
238 | break; | ||
239 | case 0xf1: /* play note twice */ | ||
240 | UniWriteByte(UNI_MEDEFFECTF1); | ||
241 | break; | ||
242 | case 0xf2: /* delay note */ | ||
243 | UniWriteByte(UNI_MEDEFFECTF2); | ||
244 | break; | ||
245 | case 0xf3: /* play note three times */ | ||
246 | UniWriteByte(UNI_MEDEFFECTF3); | ||
247 | break; | ||
248 | case 0xfe: /* stop playing */ | ||
249 | UniPTEffect(0xb, of.numpat); | ||
250 | break; | ||
251 | case 0xff: /* note cut */ | ||
252 | UniPTEffect(0xc, 0); | ||
253 | break; | ||
254 | default: | ||
255 | if (dat <= 10) | ||
256 | UniPTEffect(0xf, dat); | ||
257 | else if (dat <= 240) { | ||
258 | if (bpmtempos) | ||
259 | UniPTEffect(0xf, (dat < 32) ? 32 : dat); | ||
260 | else | ||
261 | UniEffect(UNI_MEDSPEED, ((UWORD)dat * 125) / 33); | ||
262 | } | ||
263 | } | ||
264 | break; | ||
265 | default: /* all normal PT effects are handled here */ | ||
266 | UniPTEffect(eff, dat); | ||
267 | break; | ||
268 | } | ||
269 | } | ||
270 | |||
271 | static UBYTE *MED_Convert1(int count, int col) | ||
272 | { | ||
273 | int t; | ||
274 | UBYTE inst, note, eff, dat; | ||
275 | MMD1NOTE *n; | ||
276 | |||
277 | UniReset(); | ||
278 | for (t = 0; t < count; t++) { | ||
279 | n = &d1note(t, col); | ||
280 | |||
281 | note = n->a & 0x7f; | ||
282 | inst = n->b & 0x3f; | ||
283 | eff = n->c & 0xf; | ||
284 | dat = n->d; | ||
285 | |||
286 | if (inst) | ||
287 | UniInstrument(inst - 1); | ||
288 | if (note) | ||
289 | UniNote(note + 3 * OCTAVE - 1); | ||
290 | EffectCvt(eff, dat); | ||
291 | UniNewline(); | ||
292 | } | ||
293 | return UniDup(); | ||
294 | } | ||
295 | |||
296 | static UBYTE *MED_Convert0(int count, int col) | ||
297 | { | ||
298 | int t; | ||
299 | UBYTE a, b, inst, note, eff, dat; | ||
300 | MMD0NOTE *n; | ||
301 | |||
302 | UniReset(); | ||
303 | for (t = 0; t < count; t++) { | ||
304 | n = &d0note(t, col); | ||
305 | a = n->a; | ||
306 | b = n->b; | ||
307 | |||
308 | note = a & 0x3f; | ||
309 | a >>= 6; | ||
310 | a = ((a & 1) << 1) | (a >> 1); | ||
311 | inst = (b >> 4) | (a << 4); | ||
312 | eff = b & 0xf; | ||
313 | dat = n->c; | ||
314 | |||
315 | if (inst) | ||
316 | UniInstrument(inst - 1); | ||
317 | if (note) | ||
318 | UniNote(note + 3 * OCTAVE - 1); | ||
319 | EffectCvt(eff, dat); | ||
320 | UniNewline(); | ||
321 | } | ||
322 | return UniDup(); | ||
323 | } | ||
324 | |||
325 | static int LoadMEDPatterns(void) | ||
326 | { | ||
327 | int t, row, col; | ||
328 | UWORD numtracks, numlines, maxlines = 0, track = 0; | ||
329 | MMD0NOTE *mmdp; | ||
330 | |||
331 | /* first, scan patterns to see how many channels are used */ | ||
332 | for (t = 0; t < of.numpat; t++) { | ||
333 | _mm_fseek(modreader, ba[t], SEEK_SET); | ||
334 | numtracks = _mm_read_UBYTE(modreader); | ||
335 | numlines = _mm_read_UBYTE(modreader); | ||
336 | |||
337 | if (numtracks > of.numchn) | ||
338 | of.numchn = numtracks; | ||
339 | if (numlines > maxlines) | ||
340 | maxlines = numlines; | ||
341 | } | ||
342 | |||
343 | of.numtrk = of.numpat * of.numchn; | ||
344 | if (!AllocTracks()) | ||
345 | return 0; | ||
346 | if (!AllocPatterns()) | ||
347 | return 0; | ||
348 | |||
349 | if (! | ||
350 | (mmd0pat = | ||
351 | (MMD0NOTE *)MikMod_calloc(of.numchn * (maxlines + 1), | ||
352 | sizeof(MMD0NOTE)))) return 0; | ||
353 | |||
354 | /* second read: read and convert patterns */ | ||
355 | for (t = 0; t < of.numpat; t++) { | ||
356 | _mm_fseek(modreader, ba[t], SEEK_SET); | ||
357 | numtracks = _mm_read_UBYTE(modreader); | ||
358 | numlines = _mm_read_UBYTE(modreader); | ||
359 | |||
360 | of.pattrows[t] = ++numlines; | ||
361 | memset(mmdp = mmd0pat, 0, of.numchn * maxlines * sizeof(MMD0NOTE)); | ||
362 | for (row = numlines; row; row--) { | ||
363 | for (col = numtracks; col; col--, mmdp++) { | ||
364 | mmdp->a = _mm_read_UBYTE(modreader); | ||
365 | mmdp->b = _mm_read_UBYTE(modreader); | ||
366 | mmdp->c = _mm_read_UBYTE(modreader); | ||
367 | } | ||
368 | } | ||
369 | |||
370 | for (col = 0; col < of.numchn; col++) | ||
371 | of.tracks[track++] = MED_Convert0(numlines, col); | ||
372 | } | ||
373 | return 1; | ||
374 | } | ||
375 | |||
376 | static int LoadMMD1Patterns(void) | ||
377 | { | ||
378 | int t, row, col; | ||
379 | UWORD numtracks, numlines, maxlines = 0, track = 0; | ||
380 | MMD1NOTE *mmdp; | ||
381 | |||
382 | /* first, scan patterns to see how many channels are used */ | ||
383 | for (t = 0; t < of.numpat; t++) { | ||
384 | _mm_fseek(modreader, ba[t], SEEK_SET); | ||
385 | numtracks = _mm_read_M_UWORD(modreader); | ||
386 | numlines = _mm_read_M_UWORD(modreader); | ||
387 | if (numtracks > of.numchn) | ||
388 | of.numchn = numtracks; | ||
389 | if (numlines > maxlines) | ||
390 | maxlines = numlines; | ||
391 | } | ||
392 | |||
393 | of.numtrk = of.numpat * of.numchn; | ||
394 | if (!AllocTracks()) | ||
395 | return 0; | ||
396 | if (!AllocPatterns()) | ||
397 | return 0; | ||
398 | |||
399 | if (! | ||
400 | (mmd1pat = | ||
401 | (MMD1NOTE *)MikMod_calloc(of.numchn * (maxlines + 1), | ||
402 | sizeof(MMD1NOTE)))) return 0; | ||
403 | |||
404 | /* second read: really read and convert patterns */ | ||
405 | for (t = 0; t < of.numpat; t++) { | ||
406 | _mm_fseek(modreader, ba[t], SEEK_SET); | ||
407 | numtracks = _mm_read_M_UWORD(modreader); | ||
408 | numlines = _mm_read_M_UWORD(modreader); | ||
409 | |||
410 | _mm_fseek(modreader, sizeof(ULONG), SEEK_CUR); | ||
411 | of.pattrows[t] = ++numlines; | ||
412 | memset(mmdp = mmd1pat, 0, of.numchn * maxlines * sizeof(MMD1NOTE)); | ||
413 | |||
414 | for (row = numlines; row; row--) { | ||
415 | for (col = numtracks; col; col--, mmdp++) { | ||
416 | mmdp->a = _mm_read_UBYTE(modreader); | ||
417 | mmdp->b = _mm_read_UBYTE(modreader); | ||
418 | mmdp->c = _mm_read_UBYTE(modreader); | ||
419 | mmdp->d = _mm_read_UBYTE(modreader); | ||
420 | } | ||
421 | } | ||
422 | |||
423 | for (col = 0; col < of.numchn; col++) | ||
424 | of.tracks[track++] = MED_Convert1(numlines, col); | ||
425 | } | ||
426 | return 1; | ||
427 | } | ||
428 | |||
429 | int MED_Load(int curious) | ||
430 | { | ||
431 | int t; | ||
432 | ULONG sa[64]; | ||
433 | MEDINSTHEADER s; | ||
434 | SAMPLE *q; | ||
435 | MEDSAMPLE *mss; | ||
436 | |||
437 | /* try to read module header */ | ||
438 | mh->id = _mm_read_M_ULONG(modreader); | ||
439 | mh->modlen = _mm_read_M_ULONG(modreader); | ||
440 | mh->MEDSONGP = _mm_read_M_ULONG(modreader); | ||
441 | mh->psecnum = _mm_read_M_UWORD(modreader); | ||
442 | mh->pseq = _mm_read_M_UWORD(modreader); | ||
443 | mh->MEDBlockPP = _mm_read_M_ULONG(modreader); | ||
444 | mh->reserved1 = _mm_read_M_ULONG(modreader); | ||
445 | mh->MEDINSTHEADERPP = _mm_read_M_ULONG(modreader); | ||
446 | mh->reserved2 = _mm_read_M_ULONG(modreader); | ||
447 | mh->MEDEXPP = _mm_read_M_ULONG(modreader); | ||
448 | mh->reserved3 = _mm_read_M_ULONG(modreader); | ||
449 | mh->pstate = _mm_read_M_UWORD(modreader); | ||
450 | mh->pblock = _mm_read_M_UWORD(modreader); | ||
451 | mh->pline = _mm_read_M_UWORD(modreader); | ||
452 | mh->pseqnum = _mm_read_M_UWORD(modreader); | ||
453 | mh->actplayline = _mm_read_M_SWORD(modreader); | ||
454 | mh->counter = _mm_read_UBYTE(modreader); | ||
455 | mh->extra_songs = _mm_read_UBYTE(modreader); | ||
456 | |||
457 | /* Seek to MEDSONG struct */ | ||
458 | _mm_fseek(modreader, mh->MEDSONGP, SEEK_SET); | ||
459 | |||
460 | /* Load the MED Song Header */ | ||
461 | mss = ms->sample; /* load the sample data first */ | ||
462 | for (t = 63; t; t--, mss++) { | ||
463 | mss->rep = _mm_read_M_UWORD(modreader); | ||
464 | mss->replen = _mm_read_M_UWORD(modreader); | ||
465 | mss->midich = _mm_read_UBYTE(modreader); | ||
466 | mss->midipreset = _mm_read_UBYTE(modreader); | ||
467 | mss->svol = _mm_read_UBYTE(modreader); | ||
468 | mss->strans = _mm_read_SBYTE(modreader); | ||
469 | } | ||
470 | |||
471 | ms->numblocks = _mm_read_M_UWORD(modreader); | ||
472 | ms->songlen = _mm_read_M_UWORD(modreader); | ||
473 | _mm_read_UBYTES(ms->playseq, 256, modreader); | ||
474 | ms->deftempo = _mm_read_M_UWORD(modreader); | ||
475 | ms->playtransp = _mm_read_SBYTE(modreader); | ||
476 | ms->flags = _mm_read_UBYTE(modreader); | ||
477 | ms->flags2 = _mm_read_UBYTE(modreader); | ||
478 | ms->tempo2 = _mm_read_UBYTE(modreader); | ||
479 | _mm_read_UBYTES(ms->trkvol, 16, modreader); | ||
480 | ms->mastervol = _mm_read_UBYTE(modreader); | ||
481 | ms->numsamples = _mm_read_UBYTE(modreader); | ||
482 | |||
483 | /* check for a bad header */ | ||
484 | if (_mm_eof(modreader)) { | ||
485 | _mm_errno = MMERR_LOADING_HEADER; | ||
486 | return 0; | ||
487 | } | ||
488 | |||
489 | /* load extension structure */ | ||
490 | if (mh->MEDEXPP) { | ||
491 | _mm_fseek(modreader, mh->MEDEXPP, SEEK_SET); | ||
492 | me->nextmod = _mm_read_M_ULONG(modreader); | ||
493 | me->exp_smp = _mm_read_M_ULONG(modreader); | ||
494 | me->s_ext_entries = _mm_read_M_UWORD(modreader); | ||
495 | me->s_ext_entrsz = _mm_read_M_UWORD(modreader); | ||
496 | me->annotxt = _mm_read_M_ULONG(modreader); | ||
497 | me->annolen = _mm_read_M_ULONG(modreader); | ||
498 | me->iinfo = _mm_read_M_ULONG(modreader); | ||
499 | me->i_ext_entries = _mm_read_M_UWORD(modreader); | ||
500 | me->i_ext_entrsz = _mm_read_M_UWORD(modreader); | ||
501 | me->jumpmask = _mm_read_M_ULONG(modreader); | ||
502 | me->rgbtable = _mm_read_M_ULONG(modreader); | ||
503 | me->channelsplit = _mm_read_M_ULONG(modreader); | ||
504 | me->n_info = _mm_read_M_ULONG(modreader); | ||
505 | me->songname = _mm_read_M_ULONG(modreader); | ||
506 | me->songnamelen = _mm_read_M_ULONG(modreader); | ||
507 | me->dumps = _mm_read_M_ULONG(modreader); | ||
508 | } | ||
509 | |||
510 | /* seek to and read the samplepointer array */ | ||
511 | _mm_fseek(modreader, mh->MEDINSTHEADERPP, SEEK_SET); | ||
512 | if (!_mm_read_M_ULONGS(sa, ms->numsamples, modreader)) { | ||
513 | _mm_errno = MMERR_LOADING_HEADER; | ||
514 | return 0; | ||
515 | } | ||
516 | |||
517 | /* alloc and read the blockpointer array */ | ||
518 | if (!(ba = (ULONG *)MikMod_calloc(ms->numblocks, sizeof(ULONG)))) | ||
519 | return 0; | ||
520 | _mm_fseek(modreader, mh->MEDBlockPP, SEEK_SET); | ||
521 | if (!_mm_read_M_ULONGS(ba, ms->numblocks, modreader)) { | ||
522 | _mm_errno = MMERR_LOADING_HEADER; | ||
523 | return 0; | ||
524 | } | ||
525 | |||
526 | /* copy song positions */ | ||
527 | if (!AllocPositions(ms->songlen)) | ||
528 | return 0; | ||
529 | for (t = 0; t < ms->songlen; t++) | ||
530 | of.positions[t] = ms->playseq[t]; | ||
531 | |||
532 | decimalvolumes = (ms->flags & 0x10) ? 0 : 1; | ||
533 | bpmtempos = (ms->flags2 & 0x20) ? 1 : 0; | ||
534 | |||
535 | if (bpmtempos) { | ||
536 | int bpmlen = (ms->flags2 & 0x1f) + 1; | ||
537 | of.initspeed = ms->tempo2; | ||
538 | of.inittempo = ms->deftempo * bpmlen / 4; | ||
539 | |||
540 | if (bpmlen != 4) { | ||
541 | /* Let's do some math : compute GCD of BPM beat length and speed */ | ||
542 | int a, b; | ||
543 | |||
544 | a = bpmlen; | ||
545 | b = ms->tempo2; | ||
546 | |||
547 | if (a > b) { | ||
548 | t = b; | ||
549 | b = a; | ||
550 | a = t; | ||
551 | } | ||
552 | while ((a != b) && (a)) { | ||
553 | t = a; | ||
554 | a = b - a; | ||
555 | b = t; | ||
556 | if (a > b) { | ||
557 | t = b; | ||
558 | b = a; | ||
559 | a = t; | ||
560 | } | ||
561 | } | ||
562 | |||
563 | of.initspeed /= b; | ||
564 | of.inittempo = ms->deftempo * bpmlen / (4 * b); | ||
565 | } | ||
566 | } else { | ||
567 | of.initspeed = ms->tempo2; | ||
568 | of.inittempo = ms->deftempo ? ((UWORD)ms->deftempo * 125) / 33 : 128; | ||
569 | if ((ms->deftempo <= 10) && (ms->deftempo)) | ||
570 | of.inittempo = (of.inittempo * 33) / 6; | ||
571 | of.flags |= UF_HIGHBPM; | ||
572 | } | ||
573 | MED_Version[12] = mh->id; | ||
574 | of.modtype = StrDup(MED_Version); | ||
575 | of.numchn = 0; /* will be counted later */ | ||
576 | of.numpat = ms->numblocks; | ||
577 | of.numpos = ms->songlen; | ||
578 | of.numins = ms->numsamples; | ||
579 | of.numsmp = of.numins; | ||
580 | of.reppos = 0; | ||
581 | if ((mh->MEDEXPP) && (me->songname) && (me->songnamelen)) { | ||
582 | char *name; | ||
583 | |||
584 | _mm_fseek(modreader, me->songname, SEEK_SET); | ||
585 | name = MikMod_malloc(me->songnamelen); | ||
586 | _mm_read_UBYTES(name, me->songnamelen, modreader); | ||
587 | of.songname = DupStr(name, me->songnamelen, 1); | ||
588 | MikMod_free(name); | ||
589 | } else | ||
590 | of.songname = DupStr(NULL, 0, 0); | ||
591 | if ((mh->MEDEXPP) && (me->annotxt) && (me->annolen)) { | ||
592 | _mm_fseek(modreader, me->annotxt, SEEK_SET); | ||
593 | ReadComment(me->annolen); | ||
594 | } | ||
595 | |||
596 | if (!AllocSamples()) | ||
597 | return 0; | ||
598 | q = of.samples; | ||
599 | for (t = 0; t < of.numins; t++) { | ||
600 | q->flags = SF_SIGNED; | ||
601 | q->volume = 64; | ||
602 | if (sa[t]) { | ||
603 | _mm_fseek(modreader, sa[t], SEEK_SET); | ||
604 | s.length = _mm_read_M_ULONG(modreader); | ||
605 | s.type = _mm_read_M_SWORD(modreader); | ||
606 | |||
607 | if (s.type) { | ||
608 | #ifdef MIKMOD_DEBUG | ||
609 | fprintf(stderr, "\rNon-sample instruments not supported in MED loader yet\n"); | ||
610 | #endif | ||
611 | if (!curious) { | ||
612 | _mm_errno = MMERR_MED_SYNTHSAMPLES; | ||
613 | return 0; | ||
614 | } | ||
615 | s.length = 0; | ||
616 | } | ||
617 | |||
618 | if (_mm_eof(modreader)) { | ||
619 | _mm_errno = MMERR_LOADING_SAMPLEINFO; | ||
620 | return 0; | ||
621 | } | ||
622 | |||
623 | q->length = s.length; | ||
624 | q->seekpos = _mm_ftell(modreader); | ||
625 | q->loopstart = ms->sample[t].rep << 1; | ||
626 | q->loopend = q->loopstart + (ms->sample[t].replen << 1); | ||
627 | |||
628 | if (ms->sample[t].replen > 1) | ||
629 | q->flags |= SF_LOOP; | ||
630 | |||
631 | /* don't load sample if length>='MMD0'... | ||
632 | such kluges make libmikmod's code unique !!! */ | ||
633 | if (q->length >= MMD0_string) | ||
634 | q->length = 0; | ||
635 | } else | ||
636 | q->length = 0; | ||
637 | |||
638 | if ((mh->MEDEXPP) && (me->exp_smp) && | ||
639 | (t < me->s_ext_entries) && (me->s_ext_entrsz >= 4)) { | ||
640 | MEDINSTEXT ie; | ||
641 | |||
642 | _mm_fseek(modreader, me->exp_smp + t * me->s_ext_entrsz, | ||
643 | SEEK_SET); | ||
644 | ie.hold = _mm_read_UBYTE(modreader); | ||
645 | ie.decay = _mm_read_UBYTE(modreader); | ||
646 | ie.suppress_midi_off = _mm_read_UBYTE(modreader); | ||
647 | ie.finetune = _mm_read_SBYTE(modreader); | ||
648 | |||
649 | q->speed = finetune[ie.finetune & 0xf]; | ||
650 | } else | ||
651 | q->speed = 8363; | ||
652 | |||
653 | if ((mh->MEDEXPP) && (me->iinfo) && | ||
654 | (t < me->i_ext_entries) && (me->i_ext_entrsz >= 40)) { | ||
655 | MEDINSTINFO ii; | ||
656 | |||
657 | _mm_fseek(modreader, me->iinfo + t * me->i_ext_entrsz, SEEK_SET); | ||
658 | _mm_read_UBYTES(ii.name, 40, modreader); | ||
659 | q->samplename = DupStr((char*)ii.name, 40, 1); | ||
660 | } else | ||
661 | q->samplename = NULL; | ||
662 | |||
663 | q++; | ||
664 | } | ||
665 | |||
666 | if (mh->id == MMD0_string) { | ||
667 | if (!LoadMEDPatterns()) { | ||
668 | _mm_errno = MMERR_LOADING_PATTERN; | ||
669 | return 0; | ||
670 | } | ||
671 | } else if (mh->id == MMD1_string) { | ||
672 | if (!LoadMMD1Patterns()) { | ||
673 | _mm_errno = MMERR_LOADING_PATTERN; | ||
674 | return 0; | ||
675 | } | ||
676 | } else { | ||
677 | _mm_errno = MMERR_NOT_A_MODULE; | ||
678 | return 0; | ||
679 | } | ||
680 | return 1; | ||
681 | } | ||
682 | |||
683 | CHAR *MED_LoadTitle(void) | ||
684 | { | ||
685 | ULONG posit, namelen; | ||
686 | CHAR *name, *retvalue = NULL; | ||
687 | |||
688 | _mm_fseek(modreader, 0x20, SEEK_SET); | ||
689 | posit = _mm_read_M_ULONG(modreader); | ||
690 | |||
691 | if (posit) { | ||
692 | _mm_fseek(modreader, posit + 0x2C, SEEK_SET); | ||
693 | posit = _mm_read_M_ULONG(modreader); | ||
694 | namelen = _mm_read_M_ULONG(modreader); | ||
695 | |||
696 | _mm_fseek(modreader, posit, SEEK_SET); | ||
697 | name = MikMod_malloc(namelen); | ||
698 | _mm_read_UBYTES(name, namelen, modreader); | ||
699 | retvalue = DupStr(name, namelen, 1); | ||
700 | MikMod_free(name); | ||
701 | } | ||
702 | |||
703 | return retvalue; | ||
704 | } | ||
705 | |||
706 | /*========== Loader information */ | ||
707 | |||
708 | MIKMODAPI MLOADER load_med = { | ||
709 | NULL, | ||
710 | "MED", | ||
711 | "MED (OctaMED)", | ||
712 | MED_Init, | ||
713 | MED_Test, | ||
714 | MED_Load, | ||
715 | MED_Cleanup, | ||
716 | MED_LoadTitle | ||
717 | }; | ||
718 | |||
719 | /* ex:set ts=4: */ | ||
diff --git a/apps/plugins/mikmod/load_mod.c b/apps/plugins/mikmod/load_mod.c new file mode 100644 index 0000000000..92b9787c50 --- /dev/null +++ b/apps/plugins/mikmod/load_mod.c | |||
@@ -0,0 +1,512 @@ | |||
1 | /* MikMod sound library | ||
2 | (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file | ||
3 | AUTHORS 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: load_mod.c,v 1.3 2005/04/07 19:57:38 realtech Exp $ | ||
24 | |||
25 | Generic MOD loader (Protracker, StarTracker, FastTracker, etc) | ||
26 | |||
27 | ==============================================================================*/ | ||
28 | |||
29 | #ifdef HAVE_CONFIG_H | ||
30 | #include "config.h" | ||
31 | #endif | ||
32 | |||
33 | #ifdef HAVE_UNISTD_H | ||
34 | #include <unistd.h> | ||
35 | #endif | ||
36 | |||
37 | #include <ctype.h> | ||
38 | #include <stdio.h> | ||
39 | #ifdef HAVE_MEMORY_H | ||
40 | #include <memory.h> | ||
41 | #endif | ||
42 | #include <string.h> | ||
43 | |||
44 | #include "mikmod_internals.h" | ||
45 | |||
46 | #ifdef SUNOS | ||
47 | extern int fprintf(FILE *, const char *, ...); | ||
48 | #endif | ||
49 | |||
50 | /*========== Module structure */ | ||
51 | |||
52 | typedef struct MSAMPINFO { | ||
53 | CHAR samplename[23]; /* 22 in module, 23 in memory */ | ||
54 | UWORD length; | ||
55 | UBYTE finetune; | ||
56 | UBYTE volume; | ||
57 | UWORD reppos; | ||
58 | UWORD replen; | ||
59 | } MSAMPINFO; | ||
60 | |||
61 | typedef struct MODULEHEADER { | ||
62 | CHAR songname[21]; /* the songname.. 20 in module, 21 in memory */ | ||
63 | MSAMPINFO samples[31]; /* all sampleinfo */ | ||
64 | UBYTE songlength; /* number of patterns used */ | ||
65 | UBYTE magic1; /* should be 127 */ | ||
66 | UBYTE positions[128]; /* which pattern to play at pos */ | ||
67 | UBYTE magic2[4]; /* string "M.K." or "FLT4" or "FLT8" */ | ||
68 | } MODULEHEADER; | ||
69 | |||
70 | typedef struct MODTYPE { | ||
71 | CHAR id[5]; | ||
72 | UBYTE channels; | ||
73 | CHAR *name; | ||
74 | } MODTYPE; | ||
75 | |||
76 | typedef struct MODNOTE { | ||
77 | UBYTE a, b, c, d; | ||
78 | } MODNOTE; | ||
79 | |||
80 | /*========== Loader variables */ | ||
81 | |||
82 | #define MODULEHEADERSIZE 0x438 | ||
83 | |||
84 | static CHAR protracker[] = "Protracker"; | ||
85 | static CHAR startrekker[] = "Startrekker"; | ||
86 | static CHAR fasttracker[] = "Fasttracker"; | ||
87 | static CHAR oktalyser[] = "Oktalyser"; | ||
88 | static CHAR oktalyzer[] = "Oktalyzer"; | ||
89 | static CHAR taketracker[] = "TakeTracker"; | ||
90 | static CHAR orpheus[] = "Imago Orpheus (MOD format)"; | ||
91 | |||
92 | static MODULEHEADER *mh = NULL; | ||
93 | static MODNOTE *patbuf = NULL; | ||
94 | static int modtype, trekker; | ||
95 | |||
96 | /*========== Loader code */ | ||
97 | |||
98 | /* given the module ID, determine the number of channels and the tracker | ||
99 | description ; also alters modtype */ | ||
100 | static int MOD_CheckType(UBYTE *id, UBYTE *numchn, CHAR **descr) | ||
101 | { | ||
102 | modtype = trekker = 0; | ||
103 | |||
104 | /* Protracker and variants */ | ||
105 | if ((!memcmp(id, "M.K.", 4)) || (!memcmp(id, "M!K!", 4))) { | ||
106 | *descr = protracker; | ||
107 | modtype = 0; | ||
108 | *numchn = 4; | ||
109 | return 1; | ||
110 | } | ||
111 | |||
112 | /* Star Tracker */ | ||
113 | if (((!memcmp(id, "FLT", 3)) || (!memcmp(id, "EXO", 3))) && | ||
114 | (isdigit(id[3]))) { | ||
115 | *descr = startrekker; | ||
116 | modtype = trekker = 1; | ||
117 | *numchn = id[3] - '0'; | ||
118 | if (*numchn == 4 || *numchn == 8) | ||
119 | return 1; | ||
120 | #ifdef MIKMOD_DEBUG | ||
121 | else | ||
122 | fprintf(stderr, "\rUnknown FLT%d module type\n", *numchn); | ||
123 | #endif | ||
124 | return 0; | ||
125 | } | ||
126 | |||
127 | /* Oktalyzer (Amiga) */ | ||
128 | if (!memcmp(id, "OKTA", 4)) { | ||
129 | *descr = oktalyzer; | ||
130 | modtype = 1; | ||
131 | *numchn = 8; | ||
132 | return 1; | ||
133 | } | ||
134 | |||
135 | /* Oktalyser (Atari) */ | ||
136 | if (!memcmp(id, "CD81", 4)) { | ||
137 | *descr = oktalyser; | ||
138 | modtype = 1; | ||
139 | *numchn = 8; | ||
140 | return 1; | ||
141 | } | ||
142 | |||
143 | /* Fasttracker */ | ||
144 | if ((!memcmp(id + 1, "CHN", 3)) && (isdigit(id[0]))) { | ||
145 | *descr = fasttracker; | ||
146 | modtype = 1; | ||
147 | *numchn = id[0] - '0'; | ||
148 | return 1; | ||
149 | } | ||
150 | /* Fasttracker or Taketracker */ | ||
151 | if (((!memcmp(id + 2, "CH", 2)) || (!memcmp(id + 2, "CN", 2))) | ||
152 | && (isdigit(id[0])) && (isdigit(id[1]))) { | ||
153 | if (id[3] == 'H') { | ||
154 | *descr = fasttracker; | ||
155 | modtype = 2; /* this can also be Imago Orpheus */ | ||
156 | } else { | ||
157 | *descr = taketracker; | ||
158 | modtype = 1; | ||
159 | } | ||
160 | *numchn = (id[0] - '0') * 10 + (id[1] - '0'); | ||
161 | return 1; | ||
162 | } | ||
163 | |||
164 | return 0; | ||
165 | } | ||
166 | |||
167 | static int MOD_Test(void) | ||
168 | { | ||
169 | UBYTE id[4], numchn; | ||
170 | CHAR *descr; | ||
171 | |||
172 | _mm_fseek(modreader, MODULEHEADERSIZE, SEEK_SET); | ||
173 | if (!_mm_read_UBYTES(id, 4, modreader)) | ||
174 | return 0; | ||
175 | |||
176 | if (MOD_CheckType(id, &numchn, &descr)) | ||
177 | return 1; | ||
178 | |||
179 | return 0; | ||
180 | } | ||
181 | |||
182 | static int MOD_Init(void) | ||
183 | { | ||
184 | if (!(mh = (MODULEHEADER *)MikMod_malloc(sizeof(MODULEHEADER)))) | ||
185 | return 0; | ||
186 | return 1; | ||
187 | } | ||
188 | |||
189 | static void MOD_Cleanup(void) | ||
190 | { | ||
191 | MikMod_free(mh); | ||
192 | MikMod_free(patbuf); | ||
193 | } | ||
194 | |||
195 | /* | ||
196 | Old (amiga) noteinfo: | ||
197 | |||
198 | _____byte 1_____ byte2_ _____byte 3_____ byte4_ | ||
199 | / \ / \ / \ / \ | ||
200 | 0000 0000-00000000 0000 0000-00000000 | ||
201 | |||
202 | Upper four 12 bits for Lower four Effect command. | ||
203 | bits of sam- note period. bits of sam- | ||
204 | ple number. ple number. | ||
205 | |||
206 | */ | ||
207 | |||
208 | static UBYTE ConvertNote(MODNOTE *n, UBYTE lasteffect) | ||
209 | { | ||
210 | UBYTE instrument, effect, effdat, note; | ||
211 | UWORD period; | ||
212 | UBYTE lastnote = 0; | ||
213 | |||
214 | /* extract the various information from the 4 bytes that make up a note */ | ||
215 | instrument = (n->a & 0x10) | (n->c >> 4); | ||
216 | period = (((UWORD)n->a & 0xf) << 8) + n->b; | ||
217 | effect = n->c & 0xf; | ||
218 | effdat = n->d; | ||
219 | |||
220 | /* Convert the period to a note number */ | ||
221 | note = 0; | ||
222 | if (period) { | ||
223 | for (note = 0; note < 7 * OCTAVE; note++) | ||
224 | if (period >= npertab[note]) | ||
225 | break; | ||
226 | if (note == 7 * OCTAVE) | ||
227 | note = 0; | ||
228 | else | ||
229 | note++; | ||
230 | } | ||
231 | |||
232 | if (instrument) { | ||
233 | /* if instrument does not exist, note cut */ | ||
234 | if ((instrument > 31) || (!mh->samples[instrument - 1].length)) { | ||
235 | UniPTEffect(0xc, 0); | ||
236 | if (effect == 0xc) | ||
237 | effect = effdat = 0; | ||
238 | } else { | ||
239 | /* Protracker handling */ | ||
240 | if (!modtype) { | ||
241 | /* if we had a note, then change instrument... */ | ||
242 | if (note) | ||
243 | UniInstrument(instrument - 1); | ||
244 | /* ...otherwise, only adjust volume... */ | ||
245 | else { | ||
246 | /* ...unless an effect was specified, which forces a new | ||
247 | note to be played */ | ||
248 | if (effect || effdat) { | ||
249 | UniInstrument(instrument - 1); | ||
250 | note = lastnote; | ||
251 | } else | ||
252 | UniPTEffect(0xc, | ||
253 | mh->samples[instrument - | ||
254 | 1].volume & 0x7f); | ||
255 | } | ||
256 | } else { | ||
257 | /* Fasttracker handling */ | ||
258 | UniInstrument(instrument - 1); | ||
259 | if (!note) | ||
260 | note = lastnote; | ||
261 | } | ||
262 | } | ||
263 | } | ||
264 | if (note) { | ||
265 | UniNote(note + 2 * OCTAVE - 1); | ||
266 | lastnote = note; | ||
267 | } | ||
268 | |||
269 | /* Convert pattern jump from Dec to Hex */ | ||
270 | if (effect == 0xd) | ||
271 | effdat = (((effdat & 0xf0) >> 4) * 10) + (effdat & 0xf); | ||
272 | |||
273 | /* Volume slide, up has priority */ | ||
274 | if ((effect == 0xa) && (effdat & 0xf) && (effdat & 0xf0)) | ||
275 | effdat &= 0xf0; | ||
276 | |||
277 | /* Handle ``heavy'' volumes correctly */ | ||
278 | if ((effect == 0xc) && (effdat > 0x40)) | ||
279 | effdat = 0x40; | ||
280 | |||
281 | /* An isolated 100, 200 or 300 effect should be ignored (no | ||
282 | "standalone" porta memory in mod files). However, a sequence such | ||
283 | as 1XX, 100, 100, 100 is fine. */ | ||
284 | if ((!effdat) && ((effect == 1)||(effect == 2)||(effect ==3)) && | ||
285 | (lasteffect < 0x10) && (effect != lasteffect)) | ||
286 | effect = 0; | ||
287 | |||
288 | UniPTEffect(effect, effdat); | ||
289 | if (effect == 8) | ||
290 | of.flags |= UF_PANNING; | ||
291 | |||
292 | return effect; | ||
293 | } | ||
294 | |||
295 | static UBYTE *ConvertTrack(MODNOTE *n, int numchn) | ||
296 | { | ||
297 | int t; | ||
298 | UBYTE lasteffect = 0x10; /* non existant effect */ | ||
299 | |||
300 | UniReset(); | ||
301 | for (t = 0; t < 64; t++) { | ||
302 | lasteffect = ConvertNote(n,lasteffect); | ||
303 | UniNewline(); | ||
304 | n += numchn; | ||
305 | } | ||
306 | return UniDup(); | ||
307 | } | ||
308 | |||
309 | /* Loads all patterns of a modfile and converts them into the 3 byte format. */ | ||
310 | static int ML_LoadPatterns(void) | ||
311 | { | ||
312 | int t, s, tracks = 0; | ||
313 | |||
314 | if (!AllocPatterns()) | ||
315 | return 0; | ||
316 | if (!AllocTracks()) | ||
317 | return 0; | ||
318 | |||
319 | /* Allocate temporary buffer for loading and converting the patterns */ | ||
320 | if (!(patbuf = (MODNOTE *)MikMod_calloc(64U * of.numchn, sizeof(MODNOTE)))) | ||
321 | return 0; | ||
322 | |||
323 | if (trekker && of.numchn == 8) { | ||
324 | /* Startrekker module dual pattern */ | ||
325 | for (t = 0; t < of.numpat; t++) { | ||
326 | for (s = 0; s < (64U * 4); s++) { | ||
327 | patbuf[s].a = _mm_read_UBYTE(modreader); | ||
328 | patbuf[s].b = _mm_read_UBYTE(modreader); | ||
329 | patbuf[s].c = _mm_read_UBYTE(modreader); | ||
330 | patbuf[s].d = _mm_read_UBYTE(modreader); | ||
331 | } | ||
332 | for (s = 0; s < 4; s++) | ||
333 | if (!(of.tracks[tracks++] = ConvertTrack(patbuf + s, 4))) | ||
334 | return 0; | ||
335 | for (s = 0; s < (64U * 4); s++) { | ||
336 | patbuf[s].a = _mm_read_UBYTE(modreader); | ||
337 | patbuf[s].b = _mm_read_UBYTE(modreader); | ||
338 | patbuf[s].c = _mm_read_UBYTE(modreader); | ||
339 | patbuf[s].d = _mm_read_UBYTE(modreader); | ||
340 | } | ||
341 | for (s = 0; s < 4; s++) | ||
342 | if (!(of.tracks[tracks++] = ConvertTrack(patbuf + s, 4))) | ||
343 | return 0; | ||
344 | } | ||
345 | } else { | ||
346 | /* Generic module pattern */ | ||
347 | for (t = 0; t < of.numpat; t++) { | ||
348 | /* Load the pattern into the temp buffer and convert it */ | ||
349 | for (s = 0; s < (64U * of.numchn); s++) { | ||
350 | patbuf[s].a = _mm_read_UBYTE(modreader); | ||
351 | patbuf[s].b = _mm_read_UBYTE(modreader); | ||
352 | patbuf[s].c = _mm_read_UBYTE(modreader); | ||
353 | patbuf[s].d = _mm_read_UBYTE(modreader); | ||
354 | } | ||
355 | for (s = 0; s < of.numchn; s++) | ||
356 | if (!(of.tracks[tracks++] = ConvertTrack(patbuf + s, of.numchn))) | ||
357 | return 0; | ||
358 | } | ||
359 | } | ||
360 | return 1; | ||
361 | } | ||
362 | |||
363 | static int MOD_Load(int curious) | ||
364 | { | ||
365 | int t, scan; | ||
366 | SAMPLE *q; | ||
367 | MSAMPINFO *s; | ||
368 | CHAR *descr; | ||
369 | |||
370 | /* try to read module header */ | ||
371 | _mm_read_string((CHAR *)mh->songname, 20, modreader); | ||
372 | mh->songname[20] = 0; /* just in case */ | ||
373 | |||
374 | for (t = 0; t < 31; t++) { | ||
375 | s = &mh->samples[t]; | ||
376 | _mm_read_string(s->samplename, 22, modreader); | ||
377 | s->samplename[22] = 0; /* just in case */ | ||
378 | s->length = _mm_read_M_UWORD(modreader); | ||
379 | s->finetune = _mm_read_UBYTE(modreader); | ||
380 | s->volume = _mm_read_UBYTE(modreader); | ||
381 | s->reppos = _mm_read_M_UWORD(modreader); | ||
382 | s->replen = _mm_read_M_UWORD(modreader); | ||
383 | } | ||
384 | |||
385 | mh->songlength = _mm_read_UBYTE(modreader); | ||
386 | |||
387 | /* this fixes mods which declare more than 128 positions. | ||
388 | * eg: beatwave.mod */ | ||
389 | if (mh->songlength > 128) { mh->songlength = 128; } | ||
390 | |||
391 | mh->magic1 = _mm_read_UBYTE(modreader); | ||
392 | _mm_read_UBYTES(mh->positions, 128, modreader); | ||
393 | _mm_read_UBYTES(mh->magic2, 4, modreader); | ||
394 | |||
395 | if (_mm_eof(modreader)) { | ||
396 | _mm_errno = MMERR_LOADING_HEADER; | ||
397 | return 0; | ||
398 | } | ||
399 | |||
400 | /* set module variables */ | ||
401 | of.initspeed = 6; | ||
402 | of.inittempo = 125; | ||
403 | if (!(MOD_CheckType(mh->magic2, &of.numchn, &descr))) { | ||
404 | _mm_errno = MMERR_NOT_A_MODULE; | ||
405 | return 0; | ||
406 | } | ||
407 | if (trekker && of.numchn == 8) | ||
408 | for (t = 0; t < 128; t++) | ||
409 | /* if module pretends to be FLT8, yet the order table | ||
410 | contains odd numbers, chances are it's a lying FLT4... */ | ||
411 | if (mh->positions[t] & 1) { | ||
412 | of.numchn = 4; | ||
413 | break; | ||
414 | } | ||
415 | if (trekker && of.numchn == 8) | ||
416 | for (t = 0; t < 128; t++) | ||
417 | mh->positions[t] >>= 1; | ||
418 | |||
419 | of.songname = DupStr(mh->songname, 21, 1); | ||
420 | of.numpos = mh->songlength; | ||
421 | of.reppos = 0; | ||
422 | |||
423 | /* Count the number of patterns */ | ||
424 | of.numpat = 0; | ||
425 | for (t = 0; t < of.numpos; t++) | ||
426 | if (mh->positions[t] > of.numpat) | ||
427 | of.numpat = mh->positions[t]; | ||
428 | |||
429 | /* since some old modules embed extra patterns, we have to check the | ||
430 | whole list to get the samples' file offsets right - however we can find | ||
431 | garbage here, so check carefully */ | ||
432 | scan = 1; | ||
433 | for (t = of.numpos; t < 128; t++) | ||
434 | if (mh->positions[t] >= 0x80) | ||
435 | scan = 0; | ||
436 | if (scan) | ||
437 | for (t = of.numpos; t < 128; t++) { | ||
438 | if (mh->positions[t] > of.numpat) | ||
439 | of.numpat = mh->positions[t]; | ||
440 | if ((curious) && (mh->positions[t])) | ||
441 | of.numpos = t + 1; | ||
442 | } | ||
443 | of.numpat++; | ||
444 | of.numtrk = of.numpat * of.numchn; | ||
445 | |||
446 | if (!AllocPositions(of.numpos)) | ||
447 | return 0; | ||
448 | for (t = 0; t < of.numpos; t++) | ||
449 | of.positions[t] = mh->positions[t]; | ||
450 | |||
451 | /* Finally, init the sampleinfo structures */ | ||
452 | of.numins = of.numsmp = 31; | ||
453 | if (!AllocSamples()) | ||
454 | return 0; | ||
455 | s = mh->samples; | ||
456 | q = of.samples; | ||
457 | for (t = 0; t < of.numins; t++) { | ||
458 | /* convert the samplename */ | ||
459 | q->samplename = DupStr(s->samplename, 23, 1); | ||
460 | /* init the sampleinfo variables and convert the size pointers */ | ||
461 | q->speed = finetune[s->finetune & 0xf]; | ||
462 | q->volume = s->volume & 0x7f; | ||
463 | q->loopstart = (ULONG)s->reppos << 1; | ||
464 | q->loopend = q->loopstart + ((ULONG)s->replen << 1); | ||
465 | q->length = (ULONG)s->length << 1; | ||
466 | q->flags = SF_SIGNED; | ||
467 | /* Imago Orpheus creates MODs with 16 bit samples, check */ | ||
468 | if ((modtype == 2) && (s->volume & 0x80)) { | ||
469 | q->flags |= SF_16BITS; | ||
470 | descr = orpheus; | ||
471 | } | ||
472 | if (s->replen > 2) | ||
473 | q->flags |= SF_LOOP; | ||
474 | |||
475 | s++; | ||
476 | q++; | ||
477 | } | ||
478 | |||
479 | of.modtype = StrDup(descr); | ||
480 | |||
481 | if (!ML_LoadPatterns()) | ||
482 | return 0; | ||
483 | |||
484 | return 1; | ||
485 | } | ||
486 | |||
487 | static CHAR *MOD_LoadTitle(void) | ||
488 | { | ||
489 | CHAR s[21]; | ||
490 | |||
491 | _mm_fseek(modreader, 0, SEEK_SET); | ||
492 | if (!_mm_read_UBYTES(s, 20, modreader)) | ||
493 | return NULL; | ||
494 | s[20] = 0; /* just in case */ | ||
495 | |||
496 | return (DupStr(s, 21, 1)); | ||
497 | } | ||
498 | |||
499 | /*========== Loader information */ | ||
500 | |||
501 | MIKMODAPI MLOADER load_mod = { | ||
502 | NULL, | ||
503 | "Standard module", | ||
504 | "MOD (31 instruments)", | ||
505 | MOD_Init, | ||
506 | MOD_Test, | ||
507 | MOD_Load, | ||
508 | MOD_Cleanup, | ||
509 | MOD_LoadTitle | ||
510 | }; | ||
511 | |||
512 | /* ex:set ts=4: */ | ||
diff --git a/apps/plugins/mikmod/load_mtm.c b/apps/plugins/mikmod/load_mtm.c new file mode 100644 index 0000000000..abd1da41f5 --- /dev/null +++ b/apps/plugins/mikmod/load_mtm.c | |||
@@ -0,0 +1,285 @@ | |||
1 | /* MikMod sound library | ||
2 | (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file | ||
3 | AUTHORS 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: load_mtm.c,v 1.3 2005/04/07 19:57:38 realtech Exp $ | ||
24 | |||
25 | MTM module loader | ||
26 | |||
27 | ==============================================================================*/ | ||
28 | |||
29 | #ifdef HAVE_CONFIG_H | ||
30 | #include "config.h" | ||
31 | #endif | ||
32 | |||
33 | #ifdef HAVE_UNISTD_H | ||
34 | #include <unistd.h> | ||
35 | #endif | ||
36 | |||
37 | #include <stdio.h> | ||
38 | #ifdef HAVE_MEMORY_H | ||
39 | #include <memory.h> | ||
40 | #endif | ||
41 | #include <string.h> | ||
42 | |||
43 | #include "mikmod_internals.h" | ||
44 | |||
45 | #ifdef SUNOS | ||
46 | extern int fprintf(FILE *, const char *, ...); | ||
47 | #endif | ||
48 | |||
49 | /*========== Module structure */ | ||
50 | |||
51 | typedef struct MTMHEADER { | ||
52 | UBYTE id[3]; /* MTM file marker */ | ||
53 | UBYTE version; /* upper major, lower nibble minor version number */ | ||
54 | CHAR songname[20]; /* ASCIIZ songname */ | ||
55 | UWORD numtracks; /* number of tracks saved */ | ||
56 | UBYTE lastpattern; /* last pattern number saved */ | ||
57 | UBYTE lastorder; /* last order number to play (songlength-1) */ | ||
58 | UWORD commentsize; /* length of comment field */ | ||
59 | UBYTE numsamples; /* number of samples saved */ | ||
60 | UBYTE attribute; /* attribute byte (unused) */ | ||
61 | UBYTE beatspertrack; | ||
62 | UBYTE numchannels; /* number of channels used */ | ||
63 | UBYTE panpos[32]; /* voice pan positions */ | ||
64 | } MTMHEADER; | ||
65 | |||
66 | typedef struct MTMSAMPLE { | ||
67 | CHAR samplename[22]; | ||
68 | ULONG length; | ||
69 | ULONG reppos; | ||
70 | ULONG repend; | ||
71 | UBYTE finetune; | ||
72 | UBYTE volume; | ||
73 | UBYTE attribute; | ||
74 | } MTMSAMPLE; | ||
75 | |||
76 | typedef struct MTMNOTE { | ||
77 | UBYTE a,b,c; | ||
78 | } MTMNOTE; | ||
79 | |||
80 | /*========== Loader variables */ | ||
81 | |||
82 | static MTMHEADER *mh = NULL; | ||
83 | static MTMNOTE *mtmtrk = NULL; | ||
84 | static UWORD pat[32]; | ||
85 | |||
86 | static CHAR MTM_Version[] = "MTM"; | ||
87 | |||
88 | /*========== Loader code */ | ||
89 | |||
90 | int MTM_Test(void) | ||
91 | { | ||
92 | UBYTE id[3]; | ||
93 | |||
94 | if(!_mm_read_UBYTES(id,3,modreader)) return 0; | ||
95 | if(!memcmp(id,"MTM",3)) return 1; | ||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | int MTM_Init(void) | ||
100 | { | ||
101 | if(!(mtmtrk=(MTMNOTE*)MikMod_calloc(64,sizeof(MTMNOTE)))) return 0; | ||
102 | if(!(mh=(MTMHEADER*)MikMod_malloc(sizeof(MTMHEADER)))) return 0; | ||
103 | |||
104 | return 1; | ||
105 | } | ||
106 | |||
107 | void MTM_Cleanup(void) | ||
108 | { | ||
109 | MikMod_free(mtmtrk); | ||
110 | MikMod_free(mh); | ||
111 | } | ||
112 | |||
113 | static UBYTE* MTM_Convert(void) | ||
114 | { | ||
115 | int t; | ||
116 | UBYTE a,b,inst,note,eff,dat; | ||
117 | |||
118 | UniReset(); | ||
119 | for(t=0;t<64;t++) { | ||
120 | a=mtmtrk[t].a; | ||
121 | b=mtmtrk[t].b; | ||
122 | inst=((a&0x3)<<4)|(b>>4); | ||
123 | note=a>>2; | ||
124 | eff=b&0xf; | ||
125 | dat=mtmtrk[t].c; | ||
126 | |||
127 | if(inst) UniInstrument(inst-1); | ||
128 | if(note) UniNote(note+2*OCTAVE); | ||
129 | |||
130 | /* MTM bug workaround : when the effect is volslide, slide-up *always* | ||
131 | overrides slide-down. */ | ||
132 | if(eff==0xa && (dat&0xf0)) dat&=0xf0; | ||
133 | |||
134 | /* Convert pattern jump from Dec to Hex */ | ||
135 | if(eff==0xd) | ||
136 | dat=(((dat&0xf0)>>4)*10)+(dat&0xf); | ||
137 | UniPTEffect(eff,dat); | ||
138 | UniNewline(); | ||
139 | } | ||
140 | return UniDup(); | ||
141 | } | ||
142 | |||
143 | int MTM_Load(int curious) | ||
144 | { | ||
145 | int t,u; | ||
146 | MTMSAMPLE s; | ||
147 | SAMPLE *q; | ||
148 | |||
149 | /* try to read module header */ | ||
150 | _mm_read_UBYTES(mh->id,3,modreader); | ||
151 | mh->version =_mm_read_UBYTE(modreader); | ||
152 | _mm_read_string(mh->songname,20,modreader); | ||
153 | mh->numtracks =_mm_read_I_UWORD(modreader); | ||
154 | mh->lastpattern =_mm_read_UBYTE(modreader); | ||
155 | mh->lastorder =_mm_read_UBYTE(modreader); | ||
156 | mh->commentsize =_mm_read_I_UWORD(modreader); | ||
157 | mh->numsamples =_mm_read_UBYTE(modreader); | ||
158 | mh->attribute =_mm_read_UBYTE(modreader); | ||
159 | mh->beatspertrack=_mm_read_UBYTE(modreader); | ||
160 | mh->numchannels =_mm_read_UBYTE(modreader); | ||
161 | _mm_read_UBYTES(mh->panpos,32,modreader); | ||
162 | |||
163 | if(_mm_eof(modreader)) { | ||
164 | _mm_errno = MMERR_LOADING_HEADER; | ||
165 | return 0; | ||
166 | } | ||
167 | |||
168 | /* set module variables */ | ||
169 | of.initspeed = 6; | ||
170 | of.inittempo = 125; | ||
171 | of.modtype = StrDup(MTM_Version); | ||
172 | of.numchn = mh->numchannels; | ||
173 | of.numtrk = mh->numtracks+1; /* get number of channels */ | ||
174 | of.songname = DupStr(mh->songname,20,1); /* make a cstr of songname */ | ||
175 | of.numpos = mh->lastorder+1; /* copy the songlength */ | ||
176 | of.numpat = mh->lastpattern+1; | ||
177 | of.reppos = 0; | ||
178 | of.flags |= UF_PANNING; | ||
179 | for(t=0;t<32;t++) of.panning[t]=mh->panpos[t]<< 4; | ||
180 | of.numins=of.numsmp=mh->numsamples; | ||
181 | |||
182 | if(!AllocSamples()) return 0; | ||
183 | q=of.samples; | ||
184 | for(t=0;t<of.numins;t++) { | ||
185 | /* try to read sample info */ | ||
186 | _mm_read_string(s.samplename,22,modreader); | ||
187 | s.length =_mm_read_I_ULONG(modreader); | ||
188 | s.reppos =_mm_read_I_ULONG(modreader); | ||
189 | s.repend =_mm_read_I_ULONG(modreader); | ||
190 | s.finetune =_mm_read_UBYTE(modreader); | ||
191 | s.volume =_mm_read_UBYTE(modreader); | ||
192 | s.attribute =_mm_read_UBYTE(modreader); | ||
193 | |||
194 | if(_mm_eof(modreader)) { | ||
195 | _mm_errno = MMERR_LOADING_SAMPLEINFO; | ||
196 | return 0; | ||
197 | } | ||
198 | |||
199 | q->samplename = DupStr(s.samplename,22,1); | ||
200 | q->seekpos = 0; | ||
201 | q->speed = finetune[s.finetune]; | ||
202 | q->length = s.length; | ||
203 | q->loopstart = s.reppos; | ||
204 | q->loopend = s.repend; | ||
205 | q->volume = s.volume; | ||
206 | if((s.repend-s.reppos)>2) q->flags |= SF_LOOP; | ||
207 | |||
208 | if(s.attribute&1) { | ||
209 | /* If the sample is 16-bits, convert the length and replen | ||
210 | byte-values into sample-values */ | ||
211 | q->flags|=SF_16BITS; | ||
212 | q->length>>=1; | ||
213 | q->loopstart>>=1; | ||
214 | q->loopend>>=1; | ||
215 | } | ||
216 | q++; | ||
217 | } | ||
218 | |||
219 | if(!AllocPositions(of.numpos)) return 0; | ||
220 | for(t=0;t<of.numpos;t++) | ||
221 | of.positions[t]=_mm_read_UBYTE(modreader); | ||
222 | for(;t<128;t++) _mm_read_UBYTE(modreader); | ||
223 | if(_mm_eof(modreader)) { | ||
224 | _mm_errno = MMERR_LOADING_HEADER; | ||
225 | return 0; | ||
226 | } | ||
227 | |||
228 | if(!AllocTracks()) return 0; | ||
229 | if(!AllocPatterns()) return 0; | ||
230 | |||
231 | of.tracks[0]=MTM_Convert(); /* track 0 is empty */ | ||
232 | for(t=1;t<of.numtrk;t++) { | ||
233 | int s; | ||
234 | |||
235 | for(s=0;s<64;s++) { | ||
236 | mtmtrk[s].a=_mm_read_UBYTE(modreader); | ||
237 | mtmtrk[s].b=_mm_read_UBYTE(modreader); | ||
238 | mtmtrk[s].c=_mm_read_UBYTE(modreader); | ||
239 | } | ||
240 | |||
241 | if(_mm_eof(modreader)) { | ||
242 | _mm_errno = MMERR_LOADING_TRACK; | ||
243 | return 0; | ||
244 | } | ||
245 | |||
246 | if(!(of.tracks[t]=MTM_Convert())) return 0; | ||
247 | } | ||
248 | |||
249 | for(t=0;t<of.numpat;t++) { | ||
250 | _mm_read_I_UWORDS(pat,32,modreader); | ||
251 | for(u=0;u<of.numchn;u++) | ||
252 | of.patterns[((long)t*of.numchn)+u]=pat[u]; | ||
253 | } | ||
254 | |||
255 | /* read comment field */ | ||
256 | if(mh->commentsize) | ||
257 | if(!ReadLinedComment(mh->commentsize, 40)) return 0; | ||
258 | |||
259 | return 1; | ||
260 | } | ||
261 | |||
262 | CHAR *MTM_LoadTitle(void) | ||
263 | { | ||
264 | CHAR s[20]; | ||
265 | |||
266 | _mm_fseek(modreader,4,SEEK_SET); | ||
267 | if(!_mm_read_UBYTES(s,20,modreader)) return NULL; | ||
268 | |||
269 | return(DupStr(s,20,1)); | ||
270 | } | ||
271 | |||
272 | /*========== Loader information */ | ||
273 | |||
274 | MIKMODAPI MLOADER load_mtm={ | ||
275 | NULL, | ||
276 | "MTM", | ||
277 | "MTM (MultiTracker Module editor)", | ||
278 | MTM_Init, | ||
279 | MTM_Test, | ||
280 | MTM_Load, | ||
281 | MTM_Cleanup, | ||
282 | MTM_LoadTitle | ||
283 | }; | ||
284 | |||
285 | /* ex:set ts=4: */ | ||
diff --git a/apps/plugins/mikmod/load_okt.c b/apps/plugins/mikmod/load_okt.c new file mode 100644 index 0000000000..c4420e5738 --- /dev/null +++ b/apps/plugins/mikmod/load_okt.c | |||
@@ -0,0 +1,460 @@ | |||
1 | /* MikMod sound library | ||
2 | (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file | ||
3 | AUTHORS 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: load_okt.c,v 1.3 2005/04/07 19:57:38 realtech Exp $ | ||
24 | |||
25 | Oktalyzer (OKT) module loader | ||
26 | |||
27 | ==============================================================================*/ | ||
28 | |||
29 | /* | ||
30 | Written by UFO <ufo303@poczta.onet.pl> | ||
31 | based on the file description compiled by Harald Zappe | ||
32 | <zappe@gaea.sietec.de> | ||
33 | |||
34 | */ | ||
35 | |||
36 | #ifdef HAVE_CONFIG_H | ||
37 | #include "config.h" | ||
38 | #endif | ||
39 | |||
40 | #ifdef HAVE_UNISTD_H | ||
41 | #include <unistd.h> | ||
42 | #endif | ||
43 | |||
44 | #include <stdio.h> | ||
45 | #ifdef HAVE_MEMORY_H | ||
46 | #include <memory.h> | ||
47 | #endif | ||
48 | #include <string.h> | ||
49 | |||
50 | #include "mikmod_internals.h" | ||
51 | |||
52 | #ifdef SUNOS | ||
53 | extern int fprintf(FILE *, const char *, ...); | ||
54 | #endif | ||
55 | |||
56 | /*========== Module blocks */ | ||
57 | |||
58 | /* sample information */ | ||
59 | typedef struct OKTSAMPLE { | ||
60 | CHAR sampname[20]; | ||
61 | ULONG len; | ||
62 | UWORD loopbeg; | ||
63 | UWORD looplen; | ||
64 | UBYTE volume; | ||
65 | } OKTSAMPLE; | ||
66 | |||
67 | typedef struct OKTNOTE { | ||
68 | UBYTE note, ins, eff, dat; | ||
69 | } OKTNOTE; | ||
70 | |||
71 | /*========== Loader variables */ | ||
72 | |||
73 | static OKTNOTE *okttrk = NULL; | ||
74 | |||
75 | /*========== Loader code */ | ||
76 | |||
77 | int OKT_Test(void) | ||
78 | { | ||
79 | CHAR id[8]; | ||
80 | |||
81 | if (!_mm_read_UBYTES(id, 8, modreader)) | ||
82 | return 0; | ||
83 | if (!memcmp(id, "OKTASONG", 8)) | ||
84 | return 1; | ||
85 | |||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | /* Pattern analysis routine. | ||
90 | Effects not implemented (yet) : (in decimal) | ||
91 | 11 Arpeggio 4: Change note every 50Hz tick between N,H,N,L | ||
92 | 12 Arpeggio 5: Change note every 50Hz tick between H,H,N | ||
93 | N = normal note being played in this channel (1-36) | ||
94 | L = normal note number minus upper four bits of 'data'. | ||
95 | H = normal note number plus lower four bits of 'data'. | ||
96 | 13 Decrease note number by 'data' once per tick. | ||
97 | 17 Increase note number by 'data' once per tick. | ||
98 | 21 Decrease note number by 'data' once per line. | ||
99 | 30 Increase note number by 'data' once per line. | ||
100 | */ | ||
101 | static UBYTE *OKT_ConvertTrack(UBYTE patrows) | ||
102 | { | ||
103 | int t; | ||
104 | UBYTE ins, note, eff, dat; | ||
105 | |||
106 | UniReset(); | ||
107 | for (t = 0; t < patrows; t++) { | ||
108 | note = okttrk[t].note; | ||
109 | ins = okttrk[t].ins; | ||
110 | eff = okttrk[t].eff; | ||
111 | dat = okttrk[t].dat; | ||
112 | |||
113 | if (note) { | ||
114 | UniNote(note + 3 * OCTAVE - 1); | ||
115 | UniInstrument(ins); | ||
116 | } | ||
117 | |||
118 | if (eff) | ||
119 | switch (eff) { | ||
120 | case 1: /* Porta Up */ | ||
121 | UniPTEffect(0x1, dat); | ||
122 | break; | ||
123 | case 2: /* Portamento Down */ | ||
124 | UniPTEffect(0x2, dat); | ||
125 | break; | ||
126 | /* case 9: what is this? */ | ||
127 | case 10: /* Arpeggio 3 */ | ||
128 | case 11: /* Arpeggio 4 */ | ||
129 | case 12: /* Arpeggio 5 */ | ||
130 | UniWriteByte(UNI_OKTARP); | ||
131 | UniWriteByte(eff + 3 - 10); | ||
132 | UniWriteByte(dat); | ||
133 | break; | ||
134 | case 15: /* Amiga filter toggle, ignored */ | ||
135 | break; | ||
136 | case 25: /* Pattern Jump */ | ||
137 | dat = (dat >> 4) * 10 + (dat & 0x0f); | ||
138 | UniPTEffect(0xb, dat); | ||
139 | break; | ||
140 | case 27: /* Release - similar to Keyoff */ | ||
141 | UniWriteByte(UNI_KEYOFF); | ||
142 | break; | ||
143 | case 28: /* Set Tempo */ | ||
144 | UniPTEffect(0xf, dat & 0x0f); | ||
145 | break; | ||
146 | case 31: /* volume Control */ | ||
147 | if (dat <= 0x40) | ||
148 | UniPTEffect(0xc, dat); | ||
149 | else if (dat <= 0x50) | ||
150 | UniEffect(UNI_XMEFFECTA, (dat - 0x40)); /* fast fade out */ | ||
151 | else if (dat <= 0x60) | ||
152 | UniEffect(UNI_XMEFFECTA, (dat - 0x50) << 4); /* fast fade in */ | ||
153 | else if (dat <= 0x70) | ||
154 | UniEffect(UNI_XMEFFECTEB, (dat - 0x60)); /* slow fade out */ | ||
155 | else if (dat <= 0x80) | ||
156 | UniEffect(UNI_XMEFFECTEA, (dat - 0x70)); /* slow fade in */ | ||
157 | break; | ||
158 | #ifdef MIKMOD_DEBUG | ||
159 | default: | ||
160 | fprintf(stderr, "\rUnimplemented effect (%02d,%02x)\n", | ||
161 | eff, dat); | ||
162 | #endif | ||
163 | } | ||
164 | |||
165 | UniNewline(); | ||
166 | } | ||
167 | return UniDup(); | ||
168 | } | ||
169 | |||
170 | /* Read "channel modes" i.e. channel number and panning information */ | ||
171 | static void OKT_doCMOD(void) | ||
172 | { | ||
173 | /* amiga channel panning table */ | ||
174 | UBYTE amigapan[4] = { 0x00, 0xff, 0xff, 0x00 }; | ||
175 | int t; | ||
176 | |||
177 | of.numchn = 0; | ||
178 | of.flags |= UF_PANNING; | ||
179 | |||
180 | for (t = 0; t < 4; t++) | ||
181 | if (_mm_read_M_UWORD(modreader)) { | ||
182 | /* two channels tied to the same Amiga hardware voice */ | ||
183 | of.panning[of.numchn++] = amigapan[t]; | ||
184 | of.panning[of.numchn++] = amigapan[t]; | ||
185 | } else | ||
186 | /* one channel tied to the Amiga hardware voice */ | ||
187 | of.panning[of.numchn++] = amigapan[t]; | ||
188 | } | ||
189 | |||
190 | /* Read sample information */ | ||
191 | static int OKT_doSAMP(int len) | ||
192 | { | ||
193 | int t; | ||
194 | SAMPLE *q; | ||
195 | OKTSAMPLE s; | ||
196 | |||
197 | of.numins = of.numsmp = (len / 0x20); | ||
198 | if (!AllocSamples()) | ||
199 | return 0; | ||
200 | |||
201 | for (t = 0, q = of.samples; t < of.numins; t++, q++) { | ||
202 | _mm_read_UBYTES(s.sampname, 20, modreader); | ||
203 | s.len = _mm_read_M_ULONG(modreader); | ||
204 | s.loopbeg = _mm_read_M_UWORD(modreader) * 2; | ||
205 | s.looplen = _mm_read_M_UWORD(modreader) * 2; | ||
206 | _mm_read_UBYTE(modreader); | ||
207 | s.volume = _mm_read_UBYTE(modreader); | ||
208 | _mm_read_M_UWORD(modreader); | ||
209 | |||
210 | if (_mm_eof(modreader)) { | ||
211 | _mm_errno = MMERR_LOADING_SAMPLEINFO; | ||
212 | return 0; | ||
213 | } | ||
214 | |||
215 | if (!s.len) | ||
216 | q->seekpos = q->length = q->loopstart = q->loopend = q->flags = 0; | ||
217 | else { | ||
218 | s.len--; | ||
219 | /* sanity checks */ | ||
220 | if (s.loopbeg > s.len) | ||
221 | s.loopbeg = s.len; | ||
222 | if (s.loopbeg + s.looplen > s.len) | ||
223 | s.looplen = s.len - s.loopbeg; | ||
224 | if (s.looplen < 2) | ||
225 | s.looplen = 0; | ||
226 | |||
227 | q->length = s.len; | ||
228 | q->loopstart = s.loopbeg; | ||
229 | q->loopend = s.looplen + q->loopstart; | ||
230 | q->volume = s.volume; | ||
231 | q->flags = SF_SIGNED; | ||
232 | |||
233 | if (s.looplen) | ||
234 | q->flags |= SF_LOOP; | ||
235 | } | ||
236 | q->samplename = DupStr(s.sampname, 20, 1); | ||
237 | q->speed = 8287; | ||
238 | } | ||
239 | return 1; | ||
240 | } | ||
241 | |||
242 | /* Read speed information */ | ||
243 | static void OKT_doSPEE(void) | ||
244 | { | ||
245 | int tempo = _mm_read_M_UWORD(modreader); | ||
246 | |||
247 | of.initspeed = tempo; | ||
248 | } | ||
249 | |||
250 | /* Read song length information */ | ||
251 | static void OKT_doSLEN(void) | ||
252 | { | ||
253 | of.numpat = _mm_read_M_UWORD(modreader); | ||
254 | } | ||
255 | |||
256 | /* Read pattern length information */ | ||
257 | static void OKT_doPLEN(void) | ||
258 | { | ||
259 | of.numpos = _mm_read_M_UWORD(modreader); | ||
260 | } | ||
261 | |||
262 | /* Read order table */ | ||
263 | static int OKT_doPATT(void) | ||
264 | { | ||
265 | int t; | ||
266 | |||
267 | if (!of.numpos || !AllocPositions(of.numpos)) | ||
268 | return 0; | ||
269 | |||
270 | for (t = 0; t < 128; t++) | ||
271 | if (t < of.numpos) | ||
272 | of.positions[t] = _mm_read_UBYTE(modreader); | ||
273 | else | ||
274 | break; | ||
275 | |||
276 | return 1; | ||
277 | } | ||
278 | |||
279 | static int OKT_doPBOD(int patnum) | ||
280 | { | ||
281 | char *patbuf; | ||
282 | int rows, i; | ||
283 | int u; | ||
284 | |||
285 | if (!patnum) { | ||
286 | of.numtrk = of.numpat * of.numchn; | ||
287 | |||
288 | if (!AllocTracks() || !AllocPatterns()) | ||
289 | return 0; | ||
290 | } | ||
291 | |||
292 | /* Read pattern */ | ||
293 | of.pattrows[patnum] = rows = _mm_read_M_UWORD(modreader); | ||
294 | |||
295 | if (!(okttrk = (OKTNOTE *) MikMod_calloc(rows, sizeof(OKTNOTE))) || | ||
296 | !(patbuf = (char *)MikMod_calloc(rows * of.numchn, sizeof(OKTNOTE)))) | ||
297 | return 0; | ||
298 | _mm_read_UBYTES(patbuf, rows * of.numchn * sizeof(OKTNOTE), modreader); | ||
299 | if (_mm_eof(modreader)) { | ||
300 | _mm_errno = MMERR_LOADING_PATTERN; | ||
301 | return 0; | ||
302 | } | ||
303 | |||
304 | for (i = 0; i < of.numchn; i++) { | ||
305 | for (u = 0; u < rows; u++) { | ||
306 | okttrk[u].note = patbuf[(u * of.numchn + i) * sizeof(OKTNOTE)]; | ||
307 | okttrk[u].ins = patbuf[(u * of.numchn + i) * sizeof(OKTNOTE) + 1]; | ||
308 | okttrk[u].eff = patbuf[(u * of.numchn + i) * sizeof(OKTNOTE) + 2]; | ||
309 | okttrk[u].dat = patbuf[(u * of.numchn + i) * sizeof(OKTNOTE) + 3]; | ||
310 | } | ||
311 | |||
312 | if (!(of.tracks[patnum * of.numchn + i] = OKT_ConvertTrack(rows))) | ||
313 | return 0; | ||
314 | } | ||
315 | MikMod_free(patbuf); | ||
316 | MikMod_free(okttrk); | ||
317 | return 1; | ||
318 | } | ||
319 | |||
320 | static void OKT_doSBOD(int insnum) | ||
321 | { | ||
322 | of.samples[insnum].seekpos = _mm_ftell(modreader); | ||
323 | } | ||
324 | |||
325 | int OKT_Load(int curious) | ||
326 | { | ||
327 | UBYTE id[4]; | ||
328 | ULONG len; | ||
329 | ULONG fp; | ||
330 | int seen_cmod = 0, seen_samp = 0, seen_slen = 0, seen_plen = 0, seen_patt | ||
331 | = 0, seen_spee = 0; | ||
332 | int patnum = 0, insnum = 0; | ||
333 | |||
334 | /* skip OKTALYZER header */ | ||
335 | _mm_fseek(modreader, 8, SEEK_SET); | ||
336 | of.songname = StrDup(""); | ||
337 | |||
338 | of.modtype = StrDup("Amiga Oktalyzer"); | ||
339 | of.numpos = of.reppos = 0; | ||
340 | |||
341 | /* default values */ | ||
342 | of.initspeed = 6; | ||
343 | of.inittempo = 125; | ||
344 | |||
345 | while (1) { | ||
346 | /* read block header */ | ||
347 | _mm_read_UBYTES(id, 4, modreader); | ||
348 | len = _mm_read_M_ULONG(modreader); | ||
349 | |||
350 | if (_mm_eof(modreader)) | ||
351 | break; | ||
352 | fp = _mm_ftell(modreader); | ||
353 | |||
354 | if (!memcmp(id, "CMOD", 4)) { | ||
355 | if (!seen_cmod) { | ||
356 | OKT_doCMOD(); | ||
357 | seen_cmod = 1; | ||
358 | } else { | ||
359 | _mm_errno = MMERR_LOADING_HEADER; | ||
360 | return 0; | ||
361 | } | ||
362 | } else if (!memcmp(id, "SAMP", 4)) { | ||
363 | if (!seen_samp && OKT_doSAMP(len)) | ||
364 | seen_samp = 1; | ||
365 | else { | ||
366 | _mm_errno = MMERR_LOADING_HEADER; | ||
367 | return 0; | ||
368 | } | ||
369 | } else if (!memcmp(id, "SPEE", 4)) { | ||
370 | if (!seen_spee) { | ||
371 | OKT_doSPEE(); | ||
372 | seen_spee = 1; | ||
373 | } else { | ||
374 | _mm_errno = MMERR_LOADING_HEADER; | ||
375 | return 0; | ||
376 | } | ||
377 | } else if (!memcmp(id, "SLEN", 4)) { | ||
378 | if (!seen_slen) { | ||
379 | OKT_doSLEN(); | ||
380 | seen_slen = 1; | ||
381 | } else { | ||
382 | _mm_errno = MMERR_LOADING_HEADER; | ||
383 | return 0; | ||
384 | } | ||
385 | } else if (!memcmp(id, "PLEN", 4)) { | ||
386 | if (!seen_plen) { | ||
387 | OKT_doPLEN(); | ||
388 | seen_plen = 1; | ||
389 | } else { | ||
390 | _mm_errno = MMERR_LOADING_HEADER; | ||
391 | return 0; | ||
392 | } | ||
393 | } else if (!memcmp(id, "PATT", 4)) { | ||
394 | if (!seen_plen) { | ||
395 | _mm_errno = MMERR_LOADING_HEADER; | ||
396 | return 0; | ||
397 | } | ||
398 | if (!seen_patt && OKT_doPATT()) | ||
399 | seen_patt = 1; | ||
400 | else { | ||
401 | _mm_errno = MMERR_LOADING_HEADER; | ||
402 | return 0; | ||
403 | } | ||
404 | } else if (!memcmp(id,"PBOD", 4)) { | ||
405 | /* need to know numpat and numchn */ | ||
406 | if (!seen_slen || !seen_cmod || (patnum >= of.numpat)) { | ||
407 | _mm_errno = MMERR_LOADING_HEADER; | ||
408 | return 0; | ||
409 | } | ||
410 | if (!OKT_doPBOD(patnum++)) { | ||
411 | _mm_errno = MMERR_LOADING_PATTERN; | ||
412 | return 0; | ||
413 | } | ||
414 | } else if (!memcmp(id,"SBOD",4)) { | ||
415 | /* need to know numsmp */ | ||
416 | if (!seen_samp) { | ||
417 | _mm_errno = MMERR_LOADING_HEADER; | ||
418 | return 0; | ||
419 | } | ||
420 | while ((insnum < of.numins) && !of.samples[insnum].length) | ||
421 | insnum++; | ||
422 | if (insnum >= of.numins) { | ||
423 | _mm_errno = MMERR_LOADING_HEADER; | ||
424 | return 0; | ||
425 | } | ||
426 | OKT_doSBOD(insnum++); | ||
427 | } | ||
428 | |||
429 | /* goto next block start position */ | ||
430 | _mm_fseek(modreader, fp + len, SEEK_SET); | ||
431 | } | ||
432 | |||
433 | if (!seen_cmod || !seen_samp || !seen_patt || | ||
434 | !seen_slen || !seen_plen || (patnum != of.numpat)) { | ||
435 | _mm_errno = MMERR_LOADING_HEADER; | ||
436 | return 0; | ||
437 | } | ||
438 | |||
439 | return 1; | ||
440 | } | ||
441 | |||
442 | CHAR *OKT_LoadTitle(void) | ||
443 | { | ||
444 | return StrDup(""); | ||
445 | } | ||
446 | |||
447 | /*========== Loader information */ | ||
448 | |||
449 | MIKMODAPI MLOADER load_okt = { | ||
450 | NULL, | ||
451 | "OKT", | ||
452 | "OKT (Amiga Oktalyzer)", | ||
453 | NULL, | ||
454 | OKT_Test, | ||
455 | OKT_Load, | ||
456 | NULL, | ||
457 | OKT_LoadTitle | ||
458 | }; | ||
459 | |||
460 | /* ex:set ts=4: */ | ||
diff --git a/apps/plugins/mikmod/load_s3m.c b/apps/plugins/mikmod/load_s3m.c new file mode 100644 index 0000000000..4ecb5bdd1f --- /dev/null +++ b/apps/plugins/mikmod/load_s3m.c | |||
@@ -0,0 +1,470 @@ | |||
1 | /* MikMod sound library | ||
2 | (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file | ||
3 | AUTHORS 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: load_s3m.c,v 1.3 2005/04/07 19:57:38 realtech Exp $ | ||
24 | |||
25 | Screamtracker (S3M) module loader | ||
26 | |||
27 | ==============================================================================*/ | ||
28 | |||
29 | #ifdef HAVE_CONFIG_H | ||
30 | #include "config.h" | ||
31 | #endif | ||
32 | |||
33 | #ifdef HAVE_UNISTD_H | ||
34 | #include <unistd.h> | ||
35 | #endif | ||
36 | |||
37 | #include <stdio.h> | ||
38 | #ifdef HAVE_MEMORY_H | ||
39 | #include <memory.h> | ||
40 | #endif | ||
41 | #include <string.h> | ||
42 | |||
43 | #include "mikmod_internals.h" | ||
44 | |||
45 | #ifdef SUNOS | ||
46 | extern int fprintf(FILE *, const char *, ...); | ||
47 | #endif | ||
48 | |||
49 | /*========== Module structure */ | ||
50 | |||
51 | /* header */ | ||
52 | typedef struct S3MHEADER { | ||
53 | CHAR songname[28]; | ||
54 | UBYTE t1a; | ||
55 | UBYTE type; | ||
56 | UBYTE unused1[2]; | ||
57 | UWORD ordnum; | ||
58 | UWORD insnum; | ||
59 | UWORD patnum; | ||
60 | UWORD flags; | ||
61 | UWORD tracker; | ||
62 | UWORD fileformat; | ||
63 | CHAR scrm[4]; | ||
64 | UBYTE mastervol; | ||
65 | UBYTE initspeed; | ||
66 | UBYTE inittempo; | ||
67 | UBYTE mastermult; | ||
68 | UBYTE ultraclick; | ||
69 | UBYTE pantable; | ||
70 | UBYTE unused2[8]; | ||
71 | UWORD special; | ||
72 | UBYTE channels[32]; | ||
73 | } S3MHEADER; | ||
74 | |||
75 | /* sample information */ | ||
76 | typedef struct S3MSAMPLE { | ||
77 | UBYTE type; | ||
78 | CHAR filename[12]; | ||
79 | UBYTE memsegh; | ||
80 | UWORD memsegl; | ||
81 | ULONG length; | ||
82 | ULONG loopbeg; | ||
83 | ULONG loopend; | ||
84 | UBYTE volume; | ||
85 | UBYTE dsk; | ||
86 | UBYTE pack; | ||
87 | UBYTE flags; | ||
88 | ULONG c2spd; | ||
89 | UBYTE unused[12]; | ||
90 | CHAR sampname[28]; | ||
91 | CHAR scrs[4]; | ||
92 | } S3MSAMPLE; | ||
93 | |||
94 | typedef struct S3MNOTE { | ||
95 | UBYTE note,ins,vol,cmd,inf; | ||
96 | } S3MNOTE; | ||
97 | |||
98 | /*========== Loader variables */ | ||
99 | |||
100 | static S3MNOTE *s3mbuf = NULL; /* pointer to a complete S3M pattern */ | ||
101 | static S3MHEADER *mh = NULL; | ||
102 | static UWORD *paraptr = NULL; /* parapointer array (see S3M docs) */ | ||
103 | static unsigned int tracker; /* tracker id */ | ||
104 | |||
105 | /* tracker identifiers */ | ||
106 | #define NUMTRACKERS 4 | ||
107 | static CHAR* S3M_Version[] = { | ||
108 | "Screamtracker x.xx", | ||
109 | "Imago Orpheus x.xx (S3M format)", | ||
110 | "Impulse Tracker x.xx (S3M format)", | ||
111 | "Unknown tracker x.xx (S3M format)", | ||
112 | "Impulse Tracker 2.14p3 (S3M format)", | ||
113 | "Impulse Tracker 2.14p4 (S3M format)" | ||
114 | }; | ||
115 | /* version number position in above array */ | ||
116 | static int numeric[NUMTRACKERS]={14,14,16,16}; | ||
117 | |||
118 | /*========== Loader code */ | ||
119 | |||
120 | int S3M_Test(void) | ||
121 | { | ||
122 | UBYTE id[4]; | ||
123 | |||
124 | _mm_fseek(modreader,0x2c,SEEK_SET); | ||
125 | if(!_mm_read_UBYTES(id,4,modreader)) return 0; | ||
126 | if(!memcmp(id,"SCRM",4)) return 1; | ||
127 | return 0; | ||
128 | } | ||
129 | |||
130 | int S3M_Init(void) | ||
131 | { | ||
132 | if(!(s3mbuf=(S3MNOTE*)MikMod_malloc(32*64*sizeof(S3MNOTE)))) return 0; | ||
133 | if(!(mh=(S3MHEADER*)MikMod_malloc(sizeof(S3MHEADER)))) return 0; | ||
134 | if(!(poslookup=(UBYTE*)MikMod_malloc(sizeof(UBYTE)*256))) return 0; | ||
135 | memset(poslookup,-1,256); | ||
136 | |||
137 | return 1; | ||
138 | } | ||
139 | |||
140 | void S3M_Cleanup(void) | ||
141 | { | ||
142 | MikMod_free(s3mbuf); | ||
143 | MikMod_free(paraptr); | ||
144 | MikMod_free(poslookup); | ||
145 | MikMod_free(mh); | ||
146 | MikMod_free(origpositions); | ||
147 | } | ||
148 | |||
149 | /* Because so many s3m files have 16 channels as the set number used, but really | ||
150 | only use far less (usually 8 to 12 still), I had to make this function, which | ||
151 | determines the number of channels that are actually USED by a pattern. | ||
152 | |||
153 | For every channel that's used, it sets the appropriate array entry of the | ||
154 | global variable 'remap' | ||
155 | |||
156 | NOTE: You must first seek to the file location of the pattern before calling | ||
157 | this procedure. | ||
158 | |||
159 | Returns 1 on fail. */ | ||
160 | static int S3M_GetNumChannels(void) | ||
161 | { | ||
162 | int row=0,flag,ch; | ||
163 | |||
164 | while(row<64) { | ||
165 | flag=_mm_read_UBYTE(modreader); | ||
166 | |||
167 | if(_mm_eof(modreader)) { | ||
168 | _mm_errno = MMERR_LOADING_PATTERN; | ||
169 | return 1; | ||
170 | } | ||
171 | |||
172 | if(flag) { | ||
173 | ch=flag&31; | ||
174 | if(mh->channels[ch]<32) remap[ch] = 0; | ||
175 | if(flag&32) {_mm_read_UBYTE(modreader);_mm_read_UBYTE(modreader);} | ||
176 | if(flag&64) _mm_read_UBYTE(modreader); | ||
177 | if(flag&128){_mm_read_UBYTE(modreader);_mm_read_UBYTE(modreader);} | ||
178 | } else row++; | ||
179 | } | ||
180 | return 0; | ||
181 | } | ||
182 | |||
183 | static int S3M_ReadPattern(void) | ||
184 | { | ||
185 | int row=0,flag,ch; | ||
186 | S3MNOTE *n,dummy; | ||
187 | |||
188 | /* clear pattern data */ | ||
189 | memset(s3mbuf,255,32*64*sizeof(S3MNOTE)); | ||
190 | |||
191 | while(row<64) { | ||
192 | flag=_mm_read_UBYTE(modreader); | ||
193 | |||
194 | if(_mm_eof(modreader)) { | ||
195 | _mm_errno = MMERR_LOADING_PATTERN; | ||
196 | return 0; | ||
197 | } | ||
198 | |||
199 | if(flag) { | ||
200 | ch=remap[flag&31]; | ||
201 | |||
202 | if(ch!=-1) | ||
203 | n=&s3mbuf[(64U*ch)+row]; | ||
204 | else | ||
205 | n=&dummy; | ||
206 | |||
207 | if(flag&32) { | ||
208 | n->note=_mm_read_UBYTE(modreader); | ||
209 | n->ins=_mm_read_UBYTE(modreader); | ||
210 | } | ||
211 | if(flag&64) { | ||
212 | n->vol=_mm_read_UBYTE(modreader); | ||
213 | if (n->vol>64) n->vol=64; | ||
214 | } | ||
215 | if(flag&128) { | ||
216 | n->cmd=_mm_read_UBYTE(modreader); | ||
217 | n->inf=_mm_read_UBYTE(modreader); | ||
218 | } | ||
219 | } else row++; | ||
220 | } | ||
221 | return 1; | ||
222 | } | ||
223 | |||
224 | static UBYTE* S3M_ConvertTrack(S3MNOTE* tr) | ||
225 | { | ||
226 | int t; | ||
227 | |||
228 | UniReset(); | ||
229 | for(t=0;t<64;t++) { | ||
230 | UBYTE note,ins,vol; | ||
231 | |||
232 | note=tr[t].note; | ||
233 | ins=tr[t].ins; | ||
234 | vol=tr[t].vol; | ||
235 | |||
236 | if((ins)&&(ins!=255)) UniInstrument(ins-1); | ||
237 | if(note!=255) { | ||
238 | if(note==254) { | ||
239 | UniPTEffect(0xc,0); /* note cut command */ | ||
240 | vol=255; | ||
241 | } else | ||
242 | UniNote(((note>>4)*OCTAVE)+(note&0xf)); /* normal note */ | ||
243 | } | ||
244 | if(vol<255) UniPTEffect(0xc,vol); | ||
245 | |||
246 | S3MIT_ProcessCmd(tr[t].cmd,tr[t].inf, | ||
247 | tracker == 1 ? S3MIT_OLDSTYLE | S3MIT_SCREAM : S3MIT_OLDSTYLE); | ||
248 | UniNewline(); | ||
249 | } | ||
250 | return UniDup(); | ||
251 | } | ||
252 | |||
253 | int S3M_Load(int curious) | ||
254 | { | ||
255 | int t,u,track = 0; | ||
256 | SAMPLE *q; | ||
257 | UBYTE pan[32]; | ||
258 | |||
259 | /* try to read module header */ | ||
260 | _mm_read_string(mh->songname,28,modreader); | ||
261 | mh->t1a =_mm_read_UBYTE(modreader); | ||
262 | mh->type =_mm_read_UBYTE(modreader); | ||
263 | _mm_read_UBYTES(mh->unused1,2,modreader); | ||
264 | mh->ordnum =_mm_read_I_UWORD(modreader); | ||
265 | mh->insnum =_mm_read_I_UWORD(modreader); | ||
266 | mh->patnum =_mm_read_I_UWORD(modreader); | ||
267 | mh->flags =_mm_read_I_UWORD(modreader); | ||
268 | mh->tracker =_mm_read_I_UWORD(modreader); | ||
269 | mh->fileformat =_mm_read_I_UWORD(modreader); | ||
270 | _mm_read_string(mh->scrm,4,modreader); | ||
271 | mh->mastervol =_mm_read_UBYTE(modreader); | ||
272 | mh->initspeed =_mm_read_UBYTE(modreader); | ||
273 | mh->inittempo =_mm_read_UBYTE(modreader); | ||
274 | mh->mastermult =_mm_read_UBYTE(modreader); | ||
275 | mh->ultraclick =_mm_read_UBYTE(modreader); | ||
276 | mh->pantable =_mm_read_UBYTE(modreader); | ||
277 | _mm_read_UBYTES(mh->unused2,8,modreader); | ||
278 | mh->special =_mm_read_I_UWORD(modreader); | ||
279 | _mm_read_UBYTES(mh->channels,32,modreader); | ||
280 | |||
281 | if(_mm_eof(modreader)) { | ||
282 | _mm_errno = MMERR_LOADING_HEADER; | ||
283 | return 0; | ||
284 | } | ||
285 | |||
286 | /* then we can decide the module type */ | ||
287 | tracker=mh->tracker>>12; | ||
288 | if((!tracker)||(tracker>=NUMTRACKERS)) | ||
289 | tracker=NUMTRACKERS-1; /* unknown tracker */ | ||
290 | else { | ||
291 | if(mh->tracker>=0x3217) | ||
292 | tracker=NUMTRACKERS+1; /* IT 2.14p4 */ | ||
293 | else if(mh->tracker>=0x3216) | ||
294 | tracker=NUMTRACKERS; /* IT 2.14p3 */ | ||
295 | else tracker--; | ||
296 | } | ||
297 | of.modtype = StrDup(S3M_Version[tracker]); | ||
298 | if(tracker<NUMTRACKERS) { | ||
299 | of.modtype[numeric[tracker]] = ((mh->tracker>>8) &0xf)+'0'; | ||
300 | of.modtype[numeric[tracker]+2] = ((mh->tracker>>4)&0xf)+'0'; | ||
301 | of.modtype[numeric[tracker]+3] = ((mh->tracker)&0xf)+'0'; | ||
302 | } | ||
303 | /* set module variables */ | ||
304 | of.songname = DupStr(mh->songname,28,0); | ||
305 | of.numpat = mh->patnum; | ||
306 | of.reppos = 0; | ||
307 | of.numins = of.numsmp = mh->insnum; | ||
308 | of.initspeed = mh->initspeed; | ||
309 | of.inittempo = mh->inittempo; | ||
310 | of.initvolume = mh->mastervol<<1; | ||
311 | of.flags |= UF_ARPMEM | UF_PANNING; | ||
312 | if((mh->tracker==0x1300)||(mh->flags&64)) | ||
313 | of.flags|=UF_S3MSLIDES; | ||
314 | of.bpmlimit = 32; | ||
315 | |||
316 | /* read the order data */ | ||
317 | if(!AllocPositions(mh->ordnum)) return 0; | ||
318 | if(!(origpositions=MikMod_calloc(mh->ordnum,sizeof(UWORD)))) return 0; | ||
319 | |||
320 | for(t=0;t<mh->ordnum;t++) { | ||
321 | origpositions[t]=_mm_read_UBYTE(modreader); | ||
322 | if((origpositions[t]>=mh->patnum)&&(origpositions[t]<254)) | ||
323 | origpositions[t]=255/*mh->patnum-1*/; | ||
324 | } | ||
325 | |||
326 | if(_mm_eof(modreader)) { | ||
327 | _mm_errno = MMERR_LOADING_HEADER; | ||
328 | return 0; | ||
329 | } | ||
330 | |||
331 | poslookupcnt=mh->ordnum; | ||
332 | S3MIT_CreateOrders(curious); | ||
333 | |||
334 | if(!(paraptr=(UWORD*)MikMod_malloc((of.numins+of.numpat)*sizeof(UWORD)))) | ||
335 | return 0; | ||
336 | |||
337 | /* read the instrument+pattern parapointers */ | ||
338 | _mm_read_I_UWORDS(paraptr,of.numins+of.numpat,modreader); | ||
339 | |||
340 | if(mh->pantable==252) { | ||
341 | /* read the panning table (ST 3.2 addition. See below for further | ||
342 | portions of channel panning [past reampper]). */ | ||
343 | _mm_read_UBYTES(pan,32,modreader); | ||
344 | } | ||
345 | |||
346 | if(_mm_eof(modreader)) { | ||
347 | _mm_errno = MMERR_LOADING_HEADER; | ||
348 | return 0; | ||
349 | } | ||
350 | |||
351 | /* load samples */ | ||
352 | if(!AllocSamples()) return 0; | ||
353 | q = of.samples; | ||
354 | for(t=0;t<of.numins;t++) { | ||
355 | S3MSAMPLE s; | ||
356 | |||
357 | /* seek to instrument position */ | ||
358 | _mm_fseek(modreader,((long)paraptr[t])<<4,SEEK_SET); | ||
359 | /* and load sample info */ | ||
360 | s.type =_mm_read_UBYTE(modreader); | ||
361 | _mm_read_string(s.filename,12,modreader); | ||
362 | s.memsegh =_mm_read_UBYTE(modreader); | ||
363 | s.memsegl =_mm_read_I_UWORD(modreader); | ||
364 | s.length =_mm_read_I_ULONG(modreader); | ||
365 | s.loopbeg =_mm_read_I_ULONG(modreader); | ||
366 | s.loopend =_mm_read_I_ULONG(modreader); | ||
367 | s.volume =_mm_read_UBYTE(modreader); | ||
368 | s.dsk =_mm_read_UBYTE(modreader); | ||
369 | s.pack =_mm_read_UBYTE(modreader); | ||
370 | s.flags =_mm_read_UBYTE(modreader); | ||
371 | s.c2spd =_mm_read_I_ULONG(modreader); | ||
372 | _mm_read_UBYTES(s.unused,12,modreader); | ||
373 | _mm_read_string(s.sampname,28,modreader); | ||
374 | _mm_read_string(s.scrs,4,modreader); | ||
375 | |||
376 | /* ScreamTracker imposes a 64000 bytes (not 64k !) limit */ | ||
377 | if (s.length > 64000) | ||
378 | s.length = 64000; | ||
379 | |||
380 | if(_mm_eof(modreader)) { | ||
381 | _mm_errno = MMERR_LOADING_SAMPLEINFO; | ||
382 | return 0; | ||
383 | } | ||
384 | |||
385 | q->samplename = DupStr(s.sampname,28,0); | ||
386 | q->speed = s.c2spd; | ||
387 | q->length = s.length; | ||
388 | q->loopstart = s.loopbeg; | ||
389 | q->loopend = s.loopend; | ||
390 | q->volume = s.volume; | ||
391 | q->seekpos = (((long)s.memsegh)<<16|s.memsegl)<<4; | ||
392 | |||
393 | if(s.flags&1) q->flags |= SF_LOOP; | ||
394 | if(s.flags&4) q->flags |= SF_16BITS; | ||
395 | if(mh->fileformat==1) q->flags |= SF_SIGNED; | ||
396 | |||
397 | /* don't load sample if it doesn't have the SCRS tag */ | ||
398 | if(memcmp(s.scrs,"SCRS",4)) q->length = 0; | ||
399 | |||
400 | q++; | ||
401 | } | ||
402 | |||
403 | /* determine the number of channels actually used. */ | ||
404 | of.numchn = 0; | ||
405 | memset(remap,-1,32*sizeof(UBYTE)); | ||
406 | for(t=0;t<of.numpat;t++) { | ||
407 | /* seek to pattern position (+2 skip pattern length) */ | ||
408 | _mm_fseek(modreader,(long)((paraptr[of.numins+t])<<4)+2,SEEK_SET); | ||
409 | if(S3M_GetNumChannels()) return 0; | ||
410 | } | ||
411 | |||
412 | /* build the remap array */ | ||
413 | for(t=0;t<32;t++) | ||
414 | if(!remap[t]) | ||
415 | remap[t]=of.numchn++; | ||
416 | |||
417 | /* set panning positions after building remap chart! */ | ||
418 | for(t=0;t<32;t++) | ||
419 | if((mh->channels[t]<32)&&(remap[t]!=-1)) { | ||
420 | if(mh->channels[t]<8) | ||
421 | of.panning[remap[t]]=0x30; | ||
422 | else | ||
423 | of.panning[remap[t]]=0xc0; | ||
424 | } | ||
425 | if(mh->pantable==252) | ||
426 | /* set panning positions according to panning table (new for st3.2) */ | ||
427 | for(t=0;t<32;t++) | ||
428 | if((pan[t]&0x20)&&(mh->channels[t]<32)&&(remap[t]!=-1)) | ||
429 | of.panning[remap[t]]=(pan[t]&0xf)<<4; | ||
430 | |||
431 | /* load pattern info */ | ||
432 | of.numtrk=of.numpat*of.numchn; | ||
433 | if(!AllocTracks()) return 0; | ||
434 | if(!AllocPatterns()) return 0; | ||
435 | |||
436 | for(t=0;t<of.numpat;t++) { | ||
437 | /* seek to pattern position (+2 skip pattern length) */ | ||
438 | _mm_fseek(modreader,(((long)paraptr[of.numins+t])<<4)+2,SEEK_SET); | ||
439 | if(!S3M_ReadPattern()) return 0; | ||
440 | for(u=0;u<of.numchn;u++) | ||
441 | if(!(of.tracks[track++]=S3M_ConvertTrack(&s3mbuf[u*64]))) return 0; | ||
442 | } | ||
443 | |||
444 | return 1; | ||
445 | } | ||
446 | |||
447 | CHAR *S3M_LoadTitle(void) | ||
448 | { | ||
449 | CHAR s[28]; | ||
450 | |||
451 | _mm_fseek(modreader,0,SEEK_SET); | ||
452 | if(!_mm_read_UBYTES(s,28,modreader)) return NULL; | ||
453 | |||
454 | return(DupStr(s,28,0)); | ||
455 | } | ||
456 | |||
457 | /*========== Loader information */ | ||
458 | |||
459 | MIKMODAPI MLOADER load_s3m={ | ||
460 | NULL, | ||
461 | "S3M", | ||
462 | "S3M (Scream Tracker 3)", | ||
463 | S3M_Init, | ||
464 | S3M_Test, | ||
465 | S3M_Load, | ||
466 | S3M_Cleanup, | ||
467 | S3M_LoadTitle | ||
468 | }; | ||
469 | |||
470 | /* ex:set ts=4: */ | ||
diff --git a/apps/plugins/mikmod/load_stm.c b/apps/plugins/mikmod/load_stm.c new file mode 100644 index 0000000000..57df85c92d --- /dev/null +++ b/apps/plugins/mikmod/load_stm.c | |||
@@ -0,0 +1,374 @@ | |||
1 | /* MikMod sound library | ||
2 | (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file | ||
3 | AUTHORS 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: load_stm.c,v 1.3 2005/04/07 19:57:38 realtech Exp $ | ||
24 | |||
25 | Screamtracker 2 (STM) module loader | ||
26 | |||
27 | ==============================================================================*/ | ||
28 | |||
29 | #ifdef HAVE_CONFIG_H | ||
30 | #include "config.h" | ||
31 | #endif | ||
32 | |||
33 | #ifdef HAVE_UNISTD_H | ||
34 | #include <unistd.h> | ||
35 | #endif | ||
36 | |||
37 | #include <stdio.h> | ||
38 | #ifdef HAVE_MEMORY_H | ||
39 | #include <memory.h> | ||
40 | #endif | ||
41 | #include <string.h> | ||
42 | |||
43 | #include "mikmod_internals.h" | ||
44 | |||
45 | #ifdef SUNOS | ||
46 | extern int fprintf(FILE *, const char *, ...); | ||
47 | #endif | ||
48 | |||
49 | /*========== Module structure */ | ||
50 | |||
51 | /* sample information */ | ||
52 | typedef struct STMSAMPLE { | ||
53 | CHAR filename[12]; | ||
54 | UBYTE unused; /* 0x00 */ | ||
55 | UBYTE instdisk; /* Instrument disk */ | ||
56 | UWORD reserved; | ||
57 | UWORD length; /* Sample length */ | ||
58 | UWORD loopbeg; /* Loop start point */ | ||
59 | UWORD loopend; /* Loop end point */ | ||
60 | UBYTE volume; /* Volume */ | ||
61 | UBYTE reserved2; | ||
62 | UWORD c2spd; /* Good old c2spd */ | ||
63 | ULONG reserved3; | ||
64 | UWORD isa; | ||
65 | } STMSAMPLE; | ||
66 | |||
67 | /* header */ | ||
68 | typedef struct STMHEADER { | ||
69 | CHAR songname[20]; | ||
70 | CHAR trackername[8]; /* !Scream! for ST 2.xx */ | ||
71 | UBYTE unused; /* 0x1A */ | ||
72 | UBYTE filetype; /* 1=song, 2=module */ | ||
73 | UBYTE ver_major; | ||
74 | UBYTE ver_minor; | ||
75 | UBYTE inittempo; /* initspeed= stm inittempo>>4 */ | ||
76 | UBYTE numpat; /* number of patterns */ | ||
77 | UBYTE globalvol; | ||
78 | UBYTE reserved[13]; | ||
79 | STMSAMPLE sample[31]; /* STM sample data */ | ||
80 | UBYTE patorder[128]; /* Docs say 64 - actually 128 */ | ||
81 | } STMHEADER; | ||
82 | |||
83 | typedef struct STMNOTE { | ||
84 | UBYTE note,insvol,volcmd,cmdinf; | ||
85 | } STMNOTE; | ||
86 | |||
87 | /*========== Loader variables */ | ||
88 | |||
89 | static STMNOTE *stmbuf = NULL; | ||
90 | static STMHEADER *mh = NULL; | ||
91 | |||
92 | /* tracker identifiers */ | ||
93 | static CHAR* STM_Version[STM_NTRACKERS] = { | ||
94 | "Screamtracker 2", | ||
95 | "Converted by MOD2STM (STM format)", | ||
96 | "Wuzamod (STM format)" | ||
97 | }; | ||
98 | |||
99 | /*========== Loader code */ | ||
100 | |||
101 | int STM_Test(void) | ||
102 | { | ||
103 | UBYTE str[44]; | ||
104 | int t; | ||
105 | |||
106 | _mm_fseek(modreader,20,SEEK_SET); | ||
107 | _mm_read_UBYTES(str,44,modreader); | ||
108 | if(str[9]!=2) return 0; /* STM Module = filetype 2 */ | ||
109 | |||
110 | /* Prevent false positives for S3M files */ | ||
111 | if(!memcmp(str+40,"SCRM",4)) | ||
112 | return 0; | ||
113 | |||
114 | for (t=0;t<STM_NTRACKERS;t++) | ||
115 | if(!memcmp(str,STM_Signatures[t],8)) | ||
116 | return 1; | ||
117 | |||
118 | return 0; | ||
119 | } | ||
120 | |||
121 | int STM_Init(void) | ||
122 | { | ||
123 | if(!(mh=(STMHEADER*)MikMod_malloc(sizeof(STMHEADER)))) return 0; | ||
124 | if(!(stmbuf=(STMNOTE*)MikMod_calloc(64U*4,sizeof(STMNOTE)))) return 0; | ||
125 | |||
126 | return 1; | ||
127 | } | ||
128 | |||
129 | static void STM_Cleanup(void) | ||
130 | { | ||
131 | MikMod_free(mh); | ||
132 | MikMod_free(stmbuf); | ||
133 | } | ||
134 | |||
135 | static void STM_ConvertNote(STMNOTE *n) | ||
136 | { | ||
137 | UBYTE note,ins,vol,cmd,inf; | ||
138 | |||
139 | /* extract the various information from the 4 bytes that make up a note */ | ||
140 | note = n->note; | ||
141 | ins = n->insvol>>3; | ||
142 | vol = (n->insvol&7)+((n->volcmd&0x70)>>1); | ||
143 | cmd = n->volcmd&15; | ||
144 | inf = n->cmdinf; | ||
145 | |||
146 | if((ins)&&(ins<32)) UniInstrument(ins-1); | ||
147 | |||
148 | /* special values of [SBYTE0] are handled here | ||
149 | we have no idea if these strange values will ever be encountered. | ||
150 | but it appears as those stms sound correct. */ | ||
151 | if((note==254)||(note==252)) { | ||
152 | UniPTEffect(0xc,0); /* note cut */ | ||
153 | n->volcmd|=0x80; | ||
154 | } else | ||
155 | /* if note < 251, then all three bytes are stored in the file */ | ||
156 | if(note<251) UniNote((((note>>4)+2)*OCTAVE)+(note&0xf)); | ||
157 | |||
158 | if((!(n->volcmd&0x80))&&(vol<65)) UniPTEffect(0xc,vol); | ||
159 | if(cmd!=255) | ||
160 | switch(cmd) { | ||
161 | case 1: /* Axx set speed to xx */ | ||
162 | UniPTEffect(0xf,inf>>4); | ||
163 | break; | ||
164 | case 2: /* Bxx position jump */ | ||
165 | UniPTEffect(0xb,inf); | ||
166 | break; | ||
167 | case 3: /* Cxx patternbreak to row xx */ | ||
168 | UniPTEffect(0xd,(((inf&0xf0)>>4)*10)+(inf&0xf)); | ||
169 | break; | ||
170 | case 4: /* Dxy volumeslide */ | ||
171 | UniEffect(UNI_S3MEFFECTD,inf); | ||
172 | break; | ||
173 | case 5: /* Exy toneslide down */ | ||
174 | UniEffect(UNI_S3MEFFECTE,inf); | ||
175 | break; | ||
176 | case 6: /* Fxy toneslide up */ | ||
177 | UniEffect(UNI_S3MEFFECTF,inf); | ||
178 | break; | ||
179 | case 7: /* Gxx Tone portamento,speed xx */ | ||
180 | UniPTEffect(0x3,inf); | ||
181 | break; | ||
182 | case 8: /* Hxy vibrato */ | ||
183 | UniPTEffect(0x4,inf); | ||
184 | break; | ||
185 | case 9: /* Ixy tremor, ontime x, offtime y */ | ||
186 | UniEffect(UNI_S3MEFFECTI,inf); | ||
187 | break; | ||
188 | case 0: /* protracker arpeggio */ | ||
189 | if(!inf) break; | ||
190 | /* fall through */ | ||
191 | case 0xa: /* Jxy arpeggio */ | ||
192 | UniPTEffect(0x0,inf); | ||
193 | break; | ||
194 | case 0xb: /* Kxy Dual command H00 & Dxy */ | ||
195 | UniPTEffect(0x4,0); | ||
196 | UniEffect(UNI_S3MEFFECTD,inf); | ||
197 | break; | ||
198 | case 0xc: /* Lxy Dual command G00 & Dxy */ | ||
199 | UniPTEffect(0x3,0); | ||
200 | UniEffect(UNI_S3MEFFECTD,inf); | ||
201 | break; | ||
202 | /* Support all these above, since ST2 can LOAD these values but can | ||
203 | actually only play up to J - and J is only half-way implemented | ||
204 | in ST2 */ | ||
205 | case 0x18: /* Xxx amiga panning command 8xx */ | ||
206 | UniPTEffect(0x8,inf); | ||
207 | of.flags |= UF_PANNING; | ||
208 | break; | ||
209 | } | ||
210 | } | ||
211 | |||
212 | static UBYTE *STM_ConvertTrack(STMNOTE *n) | ||
213 | { | ||
214 | int t; | ||
215 | |||
216 | UniReset(); | ||
217 | for(t=0;t<64;t++) { | ||
218 | STM_ConvertNote(n); | ||
219 | UniNewline(); | ||
220 | n+=of.numchn; | ||
221 | } | ||
222 | return UniDup(); | ||
223 | } | ||
224 | |||
225 | static int STM_LoadPatterns(void) | ||
226 | { | ||
227 | int t,s,tracks=0; | ||
228 | |||
229 | if(!AllocPatterns()) return 0; | ||
230 | if(!AllocTracks()) return 0; | ||
231 | |||
232 | /* Allocate temporary buffer for loading and converting the patterns */ | ||
233 | for(t=0;t<of.numpat;t++) { | ||
234 | for(s=0;s<(64U*of.numchn);s++) { | ||
235 | stmbuf[s].note = _mm_read_UBYTE(modreader); | ||
236 | stmbuf[s].insvol = _mm_read_UBYTE(modreader); | ||
237 | stmbuf[s].volcmd = _mm_read_UBYTE(modreader); | ||
238 | stmbuf[s].cmdinf = _mm_read_UBYTE(modreader); | ||
239 | } | ||
240 | |||
241 | if(_mm_eof(modreader)) { | ||
242 | _mm_errno = MMERR_LOADING_PATTERN; | ||
243 | return 0; | ||
244 | } | ||
245 | |||
246 | for(s=0;s<of.numchn;s++) | ||
247 | if(!(of.tracks[tracks++]=STM_ConvertTrack(stmbuf+s))) return 0; | ||
248 | } | ||
249 | return 1; | ||
250 | } | ||
251 | |||
252 | int STM_Load(int curious) | ||
253 | { | ||
254 | int t; | ||
255 | ULONG MikMod_ISA; /* We must generate our own ISA, it's not stored in stm */ | ||
256 | SAMPLE *q; | ||
257 | |||
258 | /* try to read stm header */ | ||
259 | _mm_read_string(mh->songname,20,modreader); | ||
260 | _mm_read_string(mh->trackername,8,modreader); | ||
261 | mh->unused =_mm_read_UBYTE(modreader); | ||
262 | mh->filetype =_mm_read_UBYTE(modreader); | ||
263 | mh->ver_major =_mm_read_UBYTE(modreader); | ||
264 | mh->ver_minor =_mm_read_UBYTE(modreader); | ||
265 | mh->inittempo =_mm_read_UBYTE(modreader); | ||
266 | if(!mh->inittempo) { | ||
267 | _mm_errno=MMERR_NOT_A_MODULE; | ||
268 | return 0; | ||
269 | } | ||
270 | mh->numpat =_mm_read_UBYTE(modreader); | ||
271 | mh->globalvol =_mm_read_UBYTE(modreader); | ||
272 | _mm_read_UBYTES(mh->reserved,13,modreader); | ||
273 | |||
274 | for(t=0;t<31;t++) { | ||
275 | STMSAMPLE *s=&mh->sample[t]; /* STM sample data */ | ||
276 | |||
277 | _mm_read_string(s->filename,12,modreader); | ||
278 | s->unused =_mm_read_UBYTE(modreader); | ||
279 | s->instdisk =_mm_read_UBYTE(modreader); | ||
280 | s->reserved =_mm_read_I_UWORD(modreader); | ||
281 | s->length =_mm_read_I_UWORD(modreader); | ||
282 | s->loopbeg =_mm_read_I_UWORD(modreader); | ||
283 | s->loopend =_mm_read_I_UWORD(modreader); | ||
284 | s->volume =_mm_read_UBYTE(modreader); | ||
285 | s->reserved2=_mm_read_UBYTE(modreader); | ||
286 | s->c2spd =_mm_read_I_UWORD(modreader); | ||
287 | s->reserved3=_mm_read_I_ULONG(modreader); | ||
288 | s->isa =_mm_read_I_UWORD(modreader); | ||
289 | } | ||
290 | _mm_read_UBYTES(mh->patorder,128,modreader); | ||
291 | |||
292 | if(_mm_eof(modreader)) { | ||
293 | _mm_errno = MMERR_LOADING_HEADER; | ||
294 | return 0; | ||
295 | } | ||
296 | |||
297 | /* set module variables */ | ||
298 | for(t=0;t<STM_NTRACKERS;t++) | ||
299 | if(!memcmp(mh->trackername,STM_Signatures[t],8)) break; | ||
300 | of.modtype = StrDup(STM_Version[t]); | ||
301 | of.songname = DupStr(mh->songname,20,1); /* make a cstr of songname */ | ||
302 | of.numpat = mh->numpat; | ||
303 | of.inittempo = 125; /* mh->inittempo+0x1c; */ | ||
304 | of.initspeed = mh->inittempo>>4; | ||
305 | of.numchn = 4; /* get number of channels */ | ||
306 | of.reppos = 0; | ||
307 | of.flags |= UF_S3MSLIDES; | ||
308 | of.bpmlimit = 32; | ||
309 | |||
310 | t=0; | ||
311 | if(!AllocPositions(0x80)) return 0; | ||
312 | /* 99 terminates the patorder list */ | ||
313 | while((mh->patorder[t]<=99)&&(mh->patorder[t]<mh->numpat)) { | ||
314 | of.positions[t]=mh->patorder[t]; | ||
315 | t++; | ||
316 | } | ||
317 | if(mh->patorder[t]<=99) t++; | ||
318 | of.numpos=t; | ||
319 | of.numtrk=of.numpat*of.numchn; | ||
320 | of.numins=of.numsmp=31; | ||
321 | |||
322 | if(!AllocSamples()) return 0; | ||
323 | if(!STM_LoadPatterns()) return 0; | ||
324 | MikMod_ISA=_mm_ftell(modreader); | ||
325 | MikMod_ISA=(MikMod_ISA+15)&0xfffffff0; /* normalize */ | ||
326 | |||
327 | for(q=of.samples,t=0;t<of.numsmp;t++,q++) { | ||
328 | /* load sample info */ | ||
329 | q->samplename = DupStr(mh->sample[t].filename,12,1); | ||
330 | q->speed = (mh->sample[t].c2spd * 8363) / 8448; | ||
331 | q->volume = mh->sample[t].volume; | ||
332 | q->length = mh->sample[t].length; | ||
333 | if (/*(!mh->sample[t].volume)||*/(q->length==1)) q->length=0; | ||
334 | q->loopstart = mh->sample[t].loopbeg; | ||
335 | q->loopend = mh->sample[t].loopend; | ||
336 | q->seekpos = MikMod_ISA; | ||
337 | |||
338 | MikMod_ISA+=q->length; | ||
339 | MikMod_ISA=(MikMod_ISA+15)&0xfffffff0; /* normalize */ | ||
340 | |||
341 | /* contrary to the STM specs, sample data is signed */ | ||
342 | q->flags = SF_SIGNED; | ||
343 | |||
344 | if(q->loopend && q->loopend != 0xffff) | ||
345 | q->flags|=SF_LOOP; | ||
346 | } | ||
347 | return 1; | ||
348 | } | ||
349 | |||
350 | CHAR *STM_LoadTitle(void) | ||
351 | { | ||
352 | CHAR s[20]; | ||
353 | |||
354 | _mm_fseek(modreader,0,SEEK_SET); | ||
355 | if(!_mm_read_UBYTES(s,20,modreader)) return NULL; | ||
356 | |||
357 | return(DupStr(s,20,1)); | ||
358 | } | ||
359 | |||
360 | /*========== Loader information */ | ||
361 | |||
362 | MIKMODAPI MLOADER load_stm={ | ||
363 | NULL, | ||
364 | "STM", | ||
365 | "STM (Scream Tracker)", | ||
366 | STM_Init, | ||
367 | STM_Test, | ||
368 | STM_Load, | ||
369 | STM_Cleanup, | ||
370 | STM_LoadTitle | ||
371 | }; | ||
372 | |||
373 | |||
374 | /* ex:set ts=4: */ | ||
diff --git a/apps/plugins/mikmod/load_stx.c b/apps/plugins/mikmod/load_stx.c new file mode 100644 index 0000000000..ac6e51f4c7 --- /dev/null +++ b/apps/plugins/mikmod/load_stx.c | |||
@@ -0,0 +1,439 @@ | |||
1 | /* MikMod sound library | ||
2 | (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file | ||
3 | AUTHORS 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: load_stx.c,v 1.3 2005/04/07 19:57:38 realtech Exp $ | ||
24 | |||
25 | STMIK 0.2 (STX) module loader | ||
26 | |||
27 | ==============================================================================*/ | ||
28 | |||
29 | /* | ||
30 | |||
31 | Written by Claudio Matsuoka <claudio@helllabs.org> | ||
32 | |||
33 | */ | ||
34 | |||
35 | #ifdef HAVE_CONFIG_H | ||
36 | #include "config.h" | ||
37 | #endif | ||
38 | |||
39 | #ifdef HAVE_UNISTD_H | ||
40 | #include <unistd.h> | ||
41 | #endif | ||
42 | |||
43 | #include <stdio.h> | ||
44 | #ifdef HAVE_MEMORY_H | ||
45 | #include <memory.h> | ||
46 | #endif | ||
47 | #include <string.h> | ||
48 | |||
49 | #include "mikmod_internals.h" | ||
50 | |||
51 | #ifdef SUNOS | ||
52 | extern int fprintf(FILE *, const char *, ...); | ||
53 | #endif | ||
54 | |||
55 | /*========== Module structure */ | ||
56 | |||
57 | /* header */ | ||
58 | typedef struct STXHEADER { | ||
59 | CHAR songname[20]; | ||
60 | CHAR trackername[8]; | ||
61 | UWORD patsize; | ||
62 | UWORD unknown1; | ||
63 | UWORD patptr; | ||
64 | UWORD insptr; | ||
65 | UWORD chnptr; /* not sure */ | ||
66 | UWORD unknown2; | ||
67 | UWORD unknown3; | ||
68 | UBYTE mastermult; | ||
69 | UBYTE initspeed; | ||
70 | UWORD unknown4; | ||
71 | UWORD unknown5; | ||
72 | UWORD patnum; | ||
73 | UWORD insnum; | ||
74 | UWORD ordnum; | ||
75 | UWORD unknown6; | ||
76 | UWORD unknown7; | ||
77 | UWORD unknown8; | ||
78 | CHAR scrm[4]; | ||
79 | } STXHEADER; | ||
80 | |||
81 | /* sample information */ | ||
82 | typedef struct STXSAMPLE { | ||
83 | UBYTE type; | ||
84 | CHAR filename[12]; | ||
85 | UBYTE memsegh; | ||
86 | UWORD memsegl; | ||
87 | ULONG length; | ||
88 | ULONG loopbeg; | ||
89 | ULONG loopend; | ||
90 | UBYTE volume; | ||
91 | UBYTE dsk; | ||
92 | UBYTE pack; | ||
93 | UBYTE flags; | ||
94 | ULONG c2spd; | ||
95 | UBYTE unused[12]; | ||
96 | CHAR sampname[28]; | ||
97 | CHAR scrs[4]; | ||
98 | } STXSAMPLE; | ||
99 | |||
100 | typedef struct STXNOTE { | ||
101 | UBYTE note,ins,vol,cmd,inf; | ||
102 | } STXNOTE; | ||
103 | |||
104 | /*========== Loader variables */ | ||
105 | |||
106 | static STXNOTE *stxbuf = NULL; /* pointer to a complete STX pattern */ | ||
107 | static STXHEADER *mh = NULL; | ||
108 | static UWORD *paraptr = NULL; /* parapointer array (see STX docs) */ | ||
109 | |||
110 | /*========== Loader code */ | ||
111 | |||
112 | static int STX_Test(void) | ||
113 | { | ||
114 | UBYTE id[8]; | ||
115 | int t; | ||
116 | |||
117 | _mm_fseek(modreader,0x3C,SEEK_SET); | ||
118 | if(!_mm_read_UBYTES(id,4,modreader)) return 0; | ||
119 | if(memcmp(id,"SCRM",4)) return 0; | ||
120 | |||
121 | _mm_fseek(modreader,0x14,SEEK_SET); | ||
122 | if(!_mm_read_UBYTES(id,8,modreader)) return 0; | ||
123 | |||
124 | for(t=0;t<STM_NTRACKERS;t++) | ||
125 | if(!memcmp(id,STM_Signatures[t],8)) return 1; | ||
126 | |||
127 | return 0; | ||
128 | } | ||
129 | |||
130 | static int STX_Init(void) | ||
131 | { | ||
132 | if(!(stxbuf=(STXNOTE*)MikMod_malloc(4*64*sizeof(STXNOTE)))) return 0; | ||
133 | if(!(mh=(STXHEADER*)MikMod_malloc(sizeof(STXHEADER)))) return 0; | ||
134 | if(!(poslookup=(UBYTE*)MikMod_malloc(sizeof(UBYTE)*256))) return 0; | ||
135 | memset(poslookup,-1,256); | ||
136 | |||
137 | return 1; | ||
138 | } | ||
139 | |||
140 | static void STX_Cleanup(void) | ||
141 | { | ||
142 | MikMod_free(stxbuf); | ||
143 | MikMod_free(paraptr); | ||
144 | MikMod_free(poslookup); | ||
145 | MikMod_free(mh); | ||
146 | } | ||
147 | |||
148 | static int STX_ReadPattern(void) | ||
149 | { | ||
150 | int row=0,flag,ch; | ||
151 | STXNOTE *n,dummy; | ||
152 | |||
153 | /* clear pattern data */ | ||
154 | memset(stxbuf,255,4*64*sizeof(STXNOTE)); | ||
155 | |||
156 | while(row<64) { | ||
157 | flag=_mm_read_UBYTE(modreader); | ||
158 | |||
159 | if(_mm_eof(modreader)) { | ||
160 | _mm_errno = MMERR_LOADING_PATTERN; | ||
161 | return 0; | ||
162 | } | ||
163 | |||
164 | if(flag) { | ||
165 | ch=flag&31; | ||
166 | |||
167 | if((ch>=0)&&(ch<4)) | ||
168 | n=&stxbuf[(64U*ch)+row]; | ||
169 | else | ||
170 | n=&dummy; | ||
171 | |||
172 | if(flag&32) { | ||
173 | n->note=_mm_read_UBYTE(modreader); | ||
174 | n->ins=_mm_read_UBYTE(modreader); | ||
175 | } | ||
176 | if(flag&64) { | ||
177 | n->vol=_mm_read_UBYTE(modreader); | ||
178 | if(n->vol>64) n->vol=64; | ||
179 | } | ||
180 | if(flag&128) { | ||
181 | n->cmd=_mm_read_UBYTE(modreader); | ||
182 | n->inf=_mm_read_UBYTE(modreader); | ||
183 | } | ||
184 | } else row++; | ||
185 | } | ||
186 | return 1; | ||
187 | } | ||
188 | |||
189 | static UBYTE* STX_ConvertTrack(STXNOTE* tr) | ||
190 | { | ||
191 | int t; | ||
192 | |||
193 | UniReset(); | ||
194 | for(t=0;t<64;t++) { | ||
195 | UBYTE note,ins,vol,cmd,inf; | ||
196 | |||
197 | note=tr[t].note; | ||
198 | ins=tr[t].ins; | ||
199 | vol=tr[t].vol; | ||
200 | cmd=tr[t].cmd; | ||
201 | inf=tr[t].inf; | ||
202 | |||
203 | if((ins)&&(ins!=255)) UniInstrument(ins-1); | ||
204 | if((note)&&(note!=255)) { | ||
205 | if(note==254) { | ||
206 | UniPTEffect(0xc,0); /* note cut command */ | ||
207 | vol=255; | ||
208 | } else UniNote(24+((note>>4)*OCTAVE)+(note&0xf)); /* normal note */ | ||
209 | } | ||
210 | |||
211 | if(vol<255) UniPTEffect(0xc,vol); | ||
212 | |||
213 | if(cmd<255) switch(cmd) { | ||
214 | case 1: /* Axx set speed to xx */ | ||
215 | UniPTEffect(0xf,inf>>4); | ||
216 | break; | ||
217 | case 2: /* Bxx position jump */ | ||
218 | UniPTEffect(0xb,inf); | ||
219 | break; | ||
220 | case 3: /* Cxx patternbreak to row xx */ | ||
221 | UniPTEffect(0xd,(((inf&0xf0)>>4)*10)+(inf&0xf)); | ||
222 | break; | ||
223 | case 4: /* Dxy volumeslide */ | ||
224 | UniEffect(UNI_S3MEFFECTD,inf); | ||
225 | break; | ||
226 | case 5: /* Exy toneslide down */ | ||
227 | UniEffect(UNI_S3MEFFECTE,inf); | ||
228 | break; | ||
229 | case 6: /* Fxy toneslide up */ | ||
230 | UniEffect(UNI_S3MEFFECTF,inf); | ||
231 | break; | ||
232 | case 7: /* Gxx Tone portamento,speed xx */ | ||
233 | UniPTEffect(0x3,inf); | ||
234 | break; | ||
235 | case 8: /* Hxy vibrato */ | ||
236 | UniPTEffect(0x4,inf); | ||
237 | break; | ||
238 | case 9: /* Ixy tremor, ontime x, offtime y */ | ||
239 | UniEffect(UNI_S3MEFFECTI,inf); | ||
240 | break; | ||
241 | case 0: /* protracker arpeggio */ | ||
242 | if(!inf) break; | ||
243 | /* fall through */ | ||
244 | case 0xa: /* Jxy arpeggio */ | ||
245 | UniPTEffect(0x0,inf); | ||
246 | break; | ||
247 | case 0xb: /* Kxy Dual command H00 & Dxy */ | ||
248 | UniPTEffect(0x4,0); | ||
249 | UniEffect(UNI_S3MEFFECTD,inf); | ||
250 | break; | ||
251 | case 0xc: /* Lxy Dual command G00 & Dxy */ | ||
252 | UniPTEffect(0x3,0); | ||
253 | UniEffect(UNI_S3MEFFECTD,inf); | ||
254 | break; | ||
255 | /* Support all these above, since ST2 can LOAD these values but can | ||
256 | actually only play up to J - and J is only half-way implemented | ||
257 | in ST2 */ | ||
258 | case 0x18: /* Xxx amiga panning command 8xx */ | ||
259 | UniPTEffect(0x8,inf); | ||
260 | of.flags |= UF_PANNING; | ||
261 | break; | ||
262 | } | ||
263 | UniNewline(); | ||
264 | } | ||
265 | return UniDup(); | ||
266 | } | ||
267 | |||
268 | static int STX_Load(int curious) | ||
269 | { | ||
270 | int t,u,track = 0; | ||
271 | int version = 0; | ||
272 | SAMPLE *q; | ||
273 | |||
274 | /* try to read module header */ | ||
275 | _mm_read_string(mh->songname,20,modreader); | ||
276 | _mm_read_string(mh->trackername,8,modreader); | ||
277 | mh->patsize =_mm_read_I_UWORD(modreader); | ||
278 | mh->unknown1 =_mm_read_I_UWORD(modreader); | ||
279 | mh->patptr =_mm_read_I_UWORD(modreader); | ||
280 | mh->insptr =_mm_read_I_UWORD(modreader); | ||
281 | mh->chnptr =_mm_read_I_UWORD(modreader); | ||
282 | mh->unknown2 =_mm_read_I_UWORD(modreader); | ||
283 | mh->unknown3 =_mm_read_I_UWORD(modreader); | ||
284 | mh->mastermult =_mm_read_UBYTE(modreader); | ||
285 | mh->initspeed =_mm_read_UBYTE(modreader)>>4; | ||
286 | mh->unknown4 =_mm_read_I_UWORD(modreader); | ||
287 | mh->unknown5 =_mm_read_I_UWORD(modreader); | ||
288 | mh->patnum =_mm_read_I_UWORD(modreader); | ||
289 | mh->insnum =_mm_read_I_UWORD(modreader); | ||
290 | mh->ordnum =_mm_read_I_UWORD(modreader); | ||
291 | mh->unknown6 =_mm_read_I_UWORD(modreader); | ||
292 | mh->unknown7 =_mm_read_I_UWORD(modreader); | ||
293 | mh->unknown8 =_mm_read_I_UWORD(modreader); | ||
294 | _mm_read_string(mh->scrm,4,modreader); | ||
295 | |||
296 | if(_mm_eof(modreader)) { | ||
297 | _mm_errno = MMERR_LOADING_HEADER; | ||
298 | return 0; | ||
299 | } | ||
300 | |||
301 | /* set module variables */ | ||
302 | of.songname = DupStr(mh->songname,20,1); | ||
303 | of.numpat = mh->patnum; | ||
304 | of.reppos = 0; | ||
305 | of.numins = of.numsmp = mh->insnum; | ||
306 | of.initspeed = mh->initspeed; | ||
307 | of.inittempo = 125; | ||
308 | of.numchn = 4; | ||
309 | of.flags |= UF_S3MSLIDES; | ||
310 | of.bpmlimit = 32; | ||
311 | |||
312 | if(!(paraptr=(UWORD*)MikMod_malloc((of.numins+of.numpat)*sizeof(UWORD)))) | ||
313 | return 0; | ||
314 | |||
315 | /* read the instrument+pattern parapointers */ | ||
316 | _mm_fseek(modreader,mh->insptr<<4,SEEK_SET); | ||
317 | _mm_read_I_UWORDS(paraptr,of.numins,modreader); | ||
318 | _mm_fseek(modreader,mh->patptr<<4,SEEK_SET); | ||
319 | _mm_read_I_UWORDS(paraptr+of.numins,of.numpat,modreader); | ||
320 | |||
321 | /* check module version */ | ||
322 | _mm_fseek(modreader,paraptr[of.numins]<<4,SEEK_SET); | ||
323 | version=_mm_read_I_UWORD(modreader); | ||
324 | if(version==mh->patsize) { | ||
325 | version = 0x10; | ||
326 | of.modtype = StrDup("STMIK 0.2 (STM2STX 1.0)"); | ||
327 | } else { | ||
328 | version = 0x11; | ||
329 | of.modtype = StrDup("STMIK 0.2 (STM2STX 1.1)"); | ||
330 | } | ||
331 | |||
332 | /* read the order data */ | ||
333 | _mm_fseek(modreader,(mh->chnptr<<4)+32,SEEK_SET); | ||
334 | if(!AllocPositions(mh->ordnum)) return 0; | ||
335 | for(t=0;t<mh->ordnum;t++) { | ||
336 | of.positions[t]=_mm_read_UBYTE(modreader); | ||
337 | _mm_fseek(modreader,4,SEEK_CUR); | ||
338 | } | ||
339 | |||
340 | of.numpos=0;poslookupcnt=mh->ordnum; | ||
341 | for(t=0;t<mh->ordnum;t++) { | ||
342 | int order=of.positions[t]; | ||
343 | if(order==255) order=LAST_PATTERN; | ||
344 | of.positions[of.numpos]=order; | ||
345 | poslookup[t]=of.numpos; /* bug fix for freaky S3Ms */ | ||
346 | if(of.positions[t]<254) of.numpos++; | ||
347 | else | ||
348 | /* special end of song pattern */ | ||
349 | if((order==LAST_PATTERN)&&(!curious)) break; | ||
350 | } | ||
351 | |||
352 | if(_mm_eof(modreader)) { | ||
353 | _mm_errno = MMERR_LOADING_HEADER; | ||
354 | return 0; | ||
355 | } | ||
356 | |||
357 | /* load samples */ | ||
358 | if(!AllocSamples()) return 0; | ||
359 | for(q=of.samples,t=0;t<of.numins;t++,q++) { | ||
360 | STXSAMPLE s; | ||
361 | |||
362 | /* seek to instrument position */ | ||
363 | _mm_fseek(modreader,((long)paraptr[t])<<4,SEEK_SET); | ||
364 | /* and load sample info */ | ||
365 | s.type =_mm_read_UBYTE(modreader); | ||
366 | _mm_read_string(s.filename,12,modreader); | ||
367 | s.memsegh =_mm_read_UBYTE(modreader); | ||
368 | s.memsegl =_mm_read_I_UWORD(modreader); | ||
369 | s.length =_mm_read_I_ULONG(modreader); | ||
370 | s.loopbeg =_mm_read_I_ULONG(modreader); | ||
371 | s.loopend =_mm_read_I_ULONG(modreader); | ||
372 | s.volume =_mm_read_UBYTE(modreader); | ||
373 | s.dsk =_mm_read_UBYTE(modreader); | ||
374 | s.pack =_mm_read_UBYTE(modreader); | ||
375 | s.flags =_mm_read_UBYTE(modreader); | ||
376 | s.c2spd =_mm_read_I_ULONG(modreader); | ||
377 | _mm_read_UBYTES(s.unused,12,modreader); | ||
378 | _mm_read_string(s.sampname,28,modreader); | ||
379 | _mm_read_string(s.scrs,4,modreader); | ||
380 | |||
381 | if(_mm_eof(modreader)) { | ||
382 | _mm_errno = MMERR_LOADING_SAMPLEINFO; | ||
383 | return 0; | ||
384 | } | ||
385 | |||
386 | q->samplename = DupStr(s.sampname,28,1); | ||
387 | q->speed = (s.c2spd * 8363) / 8448; | ||
388 | q->length = s.length; | ||
389 | q->loopstart = s.loopbeg; | ||
390 | q->loopend = s.loopend; | ||
391 | q->volume = s.volume; | ||
392 | q->seekpos = (((long)s.memsegh)<<16|s.memsegl)<<4; | ||
393 | q->flags |= SF_SIGNED; | ||
394 | |||
395 | if(s.flags&1) q->flags |= SF_LOOP; | ||
396 | if(s.flags&4) q->flags |= SF_16BITS; | ||
397 | } | ||
398 | |||
399 | /* load pattern info */ | ||
400 | of.numtrk=of.numpat*of.numchn; | ||
401 | if(!AllocTracks()) return 0; | ||
402 | if(!AllocPatterns()) return 0; | ||
403 | |||
404 | for(t=0;t<of.numpat;t++) { | ||
405 | /* seek to pattern position (+2 skip pattern length) */ | ||
406 | _mm_fseek(modreader,(((long)paraptr[of.numins+t])<<4)+ | ||
407 | (version==0x10?2:0),SEEK_SET); | ||
408 | if(!STX_ReadPattern()) return 0; | ||
409 | for(u=0;u<of.numchn;u++) | ||
410 | if(!(of.tracks[track++]=STX_ConvertTrack(&stxbuf[u*64]))) return 0; | ||
411 | } | ||
412 | |||
413 | return 1; | ||
414 | } | ||
415 | |||
416 | static CHAR *STX_LoadTitle(void) | ||
417 | { | ||
418 | CHAR s[28]; | ||
419 | |||
420 | _mm_fseek(modreader,0,SEEK_SET); | ||
421 | if(!_mm_read_UBYTES(s,20,modreader)) return NULL; | ||
422 | |||
423 | return(DupStr(s,28,1)); | ||
424 | } | ||
425 | |||
426 | /*========== Loader information */ | ||
427 | |||
428 | MIKMODAPI MLOADER load_stx={ | ||
429 | NULL, | ||
430 | "STX", | ||
431 | "STX (Scream Tracker Music Interface Kit)", | ||
432 | STX_Init, | ||
433 | STX_Test, | ||
434 | STX_Load, | ||
435 | STX_Cleanup, | ||
436 | STX_LoadTitle | ||
437 | }; | ||
438 | |||
439 | /* ex:set ts=4: */ | ||
diff --git a/apps/plugins/mikmod/load_ult.c b/apps/plugins/mikmod/load_ult.c new file mode 100644 index 0000000000..aca2407a4a --- /dev/null +++ b/apps/plugins/mikmod/load_ult.c | |||
@@ -0,0 +1,339 @@ | |||
1 | /* MikMod sound library | ||
2 | (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file | ||
3 | AUTHORS 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: load_ult.c,v 1.3 2010/01/12 03:30:32 realtech Exp $ | ||
24 | |||
25 | Ultratracker (ULT) module loader | ||
26 | |||
27 | ==============================================================================*/ | ||
28 | |||
29 | #ifdef HAVE_CONFIG_H | ||
30 | #include "config.h" | ||
31 | #endif | ||
32 | |||
33 | #ifdef HAVE_UNISTD_H | ||
34 | #include <unistd.h> | ||
35 | #endif | ||
36 | |||
37 | #include <stdio.h> | ||
38 | #ifdef HAVE_MEMORY_H | ||
39 | #include <memory.h> | ||
40 | #endif | ||
41 | #include <string.h> | ||
42 | |||
43 | #include "mikmod_internals.h" | ||
44 | |||
45 | #ifdef SUNOS | ||
46 | extern int fprintf(FILE *, const char *, ...); | ||
47 | #endif | ||
48 | |||
49 | /*========== Module structure */ | ||
50 | |||
51 | /* header */ | ||
52 | typedef struct ULTHEADER { | ||
53 | CHAR id[16]; | ||
54 | CHAR songtitle[32]; | ||
55 | UBYTE reserved; | ||
56 | } ULTHEADER; | ||
57 | |||
58 | /* sample information */ | ||
59 | typedef struct ULTSAMPLE { | ||
60 | CHAR samplename[32]; | ||
61 | CHAR dosname[12]; | ||
62 | SLONG loopstart; | ||
63 | SLONG loopend; | ||
64 | SLONG sizestart; | ||
65 | SLONG sizeend; | ||
66 | UBYTE volume; | ||
67 | UBYTE flags; | ||
68 | UWORD speed; | ||
69 | SWORD finetune; | ||
70 | } ULTSAMPLE; | ||
71 | |||
72 | typedef struct ULTEVENT { | ||
73 | UBYTE note,sample,eff,dat1,dat2; | ||
74 | } ULTEVENT; | ||
75 | |||
76 | /*========== Loader variables */ | ||
77 | |||
78 | #define ULTS_16BITS 4 | ||
79 | #define ULTS_LOOP 8 | ||
80 | #define ULTS_REVERSE 16 | ||
81 | |||
82 | #define ULT_VERSION_LEN 18 | ||
83 | static CHAR ULT_Version[ULT_VERSION_LEN]="Ultra Tracker v1.x"; | ||
84 | |||
85 | static ULTEVENT ev; | ||
86 | |||
87 | /*========== Loader code */ | ||
88 | |||
89 | int ULT_Test(void) | ||
90 | { | ||
91 | CHAR id[16]; | ||
92 | |||
93 | if(!_mm_read_string(id,15,modreader)) return 0; | ||
94 | if(strncmp(id,"MAS_UTrack_V00",14)) return 0; | ||
95 | if((id[14]<'1')||(id[14]>'4')) return 0; | ||
96 | return 1; | ||
97 | } | ||
98 | |||
99 | int ULT_Init(void) | ||
100 | { | ||
101 | return 1; | ||
102 | } | ||
103 | |||
104 | void ULT_Cleanup(void) | ||
105 | { | ||
106 | } | ||
107 | |||
108 | static UBYTE ReadUltEvent(ULTEVENT* event) | ||
109 | { | ||
110 | UBYTE flag,rep=1; | ||
111 | |||
112 | flag = _mm_read_UBYTE(modreader); | ||
113 | if(flag==0xfc) { | ||
114 | rep = _mm_read_UBYTE(modreader); | ||
115 | event->note =_mm_read_UBYTE(modreader); | ||
116 | } else | ||
117 | event->note = flag; | ||
118 | |||
119 | event->sample =_mm_read_UBYTE(modreader); | ||
120 | event->eff =_mm_read_UBYTE(modreader); | ||
121 | event->dat1 =_mm_read_UBYTE(modreader); | ||
122 | event->dat2 =_mm_read_UBYTE(modreader); | ||
123 | |||
124 | return rep; | ||
125 | } | ||
126 | |||
127 | int ULT_Load(int curious) | ||
128 | { | ||
129 | int t,u,tracks=0; | ||
130 | SAMPLE *q; | ||
131 | ULTSAMPLE s; | ||
132 | ULTHEADER mh; | ||
133 | UBYTE nos,noc,rbnop; | ||
134 | |||
135 | /* try to read module header */ | ||
136 | _mm_read_string(mh.id,15,modreader); | ||
137 | _mm_read_string(mh.songtitle,32,modreader); | ||
138 | mh.reserved=_mm_read_UBYTE(modreader); | ||
139 | |||
140 | if(_mm_eof(modreader)) { | ||
141 | _mm_errno = MMERR_LOADING_HEADER; | ||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | ULT_Version[ULT_VERSION_LEN-1]='3'+(mh.id[14]-'1'); | ||
146 | of.modtype = DupStr(ULT_Version,ULT_VERSION_LEN,1); | ||
147 | of.initspeed = 6; | ||
148 | of.inittempo = 125; | ||
149 | of.reppos = 0; | ||
150 | |||
151 | /* read songtext */ | ||
152 | if ((mh.id[14]>'1')&&(mh.reserved)) | ||
153 | if(!ReadLinedComment(mh.reserved * 32, 32)) return 0; | ||
154 | |||
155 | nos=_mm_read_UBYTE(modreader); | ||
156 | if(_mm_eof(modreader)) { | ||
157 | _mm_errno = MMERR_LOADING_HEADER; | ||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | of.songname=DupStr(mh.songtitle,32,1); | ||
162 | of.numins=of.numsmp=nos; | ||
163 | |||
164 | if(!AllocSamples()) return 0; | ||
165 | q = of.samples; | ||
166 | for(t=0;t<nos;t++) { | ||
167 | /* try to read sample info */ | ||
168 | _mm_read_string(s.samplename,32,modreader); | ||
169 | _mm_read_string(s.dosname,12,modreader); | ||
170 | s.loopstart =_mm_read_I_ULONG(modreader); | ||
171 | s.loopend =_mm_read_I_ULONG(modreader); | ||
172 | s.sizestart =_mm_read_I_ULONG(modreader); | ||
173 | s.sizeend =_mm_read_I_ULONG(modreader); | ||
174 | s.volume =_mm_read_UBYTE(modreader); | ||
175 | s.flags =_mm_read_UBYTE(modreader); | ||
176 | s.speed =(mh.id[14]>='4')?_mm_read_I_UWORD(modreader):8363; | ||
177 | s.finetune =_mm_read_I_SWORD(modreader); | ||
178 | |||
179 | if(_mm_eof(modreader)) { | ||
180 | _mm_errno = MMERR_LOADING_SAMPLEINFO; | ||
181 | return 0; | ||
182 | } | ||
183 | |||
184 | q->samplename=DupStr(s.samplename,32,1); | ||
185 | /* The correct formula for the coefficient would be | ||
186 | pow(2,(double)s.finetume/OCTAVE/32768), but to avoid floating point | ||
187 | here, we'll use a first order approximation here. | ||
188 | 1/567290 == Ln(2)/OCTAVE/32768 */ | ||
189 | q->speed=s.speed+s.speed*(((SLONG)s.speed*(SLONG)s.finetune)/567290); | ||
190 | q->length = s.sizeend-s.sizestart; | ||
191 | q->volume = s.volume>>2; | ||
192 | q->loopstart = s.loopstart; | ||
193 | q->loopend = s.loopend; | ||
194 | q->flags = SF_SIGNED; | ||
195 | if(s.flags&ULTS_LOOP) q->flags|=SF_LOOP; | ||
196 | if(s.flags&ULTS_16BITS) { | ||
197 | s.sizeend+=(s.sizeend-s.sizestart); | ||
198 | s.sizestart<<=1; | ||
199 | q->flags|=SF_16BITS; | ||
200 | q->loopstart>>=1; | ||
201 | q->loopend>>=1; | ||
202 | } | ||
203 | q++; | ||
204 | } | ||
205 | |||
206 | if(!AllocPositions(256)) return 0; | ||
207 | for(t=0;t<256;t++) | ||
208 | of.positions[t]=_mm_read_UBYTE(modreader); | ||
209 | for(t=0;t<256;t++) | ||
210 | if(of.positions[t]==255) { | ||
211 | of.positions[t]=LAST_PATTERN; | ||
212 | break; | ||
213 | } | ||
214 | of.numpos=t; | ||
215 | |||
216 | noc=_mm_read_UBYTE(modreader); | ||
217 | rbnop=_mm_read_UBYTE(modreader); | ||
218 | |||
219 | of.numchn=++noc; | ||
220 | of.numpat=++rbnop; | ||
221 | of.numtrk=of.numchn*of.numpat; | ||
222 | if(!AllocTracks()) return 0; | ||
223 | if(!AllocPatterns()) return 0; | ||
224 | for(u=0;u<of.numchn;u++) | ||
225 | for(t=0;t<of.numpat;t++) | ||
226 | of.patterns[(t*of.numchn)+u]=tracks++; | ||
227 | |||
228 | // SA37775 | ||
229 | if (of.numchn>=UF_MAXCHAN) | ||
230 | of.numchn=UF_MAXCHAN - 1; | ||
231 | |||
232 | /* read pan position table for v1.5 and higher */ | ||
233 | if(mh.id[14]>='3') { | ||
234 | for(t=0;t<of.numchn;t++) of.panning[t]=_mm_read_UBYTE(modreader)<<4; | ||
235 | of.flags |= UF_PANNING; | ||
236 | } | ||
237 | |||
238 | for(t=0;t<of.numtrk;t++) { | ||
239 | int rep,row=0; | ||
240 | |||
241 | UniReset(); | ||
242 | while(row<64) { | ||
243 | rep=ReadUltEvent(&ev); | ||
244 | |||
245 | if(_mm_eof(modreader)) { | ||
246 | _mm_errno = MMERR_LOADING_TRACK; | ||
247 | return 0; | ||
248 | } | ||
249 | |||
250 | while(rep--) { | ||
251 | UBYTE eff; | ||
252 | int offset; | ||
253 | |||
254 | if(ev.sample) UniInstrument(ev.sample-1); | ||
255 | if(ev.note) UniNote(ev.note+2*OCTAVE-1); | ||
256 | |||
257 | /* first effect - various fixes by Alexander Kerkhove and | ||
258 | Thomas Neumann */ | ||
259 | eff = ev.eff>>4; | ||
260 | switch(eff) { | ||
261 | case 0x3: /* tone portamento */ | ||
262 | UniEffect(UNI_ITEFFECTG,ev.dat2); | ||
263 | break; | ||
264 | case 0x5: | ||
265 | break; | ||
266 | case 0x9: /* sample offset */ | ||
267 | offset=(ev.dat2<<8)|((ev.eff&0xf)==9?ev.dat1:0); | ||
268 | UniEffect(UNI_ULTEFFECT9,offset); | ||
269 | break; | ||
270 | case 0xb: /* panning */ | ||
271 | UniPTEffect(8,ev.dat2*0xf); | ||
272 | of.flags |= UF_PANNING; | ||
273 | break; | ||
274 | case 0xc: /* volume */ | ||
275 | UniPTEffect(eff,ev.dat2>>2); | ||
276 | break; | ||
277 | default: | ||
278 | UniPTEffect(eff,ev.dat2); | ||
279 | break; | ||
280 | } | ||
281 | |||
282 | /* second effect */ | ||
283 | eff=ev.eff&0xf; | ||
284 | switch(eff) { | ||
285 | case 0x3: /* tone portamento */ | ||
286 | UniEffect(UNI_ITEFFECTG,ev.dat1); | ||
287 | break; | ||
288 | case 0x5: | ||
289 | break; | ||
290 | case 0x9: /* sample offset */ | ||
291 | if((ev.eff>>4)!=9) | ||
292 | UniEffect(UNI_ULTEFFECT9,((UWORD)ev.dat1)<<8); | ||
293 | break; | ||
294 | case 0xb: /* panning */ | ||
295 | UniPTEffect(8,ev.dat1*0xf); | ||
296 | of.flags |= UF_PANNING; | ||
297 | break; | ||
298 | case 0xc: /* volume */ | ||
299 | UniPTEffect(eff,ev.dat1>>2); | ||
300 | break; | ||
301 | default: | ||
302 | UniPTEffect(eff,ev.dat1); | ||
303 | break; | ||
304 | } | ||
305 | |||
306 | UniNewline(); | ||
307 | row++; | ||
308 | } | ||
309 | } | ||
310 | if(!(of.tracks[t]=UniDup())) return 0; | ||
311 | } | ||
312 | return 1; | ||
313 | } | ||
314 | |||
315 | CHAR *ULT_LoadTitle(void) | ||
316 | { | ||
317 | CHAR s[32]; | ||
318 | |||
319 | _mm_fseek(modreader,15,SEEK_SET); | ||
320 | if(!_mm_read_UBYTES(s,32,modreader)) return NULL; | ||
321 | |||
322 | return(DupStr(s,32,1)); | ||
323 | } | ||
324 | |||
325 | /*========== Loader information */ | ||
326 | |||
327 | MIKMODAPI MLOADER load_ult={ | ||
328 | NULL, | ||
329 | "ULT", | ||
330 | "ULT (UltraTracker)", | ||
331 | ULT_Init, | ||
332 | ULT_Test, | ||
333 | ULT_Load, | ||
334 | ULT_Cleanup, | ||
335 | ULT_LoadTitle | ||
336 | }; | ||
337 | |||
338 | |||
339 | /* ex:set ts=4: */ | ||
diff --git a/apps/plugins/mikmod/load_uni.c b/apps/plugins/mikmod/load_uni.c new file mode 100644 index 0000000000..3140336b94 --- /dev/null +++ b/apps/plugins/mikmod/load_uni.c | |||
@@ -0,0 +1,717 @@ | |||
1 | /* MikMod sound library | ||
2 | (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file | ||
3 | AUTHORS 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: load_uni.c,v 1.3 2005/04/07 19:57:38 realtech Exp $ | ||
24 | |||
25 | UNIMOD (libmikmod's and APlayer's internal module format) loader | ||
26 | |||
27 | ==============================================================================*/ | ||
28 | |||
29 | #ifdef HAVE_CONFIG_H | ||
30 | #include "config.h" | ||
31 | #endif | ||
32 | |||
33 | #ifdef HAVE_UNISTD_H | ||
34 | #include <unistd.h> | ||
35 | #endif | ||
36 | |||
37 | #include <stdio.h> | ||
38 | #ifdef HAVE_MEMORY_H | ||
39 | #include <memory.h> | ||
40 | #endif | ||
41 | #include <string.h> | ||
42 | |||
43 | #include "mikmod_internals.h" | ||
44 | |||
45 | #ifdef SUNOS | ||
46 | extern int fprintf(FILE *, const char *, ...); | ||
47 | #endif | ||
48 | |||
49 | /*========== Module structure */ | ||
50 | |||
51 | typedef struct UNIHEADER { | ||
52 | CHAR id[4]; | ||
53 | UBYTE numchn; | ||
54 | UWORD numpos; | ||
55 | UWORD reppos; | ||
56 | UWORD numpat; | ||
57 | UWORD numtrk; | ||
58 | UWORD numins; | ||
59 | UWORD numsmp; | ||
60 | UBYTE initspeed; | ||
61 | UBYTE inittempo; | ||
62 | UBYTE initvolume; | ||
63 | UWORD flags; | ||
64 | UBYTE numvoices; | ||
65 | UWORD bpmlimit; | ||
66 | |||
67 | UBYTE positions[256]; | ||
68 | UBYTE panning[32]; | ||
69 | } UNIHEADER; | ||
70 | |||
71 | typedef struct UNISMP05 { | ||
72 | UWORD c2spd; | ||
73 | UWORD transpose; | ||
74 | UBYTE volume; | ||
75 | UBYTE panning; | ||
76 | ULONG length; | ||
77 | ULONG loopstart; | ||
78 | ULONG loopend; | ||
79 | UWORD flags; | ||
80 | CHAR* samplename; | ||
81 | UBYTE vibtype; | ||
82 | UBYTE vibsweep; | ||
83 | UBYTE vibdepth; | ||
84 | UBYTE vibrate; | ||
85 | } UNISMP05; | ||
86 | |||
87 | /*========== Loader variables */ | ||
88 | |||
89 | static UWORD universion; | ||
90 | static UNIHEADER mh; | ||
91 | |||
92 | #define UNI_SMPINCR 64 | ||
93 | static UNISMP05 *wh=NULL,*s=NULL; | ||
94 | |||
95 | /*========== Loader code */ | ||
96 | |||
97 | static char* readstring(void) | ||
98 | { | ||
99 | char *s=NULL; | ||
100 | UWORD len; | ||
101 | |||
102 | len=_mm_read_I_UWORD(modreader); | ||
103 | if(len) { | ||
104 | s=MikMod_malloc(len+1); | ||
105 | _mm_read_UBYTES(s,len,modreader); | ||
106 | s[len]=0; | ||
107 | } | ||
108 | return s; | ||
109 | } | ||
110 | |||
111 | int UNI_Test(void) | ||
112 | { | ||
113 | char id[6]; | ||
114 | |||
115 | if(!_mm_read_UBYTES(id,6,modreader)) return 0; | ||
116 | |||
117 | /* UNIMod created by MikCvt */ | ||
118 | if(!(memcmp(id,"UN0",3))) { | ||
119 | if((id[3]>='4')&&(id[3]<='6')) return 1; | ||
120 | } | ||
121 | /* UNIMod created by APlayer */ | ||
122 | if(!(memcmp(id,"APUN\01",5))) { | ||
123 | if((id[5]>=1)&&(id[5]<=6)) return 1; | ||
124 | } | ||
125 | return 0; | ||
126 | } | ||
127 | |||
128 | int UNI_Init(void) | ||
129 | { | ||
130 | return 1; | ||
131 | } | ||
132 | |||
133 | void UNI_Cleanup(void) | ||
134 | { | ||
135 | MikMod_free(wh); | ||
136 | s=NULL; | ||
137 | } | ||
138 | |||
139 | static UBYTE* readtrack(void) | ||
140 | { | ||
141 | UBYTE *t; | ||
142 | UWORD len; | ||
143 | int cur=0,chunk; | ||
144 | |||
145 | if(universion>=6) | ||
146 | len=_mm_read_M_UWORD(modreader); | ||
147 | else | ||
148 | len=_mm_read_I_UWORD(modreader); | ||
149 | |||
150 | if(!len) return NULL; | ||
151 | if(!(t=MikMod_malloc(len))) return NULL; | ||
152 | _mm_read_UBYTES(t,len,modreader); | ||
153 | |||
154 | /* Check if the track is correct */ | ||
155 | while(1) { | ||
156 | chunk=t[cur++]; | ||
157 | if(!chunk) break; | ||
158 | chunk=(chunk&0x1f)-1; | ||
159 | while(chunk>0) { | ||
160 | int opcode,oplen; | ||
161 | |||
162 | if(cur>=len) { | ||
163 | MikMod_free(t); | ||
164 | return NULL; | ||
165 | } | ||
166 | opcode=t[cur]; | ||
167 | |||
168 | /* Remap opcodes */ | ||
169 | if (universion <= 5) { | ||
170 | if (opcode > 29) { | ||
171 | MikMod_free(t); | ||
172 | return NULL; | ||
173 | } | ||
174 | switch (opcode) { | ||
175 | /* UNI_NOTE .. UNI_S3MEFFECTQ are the same */ | ||
176 | case 25: | ||
177 | opcode = UNI_S3MEFFECTT; | ||
178 | break; | ||
179 | case 26: | ||
180 | opcode = UNI_XMEFFECTA; | ||
181 | break; | ||
182 | case 27: | ||
183 | opcode = UNI_XMEFFECTG; | ||
184 | break; | ||
185 | case 28: | ||
186 | opcode = UNI_XMEFFECTH; | ||
187 | break; | ||
188 | case 29: | ||
189 | opcode = UNI_XMEFFECTP; | ||
190 | break; | ||
191 | } | ||
192 | } else { | ||
193 | /* APlayer < 1.05 does not have XMEFFECT6 */ | ||
194 | if (opcode >= UNI_XMEFFECT6 && universion < 0x105) | ||
195 | opcode++; | ||
196 | /* APlayer < 1.03 does not have ITEFFECTT */ | ||
197 | if (opcode >= UNI_ITEFFECTT && universion < 0x103) | ||
198 | opcode++; | ||
199 | /* APlayer < 1.02 does not have ITEFFECTZ */ | ||
200 | if (opcode >= UNI_ITEFFECTZ && universion < 0x102) | ||
201 | opcode++; | ||
202 | } | ||
203 | |||
204 | if((!opcode)||(opcode>=UNI_LAST)) { | ||
205 | MikMod_free(t); | ||
206 | return NULL; | ||
207 | } | ||
208 | t[cur]=opcode; | ||
209 | oplen=unioperands[opcode]+1; | ||
210 | cur+=oplen; | ||
211 | chunk-=oplen; | ||
212 | } | ||
213 | if((chunk<0)||(cur>=len)) { | ||
214 | MikMod_free(t); | ||
215 | return NULL; | ||
216 | } | ||
217 | } | ||
218 | return t; | ||
219 | } | ||
220 | |||
221 | static int loadsmp6(void) | ||
222 | { | ||
223 | int t; | ||
224 | SAMPLE *s; | ||
225 | |||
226 | s=of.samples; | ||
227 | for(t=0;t<of.numsmp;t++,s++) { | ||
228 | int flags; | ||
229 | |||
230 | flags = _mm_read_M_UWORD(modreader); | ||
231 | s->flags=0; | ||
232 | if(flags&0x0004) s->flags|=SF_STEREO; | ||
233 | if(flags&0x0002) s->flags|=SF_SIGNED; | ||
234 | if(flags&0x0001) s->flags|=SF_16BITS; | ||
235 | /* convert flags */ | ||
236 | if(universion>=0x104) { | ||
237 | if(flags&0x2000) s->flags|=SF_UST_LOOP; | ||
238 | if(flags&0x1000) s->flags|=SF_OWNPAN; | ||
239 | if(flags&0x0800) s->flags|=SF_SUSTAIN; | ||
240 | if(flags&0x0400) s->flags|=SF_REVERSE; | ||
241 | if(flags&0x0200) s->flags|=SF_BIDI; | ||
242 | if(flags&0x0100) s->flags|=SF_LOOP; | ||
243 | if(flags&0x0020) s->flags|=SF_ITPACKED; | ||
244 | if(flags&0x0010) s->flags|=SF_DELTA; | ||
245 | if(flags&0x0008) s->flags|=SF_BIG_ENDIAN; | ||
246 | } else if(universion>=0x102) { | ||
247 | if(flags&0x0800) s->flags|=SF_UST_LOOP; | ||
248 | if(flags&0x0400) s->flags|=SF_OWNPAN; | ||
249 | if(flags&0x0200) s->flags|=SF_SUSTAIN; | ||
250 | if(flags&0x0100) s->flags|=SF_REVERSE; | ||
251 | if(flags&0x0080) s->flags|=SF_BIDI; | ||
252 | if(flags&0x0040) s->flags|=SF_LOOP; | ||
253 | if(flags&0x0020) s->flags|=SF_ITPACKED; | ||
254 | if(flags&0x0010) s->flags|=SF_DELTA; | ||
255 | if(flags&0x0008) s->flags|=SF_BIG_ENDIAN; | ||
256 | } else { | ||
257 | if(flags&0x400) s->flags|=SF_UST_LOOP; | ||
258 | if(flags&0x200) s->flags|=SF_OWNPAN; | ||
259 | if(flags&0x100) s->flags|=SF_REVERSE; | ||
260 | if(flags&0x080) s->flags|=SF_SUSTAIN; | ||
261 | if(flags&0x040) s->flags|=SF_BIDI; | ||
262 | if(flags&0x020) s->flags|=SF_LOOP; | ||
263 | if(flags&0x010) s->flags|=SF_BIG_ENDIAN; | ||
264 | if(flags&0x008) s->flags|=SF_DELTA; | ||
265 | } | ||
266 | |||
267 | s->speed = _mm_read_M_ULONG(modreader); | ||
268 | s->volume = _mm_read_UBYTE(modreader); | ||
269 | s->panning = _mm_read_M_UWORD(modreader); | ||
270 | s->length = _mm_read_M_ULONG(modreader); | ||
271 | s->loopstart = _mm_read_M_ULONG(modreader); | ||
272 | s->loopend = _mm_read_M_ULONG(modreader); | ||
273 | s->susbegin = _mm_read_M_ULONG(modreader); | ||
274 | s->susend = _mm_read_M_ULONG(modreader); | ||
275 | s->globvol = _mm_read_UBYTE(modreader); | ||
276 | s->vibflags = _mm_read_UBYTE(modreader); | ||
277 | s->vibtype = _mm_read_UBYTE(modreader); | ||
278 | s->vibsweep = _mm_read_UBYTE(modreader); | ||
279 | s->vibdepth = _mm_read_UBYTE(modreader); | ||
280 | s->vibrate = _mm_read_UBYTE(modreader); | ||
281 | |||
282 | s->samplename=readstring(); | ||
283 | |||
284 | if(_mm_eof(modreader)) { | ||
285 | _mm_errno = MMERR_LOADING_SAMPLEINFO; | ||
286 | return 0; | ||
287 | } | ||
288 | } | ||
289 | return 1; | ||
290 | } | ||
291 | |||
292 | static int loadinstr6(void) | ||
293 | { | ||
294 | int t,w; | ||
295 | INSTRUMENT *i; | ||
296 | |||
297 | i=of.instruments; | ||
298 | for(t=0;t<of.numins;t++,i++) { | ||
299 | i->flags = _mm_read_UBYTE(modreader); | ||
300 | i->nnatype = _mm_read_UBYTE(modreader); | ||
301 | i->dca = _mm_read_UBYTE(modreader); | ||
302 | i->dct = _mm_read_UBYTE(modreader); | ||
303 | i->globvol = _mm_read_UBYTE(modreader); | ||
304 | i->panning = _mm_read_M_UWORD(modreader); | ||
305 | i->pitpansep = _mm_read_UBYTE(modreader); | ||
306 | i->pitpancenter = _mm_read_UBYTE(modreader); | ||
307 | i->rvolvar = _mm_read_UBYTE(modreader); | ||
308 | i->rpanvar = _mm_read_UBYTE(modreader); | ||
309 | i->volfade = _mm_read_M_UWORD(modreader); | ||
310 | |||
311 | #if defined __STDC__ || defined _MSC_VER || defined MPW_C | ||
312 | #define UNI_LoadEnvelope6(name) \ | ||
313 | i-> name##flg=_mm_read_UBYTE(modreader); \ | ||
314 | i-> name##pts=_mm_read_UBYTE(modreader); \ | ||
315 | i-> name##susbeg=_mm_read_UBYTE(modreader); \ | ||
316 | i-> name##susend=_mm_read_UBYTE(modreader); \ | ||
317 | i-> name##beg=_mm_read_UBYTE(modreader); \ | ||
318 | i-> name##end=_mm_read_UBYTE(modreader); \ | ||
319 | for(w=0;w<(universion>=0x100?32:i-> name##pts);w++) { \ | ||
320 | i-> name##env[w].pos=_mm_read_M_SWORD(modreader); \ | ||
321 | i-> name##env[w].val=_mm_read_M_SWORD(modreader); \ | ||
322 | } | ||
323 | #else | ||
324 | #define UNI_LoadEnvelope6(name) \ | ||
325 | i-> name/**/flg=_mm_read_UBYTE(modreader); \ | ||
326 | i-> name/**/pts=_mm_read_UBYTE(modreader); \ | ||
327 | i-> name/**/susbeg=_mm_read_UBYTE(modreader); \ | ||
328 | i-> name/**/susend=_mm_read_UBYTE(modreader); \ | ||
329 | i-> name/**/beg=_mm_read_UBYTE(modreader); \ | ||
330 | i-> name/**/end=_mm_read_UBYTE(modreader); \ | ||
331 | for (w=0;w<(universion>=0x100?32:i-> name/**/pts);w++) { \ | ||
332 | i-> name/**/env[w].pos=_mm_read_M_SWORD(modreader); \ | ||
333 | i-> name/**/env[w].val=_mm_read_M_SWORD(modreader); \ | ||
334 | } | ||
335 | #endif | ||
336 | |||
337 | UNI_LoadEnvelope6(vol); | ||
338 | UNI_LoadEnvelope6(pan); | ||
339 | UNI_LoadEnvelope6(pit); | ||
340 | #undef UNI_LoadEnvelope6 | ||
341 | |||
342 | if(universion>=0x103) | ||
343 | _mm_read_M_UWORDS(i->samplenumber,120,modreader); | ||
344 | else | ||
345 | for(w=0;w<120;w++) | ||
346 | i->samplenumber[w]=_mm_read_UBYTE(modreader); | ||
347 | _mm_read_UBYTES(i->samplenote,120,modreader); | ||
348 | |||
349 | i->insname=readstring(); | ||
350 | |||
351 | if(_mm_eof(modreader)) { | ||
352 | _mm_errno = MMERR_LOADING_SAMPLEINFO; | ||
353 | return 0; | ||
354 | } | ||
355 | } | ||
356 | return 1; | ||
357 | } | ||
358 | |||
359 | static int loadinstr5(void) | ||
360 | { | ||
361 | INSTRUMENT *i; | ||
362 | int t; | ||
363 | UWORD wavcnt=0; | ||
364 | UBYTE vibtype,vibsweep,vibdepth,vibrate; | ||
365 | |||
366 | i=of.instruments; | ||
367 | for(of.numsmp=t=0;t<of.numins;t++,i++) { | ||
368 | int u,numsmp; | ||
369 | |||
370 | numsmp=_mm_read_UBYTE(modreader); | ||
371 | |||
372 | memset(i->samplenumber,0xff,INSTNOTES*sizeof(UWORD)); | ||
373 | for(u=0;u<96;u++) | ||
374 | i->samplenumber[u]=of.numsmp+_mm_read_UBYTE(modreader); | ||
375 | |||
376 | #if defined __STDC__ || defined _MSC_VER || defined MPW_C | ||
377 | #define UNI_LoadEnvelope5(name) \ | ||
378 | i-> name##flg=_mm_read_UBYTE(modreader); \ | ||
379 | i-> name##pts=_mm_read_UBYTE(modreader); \ | ||
380 | i-> name##susbeg=_mm_read_UBYTE(modreader); \ | ||
381 | i-> name##susend=i-> name##susbeg; \ | ||
382 | i-> name##beg=_mm_read_UBYTE(modreader); \ | ||
383 | i-> name##end=_mm_read_UBYTE(modreader); \ | ||
384 | for(u=0;u<12;u++) { \ | ||
385 | i-> name##env[u].pos=_mm_read_I_SWORD(modreader); \ | ||
386 | i-> name##env[u].val=_mm_read_I_SWORD(modreader); \ | ||
387 | } | ||
388 | #else | ||
389 | #define UNI_LoadEnvelope5(name) \ | ||
390 | i-> name/**/flg=_mm_read_UBYTE(modreader); \ | ||
391 | i-> name/**/pts=_mm_read_UBYTE(modreader); \ | ||
392 | i-> name/**/susbeg=_mm_read_UBYTE(modreader); \ | ||
393 | i-> name/**/susend=i-> name/**/susbeg; \ | ||
394 | i-> name/**/beg=_mm_read_UBYTE(modreader); \ | ||
395 | i-> name/**/end=_mm_read_UBYTE(modreader); \ | ||
396 | for(u=0;u<12;u++) { \ | ||
397 | i-> name/**/env[u].pos=_mm_read_I_SWORD(modreader); \ | ||
398 | i-> name/**/env[u].val=_mm_read_I_SWORD(modreader); \ | ||
399 | } | ||
400 | #endif | ||
401 | |||
402 | UNI_LoadEnvelope5(vol); | ||
403 | UNI_LoadEnvelope5(pan); | ||
404 | #undef UNI_LoadEnvelope5 | ||
405 | |||
406 | vibtype =_mm_read_UBYTE(modreader); | ||
407 | vibsweep =_mm_read_UBYTE(modreader); | ||
408 | vibdepth =_mm_read_UBYTE(modreader); | ||
409 | vibrate =_mm_read_UBYTE(modreader); | ||
410 | |||
411 | i->volfade=_mm_read_I_UWORD(modreader); | ||
412 | i->insname=readstring(); | ||
413 | |||
414 | for(u=0;u<numsmp;u++,s++,of.numsmp++) { | ||
415 | /* Allocate more room for sample information if necessary */ | ||
416 | if(of.numsmp+u==wavcnt) { | ||
417 | wavcnt+=UNI_SMPINCR; | ||
418 | if(!(wh=MikMod_realloc(wh,wavcnt*sizeof(UNISMP05)))) { | ||
419 | _mm_errno=MMERR_OUT_OF_MEMORY; | ||
420 | return 0; | ||
421 | } | ||
422 | s=wh+(wavcnt-UNI_SMPINCR); | ||
423 | } | ||
424 | |||
425 | s->c2spd =_mm_read_I_UWORD(modreader); | ||
426 | s->transpose=_mm_read_SBYTE(modreader); | ||
427 | s->volume =_mm_read_UBYTE(modreader); | ||
428 | s->panning =_mm_read_UBYTE(modreader); | ||
429 | s->length =_mm_read_I_ULONG(modreader); | ||
430 | s->loopstart=_mm_read_I_ULONG(modreader); | ||
431 | s->loopend =_mm_read_I_ULONG(modreader); | ||
432 | s->flags =_mm_read_I_UWORD(modreader); | ||
433 | s->samplename=readstring(); | ||
434 | |||
435 | s->vibtype =vibtype; | ||
436 | s->vibsweep=vibsweep; | ||
437 | s->vibdepth=vibdepth; | ||
438 | s->vibrate =vibrate; | ||
439 | |||
440 | if(_mm_eof(modreader)) { | ||
441 | MikMod_free(wh);wh=NULL; | ||
442 | _mm_errno=MMERR_LOADING_SAMPLEINFO; | ||
443 | return 0; | ||
444 | } | ||
445 | } | ||
446 | } | ||
447 | |||
448 | /* sanity check */ | ||
449 | if(!of.numsmp) { | ||
450 | if(wh) { MikMod_free(wh);wh=NULL; } | ||
451 | _mm_errno=MMERR_LOADING_SAMPLEINFO; | ||
452 | return 0; | ||
453 | } | ||
454 | return 1; | ||
455 | } | ||
456 | |||
457 | static int loadsmp5(void) | ||
458 | { | ||
459 | int t,u; | ||
460 | SAMPLE *q; | ||
461 | INSTRUMENT *d; | ||
462 | |||
463 | q=of.samples;s=wh; | ||
464 | for(u=0;u<of.numsmp;u++,q++,s++) { | ||
465 | q->samplename=s->samplename; | ||
466 | |||
467 | q->length =s->length; | ||
468 | q->loopstart=s->loopstart; | ||
469 | q->loopend =s->loopend; | ||
470 | q->volume =s->volume; | ||
471 | q->speed =s->c2spd; | ||
472 | q->panning =s->panning; | ||
473 | q->vibtype =s->vibtype; | ||
474 | q->vibsweep =s->vibsweep; | ||
475 | q->vibdepth =s->vibdepth; | ||
476 | q->vibrate =s->vibrate; | ||
477 | |||
478 | /* convert flags */ | ||
479 | q->flags=0; | ||
480 | if(s->flags&128) q->flags|=SF_REVERSE; | ||
481 | if(s->flags& 64) q->flags|=SF_SUSTAIN; | ||
482 | if(s->flags& 32) q->flags|=SF_BIDI; | ||
483 | if(s->flags& 16) q->flags|=SF_LOOP; | ||
484 | if(s->flags& 8) q->flags|=SF_BIG_ENDIAN; | ||
485 | if(s->flags& 4) q->flags|=SF_DELTA; | ||
486 | if(s->flags& 2) q->flags|=SF_SIGNED; | ||
487 | if(s->flags& 1) q->flags|=SF_16BITS; | ||
488 | } | ||
489 | |||
490 | d=of.instruments;s=wh; | ||
491 | for(u=0;u<of.numins;u++,d++) | ||
492 | for(t=0;t<INSTNOTES;t++) | ||
493 | d->samplenote[t]=(d->samplenumber[t]>=of.numsmp)? | ||
494 | 255:(t+s[d->samplenumber[t]].transpose); | ||
495 | |||
496 | MikMod_free(wh);wh=NULL; | ||
497 | |||
498 | return 1; | ||
499 | } | ||
500 | |||
501 | int UNI_Load(int curious) | ||
502 | { | ||
503 | int t; | ||
504 | char *modtype,*oldtype=NULL; | ||
505 | INSTRUMENT *d; | ||
506 | SAMPLE *q; | ||
507 | |||
508 | /* read module header */ | ||
509 | _mm_read_UBYTES(mh.id,4,modreader); | ||
510 | if(mh.id[3]!='N') | ||
511 | universion=mh.id[3]-'0'; | ||
512 | else | ||
513 | universion=0x100; | ||
514 | |||
515 | if(universion>=6) { | ||
516 | if (universion==6) | ||
517 | _mm_read_UBYTE(modreader); | ||
518 | else | ||
519 | universion=_mm_read_M_UWORD(modreader); | ||
520 | |||
521 | mh.flags =_mm_read_M_UWORD(modreader); | ||
522 | mh.numchn =_mm_read_UBYTE(modreader); | ||
523 | mh.numvoices =_mm_read_UBYTE(modreader); | ||
524 | mh.numpos =_mm_read_M_UWORD(modreader); | ||
525 | mh.numpat =_mm_read_M_UWORD(modreader); | ||
526 | mh.numtrk =_mm_read_M_UWORD(modreader); | ||
527 | mh.numins =_mm_read_M_UWORD(modreader); | ||
528 | mh.numsmp =_mm_read_M_UWORD(modreader); | ||
529 | mh.reppos =_mm_read_M_UWORD(modreader); | ||
530 | mh.initspeed =_mm_read_UBYTE(modreader); | ||
531 | mh.inittempo =_mm_read_UBYTE(modreader); | ||
532 | mh.initvolume=_mm_read_UBYTE(modreader); | ||
533 | /* I expect this to show up soon in APlayer 1.06 format */ | ||
534 | if (universion >= 0x106) | ||
535 | mh.bpmlimit=_mm_read_M_UWORD(modreader); | ||
536 | else | ||
537 | mh.bpmlimit=32; | ||
538 | |||
539 | mh.flags &= UF_XMPERIODS | UF_LINEAR | UF_INST | UF_NNA; | ||
540 | mh.flags |= UF_PANNING; | ||
541 | } else { | ||
542 | mh.numchn =_mm_read_UBYTE(modreader); | ||
543 | mh.numpos =_mm_read_I_UWORD(modreader); | ||
544 | mh.reppos =(universion==5)?_mm_read_I_UWORD(modreader):0; | ||
545 | mh.numpat =_mm_read_I_UWORD(modreader); | ||
546 | mh.numtrk =_mm_read_I_UWORD(modreader); | ||
547 | mh.numins =_mm_read_I_UWORD(modreader); | ||
548 | mh.initspeed =_mm_read_UBYTE(modreader); | ||
549 | mh.inittempo =_mm_read_UBYTE(modreader); | ||
550 | _mm_read_UBYTES(mh.positions,256,modreader); | ||
551 | _mm_read_UBYTES(mh.panning,32,modreader); | ||
552 | mh.flags =_mm_read_UBYTE(modreader); | ||
553 | mh.bpmlimit =32; | ||
554 | |||
555 | mh.flags &= UF_XMPERIODS | UF_LINEAR; | ||
556 | mh.flags |= UF_INST | UF_NOWRAP | UF_PANNING; | ||
557 | } | ||
558 | |||
559 | /* set module parameters */ | ||
560 | of.flags =mh.flags; | ||
561 | of.numchn =mh.numchn; | ||
562 | of.numpos =mh.numpos; | ||
563 | of.numpat =mh.numpat; | ||
564 | of.numtrk =mh.numtrk; | ||
565 | of.numins =mh.numins; | ||
566 | of.reppos =mh.reppos; | ||
567 | of.initspeed =mh.initspeed; | ||
568 | of.inittempo =mh.inittempo; | ||
569 | if(mh.bpmlimit) | ||
570 | of.bpmlimit=mh.bpmlimit; | ||
571 | else | ||
572 | /* be bug-compatible with older releases */ | ||
573 | of.bpmlimit=32; | ||
574 | |||
575 | of.songname=readstring(); | ||
576 | if(universion<0x102) | ||
577 | oldtype=readstring(); | ||
578 | if(oldtype) { | ||
579 | size_t len=strlen(oldtype)+20; | ||
580 | if(!(modtype=MikMod_malloc(len))) return 0; | ||
581 | #ifdef HAVE_SNPRINTF | ||
582 | snprintf(modtype,len,"%s (was %s)",(universion>=0x100)?"APlayer":"MikCvt2",oldtype); | ||
583 | #else | ||
584 | sprintf(modtype,"%s (was %s)",(universion>=0x100)?"APlayer":"MikCvt2",oldtype); | ||
585 | #endif | ||
586 | } else { | ||
587 | if(!(modtype=MikMod_malloc(10))) return 0; | ||
588 | #ifdef HAVE_SNPRINTF | ||
589 | snprintf(modtype,10,"%s",(universion>=0x100)?"APlayer":"MikCvt3"); | ||
590 | #else | ||
591 | sprintf(modtype,"%s",(universion>=0x100)?"APlayer":"MikCvt3"); | ||
592 | #endif | ||
593 | } | ||
594 | of.modtype=StrDup(modtype); | ||
595 | MikMod_free(modtype);MikMod_free(oldtype); | ||
596 | of.comment=readstring(); | ||
597 | |||
598 | if(universion>=6) { | ||
599 | of.numvoices=mh.numvoices; | ||
600 | of.initvolume=mh.initvolume; | ||
601 | } | ||
602 | |||
603 | if(_mm_eof(modreader)) { | ||
604 | _mm_errno=MMERR_LOADING_HEADER; | ||
605 | return 0; | ||
606 | } | ||
607 | |||
608 | /* positions */ | ||
609 | if(!AllocPositions(of.numpos)) return 0; | ||
610 | if(universion>=6) { | ||
611 | if(universion>=0x100) | ||
612 | _mm_read_M_UWORDS(of.positions,of.numpos,modreader); | ||
613 | else | ||
614 | for(t=0;t<of.numpos;t++) of.positions[t]=_mm_read_UBYTE(modreader); | ||
615 | _mm_read_M_UWORDS(of.panning,of.numchn,modreader); | ||
616 | _mm_read_UBYTES(of.chanvol,of.numchn,modreader); | ||
617 | } else { | ||
618 | if((mh.numpos>256)||(mh.numchn>32)) { | ||
619 | _mm_errno=MMERR_LOADING_HEADER; | ||
620 | return 0; | ||
621 | } | ||
622 | for(t=0;t<of.numpos;t++) of.positions[t]=mh.positions[t]; | ||
623 | for(t=0;t<of.numchn;t++) of.panning[t]=mh.panning[t]; | ||
624 | } | ||
625 | /* convert the ``end of song'' pattern code if necessary */ | ||
626 | if(universion<0x106) | ||
627 | for(t=0;t<of.numpos;t++) | ||
628 | if(of.positions[t]==255) of.positions[t]=LAST_PATTERN; | ||
629 | |||
630 | /* instruments and samples */ | ||
631 | if(universion>=6) { | ||
632 | of.numsmp=mh.numsmp; | ||
633 | if(!AllocSamples()) return 0; | ||
634 | if(!loadsmp6()) return 0; | ||
635 | |||
636 | if(of.flags&UF_INST) { | ||
637 | if(!AllocInstruments()) return 0; | ||
638 | if(!loadinstr6()) return 0; | ||
639 | } | ||
640 | } else { | ||
641 | if(!AllocInstruments()) return 0; | ||
642 | if(!loadinstr5()) return 0; | ||
643 | if(!AllocSamples()) { | ||
644 | if(wh) { MikMod_free(wh);wh=NULL; } | ||
645 | return 0; | ||
646 | } | ||
647 | if(!loadsmp5()) return 0; | ||
648 | |||
649 | /* check if the original file had no instruments */ | ||
650 | if(of.numsmp==of.numins) { | ||
651 | for(t=0,d=of.instruments;t<of.numins;t++,d++) { | ||
652 | int u; | ||
653 | |||
654 | if((d->volpts)||(d->panpts)||(d->globvol!=64)) break; | ||
655 | for(u=0;u<96;u++) | ||
656 | if((d->samplenumber[u]!=t)||(d->samplenote[u]!=u)) break; | ||
657 | if(u!=96) break; | ||
658 | } | ||
659 | if(t==of.numins) { | ||
660 | of.flags&=~UF_INST; | ||
661 | of.flags&=~UF_NOWRAP; | ||
662 | for(t=0,d=of.instruments,q=of.samples;t<of.numins;t++,d++,q++) { | ||
663 | q->samplename=d->insname; | ||
664 | d->insname=NULL; | ||
665 | } | ||
666 | } | ||
667 | } | ||
668 | } | ||
669 | |||
670 | /* patterns */ | ||
671 | if(!AllocPatterns()) return 0; | ||
672 | if(universion>=6) { | ||
673 | _mm_read_M_UWORDS(of.pattrows,of.numpat,modreader); | ||
674 | _mm_read_M_UWORDS(of.patterns,of.numpat*of.numchn,modreader); | ||
675 | } else { | ||
676 | _mm_read_I_UWORDS(of.pattrows,of.numpat,modreader); | ||
677 | _mm_read_I_UWORDS(of.patterns,of.numpat*of.numchn,modreader); | ||
678 | } | ||
679 | |||
680 | /* tracks */ | ||
681 | if(!AllocTracks()) return 0; | ||
682 | for(t=0;t<of.numtrk;t++) | ||
683 | if(!(of.tracks[t]=readtrack())) { | ||
684 | _mm_errno=MMERR_LOADING_TRACK; | ||
685 | return 0; | ||
686 | } | ||
687 | |||
688 | return 1; | ||
689 | } | ||
690 | |||
691 | CHAR *UNI_LoadTitle(void) | ||
692 | { | ||
693 | UBYTE ver; | ||
694 | int posit[3]={304,306,26}; | ||
695 | |||
696 | _mm_fseek(modreader,3,SEEK_SET); | ||
697 | ver=_mm_read_UBYTE(modreader); | ||
698 | if(ver=='N') ver='6'; | ||
699 | |||
700 | _mm_fseek(modreader,posit[ver-'4'],SEEK_SET); | ||
701 | return readstring(); | ||
702 | } | ||
703 | |||
704 | /*========== Loader information */ | ||
705 | |||
706 | MIKMODAPI MLOADER load_uni={ | ||
707 | NULL, | ||
708 | "UNI", | ||
709 | "APUN (APlayer) and UNI (MikMod)", | ||
710 | UNI_Init, | ||
711 | UNI_Test, | ||
712 | UNI_Load, | ||
713 | UNI_Cleanup, | ||
714 | UNI_LoadTitle | ||
715 | }; | ||
716 | |||
717 | /* ex:set ts=4: */ | ||
diff --git a/apps/plugins/mikmod/load_xm.c b/apps/plugins/mikmod/load_xm.c new file mode 100644 index 0000000000..54a95aa2e6 --- /dev/null +++ b/apps/plugins/mikmod/load_xm.c | |||
@@ -0,0 +1,829 @@ | |||
1 | /* MikMod sound library | ||
2 | (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file | ||
3 | AUTHORS 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: load_xm.c,v 1.5 2008/02/29 18:49:03 denis111 Exp $ | ||
24 | |||
25 | Fasttracker (XM) module loader | ||
26 | |||
27 | ==============================================================================*/ | ||
28 | |||
29 | #ifdef HAVE_CONFIG_H | ||
30 | #include "config.h" | ||
31 | #endif | ||
32 | |||
33 | #ifdef HAVE_UNISTD_H | ||
34 | #include <unistd.h> | ||
35 | #endif | ||
36 | |||
37 | #include <stdio.h> | ||
38 | #ifdef HAVE_MEMORY_H | ||
39 | #include <memory.h> | ||
40 | #endif | ||
41 | #include <string.h> | ||
42 | |||
43 | #include "mikmod_internals.h" | ||
44 | |||
45 | #ifdef SUNOS | ||
46 | extern int fprintf(FILE *, const char *, ...); | ||
47 | #endif | ||
48 | |||
49 | /*========== Module structure */ | ||
50 | |||
51 | typedef struct XMHEADER { | ||
52 | CHAR id[17]; /* ID text: 'Extended module: ' */ | ||
53 | CHAR songname[21]; /* Module name */ | ||
54 | CHAR trackername[20]; /* Tracker name */ | ||
55 | UWORD version; /* Version number */ | ||
56 | ULONG headersize; /* Header size */ | ||
57 | UWORD songlength; /* Song length (in patten order table) */ | ||
58 | UWORD restart; /* Restart position */ | ||
59 | UWORD numchn; /* Number of channels (2,4,6,8,10,...,32) */ | ||
60 | UWORD numpat; /* Number of patterns (max 256) */ | ||
61 | UWORD numins; /* Number of instruments (max 128) */ | ||
62 | UWORD flags; | ||
63 | UWORD tempo; /* Default tempo */ | ||
64 | UWORD bpm; /* Default BPM */ | ||
65 | UBYTE orders[256]; /* Pattern order table */ | ||
66 | } XMHEADER; | ||
67 | |||
68 | typedef struct XMINSTHEADER { | ||
69 | ULONG size; /* Instrument size */ | ||
70 | CHAR name[22]; /* Instrument name */ | ||
71 | UBYTE type; /* Instrument type (always 0) */ | ||
72 | UWORD numsmp; /* Number of samples in instrument */ | ||
73 | ULONG ssize; | ||
74 | } XMINSTHEADER; | ||
75 | |||
76 | #define XMENVCNT (12*2) | ||
77 | #define XMNOTECNT (8*OCTAVE) | ||
78 | typedef struct XMPATCHHEADER { | ||
79 | UBYTE what[XMNOTECNT]; /* Sample number for all notes */ | ||
80 | UWORD volenv[XMENVCNT]; /* Points for volume envelope */ | ||
81 | UWORD panenv[XMENVCNT]; /* Points for panning envelope */ | ||
82 | UBYTE volpts; /* Number of volume points */ | ||
83 | UBYTE panpts; /* Number of panning points */ | ||
84 | UBYTE volsus; /* Volume sustain point */ | ||
85 | UBYTE volbeg; /* Volume loop start point */ | ||
86 | UBYTE volend; /* Volume loop end point */ | ||
87 | UBYTE pansus; /* Panning sustain point */ | ||
88 | UBYTE panbeg; /* Panning loop start point */ | ||
89 | UBYTE panend; /* Panning loop end point */ | ||
90 | UBYTE volflg; /* Volume type: bit 0: On; 1: Sustain; 2: Loop */ | ||
91 | UBYTE panflg; /* Panning type: bit 0: On; 1: Sustain; 2: Loop */ | ||
92 | UBYTE vibflg; /* Vibrato type */ | ||
93 | UBYTE vibsweep; /* Vibrato sweep */ | ||
94 | UBYTE vibdepth; /* Vibrato depth */ | ||
95 | UBYTE vibrate; /* Vibrato rate */ | ||
96 | UWORD volfade; /* Volume fadeout */ | ||
97 | } XMPATCHHEADER; | ||
98 | |||
99 | typedef struct XMWAVHEADER { | ||
100 | ULONG length; /* Sample length */ | ||
101 | ULONG loopstart; /* Sample loop start */ | ||
102 | ULONG looplength; /* Sample loop length */ | ||
103 | UBYTE volume; /* Volume */ | ||
104 | SBYTE finetune; /* Finetune (signed byte -128..+127) */ | ||
105 | UBYTE type; /* Loop type */ | ||
106 | UBYTE panning; /* Panning (0-255) */ | ||
107 | SBYTE relnote; /* Relative note number (signed byte) */ | ||
108 | UBYTE reserved; | ||
109 | CHAR samplename[22]; /* Sample name */ | ||
110 | UBYTE vibtype; /* Vibrato type */ | ||
111 | UBYTE vibsweep; /* Vibrato sweep */ | ||
112 | UBYTE vibdepth; /* Vibrato depth */ | ||
113 | UBYTE vibrate; /* Vibrato rate */ | ||
114 | } XMWAVHEADER; | ||
115 | |||
116 | typedef struct XMPATHEADER { | ||
117 | ULONG size; /* Pattern header length */ | ||
118 | UBYTE packing; /* Packing type (always 0) */ | ||
119 | UWORD numrows; /* Number of rows in pattern (1..256) */ | ||
120 | SWORD packsize; /* Packed patterndata size */ | ||
121 | } XMPATHEADER; | ||
122 | |||
123 | typedef struct XMNOTE { | ||
124 | UBYTE note,ins,vol,eff,dat; | ||
125 | } XMNOTE; | ||
126 | |||
127 | /*========== Loader variables */ | ||
128 | |||
129 | static XMNOTE *xmpat=NULL; | ||
130 | static XMHEADER *mh=NULL; | ||
131 | |||
132 | /* increment unit for sample array MikMod_reallocation */ | ||
133 | #define XM_SMPINCR 64 | ||
134 | static ULONG *nextwav=NULL; | ||
135 | static XMWAVHEADER *wh=NULL,*s=NULL; | ||
136 | |||
137 | /*========== Loader code */ | ||
138 | |||
139 | int XM_Test(void) | ||
140 | { | ||
141 | UBYTE id[38]; | ||
142 | |||
143 | if(!_mm_read_UBYTES(id,38,modreader)) return 0; | ||
144 | if(memcmp(id,"Extended Module: ",17)) return 0; | ||
145 | if(id[37]==0x1a) return 1; | ||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | int XM_Init(void) | ||
150 | { | ||
151 | if(!(mh=(XMHEADER *)MikMod_malloc(sizeof(XMHEADER)))) return 0; | ||
152 | return 1; | ||
153 | } | ||
154 | |||
155 | void XM_Cleanup(void) | ||
156 | { | ||
157 | MikMod_free(mh); | ||
158 | } | ||
159 | |||
160 | static int XM_ReadNote(XMNOTE* n) | ||
161 | { | ||
162 | UBYTE cmp,result=1; | ||
163 | |||
164 | memset(n,0,sizeof(XMNOTE)); | ||
165 | cmp=_mm_read_UBYTE(modreader); | ||
166 | |||
167 | if(cmp&0x80) { | ||
168 | if(cmp&1) { result++;n->note = _mm_read_UBYTE(modreader); } | ||
169 | if(cmp&2) { result++;n->ins = _mm_read_UBYTE(modreader); } | ||
170 | if(cmp&4) { result++;n->vol = _mm_read_UBYTE(modreader); } | ||
171 | if(cmp&8) { result++;n->eff = _mm_read_UBYTE(modreader); } | ||
172 | if(cmp&16) { result++;n->dat = _mm_read_UBYTE(modreader); } | ||
173 | } else { | ||
174 | n->note = cmp; | ||
175 | n->ins = _mm_read_UBYTE(modreader); | ||
176 | n->vol = _mm_read_UBYTE(modreader); | ||
177 | n->eff = _mm_read_UBYTE(modreader); | ||
178 | n->dat = _mm_read_UBYTE(modreader); | ||
179 | result += 4; | ||
180 | } | ||
181 | return result; | ||
182 | } | ||
183 | |||
184 | static UBYTE* XM_Convert(XMNOTE* xmtrack,UWORD rows) | ||
185 | { | ||
186 | int t; | ||
187 | UBYTE note,ins,vol,eff,dat; | ||
188 | |||
189 | UniReset(); | ||
190 | for(t=0;t<rows;t++) { | ||
191 | note = xmtrack->note; | ||
192 | ins = xmtrack->ins; | ||
193 | vol = xmtrack->vol; | ||
194 | eff = xmtrack->eff; | ||
195 | dat = xmtrack->dat; | ||
196 | |||
197 | if(note) { | ||
198 | if(note>XMNOTECNT) | ||
199 | UniEffect(UNI_KEYFADE,0); | ||
200 | else | ||
201 | UniNote(note-1); | ||
202 | } | ||
203 | if(ins) UniInstrument(ins-1); | ||
204 | |||
205 | switch(vol>>4) { | ||
206 | case 0x6: /* volslide down */ | ||
207 | if(vol&0xf) UniEffect(UNI_XMEFFECTA,vol&0xf); | ||
208 | break; | ||
209 | case 0x7: /* volslide up */ | ||
210 | if(vol&0xf) UniEffect(UNI_XMEFFECTA,vol<<4); | ||
211 | break; | ||
212 | |||
213 | /* volume-row fine volume slide is compatible with protracker | ||
214 | EBx and EAx effects i.e. a zero nibble means DO NOT SLIDE, as | ||
215 | opposed to 'take the last sliding value'. */ | ||
216 | case 0x8: /* finevol down */ | ||
217 | UniPTEffect(0xe,0xb0|(vol&0xf)); | ||
218 | break; | ||
219 | case 0x9: /* finevol up */ | ||
220 | UniPTEffect(0xe,0xa0|(vol&0xf)); | ||
221 | break; | ||
222 | case 0xa: /* set vibrato speed */ | ||
223 | UniEffect(UNI_XMEFFECT4,vol<<4); | ||
224 | break; | ||
225 | case 0xb: /* vibrato */ | ||
226 | UniEffect(UNI_XMEFFECT4,vol&0xf); | ||
227 | break; | ||
228 | case 0xc: /* set panning */ | ||
229 | UniPTEffect(0x8,vol<<4); | ||
230 | break; | ||
231 | case 0xd: /* panning slide left (only slide when data not zero) */ | ||
232 | if(vol&0xf) UniEffect(UNI_XMEFFECTP,vol&0xf); | ||
233 | break; | ||
234 | case 0xe: /* panning slide right (only slide when data not zero) */ | ||
235 | if(vol&0xf) UniEffect(UNI_XMEFFECTP,vol<<4); | ||
236 | break; | ||
237 | case 0xf: /* tone porta */ | ||
238 | UniPTEffect(0x3,vol<<4); | ||
239 | break; | ||
240 | default: | ||
241 | if((vol>=0x10)&&(vol<=0x50)) | ||
242 | UniPTEffect(0xc,vol-0x10); | ||
243 | } | ||
244 | |||
245 | switch(eff) { | ||
246 | case 0x4: | ||
247 | UniEffect(UNI_XMEFFECT4,dat); | ||
248 | break; | ||
249 | case 0x6: | ||
250 | UniEffect(UNI_XMEFFECT6,dat); | ||
251 | break; | ||
252 | case 0xa: | ||
253 | UniEffect(UNI_XMEFFECTA,dat); | ||
254 | break; | ||
255 | case 0xe: /* Extended effects */ | ||
256 | switch(dat>>4) { | ||
257 | case 0x1: /* XM fine porta up */ | ||
258 | UniEffect(UNI_XMEFFECTE1,dat&0xf); | ||
259 | break; | ||
260 | case 0x2: /* XM fine porta down */ | ||
261 | UniEffect(UNI_XMEFFECTE2,dat&0xf); | ||
262 | break; | ||
263 | case 0xa: /* XM fine volume up */ | ||
264 | UniEffect(UNI_XMEFFECTEA,dat&0xf); | ||
265 | break; | ||
266 | case 0xb: /* XM fine volume down */ | ||
267 | UniEffect(UNI_XMEFFECTEB,dat&0xf); | ||
268 | break; | ||
269 | default: | ||
270 | UniPTEffect(eff,dat); | ||
271 | } | ||
272 | break; | ||
273 | case 'G'-55: /* G - set global volume */ | ||
274 | UniEffect(UNI_XMEFFECTG,dat>64?128:dat<<1); | ||
275 | break; | ||
276 | case 'H'-55: /* H - global volume slide */ | ||
277 | UniEffect(UNI_XMEFFECTH,dat); | ||
278 | break; | ||
279 | case 'K'-55: /* K - keyOff and KeyFade */ | ||
280 | UniEffect(UNI_KEYFADE,dat); | ||
281 | break; | ||
282 | case 'L'-55: /* L - set envelope position */ | ||
283 | UniEffect(UNI_XMEFFECTL,dat); | ||
284 | break; | ||
285 | case 'P'-55: /* P - panning slide */ | ||
286 | UniEffect(UNI_XMEFFECTP,dat); | ||
287 | break; | ||
288 | case 'R'-55: /* R - multi retrig note */ | ||
289 | UniEffect(UNI_S3MEFFECTQ,dat); | ||
290 | break; | ||
291 | case 'T'-55: /* T - Tremor */ | ||
292 | UniEffect(UNI_S3MEFFECTI,dat); | ||
293 | break; | ||
294 | case 'X'-55: | ||
295 | switch(dat>>4) { | ||
296 | case 1: /* X1 - Extra Fine Porta up */ | ||
297 | UniEffect(UNI_XMEFFECTX1,dat&0xf); | ||
298 | break; | ||
299 | case 2: /* X2 - Extra Fine Porta down */ | ||
300 | UniEffect(UNI_XMEFFECTX2,dat&0xf); | ||
301 | break; | ||
302 | } | ||
303 | break; | ||
304 | default: | ||
305 | if(eff<=0xf) { | ||
306 | /* the pattern jump destination is written in decimal, | ||
307 | but it seems some poor tracker software writes them | ||
308 | in hexadecimal... (sigh) */ | ||
309 | if (eff==0xd) | ||
310 | /* don't change anything if we're sure it's in hexa */ | ||
311 | if ((((dat&0xf0)>>4)<=9)&&((dat&0xf)<=9)) | ||
312 | /* otherwise, convert from dec to hex */ | ||
313 | dat=(((dat&0xf0)>>4)*10)+(dat&0xf); | ||
314 | UniPTEffect(eff,dat); | ||
315 | } | ||
316 | break; | ||
317 | } | ||
318 | UniNewline(); | ||
319 | xmtrack++; | ||
320 | } | ||
321 | return UniDup(); | ||
322 | } | ||
323 | |||
324 | static int LoadPatterns(int dummypat) | ||
325 | { | ||
326 | int t,u,v,numtrk; | ||
327 | |||
328 | if(!AllocTracks()) return 0; | ||
329 | if(!AllocPatterns()) return 0; | ||
330 | |||
331 | numtrk=0; | ||
332 | for(t=0;t<mh->numpat;t++) { | ||
333 | XMPATHEADER ph; | ||
334 | |||
335 | ph.size =_mm_read_I_ULONG(modreader); | ||
336 | if (ph.size<(mh->version==0x0102?8:9)) { | ||
337 | _mm_errno=MMERR_LOADING_PATTERN; | ||
338 | return 0; | ||
339 | } | ||
340 | ph.packing =_mm_read_UBYTE(modreader); | ||
341 | if(ph.packing) { | ||
342 | _mm_errno=MMERR_LOADING_PATTERN; | ||
343 | return 0; | ||
344 | } | ||
345 | if(mh->version==0x0102) | ||
346 | ph.numrows =_mm_read_UBYTE(modreader)+1; | ||
347 | else | ||
348 | ph.numrows =_mm_read_I_UWORD(modreader); | ||
349 | ph.packsize =_mm_read_I_UWORD(modreader); | ||
350 | |||
351 | ph.size-=(mh->version==0x0102?8:9); | ||
352 | if(ph.size) | ||
353 | _mm_fseek(modreader,ph.size,SEEK_CUR); | ||
354 | |||
355 | of.pattrows[t]=ph.numrows; | ||
356 | |||
357 | if(ph.numrows) { | ||
358 | if(!(xmpat=(XMNOTE*)MikMod_calloc(ph.numrows*of.numchn,sizeof(XMNOTE)))) | ||
359 | return 0; | ||
360 | |||
361 | /* when packsize is 0, don't try to load a pattern.. it's empty. */ | ||
362 | if(ph.packsize) | ||
363 | for(u=0;u<ph.numrows;u++) | ||
364 | for(v=0;v<of.numchn;v++) { | ||
365 | if(!ph.packsize) break; | ||
366 | |||
367 | ph.packsize-=XM_ReadNote(&xmpat[(v*ph.numrows)+u]); | ||
368 | if(ph.packsize<0) { | ||
369 | MikMod_free(xmpat);xmpat=NULL; | ||
370 | _mm_errno=MMERR_LOADING_PATTERN; | ||
371 | return 0; | ||
372 | } | ||
373 | } | ||
374 | |||
375 | if(ph.packsize) { | ||
376 | _mm_fseek(modreader,ph.packsize,SEEK_CUR); | ||
377 | } | ||
378 | |||
379 | if(_mm_eof(modreader)) { | ||
380 | MikMod_free(xmpat);xmpat=NULL; | ||
381 | _mm_errno=MMERR_LOADING_PATTERN; | ||
382 | return 0; | ||
383 | } | ||
384 | |||
385 | for(v=0;v<of.numchn;v++) | ||
386 | of.tracks[numtrk++]=XM_Convert(&xmpat[v*ph.numrows],ph.numrows); | ||
387 | |||
388 | MikMod_free(xmpat);xmpat=NULL; | ||
389 | } else { | ||
390 | for(v=0;v<of.numchn;v++) | ||
391 | of.tracks[numtrk++]=XM_Convert(NULL,ph.numrows); | ||
392 | } | ||
393 | } | ||
394 | |||
395 | if(dummypat) { | ||
396 | of.pattrows[t]=64; | ||
397 | if(!(xmpat=(XMNOTE*)MikMod_calloc(64*of.numchn,sizeof(XMNOTE)))) return 0; | ||
398 | for(v=0;v<of.numchn;v++) | ||
399 | of.tracks[numtrk++]=XM_Convert(&xmpat[v*64],64); | ||
400 | MikMod_free(xmpat);xmpat=NULL; | ||
401 | } | ||
402 | |||
403 | return 1; | ||
404 | } | ||
405 | |||
406 | static void FixEnvelope(ENVPT *cur, int pts) | ||
407 | { | ||
408 | int u, old, tmp; | ||
409 | ENVPT *prev; | ||
410 | |||
411 | /* Some broken XM editing program will only save the low byte | ||
412 | of the position value. Try to compensate by adding the | ||
413 | missing high byte. */ | ||
414 | |||
415 | prev = cur++; | ||
416 | old = prev->pos; | ||
417 | |||
418 | for (u = 1; u < pts; u++, prev++, cur++) { | ||
419 | if (cur->pos < prev->pos) { | ||
420 | if (cur->pos < 0x100) { | ||
421 | if (cur->pos > old) /* same hex century */ | ||
422 | tmp = cur->pos + (prev->pos - old); | ||
423 | else | ||
424 | tmp = cur->pos | ((prev->pos + 0x100) & 0xff00); | ||
425 | old = cur->pos; | ||
426 | cur->pos = tmp; | ||
427 | #ifdef MIKMOD_DEBUG | ||
428 | fprintf(stderr, "\rbroken envelope position(%d/%d), %d %d -> %d\n", | ||
429 | u, pts, prev->pos, old, cur->pos); | ||
430 | #endif | ||
431 | } else { | ||
432 | #ifdef MIKMOD_DEBUG | ||
433 | /* different brokenness style... fix unknown */ | ||
434 | fprintf(stderr, "\rbroken envelope position(%d/%d), %d %d\n", | ||
435 | u, pts, old, cur->pos); | ||
436 | #endif | ||
437 | old = cur->pos; | ||
438 | } | ||
439 | } else | ||
440 | old = cur->pos; | ||
441 | } | ||
442 | } | ||
443 | |||
444 | static int LoadInstruments(void) | ||
445 | { | ||
446 | int t,u, ck; | ||
447 | INSTRUMENT *d; | ||
448 | ULONG next=0; | ||
449 | UWORD wavcnt=0; | ||
450 | |||
451 | if(!AllocInstruments()) return 0; | ||
452 | d=of.instruments; | ||
453 | for(t=0;t<of.numins;t++,d++) { | ||
454 | XMINSTHEADER ih; | ||
455 | long headend; | ||
456 | |||
457 | memset(d->samplenumber,0xff,INSTNOTES*sizeof(UWORD)); | ||
458 | |||
459 | /* read instrument header */ | ||
460 | headend = _mm_ftell(modreader); | ||
461 | ih.size = _mm_read_I_ULONG(modreader); | ||
462 | headend += ih.size; | ||
463 | ck = _mm_ftell(modreader); | ||
464 | _mm_fseek(modreader,0,SEEK_END); | ||
465 | if ((headend<0) || (_mm_ftell(modreader)<headend) || (headend<ck)) { | ||
466 | _mm_fseek(modreader,ck,SEEK_SET); | ||
467 | break; | ||
468 | } | ||
469 | _mm_fseek(modreader,ck,SEEK_SET); | ||
470 | _mm_read_string(ih.name, 22, modreader); | ||
471 | ih.type = _mm_read_UBYTE(modreader); | ||
472 | ih.numsmp = _mm_read_I_UWORD(modreader); | ||
473 | |||
474 | d->insname = DupStr(ih.name,22,1); | ||
475 | |||
476 | if((SWORD)ih.size>29) { | ||
477 | ih.ssize = _mm_read_I_ULONG(modreader); | ||
478 | if(((SWORD)ih.numsmp>0)&&(ih.numsmp<=XMNOTECNT)) { | ||
479 | XMPATCHHEADER pth; | ||
480 | int p; | ||
481 | |||
482 | _mm_read_UBYTES (pth.what,XMNOTECNT,modreader); | ||
483 | _mm_read_I_UWORDS (pth.volenv, XMENVCNT, modreader); | ||
484 | _mm_read_I_UWORDS (pth.panenv, XMENVCNT, modreader); | ||
485 | pth.volpts = _mm_read_UBYTE(modreader); | ||
486 | pth.panpts = _mm_read_UBYTE(modreader); | ||
487 | pth.volsus = _mm_read_UBYTE(modreader); | ||
488 | pth.volbeg = _mm_read_UBYTE(modreader); | ||
489 | pth.volend = _mm_read_UBYTE(modreader); | ||
490 | pth.pansus = _mm_read_UBYTE(modreader); | ||
491 | pth.panbeg = _mm_read_UBYTE(modreader); | ||
492 | pth.panend = _mm_read_UBYTE(modreader); | ||
493 | pth.volflg = _mm_read_UBYTE(modreader); | ||
494 | pth.panflg = _mm_read_UBYTE(modreader); | ||
495 | pth.vibflg = _mm_read_UBYTE(modreader); | ||
496 | pth.vibsweep = _mm_read_UBYTE(modreader); | ||
497 | pth.vibdepth = _mm_read_UBYTE(modreader); | ||
498 | pth.vibrate = _mm_read_UBYTE(modreader); | ||
499 | pth.volfade = _mm_read_I_UWORD(modreader); | ||
500 | |||
501 | /* read the remainder of the header | ||
502 | (2 bytes for 1.03, 22 for 1.04) */ | ||
503 | if (headend>=_mm_ftell(modreader)) for(u=headend-_mm_ftell(modreader);u;u--) _mm_read_UBYTE(modreader); | ||
504 | |||
505 | /* we can't trust the envelope point count here, as some | ||
506 | modules have incorrect values (K_OSPACE.XM reports 32 volume | ||
507 | points, for example). */ | ||
508 | if(pth.volpts>XMENVCNT/2) pth.volpts=XMENVCNT/2; | ||
509 | if(pth.panpts>XMENVCNT/2) pth.panpts=XMENVCNT/2; | ||
510 | |||
511 | if((_mm_eof(modreader))||(pth.volpts>XMENVCNT/2)||(pth.panpts>XMENVCNT/2)) { | ||
512 | if(nextwav) { MikMod_free(nextwav);nextwav=NULL; } | ||
513 | if(wh) { MikMod_free(wh);wh=NULL; } | ||
514 | _mm_errno = MMERR_LOADING_SAMPLEINFO; | ||
515 | return 0; | ||
516 | } | ||
517 | |||
518 | for(u=0;u<XMNOTECNT;u++) | ||
519 | d->samplenumber[u]=pth.what[u]+of.numsmp; | ||
520 | d->volfade = pth.volfade; | ||
521 | |||
522 | #if defined __STDC__ || defined _MSC_VER || defined MPW_C | ||
523 | #define XM_ProcessEnvelope(name) \ | ||
524 | for (u = 0; u < (XMENVCNT >> 1); u++) { \ | ||
525 | d-> name##env[u].pos = pth. name##env[u << 1]; \ | ||
526 | d-> name##env[u].val = pth. name##env[(u << 1)+ 1]; \ | ||
527 | } \ | ||
528 | if (pth. name##flg&1) d-> name##flg|=EF_ON; \ | ||
529 | if (pth. name##flg&2) d-> name##flg|=EF_SUSTAIN; \ | ||
530 | if (pth. name##flg&4) d-> name##flg|=EF_LOOP; \ | ||
531 | d-> name##susbeg=d-> name##susend=pth. name##sus; \ | ||
532 | d-> name##beg=pth. name##beg; \ | ||
533 | d-> name##end=pth. name##end; \ | ||
534 | d-> name##pts=pth. name##pts; \ | ||
535 | \ | ||
536 | /* scale envelope */ \ | ||
537 | for (p=0;p<XMENVCNT/2;p++) \ | ||
538 | d-> name##env[p].val<<=2; \ | ||
539 | \ | ||
540 | if ((d-> name##flg&EF_ON)&&(d-> name##pts<2)) \ | ||
541 | d-> name##flg&=~EF_ON | ||
542 | #else | ||
543 | #define XM_ProcessEnvelope(name) \ | ||
544 | for (u = 0; u < (XMENVCNT >> 1); u++) { \ | ||
545 | d-> name/**/env[u].pos = pth. name/**/env[u << 1]; \ | ||
546 | d-> name/**/env[u].val = pth. name/**/env[(u << 1)+ 1]; \ | ||
547 | } \ | ||
548 | if (pth. name/**/flg&1) d-> name/**/flg|=EF_ON; \ | ||
549 | if (pth. name/**/flg&2) d-> name/**/flg|=EF_SUSTAIN; \ | ||
550 | if (pth. name/**/flg&4) d-> name/**/flg|=EF_LOOP; \ | ||
551 | d-> name/**/susbeg=d-> name/**/susend= \ | ||
552 | pth. name/**/sus; \ | ||
553 | d-> name/**/beg=pth. name/**/beg; \ | ||
554 | d-> name/**/end=pth. name/**/end; \ | ||
555 | d-> name/**/pts=pth. name/**/pts; \ | ||
556 | \ | ||
557 | /* scale envelope */ \ | ||
558 | for (p=0;p<XMENVCNT/2;p++) \ | ||
559 | d-> name/**/env[p].val<<=2; \ | ||
560 | \ | ||
561 | if ((d-> name/**/flg&EF_ON)&&(d-> name/**/pts<2)) \ | ||
562 | d-> name/**/flg&=~EF_ON | ||
563 | #endif | ||
564 | |||
565 | XM_ProcessEnvelope(vol); | ||
566 | XM_ProcessEnvelope(pan); | ||
567 | #undef XM_ProcessEnvelope | ||
568 | |||
569 | if (d->volflg & EF_ON) | ||
570 | FixEnvelope(d->volenv, d->volpts); | ||
571 | if (d->panflg & EF_ON) | ||
572 | FixEnvelope(d->panenv, d->panpts); | ||
573 | |||
574 | /* Samples are stored outside the instrument struct now, so we | ||
575 | have to load them all into a temp area, count the of.numsmp | ||
576 | along the way and then do an AllocSamples() and move | ||
577 | everything over */ | ||
578 | if(mh->version>0x0103) next = 0; | ||
579 | for(u=0;u<ih.numsmp;u++,s++) { | ||
580 | /* Allocate more room for sample information if necessary */ | ||
581 | if(of.numsmp+u==wavcnt) { | ||
582 | wavcnt+=XM_SMPINCR; | ||
583 | if(!(nextwav=MikMod_realloc(nextwav,wavcnt*sizeof(ULONG)))){ | ||
584 | if(wh) { MikMod_free(wh);wh=NULL; } | ||
585 | _mm_errno = MMERR_OUT_OF_MEMORY; | ||
586 | return 0; | ||
587 | } | ||
588 | if(!(wh=MikMod_realloc(wh,wavcnt*sizeof(XMWAVHEADER)))) { | ||
589 | MikMod_free(nextwav);nextwav=NULL; | ||
590 | _mm_errno = MMERR_OUT_OF_MEMORY; | ||
591 | return 0; | ||
592 | } | ||
593 | s=wh+(wavcnt-XM_SMPINCR); | ||
594 | } | ||
595 | |||
596 | s->length =_mm_read_I_ULONG (modreader); | ||
597 | s->loopstart =_mm_read_I_ULONG (modreader); | ||
598 | s->looplength =_mm_read_I_ULONG (modreader); | ||
599 | s->volume =_mm_read_UBYTE (modreader); | ||
600 | s->finetune =_mm_read_SBYTE (modreader); | ||
601 | s->type =_mm_read_UBYTE (modreader); | ||
602 | s->panning =_mm_read_UBYTE (modreader); | ||
603 | s->relnote =_mm_read_SBYTE (modreader); | ||
604 | s->vibtype = pth.vibflg; | ||
605 | s->vibsweep = pth.vibsweep; | ||
606 | s->vibdepth = pth.vibdepth*4; | ||
607 | s->vibrate = pth.vibrate; | ||
608 | s->reserved =_mm_read_UBYTE (modreader); | ||
609 | _mm_read_string(s->samplename, 22, modreader); | ||
610 | |||
611 | nextwav[of.numsmp+u]=next; | ||
612 | next+=s->length; | ||
613 | |||
614 | if(_mm_eof(modreader)) { | ||
615 | MikMod_free(nextwav);MikMod_free(wh); | ||
616 | nextwav=NULL;wh=NULL; | ||
617 | _mm_errno = MMERR_LOADING_SAMPLEINFO; | ||
618 | return 0; | ||
619 | } | ||
620 | } | ||
621 | |||
622 | if(mh->version>0x0103) { | ||
623 | for(u=0;u<ih.numsmp;u++) | ||
624 | nextwav[of.numsmp++]+=_mm_ftell(modreader); | ||
625 | _mm_fseek(modreader,next,SEEK_CUR); | ||
626 | } else | ||
627 | of.numsmp+=ih.numsmp; | ||
628 | } else { | ||
629 | /* read the remainder of the header */ | ||
630 | ck = _mm_ftell(modreader); | ||
631 | _mm_fseek(modreader,0,SEEK_END); | ||
632 | if ((headend<0) || (_mm_ftell(modreader)<headend) || (headend<ck)) { | ||
633 | _mm_fseek(modreader,ck,SEEK_SET); | ||
634 | break; | ||
635 | } | ||
636 | _mm_fseek(modreader,ck,SEEK_SET); | ||
637 | for(u=headend-_mm_ftell(modreader);u;u--) _mm_read_UBYTE(modreader); | ||
638 | |||
639 | if(_mm_eof(modreader)) { | ||
640 | MikMod_free(nextwav);MikMod_free(wh); | ||
641 | nextwav=NULL;wh=NULL; | ||
642 | _mm_errno = MMERR_LOADING_SAMPLEINFO; | ||
643 | return 0; | ||
644 | } | ||
645 | } | ||
646 | } | ||
647 | } | ||
648 | |||
649 | /* sanity check */ | ||
650 | if(!of.numsmp) { | ||
651 | if(nextwav) { MikMod_free(nextwav);nextwav=NULL; } | ||
652 | if(wh) { MikMod_free(wh);wh=NULL; } | ||
653 | _mm_errno = MMERR_LOADING_SAMPLEINFO; | ||
654 | return 0; | ||
655 | } | ||
656 | |||
657 | return 1; | ||
658 | } | ||
659 | |||
660 | int XM_Load(int curious) | ||
661 | { | ||
662 | INSTRUMENT *d; | ||
663 | SAMPLE *q; | ||
664 | int t,u; | ||
665 | int dummypat=0; | ||
666 | char tracker[21],modtype[60]; | ||
667 | |||
668 | /* try to read module header */ | ||
669 | _mm_read_string(mh->id,17,modreader); | ||
670 | _mm_read_string(mh->songname,21,modreader); | ||
671 | _mm_read_string(mh->trackername,20,modreader); | ||
672 | mh->version =_mm_read_I_UWORD(modreader); | ||
673 | if((mh->version<0x102)||(mh->version>0x104)) { | ||
674 | _mm_errno=MMERR_NOT_A_MODULE; | ||
675 | return 0; | ||
676 | } | ||
677 | mh->headersize =_mm_read_I_ULONG(modreader); | ||
678 | mh->songlength =_mm_read_I_UWORD(modreader); | ||
679 | mh->restart =_mm_read_I_UWORD(modreader); | ||
680 | mh->numchn =_mm_read_I_UWORD(modreader); | ||
681 | mh->numpat =_mm_read_I_UWORD(modreader); | ||
682 | mh->numins =_mm_read_I_UWORD(modreader); | ||
683 | mh->flags =_mm_read_I_UWORD(modreader); | ||
684 | mh->tempo =_mm_read_I_UWORD(modreader); | ||
685 | mh->bpm =_mm_read_I_UWORD(modreader); | ||
686 | if(!mh->bpm) { | ||
687 | _mm_errno=MMERR_NOT_A_MODULE; | ||
688 | return 0; | ||
689 | } | ||
690 | _mm_read_UBYTES(mh->orders,mh->headersize-20,modreader); | ||
691 | |||
692 | if(_mm_eof(modreader)) { | ||
693 | _mm_errno = MMERR_LOADING_HEADER; | ||
694 | return 0; | ||
695 | } | ||
696 | |||
697 | /* set module variables */ | ||
698 | of.initspeed = mh->tempo; | ||
699 | of.inittempo = mh->bpm; | ||
700 | strncpy(tracker,mh->trackername,20);tracker[20]=0; | ||
701 | for(t=20;(tracker[t]<=' ')&&(t>=0);t--) tracker[t]=0; | ||
702 | |||
703 | /* some modules have the tracker name empty */ | ||
704 | if (!tracker[0]) | ||
705 | strcpy(tracker,"Unknown tracker"); | ||
706 | |||
707 | #ifdef HAVE_SNPRINTF | ||
708 | snprintf(modtype,60,"%s (XM format %d.%02d)", | ||
709 | tracker,mh->version>>8,mh->version&0xff); | ||
710 | #else | ||
711 | sprintf(modtype,"%s (XM format %d.%02d)", | ||
712 | tracker,mh->version>>8,mh->version&0xff); | ||
713 | #endif | ||
714 | of.modtype = StrDup(modtype); | ||
715 | of.numchn = mh->numchn; | ||
716 | of.numpat = mh->numpat; | ||
717 | of.numtrk = (UWORD)of.numpat*of.numchn; /* get number of channels */ | ||
718 | of.songname = DupStr(mh->songname,20,1); | ||
719 | of.numpos = mh->songlength; /* copy the songlength */ | ||
720 | of.reppos = mh->restart<mh->songlength?mh->restart:0; | ||
721 | of.numins = mh->numins; | ||
722 | of.flags |= UF_XMPERIODS | UF_INST | UF_NOWRAP | UF_FT2QUIRKS | | ||
723 | UF_PANNING; | ||
724 | if(mh->flags&1) of.flags |= UF_LINEAR; | ||
725 | of.bpmlimit = 32; | ||
726 | |||
727 | memset(of.chanvol,64,of.numchn); /* store channel volumes */ | ||
728 | |||
729 | if(!AllocPositions(of.numpos+1)) return 0; | ||
730 | for(t=0;t<of.numpos;t++) | ||
731 | of.positions[t]=mh->orders[t]; | ||
732 | |||
733 | /* We have to check for any pattern numbers in the order list greater than | ||
734 | the number of patterns total. If one or more is found, we set it equal to | ||
735 | the pattern total and make a dummy pattern to workaround the problem */ | ||
736 | for(t=0;t<of.numpos;t++) { | ||
737 | if(of.positions[t]>=of.numpat) { | ||
738 | of.positions[t]=of.numpat; | ||
739 | dummypat=1; | ||
740 | } | ||
741 | } | ||
742 | if(dummypat) { | ||
743 | of.numpat++;of.numtrk+=of.numchn; | ||
744 | } | ||
745 | |||
746 | if(mh->version<0x0104) { | ||
747 | if(!LoadInstruments()) return 0; | ||
748 | if(!LoadPatterns(dummypat)) return 0; | ||
749 | for(t=0;t<of.numsmp;t++) | ||
750 | nextwav[t]+=_mm_ftell(modreader); | ||
751 | } else { | ||
752 | if(!LoadPatterns(dummypat)) return 0; | ||
753 | if(!LoadInstruments()) return 0; | ||
754 | } | ||
755 | |||
756 | if(!AllocSamples()) { | ||
757 | MikMod_free(nextwav);MikMod_free(wh); | ||
758 | nextwav=NULL;wh=NULL; | ||
759 | return 0; | ||
760 | } | ||
761 | q = of.samples; | ||
762 | s = wh; | ||
763 | for(u=0;u<of.numsmp;u++,q++,s++) { | ||
764 | q->samplename = DupStr(s->samplename,22,1); | ||
765 | q->length = s->length; | ||
766 | q->loopstart = s->loopstart; | ||
767 | q->loopend = s->loopstart+s->looplength; | ||
768 | q->volume = s->volume; | ||
769 | q->speed = s->finetune+128; | ||
770 | q->panning = s->panning; | ||
771 | q->seekpos = nextwav[u]; | ||
772 | q->vibtype = s->vibtype; | ||
773 | q->vibsweep = s->vibsweep; | ||
774 | q->vibdepth = s->vibdepth; | ||
775 | q->vibrate = s->vibrate; | ||
776 | |||
777 | if(s->type & 0x10) { | ||
778 | q->length >>= 1; | ||
779 | q->loopstart >>= 1; | ||
780 | q->loopend >>= 1; | ||
781 | } | ||
782 | |||
783 | q->flags|=SF_OWNPAN|SF_DELTA|SF_SIGNED; | ||
784 | if(s->type&0x3) q->flags|=SF_LOOP; | ||
785 | if(s->type&0x2) q->flags|=SF_BIDI; | ||
786 | if(s->type&0x10) q->flags|=SF_16BITS; | ||
787 | } | ||
788 | |||
789 | d=of.instruments; | ||
790 | s=wh; | ||
791 | for(u=0;u<of.numins;u++,d++) | ||
792 | for(t=0;t<XMNOTECNT;t++) { | ||
793 | if (d->samplenumber[t]>=of.numsmp) | ||
794 | d->samplenote[t]=255; | ||
795 | else { | ||
796 | int note=t+s[d->samplenumber[t]].relnote; | ||
797 | d->samplenote[t]=(note<0)?0:note; | ||
798 | } | ||
799 | } | ||
800 | |||
801 | MikMod_free(wh);MikMod_free(nextwav); | ||
802 | wh=NULL;nextwav=NULL; | ||
803 | return 1; | ||
804 | } | ||
805 | |||
806 | CHAR *XM_LoadTitle(void) | ||
807 | { | ||
808 | CHAR s[21]; | ||
809 | |||
810 | _mm_fseek(modreader,17,SEEK_SET); | ||
811 | if(!_mm_read_UBYTES(s,21,modreader)) return NULL; | ||
812 | |||
813 | return(DupStr(s,21,1)); | ||
814 | } | ||
815 | |||
816 | /*========== Loader information */ | ||
817 | |||
818 | MIKMODAPI MLOADER load_xm={ | ||
819 | NULL, | ||
820 | "XM", | ||
821 | "XM (FastTracker 2)", | ||
822 | XM_Init, | ||
823 | XM_Test, | ||
824 | XM_Load, | ||
825 | XM_Cleanup, | ||
826 | XM_LoadTitle | ||
827 | }; | ||
828 | |||
829 | /* ex:set ts=4: */ | ||
diff --git a/apps/plugins/mikmod/mdreg.c b/apps/plugins/mikmod/mdreg.c new file mode 100644 index 0000000000..8385e15ff5 --- /dev/null +++ b/apps/plugins/mikmod/mdreg.c | |||
@@ -0,0 +1,131 @@ | |||
1 | /* MikMod sound library | ||
2 | (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for | ||
3 | 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: mdreg.c,v 1.2 2005/03/30 19:11:13 realtech Exp $ | ||
24 | |||
25 | Routine for registering all drivers in libmikmod for the current platform. | ||
26 | |||
27 | ==============================================================================*/ | ||
28 | |||
29 | #ifdef HAVE_CONFIG_H | ||
30 | #include "config.h" | ||
31 | #endif | ||
32 | |||
33 | #include "mikmod_internals.h" | ||
34 | |||
35 | void _mm_registeralldrivers(void) | ||
36 | { | ||
37 | #if 0 | ||
38 | |||
39 | /* Register network drivers */ | ||
40 | #ifdef DRV_AF | ||
41 | _mm_registerdriver(&drv_AF); | ||
42 | #endif | ||
43 | #ifdef DRV_ESD | ||
44 | _mm_registerdriver(&drv_esd); | ||
45 | #endif | ||
46 | #ifdef DRV_NAS | ||
47 | _mm_registerdriver(&drv_nas); | ||
48 | #endif | ||
49 | |||
50 | /* Register hardware drivers - hardware mixing */ | ||
51 | #ifdef DRV_ULTRA | ||
52 | _mm_registerdriver(&drv_ultra); | ||
53 | #endif | ||
54 | |||
55 | /* Register hardware drivers - software mixing */ | ||
56 | #ifdef DRV_AIX | ||
57 | _mm_registerdriver(&drv_aix); | ||
58 | #endif | ||
59 | #ifdef DRV_ALSA | ||
60 | _mm_registerdriver(&drv_alsa); | ||
61 | #endif | ||
62 | #ifdef DRV_HP | ||
63 | _mm_registerdriver(&drv_hp); | ||
64 | #endif | ||
65 | #ifdef DRV_OSS | ||
66 | _mm_registerdriver(&drv_oss); | ||
67 | #endif | ||
68 | #ifdef DRV_SGI | ||
69 | _mm_registerdriver(&drv_sgi); | ||
70 | #endif | ||
71 | #ifdef DRV_SUN | ||
72 | _mm_registerdriver(&drv_sun); | ||
73 | #endif | ||
74 | #ifdef DRV_DART | ||
75 | _mm_registerdriver(&drv_dart); | ||
76 | #endif | ||
77 | #ifdef DRV_OS2 | ||
78 | _mm_registerdriver(&drv_os2); | ||
79 | #endif | ||
80 | #ifdef DRV_DS | ||
81 | _mm_registerdriver(&drv_ds); | ||
82 | #endif | ||
83 | #ifdef DRV_WIN | ||
84 | _mm_registerdriver(&drv_win); | ||
85 | #endif | ||
86 | #ifdef DRV_MAC | ||
87 | _mm_registerdriver(&drv_mac); | ||
88 | #endif | ||
89 | #ifdef DRV_OSX | ||
90 | _mm_registerdriver(&drv_osx); | ||
91 | #endif | ||
92 | #ifdef DRV_GP32 | ||
93 | _mm_registerdriver(&drv_gp32); | ||
94 | #endif | ||
95 | |||
96 | /* dos drivers */ | ||
97 | #ifdef DRV_WSS | ||
98 | /* wss first, since some cards emulate sb */ | ||
99 | _mm_registerdriver(&drv_wss); | ||
100 | #endif | ||
101 | #ifdef DRV_SB | ||
102 | _mm_registerdriver(&drv_sb); | ||
103 | #endif | ||
104 | |||
105 | /* Register disk writers */ | ||
106 | _mm_registerdriver(&drv_raw); | ||
107 | _mm_registerdriver(&drv_wav); | ||
108 | #ifdef DRV_AIFF | ||
109 | _mm_registerdriver(&drv_aiff); | ||
110 | #endif | ||
111 | |||
112 | /* Register other drivers */ | ||
113 | #ifdef DRV_PIPE | ||
114 | _mm_registerdriver(&drv_pipe); | ||
115 | #endif | ||
116 | #ifndef macintosh | ||
117 | _mm_registerdriver(&drv_stdout); | ||
118 | #endif | ||
119 | |||
120 | #endif | ||
121 | _mm_registerdriver(&drv_nos); | ||
122 | } | ||
123 | |||
124 | void MikMod_RegisterAllDrivers(void) | ||
125 | { | ||
126 | MUTEX_LOCK(lists); | ||
127 | _mm_registeralldrivers(); | ||
128 | MUTEX_UNLOCK(lists); | ||
129 | } | ||
130 | |||
131 | /* ex:set ts=4: */ | ||
diff --git a/apps/plugins/mikmod/mdriver.c b/apps/plugins/mikmod/mdriver.c new file mode 100644 index 0000000000..e11d32539b --- /dev/null +++ b/apps/plugins/mikmod/mdriver.c | |||
@@ -0,0 +1,965 @@ | |||
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: mdriver.c,v 1.4 2007/12/03 20:59:05 denis111 Exp $ | ||
24 | |||
25 | These routines are used to access the available soundcard drivers. | ||
26 | |||
27 | ==============================================================================*/ | ||
28 | |||
29 | #ifdef HAVE_CONFIG_H | ||
30 | #include "config.h" | ||
31 | #endif | ||
32 | |||
33 | #ifdef HAVE_UNISTD_H | ||
34 | #include <unistd.h> | ||
35 | #endif | ||
36 | |||
37 | #if 0 | ||
38 | #if defined unix || (defined __APPLE__ && defined __MACH__) | ||
39 | #include <pwd.h> | ||
40 | #include <sys/stat.h> | ||
41 | #endif | ||
42 | #endif | ||
43 | |||
44 | #include <string.h> | ||
45 | #ifdef HAVE_STRINGS_H | ||
46 | #include <strings.h> | ||
47 | #endif | ||
48 | |||
49 | #include "mikmod_internals.h" | ||
50 | |||
51 | #ifdef SUNOS | ||
52 | extern int fprintf(FILE *, const char *, ...); | ||
53 | #endif | ||
54 | |||
55 | static MDRIVER *firstdriver=NULL; | ||
56 | MIKMODAPI MDRIVER *md_driver=NULL; | ||
57 | extern MODULE *pf; /* modfile being played */ | ||
58 | |||
59 | /* Initial global settings */ | ||
60 | MIKMODAPI UWORD md_device = 0; /* autodetect */ | ||
61 | MIKMODAPI UWORD md_mixfreq = 44100; | ||
62 | MIKMODAPI UWORD md_mode = DMODE_STEREO | DMODE_16BITS | | ||
63 | DMODE_SURROUND |DMODE_SOFT_MUSIC | | ||
64 | DMODE_SOFT_SNDFX; | ||
65 | MIKMODAPI UBYTE md_pansep = 128; /* 128 == 100% (full left/right) */ | ||
66 | MIKMODAPI UBYTE md_reverb = 0; /* no reverb */ | ||
67 | MIKMODAPI UBYTE md_volume = 128; /* global sound volume (0-128) */ | ||
68 | MIKMODAPI UBYTE md_musicvolume = 128; /* volume of song */ | ||
69 | MIKMODAPI UBYTE md_sndfxvolume = 128; /* volume of sound effects */ | ||
70 | UWORD md_bpm = 125; /* tempo */ | ||
71 | |||
72 | /* Do not modify the numchn variables yourself! use MD_SetVoices() */ | ||
73 | UBYTE md_numchn=0,md_sngchn=0,md_sfxchn=0; | ||
74 | UBYTE md_hardchn=0,md_softchn=0; | ||
75 | |||
76 | void (*md_player)(void) = Player_HandleTick; | ||
77 | static volatile int isplaying=0, initialized = 0; | ||
78 | static UBYTE *sfxinfo; | ||
79 | static int sfxpool; | ||
80 | |||
81 | static SAMPLE **md_sample = NULL; | ||
82 | |||
83 | /* Previous driver in use */ | ||
84 | static SWORD olddevice = -1; | ||
85 | |||
86 | /* Limits the number of hardware voices to the specified amount. | ||
87 | This function should only be used by the low-level drivers. */ | ||
88 | static void LimitHardVoices(int limit) | ||
89 | { | ||
90 | int t=0; | ||
91 | |||
92 | if (!(md_mode & DMODE_SOFT_SNDFX) && (md_sfxchn>limit)) md_sfxchn=limit; | ||
93 | if (!(md_mode & DMODE_SOFT_MUSIC) && (md_sngchn>limit)) md_sngchn=limit; | ||
94 | |||
95 | if (!(md_mode & DMODE_SOFT_SNDFX)) | ||
96 | md_hardchn=md_sfxchn; | ||
97 | else | ||
98 | md_hardchn=0; | ||
99 | |||
100 | if (!(md_mode & DMODE_SOFT_MUSIC)) md_hardchn += md_sngchn; | ||
101 | |||
102 | while (md_hardchn>limit) { | ||
103 | if (++t & 1) { | ||
104 | if (!(md_mode & DMODE_SOFT_SNDFX) && (md_sfxchn>4)) md_sfxchn--; | ||
105 | } else { | ||
106 | if (!(md_mode & DMODE_SOFT_MUSIC) && (md_sngchn>8)) md_sngchn--; | ||
107 | } | ||
108 | |||
109 | if (!(md_mode & DMODE_SOFT_SNDFX)) | ||
110 | md_hardchn=md_sfxchn; | ||
111 | else | ||
112 | md_hardchn=0; | ||
113 | |||
114 | if (!(md_mode & DMODE_SOFT_MUSIC)) | ||
115 | md_hardchn+=md_sngchn; | ||
116 | } | ||
117 | md_numchn=md_hardchn+md_softchn; | ||
118 | } | ||
119 | |||
120 | /* Limits the number of hardware voices to the specified amount. | ||
121 | This function should only be used by the low-level drivers. */ | ||
122 | static void LimitSoftVoices(int limit) | ||
123 | { | ||
124 | int t=0; | ||
125 | |||
126 | if ((md_mode & DMODE_SOFT_SNDFX) && (md_sfxchn>limit)) md_sfxchn=limit; | ||
127 | if ((md_mode & DMODE_SOFT_MUSIC) && (md_sngchn>limit)) md_sngchn=limit; | ||
128 | |||
129 | if (md_mode & DMODE_SOFT_SNDFX) | ||
130 | md_softchn=md_sfxchn; | ||
131 | else | ||
132 | md_softchn=0; | ||
133 | |||
134 | if (md_mode & DMODE_SOFT_MUSIC) md_softchn+=md_sngchn; | ||
135 | |||
136 | while (md_softchn>limit) { | ||
137 | if (++t & 1) { | ||
138 | if ((md_mode & DMODE_SOFT_SNDFX) && (md_sfxchn>4)) md_sfxchn--; | ||
139 | } else { | ||
140 | if ((md_mode & DMODE_SOFT_MUSIC) && (md_sngchn>8)) md_sngchn--; | ||
141 | } | ||
142 | |||
143 | if (!(md_mode & DMODE_SOFT_SNDFX)) | ||
144 | md_softchn=md_sfxchn; | ||
145 | else | ||
146 | md_softchn=0; | ||
147 | |||
148 | if (!(md_mode & DMODE_SOFT_MUSIC)) | ||
149 | md_softchn+=md_sngchn; | ||
150 | } | ||
151 | md_numchn=md_hardchn+md_softchn; | ||
152 | } | ||
153 | |||
154 | /* Note: 'type' indicates whether the returned value should be for music or for | ||
155 | sound effects. */ | ||
156 | ULONG MD_SampleSpace(int type) | ||
157 | { | ||
158 | if(type==MD_MUSIC) | ||
159 | type=(md_mode & DMODE_SOFT_MUSIC)?MD_SOFTWARE:MD_HARDWARE; | ||
160 | else if(type==MD_SNDFX) | ||
161 | type=(md_mode & DMODE_SOFT_SNDFX)?MD_SOFTWARE:MD_HARDWARE; | ||
162 | |||
163 | return md_driver->FreeSampleSpace(type); | ||
164 | } | ||
165 | |||
166 | ULONG MD_SampleLength(int type,SAMPLE* s) | ||
167 | { | ||
168 | if(type==MD_MUSIC) | ||
169 | type=(md_mode & DMODE_SOFT_MUSIC)?MD_SOFTWARE:MD_HARDWARE; | ||
170 | else | ||
171 | if(type==MD_SNDFX) | ||
172 | type=(md_mode & DMODE_SOFT_SNDFX)?MD_SOFTWARE:MD_HARDWARE; | ||
173 | |||
174 | return md_driver->RealSampleLength(type,s); | ||
175 | } | ||
176 | |||
177 | MIKMODAPI CHAR* MikMod_InfoDriver(void) | ||
178 | { | ||
179 | int t; | ||
180 | size_t len=0; | ||
181 | MDRIVER *l; | ||
182 | CHAR *list=NULL; | ||
183 | |||
184 | MUTEX_LOCK(lists); | ||
185 | /* compute size of buffer */ | ||
186 | for(l=firstdriver;l;l=l->next) | ||
187 | len+=4+(l->next?1:0)+strlen(l->Version); | ||
188 | |||
189 | if(len) | ||
190 | if((list=MikMod_malloc(len*sizeof(CHAR)))) { | ||
191 | list[0]=0; | ||
192 | /* list all registered device drivers : */ | ||
193 | for(t=1,l=firstdriver;l;l=l->next,t++) | ||
194 | sprintf(list,(l->next)?"%s%2d %s\n":"%s%2d %s", | ||
195 | list,t,l->Version); | ||
196 | } | ||
197 | MUTEX_UNLOCK(lists); | ||
198 | return list; | ||
199 | } | ||
200 | |||
201 | void _mm_registerdriver(struct MDRIVER* drv) | ||
202 | { | ||
203 | MDRIVER *cruise = firstdriver; | ||
204 | |||
205 | /* don't register a MISSING() driver */ | ||
206 | if ((drv->Name) && (drv->Version)) { | ||
207 | if (cruise) { | ||
208 | if ( cruise == drv ) | ||
209 | return; | ||
210 | while(cruise->next) { | ||
211 | cruise = cruise->next; | ||
212 | if ( cruise == drv ) | ||
213 | return; | ||
214 | } | ||
215 | cruise->next = drv; | ||
216 | } else | ||
217 | firstdriver = drv; | ||
218 | } | ||
219 | } | ||
220 | |||
221 | MIKMODAPI void MikMod_RegisterDriver(struct MDRIVER* drv) | ||
222 | { | ||
223 | /* if we try to register an invalid driver, or an already registered driver, | ||
224 | ignore this attempt */ | ||
225 | if ((!drv)||(drv->next)||(!drv->Name)) | ||
226 | return; | ||
227 | |||
228 | MUTEX_LOCK(lists); | ||
229 | _mm_registerdriver(drv); | ||
230 | MUTEX_UNLOCK(lists); | ||
231 | } | ||
232 | |||
233 | MIKMODAPI int MikMod_DriverFromAlias(CHAR *alias) | ||
234 | { | ||
235 | int rank=1; | ||
236 | MDRIVER *cruise; | ||
237 | |||
238 | MUTEX_LOCK(lists); | ||
239 | cruise=firstdriver; | ||
240 | while(cruise) { | ||
241 | if (cruise->Alias) { | ||
242 | if (!(strcasecmp(alias,cruise->Alias))) break; | ||
243 | rank++; | ||
244 | } | ||
245 | cruise=cruise->next; | ||
246 | } | ||
247 | if(!cruise) rank=0; | ||
248 | MUTEX_UNLOCK(lists); | ||
249 | |||
250 | return rank; | ||
251 | } | ||
252 | |||
253 | MIKMODAPI MDRIVER *MikMod_DriverByOrdinal(int ordinal) | ||
254 | { | ||
255 | MDRIVER *cruise; | ||
256 | |||
257 | /* Allow only driver ordinals > 0 */ | ||
258 | if (!ordinal) | ||
259 | return 0; | ||
260 | |||
261 | MUTEX_LOCK(lists); | ||
262 | cruise = firstdriver; | ||
263 | while (cruise && --ordinal) | ||
264 | cruise = cruise->next; | ||
265 | MUTEX_UNLOCK(lists); | ||
266 | return cruise; | ||
267 | } | ||
268 | |||
269 | SWORD MD_SampleLoad(SAMPLOAD* s, int type) | ||
270 | { | ||
271 | SWORD result; | ||
272 | |||
273 | if(type==MD_MUSIC) | ||
274 | type=(md_mode & DMODE_SOFT_MUSIC)?MD_SOFTWARE:MD_HARDWARE; | ||
275 | else if(type==MD_SNDFX) | ||
276 | type=(md_mode & DMODE_SOFT_SNDFX)?MD_SOFTWARE:MD_HARDWARE; | ||
277 | |||
278 | SL_Init(s); | ||
279 | result=md_driver->SampleLoad(s,type); | ||
280 | SL_Exit(s); | ||
281 | |||
282 | return result; | ||
283 | } | ||
284 | |||
285 | void MD_SampleUnload(SWORD handle) | ||
286 | { | ||
287 | md_driver->SampleUnload(handle); | ||
288 | } | ||
289 | |||
290 | MIKMODAPI MikMod_player_t MikMod_RegisterPlayer(MikMod_player_t player) | ||
291 | { | ||
292 | MikMod_player_t result; | ||
293 | |||
294 | MUTEX_LOCK(vars); | ||
295 | result=md_player; | ||
296 | md_player=player; | ||
297 | MUTEX_UNLOCK(vars); | ||
298 | |||
299 | return result; | ||
300 | } | ||
301 | |||
302 | MIKMODAPI void MikMod_Update(void) | ||
303 | { | ||
304 | MUTEX_LOCK(vars); | ||
305 | if(isplaying) { | ||
306 | if((!pf)||(!pf->forbid)) | ||
307 | md_driver->Update(); | ||
308 | else { | ||
309 | if (md_driver->Pause) | ||
310 | md_driver->Pause(); | ||
311 | } | ||
312 | } | ||
313 | MUTEX_UNLOCK(vars); | ||
314 | } | ||
315 | |||
316 | void Voice_SetVolume_internal(SBYTE voice,UWORD vol) | ||
317 | { | ||
318 | ULONG tmp; | ||
319 | |||
320 | if((voice<0)||(voice>=md_numchn)) return; | ||
321 | |||
322 | /* range checks */ | ||
323 | if(md_musicvolume>128) md_musicvolume=128; | ||
324 | if(md_sndfxvolume>128) md_sndfxvolume=128; | ||
325 | if(md_volume>128) md_volume=128; | ||
326 | |||
327 | tmp=(ULONG)vol*(ULONG)md_volume* | ||
328 | ((voice<md_sngchn)?(ULONG)md_musicvolume:(ULONG)md_sndfxvolume); | ||
329 | md_driver->VoiceSetVolume(voice,tmp/16384UL); | ||
330 | } | ||
331 | |||
332 | MIKMODAPI void Voice_SetVolume(SBYTE voice,UWORD vol) | ||
333 | { | ||
334 | MUTEX_LOCK(vars); | ||
335 | Voice_SetVolume_internal(voice,vol); | ||
336 | MUTEX_UNLOCK(vars); | ||
337 | } | ||
338 | |||
339 | MIKMODAPI UWORD Voice_GetVolume(SBYTE voice) | ||
340 | { | ||
341 | UWORD result=0; | ||
342 | |||
343 | MUTEX_LOCK(vars); | ||
344 | if((voice>=0)&&(voice<md_numchn)) | ||
345 | result=md_driver->VoiceGetVolume(voice); | ||
346 | MUTEX_UNLOCK(vars); | ||
347 | |||
348 | return result; | ||
349 | } | ||
350 | |||
351 | void Voice_SetFrequency_internal(SBYTE voice,ULONG frq) | ||
352 | { | ||
353 | if((voice<0)||(voice>=md_numchn)) return; | ||
354 | if((md_sample[voice])&&(md_sample[voice]->divfactor)) | ||
355 | frq/=md_sample[voice]->divfactor; | ||
356 | md_driver->VoiceSetFrequency(voice,frq); | ||
357 | } | ||
358 | |||
359 | MIKMODAPI void Voice_SetFrequency(SBYTE voice,ULONG frq) | ||
360 | { | ||
361 | MUTEX_LOCK(vars); | ||
362 | Voice_SetFrequency_internal(voice,frq); | ||
363 | MUTEX_UNLOCK(vars); | ||
364 | } | ||
365 | |||
366 | MIKMODAPI ULONG Voice_GetFrequency(SBYTE voice) | ||
367 | { | ||
368 | ULONG result=0; | ||
369 | |||
370 | MUTEX_LOCK(vars); | ||
371 | if((voice>=0)&&(voice<md_numchn)) | ||
372 | result=md_driver->VoiceGetFrequency(voice); | ||
373 | MUTEX_UNLOCK(vars); | ||
374 | |||
375 | return result; | ||
376 | } | ||
377 | |||
378 | void Voice_SetPanning_internal(SBYTE voice,ULONG pan) | ||
379 | { | ||
380 | if((voice<0)||(voice>=md_numchn)) return; | ||
381 | if(pan!=PAN_SURROUND) { | ||
382 | if(md_pansep>128) md_pansep=128; | ||
383 | if(md_mode & DMODE_REVERSE) pan=255-pan; | ||
384 | pan = (((SWORD)(pan-128)*md_pansep)/128)+128; | ||
385 | } | ||
386 | md_driver->VoiceSetPanning(voice, pan); | ||
387 | } | ||
388 | |||
389 | MIKMODAPI void Voice_SetPanning(SBYTE voice,ULONG pan) | ||
390 | { | ||
391 | #ifdef MIKMOD_DEBUG | ||
392 | if((pan!=PAN_SURROUND)&&((pan<0)||(pan>255))) | ||
393 | fprintf(stderr,"\rVoice_SetPanning called with pan=%ld\n",(long)pan); | ||
394 | #endif | ||
395 | |||
396 | MUTEX_LOCK(vars); | ||
397 | Voice_SetPanning_internal(voice,pan); | ||
398 | MUTEX_UNLOCK(vars); | ||
399 | } | ||
400 | |||
401 | MIKMODAPI ULONG Voice_GetPanning(SBYTE voice) | ||
402 | { | ||
403 | ULONG result=PAN_CENTER; | ||
404 | |||
405 | MUTEX_LOCK(vars); | ||
406 | if((voice>=0)&&(voice<md_numchn)) | ||
407 | result=md_driver->VoiceGetPanning(voice); | ||
408 | MUTEX_UNLOCK(vars); | ||
409 | |||
410 | return result; | ||
411 | } | ||
412 | |||
413 | void Voice_Play_internal(SBYTE voice,SAMPLE* s,ULONG start) | ||
414 | { | ||
415 | ULONG repend; | ||
416 | |||
417 | if((voice<0)||(voice>=md_numchn)) return; | ||
418 | |||
419 | md_sample[voice]=s; | ||
420 | repend=s->loopend; | ||
421 | |||
422 | if(s->flags&SF_LOOP) | ||
423 | /* repend can't be bigger than size */ | ||
424 | if(repend>s->length) repend=s->length; | ||
425 | |||
426 | md_driver->VoicePlay(voice,s->handle,start,s->length,s->loopstart,repend,s->flags); | ||
427 | } | ||
428 | |||
429 | MIKMODAPI void Voice_Play(SBYTE voice,SAMPLE* s,ULONG start) | ||
430 | { | ||
431 | if(start>s->length) return; | ||
432 | |||
433 | MUTEX_LOCK(vars); | ||
434 | Voice_Play_internal(voice,s,start); | ||
435 | MUTEX_UNLOCK(vars); | ||
436 | } | ||
437 | |||
438 | void Voice_Stop_internal(SBYTE voice) | ||
439 | { | ||
440 | if((voice<0)||(voice>=md_numchn)) return; | ||
441 | if(voice>=md_sngchn) | ||
442 | /* It is a sound effects channel, so flag the voice as non-critical! */ | ||
443 | sfxinfo[voice-md_sngchn]=0; | ||
444 | md_driver->VoiceStop(voice); | ||
445 | } | ||
446 | |||
447 | MIKMODAPI void Voice_Stop(SBYTE voice) | ||
448 | { | ||
449 | MUTEX_LOCK(vars); | ||
450 | Voice_Stop_internal(voice); | ||
451 | MUTEX_UNLOCK(vars); | ||
452 | } | ||
453 | |||
454 | int Voice_Stopped_internal(SBYTE voice) | ||
455 | { | ||
456 | if((voice<0)||(voice>=md_numchn)) return 0; | ||
457 | return(md_driver->VoiceStopped(voice)); | ||
458 | } | ||
459 | |||
460 | MIKMODAPI int Voice_Stopped(SBYTE voice) | ||
461 | { | ||
462 | int result; | ||
463 | |||
464 | MUTEX_LOCK(vars); | ||
465 | result=Voice_Stopped_internal(voice); | ||
466 | MUTEX_UNLOCK(vars); | ||
467 | |||
468 | return result; | ||
469 | } | ||
470 | |||
471 | MIKMODAPI SLONG Voice_GetPosition(SBYTE voice) | ||
472 | { | ||
473 | SLONG result=0; | ||
474 | |||
475 | MUTEX_LOCK(vars); | ||
476 | if((voice>=0)&&(voice<md_numchn)) { | ||
477 | if (md_driver->VoiceGetPosition) | ||
478 | result=(md_driver->VoiceGetPosition(voice)); | ||
479 | else | ||
480 | result=-1; | ||
481 | } | ||
482 | MUTEX_UNLOCK(vars); | ||
483 | |||
484 | return result; | ||
485 | } | ||
486 | |||
487 | MIKMODAPI ULONG Voice_RealVolume(SBYTE voice) | ||
488 | { | ||
489 | ULONG result=0; | ||
490 | |||
491 | MUTEX_LOCK(vars); | ||
492 | if((voice>=0)&&(voice<md_numchn)&& md_driver->VoiceRealVolume) | ||
493 | result=(md_driver->VoiceRealVolume(voice)); | ||
494 | MUTEX_UNLOCK(vars); | ||
495 | |||
496 | return result; | ||
497 | } | ||
498 | |||
499 | extern MikMod_callback_t vc_callback; | ||
500 | |||
501 | MIKMODAPI void VC_SetCallback(MikMod_callback_t callback) | ||
502 | { | ||
503 | vc_callback = callback; | ||
504 | } | ||
505 | |||
506 | static int _mm_init(CHAR *cmdline) | ||
507 | { | ||
508 | UWORD t; | ||
509 | |||
510 | _mm_critical = 1; | ||
511 | |||
512 | /* if md_device==0, try to find a device number */ | ||
513 | if(!md_device) { | ||
514 | cmdline=NULL; | ||
515 | |||
516 | for(t=1,md_driver=firstdriver;md_driver;md_driver=md_driver->next,t++) | ||
517 | if(md_driver->IsPresent()) break; | ||
518 | |||
519 | if(!md_driver) { | ||
520 | _mm_errno = MMERR_DETECTING_DEVICE; | ||
521 | if(_mm_errorhandler) _mm_errorhandler(); | ||
522 | md_driver = &drv_nos; | ||
523 | return 1; | ||
524 | } | ||
525 | |||
526 | md_device = t; | ||
527 | } else { | ||
528 | /* if n>0, use that driver */ | ||
529 | for(t=1,md_driver=firstdriver;(md_driver)&&(t!=md_device);md_driver=md_driver->next) | ||
530 | t++; | ||
531 | |||
532 | if(!md_driver) { | ||
533 | _mm_errno = MMERR_INVALID_DEVICE; | ||
534 | if(_mm_errorhandler) _mm_errorhandler(); | ||
535 | md_driver = &drv_nos; | ||
536 | return 1; | ||
537 | } | ||
538 | |||
539 | /* arguments here might be necessary for the presence check to succeed */ | ||
540 | if(cmdline&&(md_driver->CommandLine)) | ||
541 | md_driver->CommandLine(cmdline); | ||
542 | |||
543 | if(!md_driver->IsPresent()) { | ||
544 | _mm_errno = MMERR_DETECTING_DEVICE; | ||
545 | if(_mm_errorhandler) _mm_errorhandler(); | ||
546 | md_driver = &drv_nos; | ||
547 | return 1; | ||
548 | } | ||
549 | } | ||
550 | |||
551 | olddevice = md_device; | ||
552 | if(md_driver->Init()) { | ||
553 | MikMod_Exit_internal(); | ||
554 | if(_mm_errorhandler) _mm_errorhandler(); | ||
555 | return 1; | ||
556 | } | ||
557 | |||
558 | initialized=1; | ||
559 | _mm_critical=0; | ||
560 | |||
561 | return 0; | ||
562 | } | ||
563 | |||
564 | MIKMODAPI int MikMod_Init(CHAR *cmdline) | ||
565 | { | ||
566 | int result; | ||
567 | |||
568 | MUTEX_LOCK(vars); | ||
569 | MUTEX_LOCK(lists); | ||
570 | result=_mm_init(cmdline); | ||
571 | MUTEX_UNLOCK(lists); | ||
572 | MUTEX_UNLOCK(vars); | ||
573 | |||
574 | return result; | ||
575 | } | ||
576 | |||
577 | void MikMod_Exit_internal(void) | ||
578 | { | ||
579 | MikMod_DisableOutput_internal(); | ||
580 | md_driver->Exit(); | ||
581 | md_numchn = md_sfxchn = md_sngchn = 0; | ||
582 | md_driver = &drv_nos; | ||
583 | |||
584 | if(sfxinfo) MikMod_free(sfxinfo); | ||
585 | if(md_sample) MikMod_free(md_sample); | ||
586 | md_sample = NULL; | ||
587 | sfxinfo = NULL; | ||
588 | |||
589 | initialized = 0; | ||
590 | } | ||
591 | |||
592 | MIKMODAPI void MikMod_Exit(void) | ||
593 | { | ||
594 | MUTEX_LOCK(vars); | ||
595 | MUTEX_LOCK(lists); | ||
596 | MikMod_Exit_internal(); | ||
597 | MUTEX_UNLOCK(lists); | ||
598 | MUTEX_UNLOCK(vars); | ||
599 | } | ||
600 | |||
601 | /* Reset the driver using the new global variable settings. | ||
602 | If the driver has not been initialized, it will be now. */ | ||
603 | static int _mm_reset(CHAR *cmdline) | ||
604 | { | ||
605 | int wasplaying = 0; | ||
606 | |||
607 | if(!initialized) return _mm_init(cmdline); | ||
608 | |||
609 | if (isplaying) { | ||
610 | wasplaying = 1; | ||
611 | md_driver->PlayStop(); | ||
612 | } | ||
613 | |||
614 | if((!md_driver->Reset)||(md_device != olddevice)) { | ||
615 | /* md_driver->Reset was NULL, or md_device was changed, so do a full | ||
616 | reset of the driver. */ | ||
617 | md_driver->Exit(); | ||
618 | if(_mm_init(cmdline)) { | ||
619 | MikMod_Exit_internal(); | ||
620 | if(_mm_errno) | ||
621 | if(_mm_errorhandler) _mm_errorhandler(); | ||
622 | return 1; | ||
623 | } | ||
624 | } else { | ||
625 | if(md_driver->Reset()) { | ||
626 | MikMod_Exit_internal(); | ||
627 | if(_mm_errno) | ||
628 | if(_mm_errorhandler) _mm_errorhandler(); | ||
629 | return 1; | ||
630 | } | ||
631 | } | ||
632 | |||
633 | if (wasplaying) md_driver->PlayStart(); | ||
634 | return 0; | ||
635 | } | ||
636 | |||
637 | MIKMODAPI int MikMod_Reset(CHAR *cmdline) | ||
638 | { | ||
639 | int result; | ||
640 | |||
641 | MUTEX_LOCK(vars); | ||
642 | MUTEX_LOCK(lists); | ||
643 | result=_mm_reset(cmdline); | ||
644 | MUTEX_UNLOCK(lists); | ||
645 | MUTEX_UNLOCK(vars); | ||
646 | |||
647 | return result; | ||
648 | } | ||
649 | |||
650 | /* If either parameter is -1, the current set value will be retained. */ | ||
651 | int MikMod_SetNumVoices_internal(int music, int sfx) | ||
652 | { | ||
653 | int resume = 0; | ||
654 | int t, oldchn = 0; | ||
655 | |||
656 | if((!music)&&(!sfx)) return 1; | ||
657 | _mm_critical = 1; | ||
658 | if(isplaying) { | ||
659 | MikMod_DisableOutput_internal(); | ||
660 | oldchn = md_numchn; | ||
661 | resume = 1; | ||
662 | } | ||
663 | |||
664 | if(sfxinfo) MikMod_free(sfxinfo); | ||
665 | if(md_sample) MikMod_free(md_sample); | ||
666 | md_sample = NULL; | ||
667 | sfxinfo = NULL; | ||
668 | |||
669 | if(music!=-1) md_sngchn = music; | ||
670 | if(sfx!=-1) md_sfxchn = sfx; | ||
671 | md_numchn = md_sngchn + md_sfxchn; | ||
672 | |||
673 | LimitHardVoices(md_driver->HardVoiceLimit); | ||
674 | LimitSoftVoices(md_driver->SoftVoiceLimit); | ||
675 | |||
676 | if(md_driver->SetNumVoices()) { | ||
677 | MikMod_Exit_internal(); | ||
678 | if(_mm_errno) | ||
679 | if(_mm_errorhandler!=NULL) _mm_errorhandler(); | ||
680 | md_numchn = md_softchn = md_hardchn = md_sfxchn = md_sngchn = 0; | ||
681 | return 1; | ||
682 | } | ||
683 | |||
684 | if(md_sngchn+md_sfxchn) | ||
685 | md_sample=(SAMPLE**)MikMod_calloc(md_sngchn+md_sfxchn,sizeof(SAMPLE*)); | ||
686 | if(md_sfxchn) | ||
687 | sfxinfo = (UBYTE *)MikMod_calloc(md_sfxchn,sizeof(UBYTE)); | ||
688 | |||
689 | /* make sure the player doesn't start with garbage */ | ||
690 | for(t=oldchn;t<md_numchn;t++) Voice_Stop_internal(t); | ||
691 | |||
692 | sfxpool = 0; | ||
693 | if(resume) MikMod_EnableOutput_internal(); | ||
694 | _mm_critical = 0; | ||
695 | |||
696 | return 0; | ||
697 | } | ||
698 | |||
699 | MIKMODAPI int MikMod_SetNumVoices(int music, int sfx) | ||
700 | { | ||
701 | int result; | ||
702 | |||
703 | MUTEX_LOCK(vars); | ||
704 | result=MikMod_SetNumVoices_internal(music,sfx); | ||
705 | MUTEX_UNLOCK(vars); | ||
706 | |||
707 | return result; | ||
708 | } | ||
709 | |||
710 | int MikMod_EnableOutput_internal(void) | ||
711 | { | ||
712 | _mm_critical = 1; | ||
713 | if(!isplaying) { | ||
714 | if(md_driver->PlayStart()) return 1; | ||
715 | isplaying = 1; | ||
716 | } | ||
717 | _mm_critical = 0; | ||
718 | return 0; | ||
719 | } | ||
720 | |||
721 | MIKMODAPI int MikMod_EnableOutput(void) | ||
722 | { | ||
723 | int result; | ||
724 | |||
725 | MUTEX_LOCK(vars); | ||
726 | result=MikMod_EnableOutput_internal(); | ||
727 | MUTEX_UNLOCK(vars); | ||
728 | |||
729 | return result; | ||
730 | } | ||
731 | |||
732 | void MikMod_DisableOutput_internal(void) | ||
733 | { | ||
734 | if(isplaying && md_driver) { | ||
735 | isplaying = 0; | ||
736 | md_driver->PlayStop(); | ||
737 | } | ||
738 | } | ||
739 | |||
740 | MIKMODAPI void MikMod_DisableOutput(void) | ||
741 | { | ||
742 | MUTEX_LOCK(vars); | ||
743 | MikMod_DisableOutput_internal(); | ||
744 | MUTEX_UNLOCK(vars); | ||
745 | } | ||
746 | |||
747 | int MikMod_Active_internal(void) | ||
748 | { | ||
749 | return isplaying; | ||
750 | } | ||
751 | |||
752 | MIKMODAPI int MikMod_Active(void) | ||
753 | { | ||
754 | int result; | ||
755 | |||
756 | MUTEX_LOCK(vars); | ||
757 | result=MikMod_Active_internal(); | ||
758 | MUTEX_UNLOCK(vars); | ||
759 | |||
760 | return result; | ||
761 | } | ||
762 | |||
763 | /* Plays a sound effects sample. Picks a voice from the number of voices | ||
764 | allocated for use as sound effects (loops through voices, skipping all active | ||
765 | criticals). | ||
766 | |||
767 | Returns the voice that the sound is being played on. */ | ||
768 | SBYTE Sample_Play_internal(SAMPLE *s,ULONG start,UBYTE flags) | ||
769 | { | ||
770 | int orig=sfxpool;/* for cases where all channels are critical */ | ||
771 | int c; | ||
772 | |||
773 | if(!md_sfxchn) return -1; | ||
774 | if(s->volume>64) s->volume = 64; | ||
775 | |||
776 | /* check the first location after sfxpool */ | ||
777 | do { | ||
778 | if(sfxinfo[sfxpool]&SFX_CRITICAL) { | ||
779 | if(md_driver->VoiceStopped(c=sfxpool+md_sngchn)) { | ||
780 | sfxinfo[sfxpool]=flags; | ||
781 | Voice_Play_internal(c,s,start); | ||
782 | md_driver->VoiceSetVolume(c,s->volume<<2); | ||
783 | Voice_SetPanning_internal(c,s->panning); | ||
784 | md_driver->VoiceSetFrequency(c,s->speed); | ||
785 | sfxpool++; | ||
786 | if(sfxpool>=md_sfxchn) sfxpool=0; | ||
787 | return c; | ||
788 | } | ||
789 | } else { | ||
790 | sfxinfo[sfxpool]=flags; | ||
791 | Voice_Play_internal(c=sfxpool+md_sngchn,s,start); | ||
792 | md_driver->VoiceSetVolume(c,s->volume<<2); | ||
793 | Voice_SetPanning_internal(c,s->panning); | ||
794 | md_driver->VoiceSetFrequency(c,s->speed); | ||
795 | sfxpool++; | ||
796 | if(sfxpool>=md_sfxchn) sfxpool=0; | ||
797 | return c; | ||
798 | } | ||
799 | |||
800 | sfxpool++; | ||
801 | if(sfxpool>=md_sfxchn) sfxpool = 0; | ||
802 | } while(sfxpool!=orig); | ||
803 | |||
804 | return -1; | ||
805 | } | ||
806 | |||
807 | MIKMODAPI SBYTE Sample_Play(SAMPLE *s,ULONG start,UBYTE flags) | ||
808 | { | ||
809 | SBYTE result; | ||
810 | |||
811 | MUTEX_LOCK(vars); | ||
812 | result=Sample_Play_internal(s,start,flags); | ||
813 | MUTEX_UNLOCK(vars); | ||
814 | |||
815 | return result; | ||
816 | } | ||
817 | |||
818 | MIKMODAPI long MikMod_GetVersion(void) | ||
819 | { | ||
820 | return LIBMIKMOD_VERSION; | ||
821 | } | ||
822 | |||
823 | /*========== MT-safe stuff */ | ||
824 | |||
825 | #ifdef HAVE_PTHREAD | ||
826 | #define INIT_MUTEX(name) \ | ||
827 | pthread_mutex_t _mm_mutex_##name=PTHREAD_MUTEX_INITIALIZER | ||
828 | #elif defined(__OS2__)||defined(__EMX__) | ||
829 | #define INIT_MUTEX(name) \ | ||
830 | HMTX _mm_mutex_##name | ||
831 | #elif defined(WIN32) | ||
832 | #define INIT_MUTEX(name) \ | ||
833 | HANDLE _mm_mutex_##name | ||
834 | #else | ||
835 | #define INIT_MUTEX(name) \ | ||
836 | void *_mm_mutex_##name = NULL | ||
837 | #endif | ||
838 | |||
839 | INIT_MUTEX(vars); | ||
840 | INIT_MUTEX(lists); | ||
841 | |||
842 | MIKMODAPI int MikMod_InitThreads(void) | ||
843 | { | ||
844 | static int firstcall=1; | ||
845 | static int result=0; | ||
846 | |||
847 | if (firstcall) { | ||
848 | firstcall=0; | ||
849 | #ifdef HAVE_PTHREAD | ||
850 | result=1; | ||
851 | #elif defined(__OS2__)||defined(__EMX__) | ||
852 | if(DosCreateMutexSem((PSZ)NULL,&_mm_mutex_lists,0,0) || | ||
853 | DosCreateMutexSem((PSZ)NULL,&_mm_mutex_vars,0,0)) { | ||
854 | _mm_mutex_lists=_mm_mutex_vars=(HMTX)NULL; | ||
855 | result=0; | ||
856 | } else | ||
857 | result=1; | ||
858 | #elif defined(WIN32) | ||
859 | if((!(_mm_mutex_lists=CreateMutex(NULL,FALSE,"libmikmod(lists)")))|| | ||
860 | (!(_mm_mutex_vars=CreateMutex(NULL,FALSE,"libmikmod(vars)")))) | ||
861 | result=0; | ||
862 | else | ||
863 | result=1; | ||
864 | #endif | ||
865 | } | ||
866 | return result; | ||
867 | } | ||
868 | |||
869 | MIKMODAPI void MikMod_Unlock(void) | ||
870 | { | ||
871 | MUTEX_UNLOCK(lists); | ||
872 | MUTEX_UNLOCK(vars); | ||
873 | } | ||
874 | |||
875 | MIKMODAPI void MikMod_Lock(void) | ||
876 | { | ||
877 | MUTEX_LOCK(vars); | ||
878 | MUTEX_LOCK(lists); | ||
879 | } | ||
880 | |||
881 | /*========== Parameter extraction helper */ | ||
882 | |||
883 | CHAR *MD_GetAtom(CHAR *atomname,CHAR *cmdline,int implicit) | ||
884 | { | ||
885 | CHAR *ret=NULL; | ||
886 | |||
887 | if(cmdline) { | ||
888 | CHAR *buf=strstr(cmdline,atomname); | ||
889 | |||
890 | if((buf)&&((buf==cmdline)||(*(buf-1)==','))) { | ||
891 | CHAR *ptr=buf+strlen(atomname); | ||
892 | |||
893 | if(*ptr=='=') { | ||
894 | for(buf=++ptr;(*ptr)&&((*ptr)!=',');ptr++); | ||
895 | ret=MikMod_malloc((1+ptr-buf)*sizeof(CHAR)); | ||
896 | if(ret) | ||
897 | strncpy(ret,buf,ptr-buf); | ||
898 | } else if((*ptr==',')||(!*ptr)) { | ||
899 | if(implicit) { | ||
900 | ret=MikMod_malloc((1+ptr-buf)*sizeof(CHAR)); | ||
901 | if(ret) | ||
902 | strncpy(ret,buf,ptr-buf); | ||
903 | } | ||
904 | } | ||
905 | } | ||
906 | } | ||
907 | return ret; | ||
908 | } | ||
909 | |||
910 | #if 0 | ||
911 | #if defined unix || (defined __APPLE__ && defined __MACH__) | ||
912 | |||
913 | /*========== Posix helper functions */ | ||
914 | |||
915 | /* Check if the file is a regular or nonexistant file (or a link to a such a | ||
916 | file), and that, should the calling program be setuid, the access rights are | ||
917 | reasonable. Returns 1 if it is safe to rewrite the file, 0 otherwise. | ||
918 | The goal is to prevent a setuid root libmikmod application from overriding | ||
919 | files like /etc/passwd with digital sound... */ | ||
920 | int MD_Access(CHAR *filename) | ||
921 | { | ||
922 | struct stat buf; | ||
923 | |||
924 | if(!stat(filename,&buf)) { | ||
925 | /* not a regular file ? */ | ||
926 | if(!S_ISREG(buf.st_mode)) return 0; | ||
927 | /* more than one hard link to the file ? */ | ||
928 | if(buf.st_nlink>1) return 0; | ||
929 | /* check access rights with the real user and group id */ | ||
930 | if(getuid()==buf.st_uid) { | ||
931 | if(!(buf.st_mode&S_IWUSR)) return 0; | ||
932 | } else if(getgid()==buf.st_gid) { | ||
933 | if(!(buf.st_mode&S_IWGRP)) return 0; | ||
934 | } else | ||
935 | if(!(buf.st_mode&S_IWOTH)) return 0; | ||
936 | } | ||
937 | |||
938 | return 1; | ||
939 | } | ||
940 | |||
941 | /* Drop all root privileges we might have */ | ||
942 | int MD_DropPrivileges(void) | ||
943 | { | ||
944 | if(!geteuid()) { | ||
945 | if(getuid()) { | ||
946 | /* we are setuid root -> drop setuid to become the real user */ | ||
947 | if(setuid(getuid())) return 1; | ||
948 | } else { | ||
949 | /* we are run as root -> drop all and become user 'nobody' */ | ||
950 | struct passwd *nobody; | ||
951 | int uid; | ||
952 | |||
953 | if(!(nobody=getpwnam("nobody"))) return 1; /* no such user ? */ | ||
954 | uid=nobody->pw_uid; | ||
955 | if (!uid) /* user 'nobody' has root privileges ? weird... */ | ||
956 | return 1; | ||
957 | if (setuid(uid)) return 1; | ||
958 | } | ||
959 | } | ||
960 | return 0; | ||
961 | } | ||
962 | |||
963 | #endif | ||
964 | #endif | ||
965 | /* ex:set ts=4: */ | ||
diff --git a/apps/plugins/mikmod/mikmod.c b/apps/plugins/mikmod/mikmod.c new file mode 100644 index 0000000000..fe1768376e --- /dev/null +++ b/apps/plugins/mikmod/mikmod.c | |||
@@ -0,0 +1,943 @@ | |||
1 | #define NO_MMSUPP_DEFINES | ||
2 | |||
3 | #include "plugin.h" | ||
4 | #include "lib/configfile.h" | ||
5 | #include "mikmod.h" | ||
6 | |||
7 | |||
8 | #undef SYNC | ||
9 | #ifdef SIMULATOR | ||
10 | #define SYNC | ||
11 | #elif NUM_CORES > 1 | ||
12 | #define USETHREADS | ||
13 | #endif | ||
14 | |||
15 | #define MAX_CHARS LCD_WIDTH/6 | ||
16 | #define MAX_LINES LCD_HEIGHT/8 | ||
17 | #define LINE_LENGTH 80 | ||
18 | |||
19 | #define DIR_PREV 1 | ||
20 | #define DIR_NEXT -1 | ||
21 | #define DIR_NONE 0 | ||
22 | |||
23 | #define PLUGIN_NEWSONG 10 | ||
24 | |||
25 | /* Persistent configuration */ | ||
26 | #define MIKMOD_CONFIGFILE "mikmod.cfg" | ||
27 | #define MIKMOD_SETTINGS_MINVERSION 1 | ||
28 | #define MIKMOD_SETTINGS_VERSION 1 | ||
29 | |||
30 | #ifdef USETHREADS | ||
31 | #define EV_EXIT 9999 | ||
32 | #define THREAD_STACK_SIZE DEFAULT_STACK_SIZE + 0x200 | ||
33 | static unsigned int thread_id; | ||
34 | static struct event_queue thread_q; | ||
35 | /* use long for aligning */ | ||
36 | unsigned long thread_stack[THREAD_STACK_SIZE/sizeof(long)]; | ||
37 | #endif | ||
38 | |||
39 | /* the current full file name */ | ||
40 | static char np_file[MAX_PATH]; | ||
41 | static int curfile = 0, direction = DIR_NEXT, entries = 0; | ||
42 | |||
43 | /* list of the mod files */ | ||
44 | static char **file_pt; | ||
45 | |||
46 | |||
47 | /* The MP3 audio buffer which we will use as heap memory */ | ||
48 | static unsigned char* audio_buffer; | ||
49 | /* amount of bytes left in audio_buffer */ | ||
50 | static size_t audio_buffer_free; | ||
51 | |||
52 | |||
53 | /* The rockbox plugin interface */ | ||
54 | MEM_FUNCTION_WRAPPERS; | ||
55 | |||
56 | bool quit; | ||
57 | int playingtime IBSS_ATTR; | ||
58 | MODULE *module IBSS_ATTR; | ||
59 | char gmbuf[BUF_SIZE*NBUF]; | ||
60 | |||
61 | |||
62 | int textlines; | ||
63 | int vscroll = 0; | ||
64 | int hscroll = 0; | ||
65 | bool screenupdated = false; | ||
66 | |||
67 | enum { | ||
68 | DISPLAY_INFO = 0, | ||
69 | DISPLAY_SAMPLE, | ||
70 | DISPLAY_INST, | ||
71 | DISPLAY_COMMENTS, | ||
72 | } display; | ||
73 | |||
74 | |||
75 | /* | ||
76 | * strncat wrapper | ||
77 | */ | ||
78 | char* mmsupp_strncat(char *s1, const char *s2, size_t n) | ||
79 | { | ||
80 | char *s = s1; | ||
81 | /* Loop over the data in s1. */ | ||
82 | while (*s != '\0') | ||
83 | s++; | ||
84 | /* s now points to s1's trailing null character, now copy | ||
85 | up to n bytes from s2 into s1 stopping if a null character | ||
86 | is encountered in s2. | ||
87 | It is not safe to use strncpy here since it copies EXACTLY n | ||
88 | characters, NULL padding if necessary. */ | ||
89 | while (n != 0 && (*s = *s2++) != '\0') | ||
90 | { | ||
91 | n--; | ||
92 | s++; | ||
93 | } | ||
94 | if (*s != '\0') | ||
95 | *s = '\0'; | ||
96 | return s1; | ||
97 | } | ||
98 | |||
99 | /* | ||
100 | * sprintf wrapper | ||
101 | */ | ||
102 | int mmsupp_sprintf(char *buf, const char *fmt, ... ) | ||
103 | { | ||
104 | bool ok; | ||
105 | va_list ap; | ||
106 | |||
107 | va_start(ap, fmt); | ||
108 | ok = rb->vsnprintf(buf, LINE_LENGTH, fmt, ap); | ||
109 | va_end(ap); | ||
110 | |||
111 | return ok; | ||
112 | } | ||
113 | |||
114 | /* | ||
115 | * printf wrapper | ||
116 | */ | ||
117 | void mmsupp_printf(const char *fmt, ...) | ||
118 | { | ||
119 | static int p_xtpt = 0; | ||
120 | char p_buf[LINE_LENGTH]; | ||
121 | bool ok; | ||
122 | va_list ap; | ||
123 | |||
124 | va_start(ap, fmt); | ||
125 | ok = rb->vsnprintf(p_buf, sizeof(p_buf), fmt, ap); | ||
126 | va_end(ap); | ||
127 | |||
128 | int i=0; | ||
129 | |||
130 | /* Device LCDs display newlines funny. */ | ||
131 | for(i=0; p_buf[i]!=0; i++) | ||
132 | if(p_buf[i] == '\n') | ||
133 | p_buf[i] = ' '; | ||
134 | |||
135 | rb->lcd_putsxy(1, p_xtpt, (unsigned char *)p_buf); | ||
136 | rb->lcd_update(); | ||
137 | |||
138 | p_xtpt += 8; | ||
139 | if(p_xtpt > LCD_HEIGHT-8) | ||
140 | { | ||
141 | p_xtpt = 0; | ||
142 | rb->lcd_clear_display(); | ||
143 | } | ||
144 | } | ||
145 | |||
146 | |||
147 | /************************* File Access ***************************/ | ||
148 | |||
149 | /* support function for qsort() */ | ||
150 | static int compare(const void* p1, const void* p2) | ||
151 | { | ||
152 | return rb->strcasecmp(*((char **)p1), *((char **)p2)); | ||
153 | } | ||
154 | |||
155 | bool mod_ext(const char ext[]) | ||
156 | { | ||
157 | if(!ext) | ||
158 | return false; | ||
159 | if(!rb->strcasecmp(ext,".669") || | ||
160 | !rb->strcasecmp(ext,".amf") || | ||
161 | !rb->strcasecmp(ext,".asy") || | ||
162 | !rb->strcasecmp(ext,".dsm") || | ||
163 | !rb->strcasecmp(ext,".far") || | ||
164 | !rb->strcasecmp(ext,".gdm") || | ||
165 | !rb->strcasecmp(ext,".gt2") || | ||
166 | !rb->strcasecmp(ext,".imf") || | ||
167 | !rb->strcasecmp(ext,".it") || | ||
168 | !rb->strcasecmp(ext,".m15") || | ||
169 | !rb->strcasecmp(ext,".med") || | ||
170 | !rb->strcasecmp(ext,".mod") || | ||
171 | !rb->strcasecmp(ext,".mtm") || | ||
172 | !rb->strcasecmp(ext,".okt") || | ||
173 | !rb->strcasecmp(ext,".s3m") || | ||
174 | !rb->strcasecmp(ext,".stm") || | ||
175 | !rb->strcasecmp(ext,".stx") || | ||
176 | !rb->strcasecmp(ext,".ult") || | ||
177 | !rb->strcasecmp(ext,".uni") || | ||
178 | !rb->strcasecmp(ext,".xm") ) | ||
179 | return true; | ||
180 | else | ||
181 | return false; | ||
182 | } | ||
183 | |||
184 | /*Read directory contents for scrolling. */ | ||
185 | void get_mod_list(void) | ||
186 | { | ||
187 | struct tree_context *tree = rb->tree_get_context(); | ||
188 | struct entry *dircache = tree->dircache; | ||
189 | int i; | ||
190 | char *pname; | ||
191 | |||
192 | file_pt = (char **) audio_buffer; | ||
193 | |||
194 | /* Remove path and leave only the name.*/ | ||
195 | pname = rb->strrchr(np_file,'/'); | ||
196 | pname++; | ||
197 | |||
198 | for (i = 0; i < tree->filesindir && audio_buffer_free > sizeof(char**); i++) | ||
199 | { | ||
200 | if (!(dircache[i].attr & ATTR_DIRECTORY) | ||
201 | && mod_ext(rb->strrchr(dircache[i].name,'.'))) | ||
202 | { | ||
203 | file_pt[entries] = dircache[i].name; | ||
204 | /* Set Selected File. */ | ||
205 | if (!rb->strcmp(file_pt[entries], pname)) | ||
206 | curfile = entries; | ||
207 | entries++; | ||
208 | |||
209 | audio_buffer += (sizeof(char**)); | ||
210 | audio_buffer_free -= (sizeof(char**)); | ||
211 | } | ||
212 | } | ||
213 | } | ||
214 | |||
215 | int change_filename(int direct) | ||
216 | { | ||
217 | bool file_erased = (file_pt[curfile] == NULL); | ||
218 | direction = direct; | ||
219 | |||
220 | curfile += (direct == DIR_PREV? entries - 1: 1); | ||
221 | if (curfile >= entries) | ||
222 | curfile -= entries; | ||
223 | |||
224 | if (file_erased) | ||
225 | { | ||
226 | /* remove 'erased' file names from list. */ | ||
227 | int count, i; | ||
228 | for (count = i = 0; i < entries; i++) | ||
229 | { | ||
230 | if (curfile == i) | ||
231 | curfile = count; | ||
232 | if (file_pt[i] != NULL) | ||
233 | file_pt[count++] = file_pt[i]; | ||
234 | } | ||
235 | entries = count; | ||
236 | } | ||
237 | |||
238 | if (entries == 0) | ||
239 | { | ||
240 | rb->splash(HZ, "No supported files"); | ||
241 | return PLUGIN_ERROR; | ||
242 | } | ||
243 | |||
244 | rb->strcpy(rb->strrchr(np_file, '/')+1, file_pt[curfile]); | ||
245 | |||
246 | return PLUGIN_NEWSONG; | ||
247 | } | ||
248 | |||
249 | /***************************************************************************** | ||
250 | * Playback | ||
251 | */ | ||
252 | |||
253 | bool swap = false; | ||
254 | bool lastswap = true; | ||
255 | |||
256 | static inline void synthbuf(void) | ||
257 | { | ||
258 | char *outptr; | ||
259 | |||
260 | #ifndef SYNC | ||
261 | if (lastswap == swap) return; | ||
262 | lastswap = swap; | ||
263 | |||
264 | outptr = (swap ? gmbuf : gmbuf + BUF_SIZE); | ||
265 | #else | ||
266 | outptr = gmbuf; | ||
267 | #endif | ||
268 | |||
269 | VC_WriteBytes(outptr, BUF_SIZE); | ||
270 | } | ||
271 | |||
272 | void get_more(unsigned char** start, size_t* size) | ||
273 | { | ||
274 | #ifndef SYNC | ||
275 | if (lastswap != swap) | ||
276 | { | ||
277 | //printf("Buffer miss!"); | ||
278 | } | ||
279 | |||
280 | #else | ||
281 | synthbuf(); | ||
282 | #endif | ||
283 | |||
284 | *size = BUF_SIZE; | ||
285 | #ifndef SYNC | ||
286 | *start = (unsigned char*)((swap ? gmbuf : gmbuf + BUF_SIZE)); | ||
287 | swap = !swap; | ||
288 | #else | ||
289 | *start = (unsigned char*)(gmbuf); | ||
290 | #endif | ||
291 | } | ||
292 | |||
293 | void showinfo() | ||
294 | { | ||
295 | char statustext[LINE_LENGTH]; | ||
296 | |||
297 | if (!module) | ||
298 | { | ||
299 | return; | ||
300 | } | ||
301 | |||
302 | rb->lcd_clear_display(); | ||
303 | |||
304 | playingtime = (int)(module->sngtime >> 10); | ||
305 | sprintf(statustext, "Name: %s", module->songname); | ||
306 | rb->lcd_putsxy(1, 1, statustext); | ||
307 | sprintf(statustext, "Type: %s", module->modtype); | ||
308 | rb->lcd_putsxy(1, 11, statustext); | ||
309 | |||
310 | sprintf(statustext, "Samples: %d", module->numsmp); | ||
311 | rb->lcd_putsxy(1, 21, statustext); | ||
312 | |||
313 | if ( module->flags & UF_INST ) | ||
314 | { | ||
315 | sprintf(statustext, "Instruments: %d", module->numins); | ||
316 | rb->lcd_putsxy(1, 31, statustext); | ||
317 | } | ||
318 | |||
319 | sprintf(statustext, "pat: %03d/%03d %2.2X", | ||
320 | module->sngpos, module->numpos - 1, module->patpos); | ||
321 | rb->lcd_putsxy(1, 51, statustext); | ||
322 | |||
323 | sprintf(statustext, "spd: %d/%d", | ||
324 | module->sngspd, module->bpm); | ||
325 | rb->lcd_putsxy(1, 61, statustext); | ||
326 | |||
327 | sprintf(statustext, "vol: %ddB", rb->global_settings->volume); | ||
328 | rb->lcd_putsxy(1, 71, statustext); | ||
329 | |||
330 | sprintf(statustext, "time: %d:%02d", | ||
331 | (playingtime / 60) % 60, playingtime % 60); | ||
332 | rb->lcd_putsxy(1, 81, statustext); | ||
333 | |||
334 | if (module->flags & UF_NNA) | ||
335 | { | ||
336 | sprintf(statustext, "chn: %d/%d+%d->%d", | ||
337 | module->realchn, module->numchn, | ||
338 | module->totalchn - module->realchn, | ||
339 | module->totalchn); | ||
340 | } | ||
341 | else | ||
342 | { | ||
343 | sprintf(statustext, "chn: %d/%d", | ||
344 | module->realchn, module->numchn); | ||
345 | } | ||
346 | rb->lcd_putsxy(0, 91, statustext); | ||
347 | |||
348 | rb->lcd_update(); | ||
349 | } | ||
350 | |||
351 | void showsamples() | ||
352 | { | ||
353 | int i, j; | ||
354 | char statustext[LINE_LENGTH]; | ||
355 | |||
356 | if ( screenupdated ) | ||
357 | { | ||
358 | return; | ||
359 | } | ||
360 | rb->lcd_clear_display(); | ||
361 | for( i=0; i<MAX_LINES && i+vscroll<module->numsmp; i++ ) | ||
362 | { | ||
363 | sprintf(statustext, "%02d %s", i+vscroll+1, module->samples[i+vscroll].samplename); | ||
364 | rb->lcd_putsxy(1, 1+(8*i), statustext); | ||
365 | } | ||
366 | rb->lcd_update(); | ||
367 | screenupdated = true; | ||
368 | } | ||
369 | |||
370 | void showinstruments() | ||
371 | { | ||
372 | int i, j; | ||
373 | char statustext[LINE_LENGTH]; | ||
374 | |||
375 | if ( screenupdated ) | ||
376 | { | ||
377 | return; | ||
378 | } | ||
379 | rb->lcd_clear_display(); | ||
380 | for( i=0; i<MAX_LINES && i+vscroll<module->numins; i++ ) | ||
381 | { | ||
382 | sprintf(statustext, "%02d %s", i+vscroll+1, module->instruments[i+vscroll].insname); | ||
383 | rb->lcd_putsxy(1, 1+(8*i), statustext); | ||
384 | } | ||
385 | rb->lcd_update(); | ||
386 | screenupdated = true; | ||
387 | } | ||
388 | |||
389 | void showcomments() | ||
390 | { | ||
391 | int i, j=0, k=0, l; | ||
392 | char statustext[LINE_LENGTH]; | ||
393 | |||
394 | if ( screenupdated ) | ||
395 | { | ||
396 | return; | ||
397 | } | ||
398 | rb->lcd_clear_display(); | ||
399 | |||
400 | for(i=0; module->comment[i]!='\0'; i++) | ||
401 | { | ||
402 | if(module->comment[i] != '\n') | ||
403 | { | ||
404 | statustext[j] = module->comment[i]; | ||
405 | j++; | ||
406 | } | ||
407 | |||
408 | if(module->comment[i] == '\n' || j>LINE_LENGTH-1) | ||
409 | { | ||
410 | rb->lcd_putsxy(1-(6*hscroll), 1+(8*k)-(8*vscroll), statustext); | ||
411 | for( l=0; l<LINE_LENGTH; l++ ) | ||
412 | { | ||
413 | statustext[l] = 0; | ||
414 | } | ||
415 | k++; | ||
416 | j=0; | ||
417 | } | ||
418 | } | ||
419 | if (j>0) | ||
420 | { | ||
421 | rb->lcd_putsxy(1-(6*hscroll), 1+(8*k)-(8*vscroll), statustext); | ||
422 | } | ||
423 | |||
424 | rb->lcd_update(); | ||
425 | screenupdated = true; | ||
426 | } | ||
427 | |||
428 | int changedisplay() | ||
429 | { | ||
430 | display = (display+1) % 4; | ||
431 | |||
432 | if (display == DISPLAY_SAMPLE) | ||
433 | { | ||
434 | textlines = module->numsmp; | ||
435 | } | ||
436 | |||
437 | if (display == DISPLAY_INST) | ||
438 | { | ||
439 | if ( module->flags & UF_INST ) | ||
440 | { | ||
441 | textlines = module->numins; | ||
442 | } | ||
443 | else | ||
444 | { | ||
445 | display = DISPLAY_COMMENTS; | ||
446 | } | ||
447 | } | ||
448 | |||
449 | if (display == DISPLAY_COMMENTS) | ||
450 | { | ||
451 | if (module->comment) | ||
452 | { | ||
453 | textlines = 100; | ||
454 | } | ||
455 | else | ||
456 | { | ||
457 | display = DISPLAY_INFO; | ||
458 | } | ||
459 | } | ||
460 | screenupdated = false; | ||
461 | vscroll = 0; | ||
462 | hscroll = 0; | ||
463 | } | ||
464 | |||
465 | struct mikmod_settings | ||
466 | { | ||
467 | int pansep; | ||
468 | int reverb; | ||
469 | bool interp; | ||
470 | bool reverse; | ||
471 | bool surround; | ||
472 | bool boost; | ||
473 | }; | ||
474 | |||
475 | static struct mikmod_settings settings = | ||
476 | { | ||
477 | 128, | ||
478 | 0, | ||
479 | 0, | ||
480 | 0, | ||
481 | 1, | ||
482 | 1 | ||
483 | }; | ||
484 | |||
485 | static struct mikmod_settings old_settings; | ||
486 | |||
487 | static struct configdata config[] = | ||
488 | { | ||
489 | { TYPE_INT, 0, 128, { .int_p = &settings.pansep }, "Panning Separation", NULL}, | ||
490 | { TYPE_INT, 0, 15, { .int_p = &settings.reverb }, "Reverberation", NULL}, | ||
491 | { TYPE_BOOL, 0, 1, { .bool_p = &settings.interp }, "Interpolation", NULL}, | ||
492 | { TYPE_BOOL, 0, 1, { .bool_p = &settings.reverse }, "Reverse Channels", NULL}, | ||
493 | { TYPE_BOOL, 0, 1, { .bool_p = &settings.surround }, "Surround", NULL}, | ||
494 | { TYPE_BOOL, 0, 1, { .bool_p = &settings.boost }, "CPU Boost", NULL}, | ||
495 | }; | ||
496 | |||
497 | void applysettings() | ||
498 | { | ||
499 | md_pansep = settings.pansep; | ||
500 | md_reverb = settings.reverb; | ||
501 | md_mode = DMODE_STEREO | DMODE_16BITS | DMODE_SOFT_MUSIC | DMODE_SOFT_SNDFX; | ||
502 | if ( settings.interp ) | ||
503 | { | ||
504 | md_mode |= DMODE_INTERP; | ||
505 | } | ||
506 | if ( settings.reverse ) | ||
507 | { | ||
508 | md_mode |= DMODE_REVERSE; | ||
509 | } | ||
510 | if ( settings.surround ) | ||
511 | { | ||
512 | md_mode |= DMODE_SURROUND; | ||
513 | } | ||
514 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ | ||
515 | if ( Player_Active() ) | ||
516 | { | ||
517 | rb->cpu_boost(settings.boost); | ||
518 | } | ||
519 | #endif | ||
520 | } | ||
521 | |||
522 | /** | ||
523 | Shows the settings menu | ||
524 | */ | ||
525 | int settings_menu(void) | ||
526 | { | ||
527 | int selection = 0; | ||
528 | bool old_val; | ||
529 | |||
530 | MENUITEM_STRINGLIST(settings_menu, "Mikmod Settings", NULL, "Panning Separation", | ||
531 | "Reverberation", "Interpolation", "Reverse Channels", "Surround", | ||
532 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ | ||
533 | "CPU Boost" | ||
534 | #endif | ||
535 | ); | ||
536 | |||
537 | do | ||
538 | { | ||
539 | selection=rb->do_menu(&settings_menu,&selection, NULL, false); | ||
540 | switch(selection) | ||
541 | { | ||
542 | case 0: | ||
543 | rb->set_int("Panning Separation", "", 1, | ||
544 | &(settings.pansep), | ||
545 | NULL, 8, 0, 128, NULL ); | ||
546 | applysettings(); | ||
547 | break; | ||
548 | |||
549 | case 1: | ||
550 | rb->set_int("Reverberation", "", 1, | ||
551 | &(settings.reverb), | ||
552 | NULL, 1, 0, 15, NULL ); | ||
553 | applysettings(); | ||
554 | break; | ||
555 | |||
556 | case 2: | ||
557 | rb->set_bool("Interpolation", &(settings.interp)); | ||
558 | applysettings(); | ||
559 | break; | ||
560 | |||
561 | case 3: | ||
562 | rb->set_bool("Reverse Channels", &(settings.reverse)); | ||
563 | applysettings(); | ||
564 | break; | ||
565 | |||
566 | case 4: | ||
567 | rb->set_bool("Surround", &(settings.surround)); | ||
568 | applysettings(); | ||
569 | break; | ||
570 | |||
571 | case 5: | ||
572 | rb->set_bool("CPU Boost", &(settings.boost)); | ||
573 | applysettings(); | ||
574 | break; | ||
575 | |||
576 | case MENU_ATTACHED_USB: | ||
577 | return PLUGIN_USB_CONNECTED; | ||
578 | } | ||
579 | } while ( selection >= 0 ); | ||
580 | return 0; | ||
581 | } | ||
582 | |||
583 | /** | ||
584 | Show the main menu | ||
585 | */ | ||
586 | int main_menu(void) | ||
587 | { | ||
588 | int selection = 0; | ||
589 | int result; | ||
590 | |||
591 | MENUITEM_STRINGLIST(main_menu,"Mikmod Main Menu",NULL, | ||
592 | "Settings", "Return", "Quit"); | ||
593 | while (1) | ||
594 | { | ||
595 | switch (rb->do_menu(&main_menu,&selection, NULL, false)) | ||
596 | { | ||
597 | case 0: | ||
598 | result = settings_menu(); | ||
599 | if ( result != 0 ) return result; | ||
600 | break; | ||
601 | |||
602 | case 1: | ||
603 | return 0; | ||
604 | |||
605 | case 2: | ||
606 | return -1; | ||
607 | |||
608 | case MENU_ATTACHED_USB: | ||
609 | return PLUGIN_USB_CONNECTED; | ||
610 | |||
611 | default: | ||
612 | return 0; | ||
613 | } | ||
614 | } | ||
615 | } | ||
616 | |||
617 | #ifdef USETHREADS | ||
618 | /* double buffering thread */ | ||
619 | void thread(void) | ||
620 | { | ||
621 | struct queue_event ev; | ||
622 | |||
623 | while (1) | ||
624 | { | ||
625 | synthbuf(); | ||
626 | rb->queue_wait_w_tmo(&thread_q, &ev, HZ/20); | ||
627 | switch (ev.id) { | ||
628 | case EV_EXIT: | ||
629 | return; | ||
630 | } | ||
631 | } | ||
632 | } | ||
633 | #endif | ||
634 | |||
635 | void mm_errorhandler(void) | ||
636 | { | ||
637 | rb->splashf(HZ, "%s", MikMod_strerror(MikMod_errno)); | ||
638 | quit = true; | ||
639 | } | ||
640 | |||
641 | int playfile(char* filename) | ||
642 | { | ||
643 | int vol = 0; | ||
644 | int button; | ||
645 | int retval = PLUGIN_OK; | ||
646 | bool changingpos = false; | ||
647 | int menureturn; | ||
648 | |||
649 | playingtime = 0; | ||
650 | |||
651 | rb->splashf(HZ, "Loading %s", filename); | ||
652 | |||
653 | module = Player_Load(filename, 64, 0); | ||
654 | |||
655 | if (!module) | ||
656 | { | ||
657 | rb->splashf(HZ, "%s", MikMod_strerror(MikMod_errno)); | ||
658 | retval = PLUGIN_ERROR; | ||
659 | quit = true; | ||
660 | } | ||
661 | else | ||
662 | { | ||
663 | display = DISPLAY_INFO; | ||
664 | Player_Start(module); | ||
665 | rb->pcm_play_data(&get_more, NULL, 0); | ||
666 | } | ||
667 | |||
668 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ | ||
669 | if ( settings.boost ) | ||
670 | rb->cpu_boost(true); | ||
671 | #endif | ||
672 | #ifdef USETHREADS | ||
673 | rb->queue_init(&thread_q, true); | ||
674 | if ((thread_id = rb->create_thread(thread, thread_stack, | ||
675 | sizeof(thread_stack), 0, "render buffering thread" | ||
676 | IF_PRIO(, PRIORITY_PLAYBACK) | ||
677 | IF_COP(, CPU))) == 0) | ||
678 | { | ||
679 | rb->splash(HZ, "Cannot create thread!"); | ||
680 | return PLUGIN_ERROR; | ||
681 | } | ||
682 | #endif | ||
683 | |||
684 | while (!quit && Player_Active() && retval == PLUGIN_OK) | ||
685 | { | ||
686 | #if !defined(SYNC) && !defined(USETHREADS) | ||
687 | synthbuf(); | ||
688 | #endif | ||
689 | switch (display) | ||
690 | { | ||
691 | case DISPLAY_SAMPLE: | ||
692 | showsamples(); | ||
693 | break; | ||
694 | case DISPLAY_INST: | ||
695 | showinstruments(); | ||
696 | break; | ||
697 | case DISPLAY_COMMENTS: | ||
698 | showcomments(); | ||
699 | break; | ||
700 | default: | ||
701 | showinfo(); | ||
702 | } | ||
703 | |||
704 | rb->yield(); | ||
705 | |||
706 | /* Prevent idle poweroff */ | ||
707 | rb->reset_poweroff_timer(); | ||
708 | |||
709 | button = rb->get_action(CONTEXT_WPS, TIMEOUT_NOBLOCK); | ||
710 | switch (button) | ||
711 | { | ||
712 | case ACTION_WPS_VOLUP: | ||
713 | if ( display != DISPLAY_INFO ) | ||
714 | { | ||
715 | if ( textlines-vscroll >= MAX_LINES ) | ||
716 | { | ||
717 | vscroll++; | ||
718 | screenupdated = false; | ||
719 | } | ||
720 | break; | ||
721 | } | ||
722 | vol = rb->global_settings->volume; | ||
723 | if (vol < rb->sound_max(SOUND_VOLUME)) | ||
724 | { | ||
725 | vol++; | ||
726 | rb->sound_set(SOUND_VOLUME, vol); | ||
727 | rb->global_settings->volume = vol; | ||
728 | } | ||
729 | break; | ||
730 | |||
731 | case ACTION_WPS_VOLDOWN: | ||
732 | if ( display != DISPLAY_INFO ) | ||
733 | { | ||
734 | if ( vscroll > 0 ) | ||
735 | { | ||
736 | vscroll--; | ||
737 | screenupdated = false; | ||
738 | } | ||
739 | break; | ||
740 | } | ||
741 | vol = rb->global_settings->volume; | ||
742 | if (vol > rb->sound_min(SOUND_VOLUME)) | ||
743 | { | ||
744 | vol--; | ||
745 | rb->sound_set(SOUND_VOLUME, vol); | ||
746 | rb->global_settings->volume = vol; | ||
747 | } | ||
748 | break; | ||
749 | |||
750 | case ACTION_WPS_SKIPPREV: | ||
751 | if(entries>1 && !changingpos) | ||
752 | { | ||
753 | if ((int)(module->sngtime >> 10) > 2) | ||
754 | { | ||
755 | Player_SetPosition(0); | ||
756 | module->sngtime = 0; | ||
757 | } | ||
758 | else { | ||
759 | retval = change_filename(DIR_PREV); | ||
760 | } | ||
761 | } | ||
762 | else | ||
763 | { | ||
764 | changingpos = false; | ||
765 | } | ||
766 | break; | ||
767 | case ACTION_WPS_SEEKBACK: | ||
768 | if ( display != DISPLAY_INFO ) | ||
769 | { | ||
770 | if ( hscroll > 0 ) | ||
771 | { | ||
772 | hscroll--; | ||
773 | screenupdated = false; | ||
774 | } | ||
775 | break; | ||
776 | } | ||
777 | Player_PrevPosition(); | ||
778 | changingpos = true; | ||
779 | break; | ||
780 | |||
781 | case ACTION_WPS_SKIPNEXT: | ||
782 | if(entries>1 && !changingpos) | ||
783 | { | ||
784 | retval = change_filename(DIR_NEXT); | ||
785 | } | ||
786 | else | ||
787 | { | ||
788 | changingpos = false; | ||
789 | } | ||
790 | break; | ||
791 | case ACTION_WPS_SEEKFWD: | ||
792 | if ( display != DISPLAY_INFO ) | ||
793 | { | ||
794 | hscroll++; | ||
795 | screenupdated = false; | ||
796 | break; | ||
797 | } | ||
798 | Player_NextPosition(); | ||
799 | changingpos = true; | ||
800 | break; | ||
801 | |||
802 | case ACTION_WPS_PLAY: | ||
803 | if(!Player_Paused()) | ||
804 | { | ||
805 | rb->pcm_play_stop(); | ||
806 | } | ||
807 | else | ||
808 | { | ||
809 | rb->pcm_play_data(&get_more, NULL, 0); | ||
810 | } | ||
811 | Player_TogglePause(); | ||
812 | break; | ||
813 | |||
814 | case ACTION_WPS_BROWSE: | ||
815 | changedisplay(); | ||
816 | break; | ||
817 | |||
818 | case ACTION_WPS_MENU: | ||
819 | menureturn = main_menu(); | ||
820 | if ( menureturn != 0 ) | ||
821 | { | ||
822 | quit = true; | ||
823 | if ( menureturn == PLUGIN_USB_CONNECTED ) | ||
824 | { | ||
825 | retval = menureturn; | ||
826 | } | ||
827 | } | ||
828 | rb->lcd_setfont(0); | ||
829 | screenupdated = false; | ||
830 | break; | ||
831 | |||
832 | case ACTION_WPS_STOP: | ||
833 | quit = true; | ||
834 | break; | ||
835 | |||
836 | default: | ||
837 | if (rb->default_event_handler(button) == SYS_USB_CONNECTED) | ||
838 | { | ||
839 | quit = true; | ||
840 | retval = PLUGIN_USB_CONNECTED; | ||
841 | } | ||
842 | } | ||
843 | } | ||
844 | |||
845 | #ifdef USETHREADS | ||
846 | rb->queue_post(&thread_q, EV_EXIT, 0); | ||
847 | rb->thread_wait(thread_id); | ||
848 | rb->queue_delete(&thread_q); | ||
849 | #endif | ||
850 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ | ||
851 | if ( settings.boost ) | ||
852 | rb->cpu_boost(false); | ||
853 | #endif | ||
854 | |||
855 | Player_Stop(); | ||
856 | Player_Free(module); | ||
857 | |||
858 | memset(gmbuf, '\0', sizeof(gmbuf)); | ||
859 | |||
860 | if ( retval == PLUGIN_OK && entries > 1 && !quit ) | ||
861 | { | ||
862 | retval = change_filename(DIR_NEXT); | ||
863 | } | ||
864 | |||
865 | return retval; | ||
866 | } | ||
867 | |||
868 | /* | ||
869 | * Plugin entry point | ||
870 | * | ||
871 | */ | ||
872 | enum plugin_status plugin_start(const void* parameter) | ||
873 | { | ||
874 | enum plugin_status retval; | ||
875 | |||
876 | if (parameter == NULL) | ||
877 | { | ||
878 | rb->splash(HZ*2, " Play .mod, .it, .s3m, .xm file "); | ||
879 | return PLUGIN_OK; | ||
880 | } | ||
881 | |||
882 | rb->lcd_setfont(0); | ||
883 | |||
884 | rb->pcm_play_stop(); | ||
885 | #if INPUT_SRC_CAPS != 0 | ||
886 | /* Select playback */ | ||
887 | rb->audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK); | ||
888 | rb->audio_set_output_source(AUDIO_SRC_PLAYBACK); | ||
889 | #endif | ||
890 | rb->pcm_set_frequency(SAMPLE_RATE); | ||
891 | |||
892 | audio_buffer = rb->plugin_get_audio_buffer((size_t *)&audio_buffer_free); | ||
893 | |||
894 | rb->strcpy(np_file, parameter); | ||
895 | get_mod_list(); | ||
896 | if(!entries) { | ||
897 | return PLUGIN_ERROR; | ||
898 | } | ||
899 | |||
900 | //add_pool(audio_buffer, audio_buffer_free); | ||
901 | init_memory_pool(audio_buffer_free, audio_buffer); | ||
902 | |||
903 | MikMod_RegisterDriver(&drv_nos); | ||
904 | MikMod_RegisterAllLoaders(); | ||
905 | MikMod_RegisterErrorHandler(mm_errorhandler); | ||
906 | |||
907 | md_mixfreq = SAMPLE_RATE; | ||
908 | |||
909 | configfile_load(MIKMOD_CONFIGFILE, config, | ||
910 | ARRAYLEN(config), MIKMOD_SETTINGS_MINVERSION); | ||
911 | rb->memcpy(&old_settings, &settings, sizeof (settings)); | ||
912 | applysettings(); | ||
913 | |||
914 | if (MikMod_Init("")) | ||
915 | { | ||
916 | rb->splashf(HZ, "%s", MikMod_strerror(MikMod_errno)); | ||
917 | return PLUGIN_ERROR; | ||
918 | } | ||
919 | |||
920 | do | ||
921 | { | ||
922 | retval = playfile(np_file); | ||
923 | } while (retval == PLUGIN_NEWSONG); | ||
924 | |||
925 | MikMod_Exit(); | ||
926 | |||
927 | rb->pcm_play_stop(); | ||
928 | rb->pcm_set_frequency(HW_SAMPR_DEFAULT); | ||
929 | |||
930 | if (retval == PLUGIN_OK) | ||
931 | { | ||
932 | rb->splash(0, "Saving Settings"); | ||
933 | if (rb->memcmp(&settings, &old_settings, sizeof (settings))) | ||
934 | { | ||
935 | configfile_save(MIKMOD_CONFIGFILE, config, | ||
936 | ARRAYLEN(config), MIKMOD_SETTINGS_MINVERSION); | ||
937 | } | ||
938 | } | ||
939 | |||
940 | destroy_memory_pool(audio_buffer); | ||
941 | |||
942 | return retval; | ||
943 | } | ||
diff --git a/apps/plugins/mikmod/mikmod.h b/apps/plugins/mikmod/mikmod.h new file mode 100644 index 0000000000..a1c201f6d2 --- /dev/null +++ b/apps/plugins/mikmod/mikmod.h | |||
@@ -0,0 +1,783 @@ | |||
1 | /* MikMod sound library | ||
2 | (c) 1998, 1999, 2000 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: mikmod.h.in,v 1.3 2005/03/30 19:09:21 realtech Exp $ | ||
24 | |||
25 | MikMod sound library include file | ||
26 | |||
27 | ==============================================================================*/ | ||
28 | |||
29 | #ifndef _MIKMOD_H_ | ||
30 | #define _MIKMOD_H_ | ||
31 | |||
32 | #include <stdio.h> | ||
33 | #include <stdlib.h> | ||
34 | |||
35 | #ifdef __cplusplus | ||
36 | extern "C" { | ||
37 | #endif | ||
38 | |||
39 | #include "mikmod_supp.h" | ||
40 | |||
41 | /* | ||
42 | * ========== Compiler magic for shared libraries | ||
43 | */ | ||
44 | |||
45 | #if defined WIN32 && defined _DLL | ||
46 | #ifdef DLL_EXPORTS | ||
47 | #define MIKMODAPI __declspec(dllexport) | ||
48 | #else | ||
49 | #define MIKMODAPI __declspec(dllimport) | ||
50 | #endif | ||
51 | #else | ||
52 | #define MIKMODAPI | ||
53 | #endif | ||
54 | |||
55 | /* | ||
56 | * ========== Library version | ||
57 | */ | ||
58 | |||
59 | #define LIBMIKMOD_VERSION_MAJOR 3L | ||
60 | #define LIBMIKMOD_VERSION_MINOR 2L | ||
61 | #define LIBMIKMOD_REVISION 0L | ||
62 | |||
63 | #define LIBMIKMOD_VERSION \ | ||
64 | ((LIBMIKMOD_VERSION_MAJOR<<16)| \ | ||
65 | (LIBMIKMOD_VERSION_MINOR<< 8)| \ | ||
66 | (LIBMIKMOD_REVISION)) | ||
67 | |||
68 | MIKMODAPI extern long MikMod_GetVersion(void); | ||
69 | |||
70 | /* | ||
71 | * ========== Platform independent-type definitions | ||
72 | */ | ||
73 | #if 0 | ||
74 | #ifdef WIN32 | ||
75 | #define WIN32_LEAN_AND_MEAN | ||
76 | #include <windows.h> | ||
77 | #include <io.h> | ||
78 | #include <mmsystem.h> | ||
79 | #endif | ||
80 | |||
81 | #if defined(__OS2__)||defined(__EMX__) | ||
82 | #define INCL_DOSSEMAPHORES | ||
83 | #include <os2.h> | ||
84 | #else | ||
85 | typedef char CHAR; | ||
86 | #endif | ||
87 | #endif | ||
88 | |||
89 | typedef char CHAR; | ||
90 | |||
91 | |||
92 | #if defined(__arch64__) || defined(__alpha) || defined(__x86_64) || defined(__powerpc64__) | ||
93 | /* 64 bit architectures */ | ||
94 | |||
95 | typedef signed char SBYTE; /* 1 byte, signed */ | ||
96 | typedef unsigned char UBYTE; /* 1 byte, unsigned */ | ||
97 | typedef signed short SWORD; /* 2 bytes, signed */ | ||
98 | typedef unsigned short UWORD; /* 2 bytes, unsigned */ | ||
99 | typedef signed int SLONG; /* 4 bytes, signed */ | ||
100 | typedef unsigned int ULONG; /* 4 bytes, unsigned */ | ||
101 | //typedef int BOOL; /* 0=false, <>0 true */ | ||
102 | |||
103 | #else | ||
104 | /* 32 bit architectures */ | ||
105 | |||
106 | typedef signed char SBYTE; /* 1 byte, signed */ | ||
107 | typedef unsigned char UBYTE; /* 1 byte, unsigned */ | ||
108 | typedef signed short SWORD; /* 2 bytes, signed */ | ||
109 | typedef unsigned short UWORD; /* 2 bytes, unsigned */ | ||
110 | typedef signed long SLONG; /* 4 bytes, signed */ | ||
111 | #if !defined(__OS2__)&&!defined(__EMX__)&&!defined(WIN32) | ||
112 | typedef unsigned long ULONG; /* 4 bytes, unsigned */ | ||
113 | //typedef int BOOL; /* 0=false, <>0 true */ | ||
114 | #endif | ||
115 | #endif | ||
116 | |||
117 | /* | ||
118 | * ========== Error codes | ||
119 | */ | ||
120 | |||
121 | enum { | ||
122 | MMERR_OPENING_FILE = 1, | ||
123 | MMERR_OUT_OF_MEMORY, | ||
124 | MMERR_DYNAMIC_LINKING, | ||
125 | |||
126 | MMERR_SAMPLE_TOO_BIG, | ||
127 | MMERR_OUT_OF_HANDLES, | ||
128 | MMERR_UNKNOWN_WAVE_TYPE, | ||
129 | |||
130 | MMERR_LOADING_PATTERN, | ||
131 | MMERR_LOADING_TRACK, | ||
132 | MMERR_LOADING_HEADER, | ||
133 | MMERR_LOADING_SAMPLEINFO, | ||
134 | MMERR_NOT_A_MODULE, | ||
135 | MMERR_NOT_A_STREAM, | ||
136 | MMERR_MED_SYNTHSAMPLES, | ||
137 | MMERR_ITPACK_INVALID_DATA, | ||
138 | |||
139 | MMERR_DETECTING_DEVICE, | ||
140 | MMERR_INVALID_DEVICE, | ||
141 | MMERR_INITIALIZING_MIXER, | ||
142 | MMERR_OPENING_AUDIO, | ||
143 | MMERR_8BIT_ONLY, | ||
144 | MMERR_16BIT_ONLY, | ||
145 | MMERR_STEREO_ONLY, | ||
146 | MMERR_ULAW, | ||
147 | MMERR_NON_BLOCK, | ||
148 | |||
149 | MMERR_AF_AUDIO_PORT, | ||
150 | |||
151 | MMERR_AIX_CONFIG_INIT, | ||
152 | MMERR_AIX_CONFIG_CONTROL, | ||
153 | MMERR_AIX_CONFIG_START, | ||
154 | |||
155 | MMERR_GUS_SETTINGS, | ||
156 | MMERR_GUS_RESET, | ||
157 | MMERR_GUS_TIMER, | ||
158 | |||
159 | MMERR_HP_SETSAMPLESIZE, | ||
160 | MMERR_HP_SETSPEED, | ||
161 | MMERR_HP_CHANNELS, | ||
162 | MMERR_HP_AUDIO_OUTPUT, | ||
163 | MMERR_HP_AUDIO_DESC, | ||
164 | MMERR_HP_BUFFERSIZE, | ||
165 | |||
166 | MMERR_OSS_SETFRAGMENT, | ||
167 | MMERR_OSS_SETSAMPLESIZE, | ||
168 | MMERR_OSS_SETSTEREO, | ||
169 | MMERR_OSS_SETSPEED, | ||
170 | |||
171 | MMERR_SGI_SPEED, | ||
172 | MMERR_SGI_16BIT, | ||
173 | MMERR_SGI_8BIT, | ||
174 | MMERR_SGI_STEREO, | ||
175 | MMERR_SGI_MONO, | ||
176 | |||
177 | MMERR_SUN_INIT, | ||
178 | |||
179 | MMERR_OS2_MIXSETUP, | ||
180 | MMERR_OS2_SEMAPHORE, | ||
181 | MMERR_OS2_TIMER, | ||
182 | MMERR_OS2_THREAD, | ||
183 | |||
184 | MMERR_DS_PRIORITY, | ||
185 | MMERR_DS_BUFFER, | ||
186 | MMERR_DS_FORMAT, | ||
187 | MMERR_DS_NOTIFY, | ||
188 | MMERR_DS_EVENT, | ||
189 | MMERR_DS_THREAD, | ||
190 | MMERR_DS_UPDATE, | ||
191 | |||
192 | MMERR_WINMM_HANDLE, | ||
193 | MMERR_WINMM_ALLOCATED, | ||
194 | MMERR_WINMM_DEVICEID, | ||
195 | MMERR_WINMM_FORMAT, | ||
196 | MMERR_WINMM_UNKNOWN, | ||
197 | |||
198 | MMERR_MAC_SPEED, | ||
199 | MMERR_MAC_START, | ||
200 | |||
201 | MMERR_OSX_UNKNOWN_DEVICE, | ||
202 | MMERR_OSX_BAD_PROPERTY, | ||
203 | MMERR_OSX_UNSUPPORTED_FORMAT, | ||
204 | MMERR_OSX_SET_STEREO, | ||
205 | MMERR_OSX_BUFFER_ALLOC, | ||
206 | MMERR_OSX_ADD_IO_PROC, | ||
207 | MMERR_OSX_DEVICE_START, | ||
208 | MMERR_OSX_PTHREAD, | ||
209 | |||
210 | MMERR_DOSWSS_STARTDMA, | ||
211 | MMERR_DOSSB_STARTDMA, | ||
212 | |||
213 | MMERR_MAX | ||
214 | }; | ||
215 | |||
216 | /* | ||
217 | * ========== Error handling | ||
218 | */ | ||
219 | |||
220 | typedef void (MikMod_handler)(void); | ||
221 | typedef MikMod_handler *MikMod_handler_t; | ||
222 | |||
223 | MIKMODAPI extern int MikMod_errno; | ||
224 | MIKMODAPI extern int MikMod_critical; | ||
225 | MIKMODAPI extern char *MikMod_strerror(int); | ||
226 | |||
227 | MIKMODAPI extern MikMod_handler_t MikMod_RegisterErrorHandler(MikMod_handler_t); | ||
228 | |||
229 | /* | ||
230 | * ========== Library initialization and core functions | ||
231 | */ | ||
232 | |||
233 | struct MDRIVER; | ||
234 | |||
235 | MIKMODAPI extern void MikMod_RegisterAllDrivers(void); | ||
236 | |||
237 | MIKMODAPI extern CHAR* MikMod_InfoDriver(void); | ||
238 | MIKMODAPI extern void MikMod_RegisterDriver(struct MDRIVER*); | ||
239 | MIKMODAPI extern int MikMod_DriverFromAlias(CHAR*); | ||
240 | MIKMODAPI extern struct MDRIVER *MikMod_DriverByOrdinal(int); | ||
241 | |||
242 | MIKMODAPI extern int MikMod_Init(CHAR*); | ||
243 | MIKMODAPI extern void MikMod_Exit(void); | ||
244 | MIKMODAPI extern int MikMod_Reset(CHAR*); | ||
245 | MIKMODAPI extern int MikMod_SetNumVoices(int,int); | ||
246 | MIKMODAPI extern int MikMod_Active(void); | ||
247 | MIKMODAPI extern int MikMod_EnableOutput(void); | ||
248 | MIKMODAPI extern void MikMod_DisableOutput(void); | ||
249 | MIKMODAPI extern void MikMod_Update(void); | ||
250 | |||
251 | MIKMODAPI extern int MikMod_InitThreads(void); | ||
252 | MIKMODAPI extern void MikMod_Lock(void); | ||
253 | MIKMODAPI extern void MikMod_Unlock(void); | ||
254 | |||
255 | MIKMODAPI extern void* MikMod_malloc(size_t); | ||
256 | MIKMODAPI extern void* MikMod_realloc(void *, size_t); | ||
257 | MIKMODAPI extern void* MikMod_calloc(size_t,size_t); | ||
258 | MIKMODAPI extern void MikMod_free(void*); | ||
259 | |||
260 | /* | ||
261 | * ========== Reader, Writer | ||
262 | */ | ||
263 | |||
264 | typedef struct MREADER { | ||
265 | int (*Seek)(struct MREADER*,long,int); | ||
266 | long (*Tell)(struct MREADER*); | ||
267 | int (*Read)(struct MREADER*,void*,size_t); | ||
268 | int (*Get)(struct MREADER*); | ||
269 | int (*Eof)(struct MREADER*); | ||
270 | long iobase; | ||
271 | long prev_iobase; | ||
272 | } MREADER; | ||
273 | |||
274 | typedef struct MWRITER { | ||
275 | int (*Seek)(struct MWRITER*,long,int); | ||
276 | long (*Tell)(struct MWRITER*); | ||
277 | int (*Write)(struct MWRITER*,void*,size_t); | ||
278 | int (*Put)(struct MWRITER*,int); | ||
279 | } MWRITER; | ||
280 | |||
281 | /* | ||
282 | * ========== Samples | ||
283 | */ | ||
284 | |||
285 | /* Sample playback should not be interrupted */ | ||
286 | #define SFX_CRITICAL 1 | ||
287 | |||
288 | /* Sample format [loading and in-memory] flags: */ | ||
289 | #define SF_16BITS 0x0001 | ||
290 | #define SF_STEREO 0x0002 | ||
291 | #define SF_SIGNED 0x0004 | ||
292 | #define SF_BIG_ENDIAN 0x0008 | ||
293 | #define SF_DELTA 0x0010 | ||
294 | #define SF_ITPACKED 0x0020 | ||
295 | |||
296 | #define SF_FORMATMASK 0x003F | ||
297 | |||
298 | /* General Playback flags */ | ||
299 | |||
300 | #define SF_LOOP 0x0100 | ||
301 | #define SF_BIDI 0x0200 | ||
302 | #define SF_REVERSE 0x0400 | ||
303 | #define SF_SUSTAIN 0x0800 | ||
304 | |||
305 | #define SF_PLAYBACKMASK 0x0C00 | ||
306 | |||
307 | /* Module-only Playback Flags */ | ||
308 | |||
309 | #define SF_OWNPAN 0x1000 | ||
310 | #define SF_UST_LOOP 0x2000 | ||
311 | |||
312 | #define SF_EXTRAPLAYBACKMASK 0x3000 | ||
313 | |||
314 | /* Panning constants */ | ||
315 | #define PAN_LEFT 0 | ||
316 | #define PAN_HALFLEFT 64 | ||
317 | #define PAN_CENTER 128 | ||
318 | #define PAN_HALFRIGHT 192 | ||
319 | #define PAN_RIGHT 255 | ||
320 | #define PAN_SURROUND 512 /* panning value for Dolby Surround */ | ||
321 | |||
322 | typedef struct SAMPLE { | ||
323 | SWORD panning; /* panning (0-255 or PAN_SURROUND) */ | ||
324 | ULONG speed; /* Base playing speed/frequency of note */ | ||
325 | UBYTE volume; /* volume 0-64 */ | ||
326 | UWORD inflags; /* sample format on disk */ | ||
327 | UWORD flags; /* sample format in memory */ | ||
328 | ULONG length; /* length of sample (in samples!) */ | ||
329 | ULONG loopstart; /* repeat position (relative to start, in samples) */ | ||
330 | ULONG loopend; /* repeat end */ | ||
331 | ULONG susbegin; /* sustain loop begin (in samples) \ Not Supported */ | ||
332 | ULONG susend; /* sustain loop end / Yet! */ | ||
333 | |||
334 | /* Variables used by the module player only! (ignored for sound effects) */ | ||
335 | UBYTE globvol; /* global volume */ | ||
336 | UBYTE vibflags; /* autovibrato flag stuffs */ | ||
337 | UBYTE vibtype; /* Vibratos moved from INSTRUMENT to SAMPLE */ | ||
338 | UBYTE vibsweep; | ||
339 | UBYTE vibdepth; | ||
340 | UBYTE vibrate; | ||
341 | CHAR* samplename; /* name of the sample */ | ||
342 | |||
343 | /* Values used internally only */ | ||
344 | UWORD avibpos; /* autovibrato pos [player use] */ | ||
345 | UBYTE divfactor; /* for sample scaling, maintains proper period slides */ | ||
346 | ULONG seekpos; /* seek position in file */ | ||
347 | SWORD handle; /* sample handle used by individual drivers */ | ||
348 | void (*onfree)(void *ctx); /* called from Sample_Free if not NULL */ | ||
349 | void *ctx; /* context passed to previous function*/ | ||
350 | } SAMPLE; | ||
351 | |||
352 | /* Sample functions */ | ||
353 | |||
354 | MIKMODAPI extern SAMPLE *Sample_LoadRaw(CHAR *,ULONG rate, ULONG channel, ULONG flags); | ||
355 | MIKMODAPI extern SAMPLE *Sample_LoadRawFP(int fp,ULONG rate,ULONG channel, ULONG flags); | ||
356 | MIKMODAPI extern SAMPLE *Sample_LoadRawMem(const char *buf, int len, ULONG rate, ULONG channel, ULONG flags); | ||
357 | MIKMODAPI extern SAMPLE *Sample_LoadRawGeneric(MREADER*reader,ULONG rate, ULONG channel, ULONG flags); | ||
358 | |||
359 | MIKMODAPI extern SAMPLE *Sample_Load(CHAR*); | ||
360 | MIKMODAPI extern SAMPLE *Sample_LoadFP(int); | ||
361 | MIKMODAPI extern SAMPLE *Sample_LoadMem(const char *buf, int len); | ||
362 | MIKMODAPI extern SAMPLE *Sample_LoadGeneric(MREADER*); | ||
363 | MIKMODAPI extern void Sample_Free(SAMPLE*); | ||
364 | MIKMODAPI extern SBYTE Sample_Play(SAMPLE*,ULONG,UBYTE); | ||
365 | |||
366 | MIKMODAPI extern void Voice_SetVolume(SBYTE,UWORD); | ||
367 | MIKMODAPI extern UWORD Voice_GetVolume(SBYTE); | ||
368 | MIKMODAPI extern void Voice_SetFrequency(SBYTE,ULONG); | ||
369 | MIKMODAPI extern ULONG Voice_GetFrequency(SBYTE); | ||
370 | MIKMODAPI extern void Voice_SetPanning(SBYTE,ULONG); | ||
371 | MIKMODAPI extern ULONG Voice_GetPanning(SBYTE); | ||
372 | MIKMODAPI extern void Voice_Play(SBYTE,SAMPLE*,ULONG); | ||
373 | MIKMODAPI extern void Voice_Stop(SBYTE); | ||
374 | MIKMODAPI extern int Voice_Stopped(SBYTE); | ||
375 | MIKMODAPI extern SLONG Voice_GetPosition(SBYTE); | ||
376 | MIKMODAPI extern ULONG Voice_RealVolume(SBYTE); | ||
377 | |||
378 | /* | ||
379 | * ========== Internal module representation (UniMod) | ||
380 | */ | ||
381 | |||
382 | /* | ||
383 | Instrument definition - for information only, the only field which may be | ||
384 | of use in user programs is the name field | ||
385 | */ | ||
386 | |||
387 | /* Instrument note count */ | ||
388 | #define INSTNOTES 120 | ||
389 | |||
390 | /* Envelope point */ | ||
391 | typedef struct ENVPT { | ||
392 | SWORD pos; | ||
393 | SWORD val; | ||
394 | } ENVPT; | ||
395 | |||
396 | /* Envelope point count */ | ||
397 | #define ENVPOINTS 32 | ||
398 | |||
399 | /* Instrument structure */ | ||
400 | typedef struct INSTRUMENT { | ||
401 | CHAR* insname; | ||
402 | |||
403 | UBYTE flags; | ||
404 | UWORD samplenumber[INSTNOTES]; | ||
405 | UBYTE samplenote[INSTNOTES]; | ||
406 | |||
407 | UBYTE nnatype; | ||
408 | UBYTE dca; /* duplicate check action */ | ||
409 | UBYTE dct; /* duplicate check type */ | ||
410 | UBYTE globvol; | ||
411 | UWORD volfade; | ||
412 | SWORD panning; /* instrument-based panning var */ | ||
413 | |||
414 | UBYTE pitpansep; /* pitch pan separation (0 to 255) */ | ||
415 | UBYTE pitpancenter; /* pitch pan center (0 to 119) */ | ||
416 | UBYTE rvolvar; /* random volume varations (0 - 100%) */ | ||
417 | UBYTE rpanvar; /* random panning varations (0 - 100%) */ | ||
418 | |||
419 | /* volume envelope */ | ||
420 | UBYTE volflg; /* bit 0: on 1: sustain 2: loop */ | ||
421 | UBYTE volpts; | ||
422 | UBYTE volsusbeg; | ||
423 | UBYTE volsusend; | ||
424 | UBYTE volbeg; | ||
425 | UBYTE volend; | ||
426 | ENVPT volenv[ENVPOINTS]; | ||
427 | /* panning envelope */ | ||
428 | UBYTE panflg; /* bit 0: on 1: sustain 2: loop */ | ||
429 | UBYTE panpts; | ||
430 | UBYTE pansusbeg; | ||
431 | UBYTE pansusend; | ||
432 | UBYTE panbeg; | ||
433 | UBYTE panend; | ||
434 | ENVPT panenv[ENVPOINTS]; | ||
435 | /* pitch envelope */ | ||
436 | UBYTE pitflg; /* bit 0: on 1: sustain 2: loop */ | ||
437 | UBYTE pitpts; | ||
438 | UBYTE pitsusbeg; | ||
439 | UBYTE pitsusend; | ||
440 | UBYTE pitbeg; | ||
441 | UBYTE pitend; | ||
442 | ENVPT pitenv[ENVPOINTS]; | ||
443 | } INSTRUMENT; | ||
444 | |||
445 | struct MP_CONTROL; | ||
446 | struct MP_VOICE; | ||
447 | |||
448 | /* | ||
449 | Module definition | ||
450 | */ | ||
451 | |||
452 | /* maximum master channels supported */ | ||
453 | #define UF_MAXCHAN 64 | ||
454 | |||
455 | /* Module flags */ | ||
456 | #define UF_XMPERIODS 0x0001 /* XM periods / finetuning */ | ||
457 | #define UF_LINEAR 0x0002 /* LINEAR periods (UF_XMPERIODS must be set) */ | ||
458 | #define UF_INST 0x0004 /* Instruments are used */ | ||
459 | #define UF_NNA 0x0008 /* IT: NNA used, set numvoices rather | ||
460 | than numchn */ | ||
461 | #define UF_S3MSLIDES 0x0010 /* uses old S3M volume slides */ | ||
462 | #define UF_BGSLIDES 0x0020 /* continue volume slides in the background */ | ||
463 | #define UF_HIGHBPM 0x0040 /* MED: can use >255 bpm */ | ||
464 | #define UF_NOWRAP 0x0080 /* XM-type (i.e. illogical) pattern break | ||
465 | semantics */ | ||
466 | #define UF_ARPMEM 0x0100 /* IT: need arpeggio memory */ | ||
467 | #define UF_FT2QUIRKS 0x0200 /* emulate some FT2 replay quirks */ | ||
468 | #define UF_PANNING 0x0400 /* module uses panning effects or have | ||
469 | non-tracker default initial panning */ | ||
470 | |||
471 | typedef struct MODULE { | ||
472 | /* general module information */ | ||
473 | CHAR* songname; /* name of the song */ | ||
474 | CHAR* modtype; /* string type of module loaded */ | ||
475 | CHAR* comment; /* module comments */ | ||
476 | |||
477 | UWORD flags; /* See module flags above */ | ||
478 | UBYTE numchn; /* number of module channels */ | ||
479 | UBYTE numvoices; /* max # voices used for full NNA playback */ | ||
480 | UWORD numpos; /* number of positions in this song */ | ||
481 | UWORD numpat; /* number of patterns in this song */ | ||
482 | UWORD numins; /* number of instruments */ | ||
483 | UWORD numsmp; /* number of samples */ | ||
484 | struct INSTRUMENT* instruments; /* all instruments */ | ||
485 | struct SAMPLE* samples; /* all samples */ | ||
486 | UBYTE realchn; /* real number of channels used */ | ||
487 | UBYTE totalchn; /* total number of channels used (incl NNAs) */ | ||
488 | |||
489 | /* playback settings */ | ||
490 | UWORD reppos; /* restart position */ | ||
491 | UBYTE initspeed; /* initial song speed */ | ||
492 | UWORD inittempo; /* initial song tempo */ | ||
493 | UBYTE initvolume; /* initial global volume (0 - 128) */ | ||
494 | UWORD panning[UF_MAXCHAN]; /* panning positions */ | ||
495 | UBYTE chanvol[UF_MAXCHAN]; /* channel positions */ | ||
496 | UWORD bpm; /* current beats-per-minute speed */ | ||
497 | UWORD sngspd; /* current song speed */ | ||
498 | SWORD volume; /* song volume (0-128) (or user volume) */ | ||
499 | |||
500 | int extspd; /* extended speed flag (default enabled) */ | ||
501 | int panflag; /* panning flag (default enabled) */ | ||
502 | int wrap; /* wrap module ? (default disabled) */ | ||
503 | int loop; /* allow module to loop ? (default enabled) */ | ||
504 | int fadeout; /* volume fade out during last pattern */ | ||
505 | |||
506 | UWORD patpos; /* current row number */ | ||
507 | SWORD sngpos; /* current song position */ | ||
508 | ULONG sngtime; /* current song time in 2^-10 seconds */ | ||
509 | |||
510 | SWORD relspd; /* relative speed factor */ | ||
511 | |||
512 | /* internal module representation */ | ||
513 | UWORD numtrk; /* number of tracks */ | ||
514 | UBYTE** tracks; /* array of numtrk pointers to tracks */ | ||
515 | UWORD* patterns; /* array of Patterns */ | ||
516 | UWORD* pattrows; /* array of number of rows for each pattern */ | ||
517 | UWORD* positions; /* all positions */ | ||
518 | |||
519 | int forbid; /* if true, no player update! */ | ||
520 | UWORD numrow; /* number of rows on current pattern */ | ||
521 | UWORD vbtick; /* tick counter (counts from 0 to sngspd) */ | ||
522 | UWORD sngremainder;/* used for song time computation */ | ||
523 | |||
524 | struct MP_CONTROL* control; /* Effects Channel info (size pf->numchn) */ | ||
525 | struct MP_VOICE* voice; /* Audio Voice information (size md_numchn) */ | ||
526 | |||
527 | UBYTE globalslide; /* global volume slide rate */ | ||
528 | UBYTE pat_repcrazy;/* module has just looped to position -1 */ | ||
529 | UWORD patbrk; /* position where to start a new pattern */ | ||
530 | UBYTE patdly; /* patterndelay counter (command memory) */ | ||
531 | UBYTE patdly2; /* patterndelay counter (real one) */ | ||
532 | SWORD posjmp; /* flag to indicate a jump is needed... */ | ||
533 | UWORD bpmlimit; /* threshold to detect bpm or speed values */ | ||
534 | } MODULE; | ||
535 | |||
536 | |||
537 | /* This structure is used to query current playing voices status */ | ||
538 | typedef struct VOICEINFO { | ||
539 | INSTRUMENT* i; /* Current channel instrument */ | ||
540 | SAMPLE* s; /* Current channel sample */ | ||
541 | SWORD panning; /* panning position */ | ||
542 | SBYTE volume; /* channel's "global" volume (0..64) */ | ||
543 | UWORD period; /* period to play the sample at */ | ||
544 | UBYTE kick; /* if true = sample has been restarted */ | ||
545 | } VOICEINFO; | ||
546 | |||
547 | /* | ||
548 | * ========== Module loaders | ||
549 | */ | ||
550 | |||
551 | struct MLOADER; | ||
552 | |||
553 | MIKMODAPI extern CHAR* MikMod_InfoLoader(void); | ||
554 | MIKMODAPI extern void MikMod_RegisterAllLoaders(void); | ||
555 | MIKMODAPI extern void MikMod_RegisterLoader(struct MLOADER*); | ||
556 | |||
557 | MIKMODAPI extern struct MLOADER load_669; /* 669 and Extended-669 (by Tran/Renaissance) */ | ||
558 | MIKMODAPI extern struct MLOADER load_amf; /* DMP Advanced Module Format (by Otto Chrons) */ | ||
559 | MIKMODAPI extern struct MLOADER load_asy; /* ASYLUM Music Format 1.0 */ | ||
560 | MIKMODAPI extern struct MLOADER load_dsm; /* DSIK internal module format */ | ||
561 | MIKMODAPI extern struct MLOADER load_far; /* Farandole Composer (by Daniel Potter) */ | ||
562 | MIKMODAPI extern struct MLOADER load_gdm; /* General DigiMusic (by Edward Schlunder) */ | ||
563 | MIKMODAPI extern struct MLOADER load_gt2; /* Graoumf tracker */ | ||
564 | MIKMODAPI extern struct MLOADER load_it; /* Impulse Tracker (by Jeffrey Lim) */ | ||
565 | MIKMODAPI extern struct MLOADER load_imf; /* Imago Orpheus (by Lutz Roeder) */ | ||
566 | MIKMODAPI extern struct MLOADER load_med; /* Amiga MED modules (by Teijo Kinnunen) */ | ||
567 | MIKMODAPI extern struct MLOADER load_m15; /* Soundtracker 15-instrument */ | ||
568 | MIKMODAPI extern struct MLOADER load_mod; /* Standard 31-instrument Module loader */ | ||
569 | MIKMODAPI extern struct MLOADER load_mtm; /* Multi-Tracker Module (by Renaissance) */ | ||
570 | MIKMODAPI extern struct MLOADER load_okt; /* Amiga Oktalyzer */ | ||
571 | MIKMODAPI extern struct MLOADER load_stm; /* ScreamTracker 2 (by Future Crew) */ | ||
572 | MIKMODAPI extern struct MLOADER load_stx; /* STMIK 0.2 (by Future Crew) */ | ||
573 | MIKMODAPI extern struct MLOADER load_s3m; /* ScreamTracker 3 (by Future Crew) */ | ||
574 | MIKMODAPI extern struct MLOADER load_ult; /* UltraTracker (by MAS) */ | ||
575 | MIKMODAPI extern struct MLOADER load_uni; /* MikMod and APlayer internal module format */ | ||
576 | MIKMODAPI extern struct MLOADER load_xm; /* FastTracker 2 (by Triton) */ | ||
577 | |||
578 | /* | ||
579 | * ========== Module player | ||
580 | */ | ||
581 | |||
582 | MIKMODAPI extern MODULE* Player_Load(CHAR*,int,int); | ||
583 | MIKMODAPI extern MODULE* Player_LoadFP(int,int,int); | ||
584 | MIKMODAPI extern MODULE* Player_LoadMem(const char *buffer,int len,int maxchan,int curious); | ||
585 | MIKMODAPI extern MODULE* Player_LoadGeneric(MREADER*,int,int); | ||
586 | MIKMODAPI extern CHAR* Player_LoadTitle(CHAR*); | ||
587 | MIKMODAPI extern CHAR* Player_LoadTitleFP(int); | ||
588 | MIKMODAPI extern CHAR* Player_LoadTitleMem(const char *buffer,int len); | ||
589 | MIKMODAPI extern CHAR* Player_LoadTitleGeneric(MREADER*); | ||
590 | |||
591 | MIKMODAPI extern void Player_Free(MODULE*); | ||
592 | MIKMODAPI extern void Player_Start(MODULE*); | ||
593 | MIKMODAPI extern int Player_Active(void); | ||
594 | MIKMODAPI extern void Player_Stop(void); | ||
595 | MIKMODAPI extern void Player_TogglePause(void); | ||
596 | MIKMODAPI extern int Player_Paused(void); | ||
597 | MIKMODAPI extern void Player_NextPosition(void); | ||
598 | MIKMODAPI extern void Player_PrevPosition(void); | ||
599 | MIKMODAPI extern void Player_SetPosition(UWORD); | ||
600 | MIKMODAPI extern int Player_Muted(UBYTE); | ||
601 | MIKMODAPI extern void Player_SetVolume(SWORD); | ||
602 | MIKMODAPI extern MODULE* Player_GetModule(void); | ||
603 | MIKMODAPI extern void Player_SetSpeed(UWORD); | ||
604 | MIKMODAPI extern void Player_SetTempo(UWORD); | ||
605 | MIKMODAPI extern void Player_Unmute(SLONG,...); | ||
606 | MIKMODAPI extern void Player_Mute(SLONG,...); | ||
607 | MIKMODAPI extern void Player_ToggleMute(SLONG,...); | ||
608 | MIKMODAPI extern int Player_GetChannelVoice(UBYTE); | ||
609 | MIKMODAPI extern UWORD Player_GetChannelPeriod(UBYTE); | ||
610 | MIKMODAPI extern int Player_QueryVoices(UWORD numvoices, VOICEINFO *vinfo); | ||
611 | MIKMODAPI extern int Player_GetRow(void); | ||
612 | MIKMODAPI extern int Player_GetOrder(void); | ||
613 | |||
614 | typedef void (*MikMod_player_t)(void); | ||
615 | typedef void (*MikMod_callback_t)(unsigned char *data, size_t len); | ||
616 | |||
617 | MIKMODAPI extern MikMod_player_t MikMod_RegisterPlayer(MikMod_player_t); | ||
618 | |||
619 | #define MUTE_EXCLUSIVE 32000 | ||
620 | #define MUTE_INCLUSIVE 32001 | ||
621 | |||
622 | /* | ||
623 | * ========== Drivers | ||
624 | */ | ||
625 | |||
626 | enum { | ||
627 | MD_MUSIC = 0, | ||
628 | MD_SNDFX | ||
629 | }; | ||
630 | |||
631 | enum { | ||
632 | MD_HARDWARE = 0, | ||
633 | MD_SOFTWARE | ||
634 | }; | ||
635 | |||
636 | /* Mixing flags */ | ||
637 | |||
638 | /* These ones take effect only after MikMod_Init or MikMod_Reset */ | ||
639 | #define DMODE_16BITS 0x0001 /* enable 16 bit output */ | ||
640 | #define DMODE_STEREO 0x0002 /* enable stereo output */ | ||
641 | #define DMODE_SOFT_SNDFX 0x0004 /* Process sound effects via software mixer */ | ||
642 | #define DMODE_SOFT_MUSIC 0x0008 /* Process music via software mixer */ | ||
643 | #define DMODE_HQMIXER 0x0010 /* Use high-quality (slower) software mixer */ | ||
644 | #define DMODE_FLOAT 0x0020 /* enable float output */ | ||
645 | /* These take effect immediately. */ | ||
646 | #define DMODE_SURROUND 0x0100 /* enable surround sound */ | ||
647 | #define DMODE_INTERP 0x0200 /* enable interpolation */ | ||
648 | #define DMODE_REVERSE 0x0400 /* reverse stereo */ | ||
649 | #define DMODE_SIMDMIXER 0x0800 /* enable SIMD mixing */ | ||
650 | #define DMODE_NOISEREDUCTION 0x1000 /* Low pass filtering */ | ||
651 | |||
652 | struct SAMPLOAD; | ||
653 | typedef struct MDRIVER { | ||
654 | struct MDRIVER* next; | ||
655 | CHAR* Name; | ||
656 | CHAR* Version; | ||
657 | |||
658 | UBYTE HardVoiceLimit; /* Limit of hardware mixer voices */ | ||
659 | UBYTE SoftVoiceLimit; /* Limit of software mixer voices */ | ||
660 | |||
661 | CHAR *Alias; | ||
662 | CHAR *CmdLineHelp; | ||
663 | |||
664 | void (*CommandLine) (CHAR*); | ||
665 | int (*IsPresent) (void); | ||
666 | SWORD (*SampleLoad) (struct SAMPLOAD*,int); | ||
667 | void (*SampleUnload) (SWORD); | ||
668 | ULONG (*FreeSampleSpace) (int); | ||
669 | ULONG (*RealSampleLength) (int,struct SAMPLE*); | ||
670 | int (*Init) (void); | ||
671 | void (*Exit) (void); | ||
672 | int (*Reset) (void); | ||
673 | int (*SetNumVoices) (void); | ||
674 | int (*PlayStart) (void); | ||
675 | void (*PlayStop) (void); | ||
676 | void (*Update) (void); | ||
677 | void (*Pause) (void); | ||
678 | void (*VoiceSetVolume) (UBYTE,UWORD); | ||
679 | UWORD (*VoiceGetVolume) (UBYTE); | ||
680 | void (*VoiceSetFrequency)(UBYTE,ULONG); | ||
681 | ULONG (*VoiceGetFrequency)(UBYTE); | ||
682 | void (*VoiceSetPanning) (UBYTE,ULONG); | ||
683 | ULONG (*VoiceGetPanning) (UBYTE); | ||
684 | void (*VoicePlay) (UBYTE,SWORD,ULONG,ULONG,ULONG,ULONG,UWORD); | ||
685 | void (*VoiceStop) (UBYTE); | ||
686 | int (*VoiceStopped) (UBYTE); | ||
687 | SLONG (*VoiceGetPosition) (UBYTE); | ||
688 | ULONG (*VoiceRealVolume) (UBYTE); | ||
689 | } MDRIVER; | ||
690 | |||
691 | /* These variables can be changed at ANY time and results will be immediate */ | ||
692 | MIKMODAPI extern UBYTE md_volume; /* global sound volume (0-128) */ | ||
693 | MIKMODAPI extern UBYTE md_musicvolume; /* volume of song */ | ||
694 | MIKMODAPI extern UBYTE md_sndfxvolume; /* volume of sound effects */ | ||
695 | MIKMODAPI extern UBYTE md_reverb; /* 0 = none; 15 = chaos */ | ||
696 | MIKMODAPI extern UBYTE md_pansep; /* 0 = mono; 128 == 100% (full left/right) */ | ||
697 | |||
698 | /* The variables below can be changed at any time, but changes will not be | ||
699 | implemented until MikMod_Reset is called. A call to MikMod_Reset may result | ||
700 | in a skip or pop in audio (depending on the soundcard driver and the settings | ||
701 | changed). */ | ||
702 | MIKMODAPI extern UWORD md_device; /* device */ | ||
703 | MIKMODAPI extern UWORD md_mixfreq; /* mixing frequency */ | ||
704 | MIKMODAPI extern UWORD md_mode; /* mode. See DMODE_? flags above */ | ||
705 | |||
706 | /* The following variable should not be changed! */ | ||
707 | MIKMODAPI extern MDRIVER* md_driver; /* Current driver in use. */ | ||
708 | |||
709 | /* Known drivers list */ | ||
710 | |||
711 | MIKMODAPI extern struct MDRIVER drv_nos; /* no sound */ | ||
712 | #if 0 | ||
713 | MIKMODAPI extern struct MDRIVER drv_pipe; /* piped output */ | ||
714 | MIKMODAPI extern struct MDRIVER drv_raw; /* raw file disk writer [music.raw] */ | ||
715 | MIKMODAPI extern struct MDRIVER drv_stdout; /* output to stdout */ | ||
716 | MIKMODAPI extern struct MDRIVER drv_wav; /* RIFF WAVE file disk writer [music.wav] */ | ||
717 | MIKMODAPI extern struct MDRIVER drv_aiff; /* AIFF file disk writer [music.aiff] */ | ||
718 | |||
719 | MIKMODAPI extern struct MDRIVER drv_ultra; /* Linux Ultrasound driver */ | ||
720 | MIKMODAPI extern struct MDRIVER drv_sam9407; /* Linux sam9407 driver */ | ||
721 | |||
722 | MIKMODAPI extern struct MDRIVER drv_AF; /* Dec Alpha AudioFile */ | ||
723 | MIKMODAPI extern struct MDRIVER drv_aix; /* AIX audio device */ | ||
724 | MIKMODAPI extern struct MDRIVER drv_alsa; /* Advanced Linux Sound Architecture (ALSA) */ | ||
725 | MIKMODAPI extern struct MDRIVER drv_esd; /* Enlightened sound daemon (EsounD) */ | ||
726 | MIKMODAPI extern struct MDRIVER drv_hp; /* HP-UX audio device */ | ||
727 | MIKMODAPI extern struct MDRIVER drv_nas; /* Network Audio System (NAS) */ | ||
728 | MIKMODAPI extern struct MDRIVER drv_oss; /* OpenSound System (Linux,FreeBSD...) */ | ||
729 | MIKMODAPI extern struct MDRIVER drv_sgi; /* SGI audio library */ | ||
730 | MIKMODAPI extern struct MDRIVER drv_sun; /* Sun/NetBSD/OpenBSD audio device */ | ||
731 | |||
732 | MIKMODAPI extern struct MDRIVER drv_dart; /* OS/2 Direct Audio RealTime */ | ||
733 | MIKMODAPI extern struct MDRIVER drv_os2; /* OS/2 MMPM/2 */ | ||
734 | |||
735 | MIKMODAPI extern struct MDRIVER drv_ds; /* Win32 DirectSound driver */ | ||
736 | MIKMODAPI extern struct MDRIVER drv_win; /* Win32 multimedia API driver */ | ||
737 | |||
738 | MIKMODAPI extern struct MDRIVER drv_mac; /* Macintosh Sound Manager driver */ | ||
739 | MIKMODAPI extern struct MDRIVER drv_osx; /* MacOS X CoreAudio Driver */ | ||
740 | |||
741 | MIKMODAPI extern struct MDRIVER drv_gp32; /* GP32 Sound driver */ | ||
742 | |||
743 | MIKMODAPI extern struct MDRIVER drv_wss; /* DOS WSS driver */ | ||
744 | MIKMODAPI extern struct MDRIVER drv_sb; /* DOS SB driver */ | ||
745 | #endif | ||
746 | /*========== Virtual channel mixer interface (for user-supplied drivers only) */ | ||
747 | |||
748 | MIKMODAPI extern int VC_Init(void); | ||
749 | MIKMODAPI extern void VC_Exit(void); | ||
750 | MIKMODAPI extern void VC_SetCallback(MikMod_callback_t callback); | ||
751 | MIKMODAPI extern int VC_SetNumVoices(void); | ||
752 | MIKMODAPI extern ULONG VC_SampleSpace(int); | ||
753 | MIKMODAPI extern ULONG VC_SampleLength(int,SAMPLE*); | ||
754 | |||
755 | MIKMODAPI extern int VC_PlayStart(void); | ||
756 | MIKMODAPI extern void VC_PlayStop(void); | ||
757 | |||
758 | MIKMODAPI extern SWORD VC_SampleLoad(struct SAMPLOAD*,int); | ||
759 | MIKMODAPI extern void VC_SampleUnload(SWORD); | ||
760 | |||
761 | MIKMODAPI extern ULONG VC_WriteBytes(SBYTE*,ULONG); | ||
762 | MIKMODAPI extern ULONG VC_SilenceBytes(SBYTE*,ULONG); | ||
763 | |||
764 | MIKMODAPI extern void VC_VoiceSetVolume(UBYTE,UWORD); | ||
765 | MIKMODAPI extern UWORD VC_VoiceGetVolume(UBYTE); | ||
766 | MIKMODAPI extern void VC_VoiceSetFrequency(UBYTE,ULONG); | ||
767 | MIKMODAPI extern ULONG VC_VoiceGetFrequency(UBYTE); | ||
768 | MIKMODAPI extern void VC_VoiceSetPanning(UBYTE,ULONG); | ||
769 | MIKMODAPI extern ULONG VC_VoiceGetPanning(UBYTE); | ||
770 | MIKMODAPI extern void VC_VoicePlay(UBYTE,SWORD,ULONG,ULONG,ULONG,ULONG,UWORD); | ||
771 | |||
772 | MIKMODAPI extern void VC_VoiceStop(UBYTE); | ||
773 | MIKMODAPI extern int VC_VoiceStopped(UBYTE); | ||
774 | MIKMODAPI extern SLONG VC_VoiceGetPosition(UBYTE); | ||
775 | MIKMODAPI extern ULONG VC_VoiceRealVolume(UBYTE); | ||
776 | |||
777 | #ifdef __cplusplus | ||
778 | } | ||
779 | #endif | ||
780 | |||
781 | #endif | ||
782 | |||
783 | /* ex:set ts=4: */ | ||
diff --git a/apps/plugins/mikmod/mikmod.make b/apps/plugins/mikmod/mikmod.make new file mode 100644 index 0000000000..112c25dda1 --- /dev/null +++ b/apps/plugins/mikmod/mikmod.make | |||
@@ -0,0 +1,33 @@ | |||
1 | # __________ __ ___. | ||
2 | # Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
3 | # Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
4 | # Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
5 | # Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
6 | # \/ \/ \/ \/ \/ | ||
7 | # $Id: Makefile 19082 2008-11-10 23:54:24Z zagor $ | ||
8 | # | ||
9 | |||
10 | MIKMODSRCDIR := $(APPSDIR)/plugins/mikmod | ||
11 | MIKMODBUILDDIR := $(BUILDDIR)/apps/plugins/mikmod | ||
12 | |||
13 | ROCKS += $(MIKMODBUILDDIR)/mikmod.rock | ||
14 | |||
15 | MIKMOD_SRC := $(call preprocess, $(MIKMODSRCDIR)/SOURCES) | ||
16 | MIKMOD_OBJ := $(call c2obj, $(MIKMOD_SRC)) | ||
17 | |||
18 | # add source files to OTHER_SRC to get automatic dependencies | ||
19 | OTHER_SRC += $(MIKMOD_SRC) | ||
20 | |||
21 | MIKMODCFLAGS = $(PLUGINFLAGS) -I$(MIKMODSRCDIR) -w | ||
22 | ifeq ($(CPU),coldfire) | ||
23 | MIKMODCFLAGS += -O0 | ||
24 | else | ||
25 | MIKMODCFLAGS += -O2 | ||
26 | endif | ||
27 | |||
28 | $(MIKMODBUILDDIR)/mikmod.rock: $(MIKMOD_OBJ) $(CODECDIR)/libtlsf.a | ||
29 | |||
30 | # new rule needed to use extra compile flags | ||
31 | $(MIKMODBUILDDIR)/%.o: $(MIKMODSRCDIR)/%.c | ||
32 | $(SILENT)mkdir -p $(dir $@) | ||
33 | $(call PRINTS,CC $(subst $(ROOTDIR)/,,$<))$(CC) $(MIKMODCFLAGS) -c $< -o $@ | ||
diff --git a/apps/plugins/mikmod/mikmod_internals.h b/apps/plugins/mikmod/mikmod_internals.h new file mode 100644 index 0000000000..284dd85936 --- /dev/null +++ b/apps/plugins/mikmod/mikmod_internals.h | |||
@@ -0,0 +1,806 @@ | |||
1 | /* MikMod sound library | ||
2 | (c) 1998, 1999, 2005 Miodrag Vallat and others - see file AUTHORS for | ||
3 | 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: mikmod_internals.h,v 1.7 2010/01/12 03:30:31 realtech Exp $ | ||
24 | |||
25 | MikMod sound library internal definitions | ||
26 | |||
27 | ==============================================================================*/ | ||
28 | |||
29 | #ifndef _MIKMOD_INTERNALS_H | ||
30 | #define _MIKMOD_INTERNALS_H | ||
31 | |||
32 | #ifdef __cplusplus | ||
33 | extern "C" { | ||
34 | #endif | ||
35 | |||
36 | #include <stdarg.h> | ||
37 | #if 0 | ||
38 | #if defined(__OS2__)||defined(__EMX__)||defined(WIN32) | ||
39 | #define strcasecmp(s,t) stricmp(s,t) | ||
40 | #endif | ||
41 | #endif | ||
42 | |||
43 | #include "mikmod.h" | ||
44 | |||
45 | /*========== More type definitions */ | ||
46 | |||
47 | /* SLONGLONG: 64bit, signed */ | ||
48 | #if defined (__arch64__) || defined(__alpha) || defined (__x64_64) || defined (_LP64) || defined (__powerpc64__) | ||
49 | typedef long SLONGLONG; | ||
50 | #define NATIVE_64BIT_INT | ||
51 | #if 0 | ||
52 | #elif defined(__WATCOMC__) | ||
53 | typedef __int64 SLONGLONG; | ||
54 | #elif defined(WIN32) && !defined(__MWERKS__) | ||
55 | typedef LONGLONG SLONGLONG; | ||
56 | #elif macintosh && !TYPE_LONGLONG | ||
57 | #include <Types.h> | ||
58 | typedef SInt64 SLONGLONG; | ||
59 | #endif | ||
60 | #else | ||
61 | typedef long long SLONGLONG; | ||
62 | #endif | ||
63 | |||
64 | /*========== Error handling */ | ||
65 | |||
66 | #define _mm_errno MikMod_errno | ||
67 | #define _mm_critical MikMod_critical | ||
68 | extern MikMod_handler_t _mm_errorhandler; | ||
69 | |||
70 | /*========== MT stuff */ | ||
71 | |||
72 | #ifdef HAVE_PTHREAD | ||
73 | #include <pthread.h> | ||
74 | #define DECLARE_MUTEX(name) \ | ||
75 | extern pthread_mutex_t _mm_mutex_##name | ||
76 | #define MUTEX_LOCK(name) \ | ||
77 | pthread_mutex_lock(&_mm_mutex_##name) | ||
78 | #define MUTEX_UNLOCK(name) \ | ||
79 | pthread_mutex_unlock(&_mm_mutex_##name) | ||
80 | #elif defined(__OS2__)||defined(__EMX__) | ||
81 | #define DECLARE_MUTEX(name) \ | ||
82 | extern HMTX _mm_mutex_##name | ||
83 | #define MUTEX_LOCK(name) \ | ||
84 | if(_mm_mutex_##name) \ | ||
85 | DosRequestMutexSem(_mm_mutex_##name,SEM_INDEFINITE_WAIT) | ||
86 | #define MUTEX_UNLOCK(name) \ | ||
87 | if(_mm_mutex_##name) \ | ||
88 | DosReleaseMutexSem(_mm_mutex_##name) | ||
89 | #elif defined(WIN32) | ||
90 | #include <windows.h> | ||
91 | #define DECLARE_MUTEX(name) \ | ||
92 | extern HANDLE _mm_mutex_##name | ||
93 | #define MUTEX_LOCK(name) \ | ||
94 | if(_mm_mutex_##name) \ | ||
95 | WaitForSingleObject(_mm_mutex_##name,INFINITE) | ||
96 | #define MUTEX_UNLOCK(name) \ | ||
97 | if(_mm_mutex_##name) \ | ||
98 | ReleaseMutex(_mm_mutex_##name) | ||
99 | #else | ||
100 | #define DECLARE_MUTEX(name) \ | ||
101 | extern void *_mm_mutex_##name | ||
102 | #define MUTEX_LOCK(name) | ||
103 | #define MUTEX_UNLOCK(name) | ||
104 | #endif | ||
105 | |||
106 | DECLARE_MUTEX(lists); | ||
107 | DECLARE_MUTEX(vars); | ||
108 | |||
109 | /*========== Portable file I/O */ | ||
110 | |||
111 | extern MREADER* _mm_new_mem_reader(const void *buffer, int len); | ||
112 | extern void _mm_delete_mem_reader(MREADER *reader); | ||
113 | |||
114 | extern MREADER* _mm_new_file_reader(int fp); | ||
115 | extern void _mm_delete_file_reader(MREADER*); | ||
116 | |||
117 | extern MWRITER* _mm_new_file_writer(int fp); | ||
118 | extern void _mm_delete_file_writer(MWRITER*); | ||
119 | |||
120 | extern int _mm_FileExists(CHAR *fname); | ||
121 | |||
122 | #define _mm_write_SBYTE(x,y) y->Put(y,(int)x) | ||
123 | #define _mm_write_UBYTE(x,y) y->Put(y,(int)x) | ||
124 | |||
125 | #define _mm_read_SBYTE(x) (SBYTE)x->Get(x) | ||
126 | #define _mm_read_UBYTE(x) (UBYTE)x->Get(x) | ||
127 | |||
128 | #define _mm_write_SBYTES(x,y,z) z->Write(z,(void *)x,y) | ||
129 | #define _mm_write_UBYTES(x,y,z) z->Write(z,(void *)x,y) | ||
130 | #define _mm_read_SBYTES(x,y,z) z->Read(z,(void *)x,y) | ||
131 | #define _mm_read_UBYTES(x,y,z) z->Read(z,(void *)x,y) | ||
132 | |||
133 | #define _mm_fseek(x,y,z) x->Seek(x,y,z) | ||
134 | #define _mm_ftell(x) x->Tell(x) | ||
135 | #define _mm_rewind(x) _mm_fseek(x,0,SEEK_SET) | ||
136 | |||
137 | #define _mm_eof(x) x->Eof(x) | ||
138 | |||
139 | extern void _mm_iobase_setcur(MREADER*); | ||
140 | extern void _mm_iobase_revert(MREADER*); | ||
141 | extern int _mm_fopen(CHAR*,CHAR*); | ||
142 | extern int _mm_fclose(int); | ||
143 | extern void _mm_write_string(CHAR*,MWRITER*); | ||
144 | extern int _mm_read_string (CHAR*,int,MREADER*); | ||
145 | |||
146 | extern SWORD _mm_read_M_SWORD(MREADER*); | ||
147 | extern SWORD _mm_read_I_SWORD(MREADER*); | ||
148 | extern UWORD _mm_read_M_UWORD(MREADER*); | ||
149 | extern UWORD _mm_read_I_UWORD(MREADER*); | ||
150 | |||
151 | extern SLONG _mm_read_M_SLONG(MREADER*); | ||
152 | extern SLONG _mm_read_I_SLONG(MREADER*); | ||
153 | extern ULONG _mm_read_M_ULONG(MREADER*); | ||
154 | extern ULONG _mm_read_I_ULONG(MREADER*); | ||
155 | |||
156 | extern int _mm_read_M_SWORDS(SWORD*,int,MREADER*); | ||
157 | extern int _mm_read_I_SWORDS(SWORD*,int,MREADER*); | ||
158 | extern int _mm_read_M_UWORDS(UWORD*,int,MREADER*); | ||
159 | extern int _mm_read_I_UWORDS(UWORD*,int,MREADER*); | ||
160 | |||
161 | extern int _mm_read_M_SLONGS(SLONG*,int,MREADER*); | ||
162 | extern int _mm_read_I_SLONGS(SLONG*,int,MREADER*); | ||
163 | extern int _mm_read_M_ULONGS(ULONG*,int,MREADER*); | ||
164 | extern int _mm_read_I_ULONGS(ULONG*,int,MREADER*); | ||
165 | |||
166 | extern void _mm_write_M_SWORD(SWORD,MWRITER*); | ||
167 | extern void _mm_write_I_SWORD(SWORD,MWRITER*); | ||
168 | extern void _mm_write_M_UWORD(UWORD,MWRITER*); | ||
169 | extern void _mm_write_I_UWORD(UWORD,MWRITER*); | ||
170 | |||
171 | extern void _mm_write_M_SLONG(SLONG,MWRITER*); | ||
172 | extern void _mm_write_I_SLONG(SLONG,MWRITER*); | ||
173 | extern void _mm_write_M_ULONG(ULONG,MWRITER*); | ||
174 | extern void _mm_write_I_ULONG(ULONG,MWRITER*); | ||
175 | |||
176 | extern void _mm_write_M_SWORDS(SWORD*,int,MWRITER*); | ||
177 | extern void _mm_write_I_SWORDS(SWORD*,int,MWRITER*); | ||
178 | extern void _mm_write_M_UWORDS(UWORD*,int,MWRITER*); | ||
179 | extern void _mm_write_I_UWORDS(UWORD*,int,MWRITER*); | ||
180 | |||
181 | extern void _mm_write_M_SLONGS(SLONG*,int,MWRITER*); | ||
182 | extern void _mm_write_I_SLONGS(SLONG*,int,MWRITER*); | ||
183 | extern void _mm_write_M_ULONGS(ULONG*,int,MWRITER*); | ||
184 | extern void _mm_write_I_ULONGS(ULONG*,int,MWRITER*); | ||
185 | |||
186 | /*========== Samples */ | ||
187 | |||
188 | /* This is a handle of sorts attached to any sample registered with | ||
189 | SL_RegisterSample. Generally, this only need be used or changed by the | ||
190 | loaders and drivers of mikmod. */ | ||
191 | typedef struct SAMPLOAD { | ||
192 | struct SAMPLOAD *next; | ||
193 | |||
194 | ULONG length; /* length of sample (in samples!) */ | ||
195 | ULONG loopstart; /* repeat position (relative to start, in samples) */ | ||
196 | ULONG loopend; /* repeat end */ | ||
197 | UWORD infmt,outfmt; | ||
198 | int scalefactor; | ||
199 | SAMPLE* sample; | ||
200 | MREADER* reader; | ||
201 | } SAMPLOAD; | ||
202 | |||
203 | /*========== Sample and waves loading interface */ | ||
204 | |||
205 | extern void SL_HalveSample(SAMPLOAD*,int); | ||
206 | extern void SL_Sample8to16(SAMPLOAD*); | ||
207 | extern void SL_Sample16to8(SAMPLOAD*); | ||
208 | extern void SL_SampleSigned(SAMPLOAD*); | ||
209 | extern void SL_SampleUnsigned(SAMPLOAD*); | ||
210 | extern int SL_LoadSamples(void); | ||
211 | extern SAMPLOAD* SL_RegisterSample(SAMPLE*,int,MREADER*); | ||
212 | extern int SL_Load(void*,SAMPLOAD*,ULONG); | ||
213 | extern int SL_Init(SAMPLOAD*); | ||
214 | extern void SL_Exit(SAMPLOAD*); | ||
215 | |||
216 | /*========== Internal module representation (UniMod) interface */ | ||
217 | |||
218 | /* number of notes in an octave */ | ||
219 | #define OCTAVE 12 | ||
220 | |||
221 | extern void UniSetRow(UBYTE*); | ||
222 | extern UBYTE UniGetByte(void); | ||
223 | extern UWORD UniGetWord(void); | ||
224 | extern UBYTE* UniFindRow(UBYTE*,UWORD); | ||
225 | extern void UniSkipOpcode(void); | ||
226 | extern void UniReset(void); | ||
227 | extern void UniWriteByte(UBYTE); | ||
228 | extern void UniWriteWord(UWORD); | ||
229 | extern void UniNewline(void); | ||
230 | extern UBYTE* UniDup(void); | ||
231 | extern int UniInit(void); | ||
232 | extern void UniCleanup(void); | ||
233 | extern void UniEffect(UWORD,UWORD); | ||
234 | #define UniInstrument(x) UniEffect(UNI_INSTRUMENT,x) | ||
235 | #define UniNote(x) UniEffect(UNI_NOTE,x) | ||
236 | extern void UniPTEffect(UBYTE,UBYTE); | ||
237 | extern void UniVolEffect(UWORD,UBYTE); | ||
238 | |||
239 | /*========== Module Commands */ | ||
240 | |||
241 | enum { | ||
242 | /* Simple note */ | ||
243 | UNI_NOTE = 1, | ||
244 | /* Instrument change */ | ||
245 | UNI_INSTRUMENT, | ||
246 | /* Protracker effects */ | ||
247 | UNI_PTEFFECT0, /* arpeggio */ | ||
248 | UNI_PTEFFECT1, /* porta up */ | ||
249 | UNI_PTEFFECT2, /* porta down */ | ||
250 | UNI_PTEFFECT3, /* porta to note */ | ||
251 | UNI_PTEFFECT4, /* vibrato */ | ||
252 | UNI_PTEFFECT5, /* dual effect 3+A */ | ||
253 | UNI_PTEFFECT6, /* dual effect 4+A */ | ||
254 | UNI_PTEFFECT7, /* tremolo */ | ||
255 | UNI_PTEFFECT8, /* pan */ | ||
256 | UNI_PTEFFECT9, /* sample offset */ | ||
257 | UNI_PTEFFECTA, /* volume slide */ | ||
258 | UNI_PTEFFECTB, /* pattern jump */ | ||
259 | UNI_PTEFFECTC, /* set volume */ | ||
260 | UNI_PTEFFECTD, /* pattern break */ | ||
261 | UNI_PTEFFECTE, /* extended effects */ | ||
262 | UNI_PTEFFECTF, /* set speed */ | ||
263 | /* Scream Tracker effects */ | ||
264 | UNI_S3MEFFECTA, /* set speed */ | ||
265 | UNI_S3MEFFECTD, /* volume slide */ | ||
266 | UNI_S3MEFFECTE, /* porta down */ | ||
267 | UNI_S3MEFFECTF, /* porta up */ | ||
268 | UNI_S3MEFFECTI, /* tremor */ | ||
269 | UNI_S3MEFFECTQ, /* retrig */ | ||
270 | UNI_S3MEFFECTR, /* tremolo */ | ||
271 | UNI_S3MEFFECTT, /* set tempo */ | ||
272 | UNI_S3MEFFECTU, /* fine vibrato */ | ||
273 | UNI_KEYOFF, /* note off */ | ||
274 | /* Fast Tracker effects */ | ||
275 | UNI_KEYFADE, /* note fade */ | ||
276 | UNI_VOLEFFECTS, /* volume column effects */ | ||
277 | UNI_XMEFFECT4, /* vibrato */ | ||
278 | UNI_XMEFFECT6, /* dual effect 4+A */ | ||
279 | UNI_XMEFFECTA, /* volume slide */ | ||
280 | UNI_XMEFFECTE1, /* fine porta up */ | ||
281 | UNI_XMEFFECTE2, /* fine porta down */ | ||
282 | UNI_XMEFFECTEA, /* fine volume slide up */ | ||
283 | UNI_XMEFFECTEB, /* fine volume slide down */ | ||
284 | UNI_XMEFFECTG, /* set global volume */ | ||
285 | UNI_XMEFFECTH, /* global volume slide */ | ||
286 | UNI_XMEFFECTL, /* set envelope position */ | ||
287 | UNI_XMEFFECTP, /* pan slide */ | ||
288 | UNI_XMEFFECTX1, /* extra fine porta up */ | ||
289 | UNI_XMEFFECTX2, /* extra fine porta down */ | ||
290 | /* Impulse Tracker effects */ | ||
291 | UNI_ITEFFECTG, /* porta to note */ | ||
292 | UNI_ITEFFECTH, /* vibrato */ | ||
293 | UNI_ITEFFECTI, /* tremor (xy not incremented) */ | ||
294 | UNI_ITEFFECTM, /* set channel volume */ | ||
295 | UNI_ITEFFECTN, /* slide / fineslide channel volume */ | ||
296 | UNI_ITEFFECTP, /* slide / fineslide channel panning */ | ||
297 | UNI_ITEFFECTT, /* slide tempo */ | ||
298 | UNI_ITEFFECTU, /* fine vibrato */ | ||
299 | UNI_ITEFFECTW, /* slide / fineslide global volume */ | ||
300 | UNI_ITEFFECTY, /* panbrello */ | ||
301 | UNI_ITEFFECTZ, /* resonant filters */ | ||
302 | UNI_ITEFFECTS0, | ||
303 | /* UltraTracker effects */ | ||
304 | UNI_ULTEFFECT9, /* Sample fine offset */ | ||
305 | /* OctaMED effects */ | ||
306 | UNI_MEDSPEED, | ||
307 | UNI_MEDEFFECTF1, /* play note twice */ | ||
308 | UNI_MEDEFFECTF2, /* delay note */ | ||
309 | UNI_MEDEFFECTF3, /* play note three times */ | ||
310 | /* Oktalyzer effects */ | ||
311 | UNI_OKTARP, /* arpeggio */ | ||
312 | |||
313 | UNI_LAST | ||
314 | }; | ||
315 | |||
316 | extern UWORD unioperands[UNI_LAST]; | ||
317 | |||
318 | /* IT / S3M Extended SS effects: */ | ||
319 | enum { | ||
320 | SS_GLISSANDO = 1, | ||
321 | SS_FINETUNE, | ||
322 | SS_VIBWAVE, | ||
323 | SS_TREMWAVE, | ||
324 | SS_PANWAVE, | ||
325 | SS_FRAMEDELAY, | ||
326 | SS_S7EFFECTS, | ||
327 | SS_PANNING, | ||
328 | SS_SURROUND, | ||
329 | SS_HIOFFSET, | ||
330 | SS_PATLOOP, | ||
331 | SS_NOTECUT, | ||
332 | SS_NOTEDELAY, | ||
333 | SS_PATDELAY | ||
334 | }; | ||
335 | |||
336 | /* IT Volume column effects */ | ||
337 | enum { | ||
338 | VOL_VOLUME = 1, | ||
339 | VOL_PANNING, | ||
340 | VOL_VOLSLIDE, | ||
341 | VOL_PITCHSLIDEDN, | ||
342 | VOL_PITCHSLIDEUP, | ||
343 | VOL_PORTAMENTO, | ||
344 | VOL_VIBRATO | ||
345 | }; | ||
346 | |||
347 | /* IT resonant filter information */ | ||
348 | |||
349 | #define UF_MAXMACRO 0x10 | ||
350 | #define UF_MAXFILTER 0x100 | ||
351 | |||
352 | #define FILT_CUT 0x80 | ||
353 | #define FILT_RESONANT 0x81 | ||
354 | |||
355 | typedef struct FILTER { | ||
356 | UBYTE filter,inf; | ||
357 | } FILTER; | ||
358 | |||
359 | /*========== Instruments */ | ||
360 | |||
361 | /* Instrument format flags */ | ||
362 | #define IF_OWNPAN 1 | ||
363 | #define IF_PITCHPAN 2 | ||
364 | |||
365 | /* Envelope flags: */ | ||
366 | #define EF_ON 1 | ||
367 | #define EF_SUSTAIN 2 | ||
368 | #define EF_LOOP 4 | ||
369 | #define EF_VOLENV 8 | ||
370 | |||
371 | /* New Note Action Flags */ | ||
372 | #define NNA_CUT 0 | ||
373 | #define NNA_CONTINUE 1 | ||
374 | #define NNA_OFF 2 | ||
375 | #define NNA_FADE 3 | ||
376 | |||
377 | #define NNA_MASK 3 | ||
378 | |||
379 | #define DCT_OFF 0 | ||
380 | #define DCT_NOTE 1 | ||
381 | #define DCT_SAMPLE 2 | ||
382 | #define DCT_INST 3 | ||
383 | |||
384 | #define DCA_CUT 0 | ||
385 | #define DCA_OFF 1 | ||
386 | #define DCA_FADE 2 | ||
387 | |||
388 | #define KEY_KICK 0 | ||
389 | #define KEY_OFF 1 | ||
390 | #define KEY_FADE 2 | ||
391 | #define KEY_KILL (KEY_OFF|KEY_FADE) | ||
392 | |||
393 | #define KICK_ABSENT 0 | ||
394 | #define KICK_NOTE 1 | ||
395 | #define KICK_KEYOFF 2 | ||
396 | #define KICK_ENV 4 | ||
397 | |||
398 | #define AV_IT 1 /* IT vs. XM vibrato info */ | ||
399 | |||
400 | /*========== Playing */ | ||
401 | |||
402 | #define POS_NONE (-2) /* no loop position defined */ | ||
403 | |||
404 | #define LAST_PATTERN (UWORD)(-1) /* special ``end of song'' pattern */ | ||
405 | |||
406 | typedef struct ENVPR { | ||
407 | UBYTE flg; /* envelope flag */ | ||
408 | UBYTE pts; /* number of envelope points */ | ||
409 | UBYTE susbeg; /* envelope sustain index begin */ | ||
410 | UBYTE susend; /* envelope sustain index end */ | ||
411 | UBYTE beg; /* envelope loop begin */ | ||
412 | UBYTE end; /* envelope loop end */ | ||
413 | SWORD p; /* current envelope counter */ | ||
414 | UWORD a; /* envelope index a */ | ||
415 | UWORD b; /* envelope index b */ | ||
416 | ENVPT* env; /* envelope points */ | ||
417 | } ENVPR; | ||
418 | |||
419 | typedef struct MP_CHANNEL { | ||
420 | INSTRUMENT* i; | ||
421 | SAMPLE* s; | ||
422 | UBYTE sample; /* which sample number */ | ||
423 | UBYTE note; /* the audible note as heard, direct rep of period */ | ||
424 | SWORD outvolume; /* output volume (vol + sampcol + instvol) */ | ||
425 | SBYTE chanvol; /* channel's "global" volume */ | ||
426 | UWORD fadevol; /* fading volume rate */ | ||
427 | SWORD panning; /* panning position */ | ||
428 | UBYTE kick; /* if true = sample has to be restarted */ | ||
429 | UBYTE kick_flag; /* kick has been true */ | ||
430 | UWORD period; /* period to play the sample at */ | ||
431 | UBYTE nna; /* New note action type + master/slave flags */ | ||
432 | |||
433 | UBYTE volflg; /* volume envelope settings */ | ||
434 | UBYTE panflg; /* panning envelope settings */ | ||
435 | UBYTE pitflg; /* pitch envelope settings */ | ||
436 | |||
437 | UBYTE keyoff; /* if true = fade out and stuff */ | ||
438 | SWORD handle; /* which sample-handle */ | ||
439 | UBYTE notedelay; /* (used for note delay) */ | ||
440 | SLONG start; /* The starting byte index in the sample */ | ||
441 | } MP_CHANNEL; | ||
442 | |||
443 | typedef struct MP_CONTROL { | ||
444 | struct MP_CHANNEL main; | ||
445 | |||
446 | struct MP_VOICE *slave; /* Audio Slave of current effects control channel */ | ||
447 | |||
448 | UBYTE slavechn; /* Audio Slave of current effects control channel */ | ||
449 | UBYTE muted; /* if set, channel not played */ | ||
450 | UWORD ultoffset; /* fine sample offset memory */ | ||
451 | UBYTE anote; /* the note that indexes the audible */ | ||
452 | UBYTE oldnote; | ||
453 | SWORD ownper; | ||
454 | SWORD ownvol; | ||
455 | UBYTE dca; /* duplicate check action */ | ||
456 | UBYTE dct; /* duplicate check type */ | ||
457 | UBYTE* row; /* row currently playing on this channel */ | ||
458 | SBYTE retrig; /* retrig value (0 means don't retrig) */ | ||
459 | ULONG speed; /* what finetune to use */ | ||
460 | SWORD volume; /* amiga volume (0 t/m 64) to play the sample at */ | ||
461 | |||
462 | SWORD tmpvolume; /* tmp volume */ | ||
463 | UWORD tmpperiod; /* tmp period */ | ||
464 | UWORD wantedperiod; /* period to slide to (with effect 3 or 5) */ | ||
465 | |||
466 | UBYTE arpmem; /* arpeggio command memory */ | ||
467 | UBYTE pansspd; /* panslide speed */ | ||
468 | UWORD slidespeed; | ||
469 | UWORD portspeed; /* noteslide speed (toneportamento) */ | ||
470 | |||
471 | UBYTE s3mtremor; /* s3m tremor (effect I) counter */ | ||
472 | UBYTE s3mtronof; /* s3m tremor ontime/offtime */ | ||
473 | UBYTE s3mvolslide; /* last used volslide */ | ||
474 | SBYTE sliding; | ||
475 | UBYTE s3mrtgspeed; /* last used retrig speed */ | ||
476 | UBYTE s3mrtgslide; /* last used retrig slide */ | ||
477 | |||
478 | UBYTE glissando; /* glissando (0 means off) */ | ||
479 | UBYTE wavecontrol; | ||
480 | |||
481 | SBYTE vibpos; /* current vibrato position */ | ||
482 | UBYTE vibspd; /* "" speed */ | ||
483 | UBYTE vibdepth; /* "" depth */ | ||
484 | |||
485 | SBYTE trmpos; /* current tremolo position */ | ||
486 | UBYTE trmspd; /* "" speed */ | ||
487 | UBYTE trmdepth; /* "" depth */ | ||
488 | |||
489 | UBYTE fslideupspd; | ||
490 | UBYTE fslidednspd; | ||
491 | UBYTE fportupspd; /* fx E1 (extra fine portamento up) data */ | ||
492 | UBYTE fportdnspd; /* fx E2 (extra fine portamento dn) data */ | ||
493 | UBYTE ffportupspd; /* fx X1 (extra fine portamento up) data */ | ||
494 | UBYTE ffportdnspd; /* fx X2 (extra fine portamento dn) data */ | ||
495 | |||
496 | ULONG hioffset; /* last used high order of sample offset */ | ||
497 | UWORD soffset; /* last used low order of sample-offset (effect 9) */ | ||
498 | |||
499 | UBYTE sseffect; /* last used Sxx effect */ | ||
500 | UBYTE ssdata; /* last used Sxx data info */ | ||
501 | UBYTE chanvolslide; /* last used channel volume slide */ | ||
502 | |||
503 | UBYTE panbwave; /* current panbrello waveform */ | ||
504 | UBYTE panbpos; /* current panbrello position */ | ||
505 | SBYTE panbspd; /* "" speed */ | ||
506 | UBYTE panbdepth; /* "" depth */ | ||
507 | |||
508 | UWORD newsamp; /* set to 1 upon a sample / inst change */ | ||
509 | UBYTE voleffect; /* Volume Column Effect Memory as used by IT */ | ||
510 | UBYTE voldata; /* Volume Column Data Memory */ | ||
511 | |||
512 | SWORD pat_reppos; /* patternloop position */ | ||
513 | UWORD pat_repcnt; /* times to loop */ | ||
514 | } MP_CONTROL; | ||
515 | |||
516 | /* Used by NNA only player (audio control. AUDTMP is used for full effects | ||
517 | control). */ | ||
518 | typedef struct MP_VOICE { | ||
519 | struct MP_CHANNEL main; | ||
520 | |||
521 | ENVPR venv; | ||
522 | ENVPR penv; | ||
523 | ENVPR cenv; | ||
524 | |||
525 | UWORD avibpos; /* autovibrato pos */ | ||
526 | UWORD aswppos; /* autovibrato sweep pos */ | ||
527 | |||
528 | ULONG totalvol; /* total volume of channel (before global mixings) */ | ||
529 | |||
530 | int mflag; | ||
531 | SWORD masterchn; | ||
532 | UWORD masterperiod; | ||
533 | |||
534 | MP_CONTROL* master; /* index of "master" effects channel */ | ||
535 | } MP_VOICE; | ||
536 | |||
537 | /*========== Loaders */ | ||
538 | |||
539 | typedef struct MLOADER { | ||
540 | struct MLOADER* next; | ||
541 | CHAR* type; | ||
542 | CHAR* version; | ||
543 | int (*Init)(void); | ||
544 | int (*Test)(void); | ||
545 | int (*Load)(int); | ||
546 | void (*Cleanup)(void); | ||
547 | CHAR* (*LoadTitle)(void); | ||
548 | } MLOADER; | ||
549 | |||
550 | /* internal loader variables */ | ||
551 | extern MREADER* modreader; | ||
552 | extern UWORD finetune[16]; | ||
553 | extern MODULE of; /* static unimod loading space */ | ||
554 | extern UWORD npertab[7*OCTAVE]; /* used by the original MOD loaders */ | ||
555 | |||
556 | extern SBYTE remap[UF_MAXCHAN]; /* for removing empty channels */ | ||
557 | extern UBYTE* poslookup; /* lookup table for pattern jumps after | ||
558 | blank pattern removal */ | ||
559 | extern UWORD poslookupcnt; | ||
560 | extern UWORD* origpositions; | ||
561 | |||
562 | extern int filters; /* resonant filters in use */ | ||
563 | extern UBYTE activemacro; /* active midi macro number for Sxx */ | ||
564 | extern UBYTE filtermacros[UF_MAXMACRO]; /* midi macro settings */ | ||
565 | extern FILTER filtersettings[UF_MAXFILTER]; /* computed filter settings */ | ||
566 | |||
567 | extern int* noteindex; | ||
568 | |||
569 | /*========== Internal loader interface */ | ||
570 | |||
571 | extern int ReadComment(UWORD); | ||
572 | extern int ReadLinedComment(UWORD,UWORD); | ||
573 | extern int AllocPositions(int); | ||
574 | extern int AllocPatterns(void); | ||
575 | extern int AllocTracks(void); | ||
576 | extern int AllocInstruments(void); | ||
577 | extern int AllocSamples(void); | ||
578 | extern CHAR* DupStr(CHAR*,UWORD,int); | ||
579 | extern CHAR* StrDup(CHAR *s); | ||
580 | |||
581 | /* loader utility functions */ | ||
582 | extern int* AllocLinear(void); | ||
583 | extern void FreeLinear(void); | ||
584 | extern int speed_to_finetune(ULONG,int); | ||
585 | extern void S3MIT_ProcessCmd(UBYTE,UBYTE,unsigned int); | ||
586 | extern void S3MIT_CreateOrders(int); | ||
587 | |||
588 | /* flags for S3MIT_ProcessCmd */ | ||
589 | #define S3MIT_OLDSTYLE 1 /* behave as old scream tracker */ | ||
590 | #define S3MIT_IT 2 /* behave as impulse tracker */ | ||
591 | #define S3MIT_SCREAM 4 /* enforce scream tracker specific limits */ | ||
592 | |||
593 | /* used to convert c4spd to linear XM periods (IT and IMF loaders). */ | ||
594 | extern UWORD getlinearperiod(UWORD,ULONG); | ||
595 | extern ULONG getfrequency(UWORD,ULONG); | ||
596 | |||
597 | /* loader shared data */ | ||
598 | #define STM_NTRACKERS 3 | ||
599 | extern CHAR *STM_Signatures[STM_NTRACKERS]; | ||
600 | |||
601 | /*========== Player interface */ | ||
602 | |||
603 | extern int Player_Init(MODULE*); | ||
604 | extern void Player_Exit(MODULE*); | ||
605 | extern void Player_HandleTick(void); | ||
606 | |||
607 | /*========== Drivers */ | ||
608 | |||
609 | /* max. number of handles a driver has to provide. (not strict) */ | ||
610 | #define MAXSAMPLEHANDLES 384 | ||
611 | |||
612 | /* These variables can be changed at ANY time and results will be immediate */ | ||
613 | extern UWORD md_bpm; /* current song / hardware BPM rate */ | ||
614 | |||
615 | /* Variables below can be changed via MD_SetNumVoices at any time. However, a | ||
616 | call to MD_SetNumVoicess while the driver is active will cause the sound to | ||
617 | skip slightly. */ | ||
618 | extern UBYTE md_numchn; /* number of song + sound effects voices */ | ||
619 | extern UBYTE md_sngchn; /* number of song voices */ | ||
620 | extern UBYTE md_sfxchn; /* number of sound effects voices */ | ||
621 | extern UBYTE md_hardchn; /* number of hardware mixed voices */ | ||
622 | extern UBYTE md_softchn; /* number of software mixed voices */ | ||
623 | |||
624 | /* This is for use by the hardware drivers only. It points to the registered | ||
625 | tickhandler function. */ | ||
626 | extern void (*md_player)(void); | ||
627 | |||
628 | extern SWORD MD_SampleLoad(SAMPLOAD*,int); | ||
629 | extern void MD_SampleUnload(SWORD); | ||
630 | extern ULONG MD_SampleSpace(int); | ||
631 | extern ULONG MD_SampleLength(int,SAMPLE*); | ||
632 | |||
633 | /* uLaw conversion */ | ||
634 | extern void unsignedtoulaw(char *,int); | ||
635 | |||
636 | /* Parameter extraction helper */ | ||
637 | extern CHAR *MD_GetAtom(CHAR*,CHAR*,int); | ||
638 | |||
639 | /* Internal software mixer stuff */ | ||
640 | extern void VC_SetupPointers(void); | ||
641 | extern int VC1_Init(void); | ||
642 | extern int VC2_Init(void); | ||
643 | |||
644 | #if defined(unix) || defined(__APPLE__) && defined(__MACH__) | ||
645 | /* POSIX helper functions */ | ||
646 | extern int MD_Access(CHAR *); | ||
647 | extern int MD_DropPrivileges(void); | ||
648 | #endif | ||
649 | |||
650 | /* Macro to define a missing driver, yet allowing binaries to dynamically link | ||
651 | with the library without missing symbol errors */ | ||
652 | #define MISSING(a) MDRIVER a = { NULL, NULL, NULL, 0, 0 } | ||
653 | |||
654 | /*========== Prototypes for non-MT safe versions of some public functions */ | ||
655 | |||
656 | extern void _mm_registerdriver(struct MDRIVER*); | ||
657 | extern void _mm_registerloader(struct MLOADER*); | ||
658 | extern int MikMod_Active_internal(void); | ||
659 | extern void MikMod_DisableOutput_internal(void); | ||
660 | extern int MikMod_EnableOutput_internal(void); | ||
661 | extern void MikMod_Exit_internal(void); | ||
662 | extern int MikMod_SetNumVoices_internal(int,int); | ||
663 | extern void Player_Exit_internal(MODULE*); | ||
664 | extern void Player_Stop_internal(void); | ||
665 | extern int Player_Paused_internal(void); | ||
666 | extern void Sample_Free_internal(SAMPLE*); | ||
667 | extern void Voice_Play_internal(SBYTE,SAMPLE*,ULONG); | ||
668 | extern void Voice_SetFrequency_internal(SBYTE,ULONG); | ||
669 | extern void Voice_SetPanning_internal(SBYTE,ULONG); | ||
670 | extern void Voice_SetVolume_internal(SBYTE,UWORD); | ||
671 | extern void Voice_Stop_internal(SBYTE); | ||
672 | extern int Voice_Stopped_internal(SBYTE); | ||
673 | |||
674 | #ifdef __cplusplus | ||
675 | } | ||
676 | #endif | ||
677 | |||
678 | /*========== SIMD mixing routines */ | ||
679 | #undef HAVE_ALTIVEC | ||
680 | #undef HAVE_SSE2 | ||
681 | |||
682 | #if defined(__APPLE__) && !defined (__i386__) | ||
683 | |||
684 | #if defined __VEC__ && !(defined(__GNUC__) && (__GNUC__ < 3)) | ||
685 | #define HAVE_ALTIVEC | ||
686 | #endif // __VEC__ | ||
687 | |||
688 | #elif defined WIN32 || defined __WIN64 || (defined __APPLE__ && defined (__i386__) && defined __VEC__) | ||
689 | |||
690 | // FIXME: emmintrin.h requires VC6 processor pack or VC2003+ | ||
691 | #define HAVE_SSE2 | ||
692 | |||
693 | /* Fixes couples warnings */ | ||
694 | #ifdef _MSC_VER | ||
695 | #pragma warning(disable:4761) | ||
696 | #pragma warning(disable:4391) | ||
697 | #pragma warning(disable:4244) | ||
698 | #endif | ||
699 | #endif | ||
700 | // TODO: Test for GCC Linux | ||
701 | |||
702 | /*========== SIMD mixing helper functions =============*/ | ||
703 | |||
704 | #define IS_ALIGNED_16(ptr) (!(((int)(ptr)) & 15)) | ||
705 | |||
706 | /* Altivec helper function */ | ||
707 | #if defined HAVE_ALTIVEC | ||
708 | |||
709 | #define simd_m128i vector signed int | ||
710 | #define simd_m128 vector float | ||
711 | |||
712 | #ifdef __GNUC__ | ||
713 | #include <ppc_intrinsics.h> | ||
714 | #endif | ||
715 | |||
716 | // Helper functions | ||
717 | |||
718 | // Set single float across the four values | ||
719 | static inline vector float vec_mul( const vector float a, const vector float b) | ||
720 | { | ||
721 | return vec_madd(a, b, (const vector float)(0.f)); | ||
722 | } | ||
723 | |||
724 | // Set single float across the four values | ||
725 | static inline vector float vec_load_ps1(const float *pF ) | ||
726 | { | ||
727 | vector float data = vec_lde(0, pF); | ||
728 | return vec_splat(vec_perm(data, data, vec_lvsl(0, pF)), 0); | ||
729 | } | ||
730 | |||
731 | // Set vector to 0 | ||
732 | static inline const vector float vec_setzero() | ||
733 | { | ||
734 | return (const vector float) (0.); | ||
735 | } | ||
736 | |||
737 | static inline vector signed char vec_set1_8(unsigned char splatchar) | ||
738 | { | ||
739 | vector unsigned char splatmap = vec_lvsl(0, &splatchar); | ||
740 | vector unsigned char result = vec_lde(0, &splatchar); | ||
741 | splatmap = vec_splat(splatmap, 0); | ||
742 | return (vector signed char)vec_perm(result, result, splatmap); | ||
743 | } | ||
744 | |||
745 | #define PERM_A0 0x00,0x01,0x02,0x03 | ||
746 | #define PERM_A1 0x04,0x05,0x06,0x07 | ||
747 | #define PERM_A2 0x08,0x09,0x0A,0x0B | ||
748 | #define PERM_A3 0x0C,0x0D,0x0E,0x0F | ||
749 | #define PERM_B0 0x10,0x11,0x12,0x13 | ||
750 | #define PERM_B1 0x14,0x15,0x16,0x17 | ||
751 | #define PERM_B2 0x18,0x19,0x1A,0x1B | ||
752 | #define PERM_B3 0x1C,0x1D,0x1E,0x1F | ||
753 | |||
754 | // Equivalent to _mm_unpacklo_epi32 | ||
755 | static inline vector signed int vec_unpacklo(vector signed int a, vector signed int b) | ||
756 | { | ||
757 | return vec_perm(a, b, (vector unsigned char)(PERM_A0,PERM_A1,PERM_B0,PERM_B1)); | ||
758 | } | ||
759 | |||
760 | // Equivalent to _mm_srli_si128(a, 8) (without the zeroing in high part). | ||
761 | static inline vector signed int vec_hiqq(vector signed int a) | ||
762 | { | ||
763 | vector signed int b = vec_splat_s32(0); | ||
764 | return vec_perm(a, b, (vector unsigned char)(PERM_A2,PERM_A3,PERM_B2,PERM_B3)); | ||
765 | } | ||
766 | |||
767 | // vec_sra is max +15. We have to do in two times ... | ||
768 | #define EXTRACT_SAMPLE_SIMD_F(srce, var, size, mul) var = vec_mul(vec_ctf(vec_sra(vec_ld(0, (vector signed int*)(srce)), vec_splat_u32(BITSHIFT-size)),0), mul); | ||
769 | #define EXTRACT_SAMPLE_SIMD_0(srce, var) var = vec_sra(vec_sra(vec_ld(0, (vector signed int*)(srce)), vec_splat_u32(15)), vec_splat_u32(BITSHIFT+16-15-0)); | ||
770 | #define EXTRACT_SAMPLE_SIMD_8(srce, var) var = vec_sra(vec_sra(vec_ld(0, (vector signed int*)(srce)), vec_splat_u32(15)), vec_splat_u32(BITSHIFT+16-15-8)); | ||
771 | #define EXTRACT_SAMPLE_SIMD_16(srce, var) var = vec_sra(vec_ld(0, (vector signed int*)(srce)), vec_splat_u32(BITSHIFT+16-16)); | ||
772 | #define PUT_SAMPLE_SIMD_W(dste, v1, v2) vec_st(vec_packs(v1, v2), 0, dste); | ||
773 | #define PUT_SAMPLE_SIMD_B(dste, v1, v2, v3, v4) vec_st(vec_add(vec_packs((vector signed short)vec_packs(v1, v2), (vector signed short)vec_packs(v3, v4)), vec_set1_8(128)), 0, dste); | ||
774 | #define PUT_SAMPLE_SIMD_F(dste, v1) vec_st(v1, 0, dste); | ||
775 | #define LOAD_PS1_SIMD(ptr) vec_load_ps1(ptr) | ||
776 | |||
777 | #elif defined HAVE_SSE2 | ||
778 | |||
779 | /* SSE2 helper function */ | ||
780 | |||
781 | #include <emmintrin.h> | ||
782 | |||
783 | static __inline __m128i mm_hiqq(const __m128i a) | ||
784 | { | ||
785 | return _mm_srli_si128(a, 8); // get the 64bit upper part. new 64bit upper is undefined (zeroed is fine). | ||
786 | } | ||
787 | |||
788 | /* 128-bit mixing macros */ | ||
789 | #define EXTRACT_SAMPLE_SIMD(srce, var, size) var = _mm_srai_epi32(_mm_load_si128((__m128i*)(srce)), BITSHIFT+16-size); | ||
790 | #define EXTRACT_SAMPLE_SIMD_F(srce, var, size, mul) var = _mm_mul_ps(_mm_cvtepi32_ps(_mm_srai_epi32(_mm_load_si128((__m128i*)(srce)), BITSHIFT-size)), mul); | ||
791 | #define EXTRACT_SAMPLE_SIMD_0(srce, var) EXTRACT_SAMPLE_SIMD(srce, var, 0) | ||
792 | #define EXTRACT_SAMPLE_SIMD_8(srce, var) EXTRACT_SAMPLE_SIMD(srce, var, 8) | ||
793 | #define EXTRACT_SAMPLE_SIMD_16(srce, var) EXTRACT_SAMPLE_SIMD(srce, var, 16) | ||
794 | #define PUT_SAMPLE_SIMD_W(dste, v1, v2) _mm_store_si128((__m128i*)(dste), _mm_packs_epi32(v1, v2)); | ||
795 | #define PUT_SAMPLE_SIMD_B(dste, v1, v2, v3, v4) _mm_store_si128((__m128i*)(dste), _mm_add_epi8(_mm_packs_epi16(_mm_packs_epi32(v1, v2), _mm_packs_epi32(v3, v4)), _mm_set1_epi8(128))); | ||
796 | #define PUT_SAMPLE_SIMD_F(dste, v1) _mm_store_ps((float*)(dste), v1); | ||
797 | #define LOAD_PS1_SIMD(ptr) _mm_load_ps1(ptr) | ||
798 | #define simd_m128i __m128i | ||
799 | #define simd_m128 __m128 | ||
800 | |||
801 | #endif | ||
802 | |||
803 | |||
804 | #endif | ||
805 | |||
806 | /* ex:set ts=4: */ | ||
diff --git a/apps/plugins/mikmod/mikmod_supp.h b/apps/plugins/mikmod/mikmod_supp.h new file mode 100644 index 0000000000..55963bf5d4 --- /dev/null +++ b/apps/plugins/mikmod/mikmod_supp.h | |||
@@ -0,0 +1,79 @@ | |||
1 | #include <string.h> | ||
2 | #include "plugin.h" | ||
3 | #include "inttypes.h" | ||
4 | #include "codecs/lib/tlsf/src/tlsf.h" | ||
5 | |||
6 | #ifndef MIKMOD_SUPP_H | ||
7 | #define MIKMOD_SUPP_H | ||
8 | |||
9 | #undef WIN32 | ||
10 | |||
11 | #ifndef NO_MMSUPP_DEFINES | ||
12 | #define snprintf(...) rb->snprintf(__VA_ARGS__) | ||
13 | #define fdprintf(...) rb->fdprintf(__VA_ARGS__) | ||
14 | #define vsnprintf(...) rb->vsnprintf(__VA_ARGS__) | ||
15 | |||
16 | #define srand(a) rb->srand(a) | ||
17 | #define rand() rb->rand() | ||
18 | #define qsort(a,b,c,d) rb->qsort(a,b,c,d) | ||
19 | #define atoi(a) rb->atoi(a) | ||
20 | |||
21 | #define strlen(a) rb->strlen(a) | ||
22 | #define strcpy(a,b) rb->strcpy(a,b) | ||
23 | #define strcat(a,b) rb->strcat(a,b) | ||
24 | #define strncmp(a,b,c) rb->strncmp(a,b,c) | ||
25 | #define strcasecmp(a,b) rb->strcasecmp(a,b) | ||
26 | |||
27 | #undef open | ||
28 | #define open(a,b) rb->open(a,b) | ||
29 | #undef lseek | ||
30 | #define lseek(a,b,c) rb->lseek(a,b,c) | ||
31 | #undef close | ||
32 | #define close(a) rb->close(a) | ||
33 | #undef read | ||
34 | #define read(a,b,c) rb->read(a,b,c) | ||
35 | #undef write | ||
36 | #define write(a,b,c) rb->write(a,b,c) | ||
37 | #undef filesize | ||
38 | #define filesize(a) rb->filesize(a) | ||
39 | #endif | ||
40 | |||
41 | #define malloc(x) tlsf_malloc(x) | ||
42 | #define free(x) tlsf_free(x) | ||
43 | #define realloc(x,y) tlsf_realloc(x,y) | ||
44 | #define calloc(x,y) tlsf_calloc(x,y) | ||
45 | |||
46 | #define strncat mmsupp_strncat | ||
47 | #define printf mmsupp_printf | ||
48 | #define sprintf mmsupp_sprintf | ||
49 | |||
50 | #define fprintf(...) | ||
51 | |||
52 | char* mmsupp_strncat(char *s1, const char *s2, size_t n); | ||
53 | void mmsupp_printf(const char *fmt, ...); | ||
54 | int mmsupp_sprintf(char *buf, const char *fmt, ... ); | ||
55 | |||
56 | extern const struct plugin_api * rb; | ||
57 | |||
58 | |||
59 | #ifdef SIMULATOR | ||
60 | #define SAMPLE_RATE SAMPR_44 /* Simulator requires 44100Hz */ | ||
61 | #else | ||
62 | #if (HW_SAMPR_CAPS & SAMPR_CAP_22) /* use 22050Hz if we can */ | ||
63 | #define SAMPLE_RATE SAMPR_22 /* 22050 */ | ||
64 | #else | ||
65 | #define SAMPLE_RATE SAMPR_44 /* 44100 */ | ||
66 | #endif | ||
67 | #endif | ||
68 | |||
69 | #define BUF_SIZE 4096*8 | ||
70 | #define NBUF 2 | ||
71 | |||
72 | /* LibMikMod defines */ | ||
73 | #define HAVE_SNPRINTF 1 | ||
74 | |||
75 | #ifndef INT_MAX | ||
76 | #define INT_MAX 2147483647 | ||
77 | #endif | ||
78 | |||
79 | #endif | ||
diff --git a/apps/plugins/mikmod/mloader.c b/apps/plugins/mikmod/mloader.c new file mode 100644 index 0000000000..7bce40578e --- /dev/null +++ b/apps/plugins/mikmod/mloader.c | |||
@@ -0,0 +1,615 @@ | |||
1 | /* MikMod sound library | ||
2 | (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file | ||
3 | AUTHORS 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: mloader.c,v 1.3 2005/04/07 19:57:39 realtech Exp $ | ||
24 | |||
25 | These routines are used to access the available module loaders | ||
26 | |||
27 | ==============================================================================*/ | ||
28 | |||
29 | #ifdef HAVE_CONFIG_H | ||
30 | #include "config.h" | ||
31 | #endif | ||
32 | |||
33 | #ifdef HAVE_UNISTD_H | ||
34 | #include <unistd.h> | ||
35 | #endif | ||
36 | |||
37 | #ifdef HAVE_MEMORY_H | ||
38 | #include <memory.h> | ||
39 | #endif | ||
40 | #include <string.h> | ||
41 | |||
42 | #include "mikmod_internals.h" | ||
43 | |||
44 | #ifdef SUNOS | ||
45 | extern int fprintf(FILE *, const char *, ...); | ||
46 | #endif | ||
47 | |||
48 | MREADER *modreader; | ||
49 | MODULE of; | ||
50 | |||
51 | static MLOADER *firstloader=NULL; | ||
52 | |||
53 | UWORD finetune[16]={ | ||
54 | 8363,8413,8463,8529,8581,8651,8723,8757, | ||
55 | 7895,7941,7985,8046,8107,8169,8232,8280 | ||
56 | }; | ||
57 | |||
58 | MIKMODAPI CHAR* MikMod_InfoLoader(void) | ||
59 | { | ||
60 | int len=0; | ||
61 | MLOADER *l; | ||
62 | CHAR *list=NULL; | ||
63 | |||
64 | MUTEX_LOCK(lists); | ||
65 | /* compute size of buffer */ | ||
66 | for(l=firstloader;l;l=l->next) len+=1+(l->next?1:0)+strlen(l->version); | ||
67 | |||
68 | if(len) | ||
69 | if((list=MikMod_malloc(len*sizeof(CHAR)))) { | ||
70 | list[0]=0; | ||
71 | /* list all registered module loders */ | ||
72 | for(l=firstloader;l;l=l->next) | ||
73 | sprintf(list,(l->next)?"%s%s\n":"%s%s",list,l->version); | ||
74 | } | ||
75 | MUTEX_UNLOCK(lists); | ||
76 | return list; | ||
77 | } | ||
78 | |||
79 | void _mm_registerloader(MLOADER* ldr) | ||
80 | { | ||
81 | MLOADER *cruise=firstloader; | ||
82 | |||
83 | if(cruise) { | ||
84 | while(cruise->next) cruise = cruise->next; | ||
85 | cruise->next=ldr; | ||
86 | } else | ||
87 | firstloader=ldr; | ||
88 | } | ||
89 | |||
90 | MIKMODAPI void MikMod_RegisterLoader(struct MLOADER* ldr) | ||
91 | { | ||
92 | /* if we try to register an invalid loader, or an already registered loader, | ||
93 | ignore this attempt */ | ||
94 | if ((!ldr)||(ldr->next)) | ||
95 | return; | ||
96 | |||
97 | MUTEX_LOCK(lists); | ||
98 | _mm_registerloader(ldr); | ||
99 | MUTEX_UNLOCK(lists); | ||
100 | } | ||
101 | |||
102 | int ReadComment(UWORD len) | ||
103 | { | ||
104 | if(len) { | ||
105 | int i; | ||
106 | |||
107 | if(!(of.comment=(CHAR*)MikMod_malloc(len+1))) return 0; | ||
108 | _mm_read_UBYTES(of.comment,len,modreader); | ||
109 | |||
110 | /* translate IT linefeeds */ | ||
111 | for(i=0;i<len;i++) | ||
112 | if(of.comment[i]=='\r') of.comment[i]='\n'; | ||
113 | |||
114 | of.comment[len]=0; /* just in case */ | ||
115 | } | ||
116 | if(!of.comment[0]) { | ||
117 | MikMod_free(of.comment); | ||
118 | of.comment=NULL; | ||
119 | } | ||
120 | return 1; | ||
121 | } | ||
122 | |||
123 | int ReadLinedComment(UWORD len,UWORD linelen) | ||
124 | { | ||
125 | CHAR *tempcomment,*line,*storage; | ||
126 | UWORD total=0,t,lines; | ||
127 | int i; | ||
128 | |||
129 | lines = (len + linelen - 1) / linelen; | ||
130 | if (len) { | ||
131 | if(!(tempcomment=(CHAR*)MikMod_malloc(len+1))) return 0; | ||
132 | if(!(storage=(CHAR*)MikMod_malloc(linelen+1))) { | ||
133 | MikMod_free(tempcomment); | ||
134 | return 0; | ||
135 | } | ||
136 | memset(tempcomment, ' ', len); | ||
137 | _mm_read_UBYTES(tempcomment,len,modreader); | ||
138 | |||
139 | /* compute message length */ | ||
140 | for(line=tempcomment,total=t=0;t<lines;t++,line+=linelen) { | ||
141 | for(i=linelen;(i>=0)&&(line[i]==' ');i--) line[i]=0; | ||
142 | for(i=0;i<linelen;i++) if (!line[i]) break; | ||
143 | total+=1+i; | ||
144 | } | ||
145 | |||
146 | if(total>lines) { | ||
147 | if(!(of.comment=(CHAR*)MikMod_malloc(total+1))) { | ||
148 | MikMod_free(storage); | ||
149 | MikMod_free(tempcomment); | ||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | /* convert message */ | ||
154 | for(line=tempcomment,t=0;t<lines;t++,line+=linelen) { | ||
155 | for(i=0;i<linelen;i++) if(!(storage[i]=line[i])) break; | ||
156 | storage[i]=0; /* if (i==linelen) */ | ||
157 | strcat(of.comment,storage);strcat(of.comment,"\r"); | ||
158 | } | ||
159 | MikMod_free(storage); | ||
160 | MikMod_free(tempcomment); | ||
161 | } | ||
162 | } | ||
163 | return 1; | ||
164 | } | ||
165 | |||
166 | int AllocPositions(int total) | ||
167 | { | ||
168 | if(!total) { | ||
169 | _mm_errno=MMERR_NOT_A_MODULE; | ||
170 | return 0; | ||
171 | } | ||
172 | if(!(of.positions=MikMod_calloc(total,sizeof(UWORD)))) return 0; | ||
173 | return 1; | ||
174 | } | ||
175 | |||
176 | int AllocPatterns(void) | ||
177 | { | ||
178 | int s,t,tracks = 0; | ||
179 | |||
180 | if((!of.numpat)||(!of.numchn)) { | ||
181 | _mm_errno=MMERR_NOT_A_MODULE; | ||
182 | return 0; | ||
183 | } | ||
184 | /* Allocate track sequencing array */ | ||
185 | if(!(of.patterns=(UWORD*)MikMod_calloc((ULONG)(of.numpat+1)*of.numchn,sizeof(UWORD)))) return 0; | ||
186 | if(!(of.pattrows=(UWORD*)MikMod_calloc(of.numpat+1,sizeof(UWORD)))) return 0; | ||
187 | |||
188 | for(t=0;t<=of.numpat;t++) { | ||
189 | of.pattrows[t]=64; | ||
190 | for(s=0;s<of.numchn;s++) | ||
191 | of.patterns[(t*of.numchn)+s]=tracks++; | ||
192 | } | ||
193 | |||
194 | return 1; | ||
195 | } | ||
196 | |||
197 | int AllocTracks(void) | ||
198 | { | ||
199 | if(!of.numtrk) { | ||
200 | _mm_errno=MMERR_NOT_A_MODULE; | ||
201 | return 0; | ||
202 | } | ||
203 | if(!(of.tracks=(UBYTE **)MikMod_calloc(of.numtrk,sizeof(UBYTE *)))) return 0; | ||
204 | return 1; | ||
205 | } | ||
206 | |||
207 | int AllocInstruments(void) | ||
208 | { | ||
209 | int t,n; | ||
210 | |||
211 | if(!of.numins) { | ||
212 | _mm_errno=MMERR_NOT_A_MODULE; | ||
213 | return 0; | ||
214 | } | ||
215 | if(!(of.instruments=(INSTRUMENT*)MikMod_calloc(of.numins,sizeof(INSTRUMENT)))) | ||
216 | return 0; | ||
217 | |||
218 | for(t=0;t<of.numins;t++) { | ||
219 | for(n=0;n<INSTNOTES;n++) { | ||
220 | /* Init note / sample lookup table */ | ||
221 | of.instruments[t].samplenote[n] = n; | ||
222 | of.instruments[t].samplenumber[n] = t; | ||
223 | } | ||
224 | of.instruments[t].globvol = 64; | ||
225 | } | ||
226 | return 1; | ||
227 | } | ||
228 | |||
229 | int AllocSamples(void) | ||
230 | { | ||
231 | UWORD u; | ||
232 | |||
233 | if(!of.numsmp) { | ||
234 | _mm_errno=MMERR_NOT_A_MODULE; | ||
235 | return 0; | ||
236 | } | ||
237 | if(!(of.samples=(SAMPLE*)MikMod_calloc(of.numsmp,sizeof(SAMPLE)))) return 0; | ||
238 | |||
239 | for(u=0;u<of.numsmp;u++) { | ||
240 | of.samples[u].panning = 128; /* center */ | ||
241 | of.samples[u].handle = -1; | ||
242 | of.samples[u].globvol = 64; | ||
243 | of.samples[u].volume = 64; | ||
244 | } | ||
245 | return 1; | ||
246 | } | ||
247 | |||
248 | static int ML_LoadSamples(void) | ||
249 | { | ||
250 | SAMPLE *s; | ||
251 | int u; | ||
252 | |||
253 | for(u=of.numsmp,s=of.samples;u;u--,s++) | ||
254 | if(s->length) SL_RegisterSample(s,MD_MUSIC,modreader); | ||
255 | |||
256 | return 1; | ||
257 | } | ||
258 | |||
259 | /* Creates a CSTR out of a character buffer of 'len' bytes, but strips any | ||
260 | terminating non-printing characters like 0, spaces etc. */ | ||
261 | CHAR *DupStr(CHAR* s,UWORD len,int strict) | ||
262 | { | ||
263 | UWORD t; | ||
264 | CHAR *d=NULL; | ||
265 | |||
266 | /* Scan for last printing char in buffer [includes high ascii up to 254] */ | ||
267 | while(len) { | ||
268 | if(s[len-1]>0x20) break; | ||
269 | len--; | ||
270 | } | ||
271 | |||
272 | /* Scan forward for possible NULL character */ | ||
273 | if(strict) { | ||
274 | for(t=0;t<len;t++) if (!s[t]) break; | ||
275 | if (t<len) len=t; | ||
276 | } | ||
277 | |||
278 | /* When the buffer wasn't completely empty, allocate a cstring and copy the | ||
279 | buffer into that string, except for any control-chars */ | ||
280 | if((d=(CHAR*)MikMod_malloc(sizeof(CHAR)*(len+1)))) { | ||
281 | for(t=0;t<len;t++) d[t]=(s[t]<32)?'.':s[t]; | ||
282 | d[len]=0; | ||
283 | } | ||
284 | return d; | ||
285 | } | ||
286 | |||
287 | CHAR *StrDup(CHAR *s) | ||
288 | { | ||
289 | size_t l = strlen(s) + 1; | ||
290 | CHAR *d = MikMod_malloc(l); | ||
291 | strcpy(d, s); | ||
292 | return d; | ||
293 | } | ||
294 | |||
295 | static void ML_XFreeSample(SAMPLE *s) | ||
296 | { | ||
297 | if(s->handle>=0) | ||
298 | MD_SampleUnload(s->handle); | ||
299 | if(s->samplename) MikMod_free(s->samplename); | ||
300 | } | ||
301 | |||
302 | static void ML_XFreeInstrument(INSTRUMENT *i) | ||
303 | { | ||
304 | if(i->insname) MikMod_free(i->insname); | ||
305 | } | ||
306 | |||
307 | static void ML_FreeEx(MODULE *mf) | ||
308 | { | ||
309 | UWORD t; | ||
310 | |||
311 | if(mf->songname) MikMod_free(mf->songname); | ||
312 | if(mf->comment) MikMod_free(mf->comment); | ||
313 | |||
314 | if(mf->modtype) MikMod_free(mf->modtype); | ||
315 | if(mf->positions) MikMod_free(mf->positions); | ||
316 | if(mf->patterns) MikMod_free(mf->patterns); | ||
317 | if(mf->pattrows) MikMod_free(mf->pattrows); | ||
318 | |||
319 | if(mf->tracks) { | ||
320 | for(t=0;t<mf->numtrk;t++) | ||
321 | if(mf->tracks[t]) MikMod_free(mf->tracks[t]); | ||
322 | MikMod_free(mf->tracks); | ||
323 | } | ||
324 | if(mf->instruments) { | ||
325 | for(t=0;t<mf->numins;t++) | ||
326 | ML_XFreeInstrument(&mf->instruments[t]); | ||
327 | MikMod_free(mf->instruments); | ||
328 | } | ||
329 | if(mf->samples) { | ||
330 | for(t=0;t<mf->numsmp;t++) | ||
331 | if(mf->samples[t].length) ML_XFreeSample(&mf->samples[t]); | ||
332 | MikMod_free(mf->samples); | ||
333 | } | ||
334 | memset(mf,0,sizeof(MODULE)); | ||
335 | if(mf!=&of) MikMod_free(mf); | ||
336 | } | ||
337 | |||
338 | static MODULE *ML_AllocUniMod(void) | ||
339 | { | ||
340 | MODULE *mf; | ||
341 | |||
342 | return (mf=MikMod_malloc(sizeof(MODULE))); | ||
343 | } | ||
344 | |||
345 | void Player_Free_internal(MODULE *mf) | ||
346 | { | ||
347 | if(mf) { | ||
348 | Player_Exit_internal(mf); | ||
349 | ML_FreeEx(mf); | ||
350 | } | ||
351 | } | ||
352 | |||
353 | MIKMODAPI void Player_Free(MODULE *mf) | ||
354 | { | ||
355 | MUTEX_LOCK(vars); | ||
356 | Player_Free_internal(mf); | ||
357 | MUTEX_UNLOCK(vars); | ||
358 | } | ||
359 | |||
360 | static CHAR* Player_LoadTitle_internal(MREADER *reader) | ||
361 | { | ||
362 | MLOADER *l; | ||
363 | |||
364 | modreader=reader; | ||
365 | _mm_errno = 0; | ||
366 | _mm_critical = 0; | ||
367 | _mm_iobase_setcur(modreader); | ||
368 | |||
369 | /* Try to find a loader that recognizes the module */ | ||
370 | for(l=firstloader;l;l=l->next) { | ||
371 | _mm_rewind(modreader); | ||
372 | if(l->Test()) break; | ||
373 | } | ||
374 | |||
375 | if(!l) { | ||
376 | _mm_errno = MMERR_NOT_A_MODULE; | ||
377 | if(_mm_errorhandler) _mm_errorhandler(); | ||
378 | return NULL; | ||
379 | } | ||
380 | |||
381 | return l->LoadTitle(); | ||
382 | } | ||
383 | |||
384 | MIKMODAPI CHAR* Player_LoadTitleFP(int fp) | ||
385 | { | ||
386 | CHAR* result=NULL; | ||
387 | MREADER* reader; | ||
388 | |||
389 | if(fp && (reader=_mm_new_file_reader(fp))) { | ||
390 | MUTEX_LOCK(lists); | ||
391 | result=Player_LoadTitle_internal(reader); | ||
392 | MUTEX_UNLOCK(lists); | ||
393 | _mm_delete_file_reader(reader); | ||
394 | } | ||
395 | return result; | ||
396 | } | ||
397 | |||
398 | MIKMODAPI CHAR* Player_LoadTitleMem(const char *buffer,int len) | ||
399 | { | ||
400 | CHAR *result=NULL; | ||
401 | MREADER* reader; | ||
402 | |||
403 | if ((reader=_mm_new_mem_reader(buffer,len))) | ||
404 | { | ||
405 | MUTEX_LOCK(lists); | ||
406 | result=Player_LoadTitle_internal(reader); | ||
407 | MUTEX_UNLOCK(lists); | ||
408 | _mm_delete_mem_reader(reader); | ||
409 | } | ||
410 | |||
411 | |||
412 | return result; | ||
413 | } | ||
414 | |||
415 | MIKMODAPI CHAR* Player_LoadTitleGeneric(MREADER *reader) | ||
416 | { | ||
417 | CHAR *result=NULL; | ||
418 | |||
419 | if (reader) { | ||
420 | MUTEX_LOCK(lists); | ||
421 | result=Player_LoadTitle_internal(reader); | ||
422 | MUTEX_UNLOCK(lists); | ||
423 | } | ||
424 | return result; | ||
425 | } | ||
426 | |||
427 | MIKMODAPI CHAR* Player_LoadTitle(CHAR* filename) | ||
428 | { | ||
429 | CHAR* result=NULL; | ||
430 | int fp; | ||
431 | MREADER* reader; | ||
432 | |||
433 | if((fp=_mm_fopen(filename,"rb"))) { | ||
434 | if((reader=_mm_new_file_reader(fp))) { | ||
435 | MUTEX_LOCK(lists); | ||
436 | result=Player_LoadTitle_internal(reader); | ||
437 | MUTEX_UNLOCK(lists); | ||
438 | _mm_delete_file_reader(reader); | ||
439 | } | ||
440 | _mm_fclose(fp); | ||
441 | } | ||
442 | return result; | ||
443 | } | ||
444 | |||
445 | /* Loads a module given an reader */ | ||
446 | MODULE* Player_LoadGeneric_internal(MREADER *reader,int maxchan,int curious) | ||
447 | { | ||
448 | int t; | ||
449 | MLOADER *l; | ||
450 | int ok; | ||
451 | MODULE *mf; | ||
452 | |||
453 | modreader = reader; | ||
454 | _mm_errno = 0; | ||
455 | _mm_critical = 0; | ||
456 | _mm_iobase_setcur(modreader); | ||
457 | |||
458 | /* Try to find a loader that recognizes the module */ | ||
459 | for(l=firstloader;l;l=l->next) { | ||
460 | _mm_rewind(modreader); | ||
461 | if(l->Test()) break; | ||
462 | } | ||
463 | |||
464 | if(!l) { | ||
465 | _mm_errno = MMERR_NOT_A_MODULE; | ||
466 | if(_mm_errorhandler) _mm_errorhandler(); | ||
467 | _mm_rewind(modreader);_mm_iobase_revert(modreader); | ||
468 | return NULL; | ||
469 | } | ||
470 | |||
471 | /* init unitrk routines */ | ||
472 | if(!UniInit()) { | ||
473 | if(_mm_errorhandler) _mm_errorhandler(); | ||
474 | _mm_rewind(modreader);_mm_iobase_revert(modreader); | ||
475 | return NULL; | ||
476 | } | ||
477 | |||
478 | /* init the module structure with vanilla settings */ | ||
479 | memset(&of,0,sizeof(MODULE)); | ||
480 | of.bpmlimit = 33; | ||
481 | of.initvolume = 128; | ||
482 | for (t = 0; t < UF_MAXCHAN; t++) of.chanvol[t] = 64; | ||
483 | for (t = 0; t < UF_MAXCHAN; t++) | ||
484 | of.panning[t] = ((t + 1) & 2) ? PAN_RIGHT : PAN_LEFT; | ||
485 | |||
486 | /* init module loader and load the header / patterns */ | ||
487 | if (!l->Init || l->Init()) { | ||
488 | _mm_rewind(modreader); | ||
489 | ok = l->Load(curious); | ||
490 | if (ok) { | ||
491 | /* propagate inflags=flags for in-module samples */ | ||
492 | for (t = 0; t < of.numsmp; t++) | ||
493 | if (of.samples[t].inflags == 0) | ||
494 | of.samples[t].inflags = of.samples[t].flags; | ||
495 | } | ||
496 | } else | ||
497 | ok = 0; | ||
498 | |||
499 | /* free loader and unitrk allocations */ | ||
500 | if (l->Cleanup) l->Cleanup(); | ||
501 | UniCleanup(); | ||
502 | |||
503 | if(!ok) { | ||
504 | ML_FreeEx(&of); | ||
505 | if(_mm_errorhandler) _mm_errorhandler(); | ||
506 | _mm_rewind(modreader);_mm_iobase_revert(modreader); | ||
507 | return NULL; | ||
508 | } | ||
509 | |||
510 | if(!ML_LoadSamples()) { | ||
511 | ML_FreeEx(&of); | ||
512 | if(_mm_errorhandler) _mm_errorhandler(); | ||
513 | _mm_rewind(modreader);_mm_iobase_revert(modreader); | ||
514 | return NULL; | ||
515 | } | ||
516 | |||
517 | if(!(mf=ML_AllocUniMod())) { | ||
518 | ML_FreeEx(&of); | ||
519 | _mm_rewind(modreader);_mm_iobase_revert(modreader); | ||
520 | if(_mm_errorhandler) _mm_errorhandler(); | ||
521 | return NULL; | ||
522 | } | ||
523 | |||
524 | /* If the module doesn't have any specific panning, create a | ||
525 | MOD-like panning, with the channels half-separated. */ | ||
526 | if (!(of.flags & UF_PANNING)) | ||
527 | for (t = 0; t < of.numchn; t++) | ||
528 | of.panning[t] = ((t + 1) & 2) ? PAN_HALFRIGHT : PAN_HALFLEFT; | ||
529 | |||
530 | /* Copy the static MODULE contents into the dynamic MODULE struct. */ | ||
531 | memcpy(mf,&of,sizeof(MODULE)); | ||
532 | |||
533 | if(maxchan>0) { | ||
534 | if(!(mf->flags&UF_NNA)&&(mf->numchn<maxchan)) | ||
535 | maxchan = mf->numchn; | ||
536 | else | ||
537 | if((mf->numvoices)&&(mf->numvoices<maxchan)) | ||
538 | maxchan = mf->numvoices; | ||
539 | |||
540 | if(maxchan<mf->numchn) mf->flags |= UF_NNA; | ||
541 | |||
542 | if(MikMod_SetNumVoices_internal(maxchan,-1)) { | ||
543 | _mm_iobase_revert(modreader); | ||
544 | Player_Free(mf); | ||
545 | return NULL; | ||
546 | } | ||
547 | } | ||
548 | if(SL_LoadSamples()) { | ||
549 | _mm_iobase_revert(modreader); | ||
550 | Player_Free_internal(mf); | ||
551 | return NULL; | ||
552 | } | ||
553 | if(Player_Init(mf)) { | ||
554 | _mm_iobase_revert(modreader); | ||
555 | Player_Free_internal(mf); | ||
556 | mf=NULL; | ||
557 | } | ||
558 | _mm_iobase_revert(modreader); | ||
559 | return mf; | ||
560 | } | ||
561 | |||
562 | MIKMODAPI MODULE* Player_LoadGeneric(MREADER *reader,int maxchan,int curious) | ||
563 | { | ||
564 | MODULE* result; | ||
565 | |||
566 | MUTEX_LOCK(vars); | ||
567 | MUTEX_LOCK(lists); | ||
568 | result=Player_LoadGeneric_internal(reader,maxchan,curious); | ||
569 | MUTEX_UNLOCK(lists); | ||
570 | MUTEX_UNLOCK(vars); | ||
571 | |||
572 | return result; | ||
573 | } | ||
574 | |||
575 | MIKMODAPI MODULE* Player_LoadMem(const char *buffer,int len,int maxchan,int curious) | ||
576 | { | ||
577 | MODULE* result=NULL; | ||
578 | MREADER* reader; | ||
579 | |||
580 | if ((reader=_mm_new_mem_reader(buffer, len))) { | ||
581 | result=Player_LoadGeneric(reader,maxchan,curious); | ||
582 | _mm_delete_mem_reader(reader); | ||
583 | } | ||
584 | return result; | ||
585 | } | ||
586 | |||
587 | /* Loads a module given a file pointer. | ||
588 | File is loaded from the current file seek position. */ | ||
589 | MIKMODAPI MODULE* Player_LoadFP(int fp,int maxchan,int curious) | ||
590 | { | ||
591 | MODULE* result=NULL; | ||
592 | struct MREADER* reader=_mm_new_file_reader (fp); | ||
593 | |||
594 | if (reader) { | ||
595 | result=Player_LoadGeneric(reader,maxchan,curious); | ||
596 | _mm_delete_file_reader(reader); | ||
597 | } | ||
598 | return result; | ||
599 | } | ||
600 | |||
601 | /* Open a module via its filename. The loader will initialize the specified | ||
602 | song-player 'player'. */ | ||
603 | MIKMODAPI MODULE* Player_Load(CHAR* filename,int maxchan,int curious) | ||
604 | { | ||
605 | int fp; | ||
606 | MODULE *mf=NULL; | ||
607 | |||
608 | if((fp=_mm_fopen(filename,"rb"))) { | ||
609 | mf=Player_LoadFP(fp,maxchan,curious); | ||
610 | _mm_fclose(fp); | ||
611 | } | ||
612 | return mf; | ||
613 | } | ||
614 | |||
615 | /* ex:set ts=4: */ | ||
diff --git a/apps/plugins/mikmod/mlreg.c b/apps/plugins/mikmod/mlreg.c new file mode 100644 index 0000000000..e57e82553b --- /dev/null +++ b/apps/plugins/mikmod/mlreg.c | |||
@@ -0,0 +1,66 @@ | |||
1 | /* MikMod sound library | ||
2 | (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for | ||
3 | 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: mlreg.c,v 1.2 2005/03/30 19:11:34 realtech Exp $ | ||
24 | |||
25 | Routine for registering all loaders in libmikmod for the current platform. | ||
26 | |||
27 | ==============================================================================*/ | ||
28 | |||
29 | #ifdef HAVE_CONFIG_H | ||
30 | #include "config.h" | ||
31 | #endif | ||
32 | |||
33 | #include "mikmod_internals.h" | ||
34 | |||
35 | void MikMod_RegisterAllLoaders_internal(void) | ||
36 | { | ||
37 | _mm_registerloader(&load_669); | ||
38 | _mm_registerloader(&load_amf); | ||
39 | _mm_registerloader(&load_asy); | ||
40 | _mm_registerloader(&load_dsm); | ||
41 | _mm_registerloader(&load_far); | ||
42 | _mm_registerloader(&load_gdm); | ||
43 | _mm_registerloader(&load_gt2); | ||
44 | _mm_registerloader(&load_it); | ||
45 | _mm_registerloader(&load_imf); | ||
46 | _mm_registerloader(&load_mod); | ||
47 | _mm_registerloader(&load_med); | ||
48 | _mm_registerloader(&load_mtm); | ||
49 | _mm_registerloader(&load_okt); | ||
50 | _mm_registerloader(&load_s3m); | ||
51 | _mm_registerloader(&load_stm); | ||
52 | _mm_registerloader(&load_stx); | ||
53 | _mm_registerloader(&load_ult); | ||
54 | _mm_registerloader(&load_uni); | ||
55 | _mm_registerloader(&load_xm); | ||
56 | |||
57 | _mm_registerloader(&load_m15); | ||
58 | } | ||
59 | |||
60 | void MikMod_RegisterAllLoaders(void) | ||
61 | { | ||
62 | MUTEX_LOCK(lists); | ||
63 | MikMod_RegisterAllLoaders_internal(); | ||
64 | MUTEX_UNLOCK(lists); | ||
65 | } | ||
66 | /* ex:set ts=4: */ | ||
diff --git a/apps/plugins/mikmod/mlutil.c b/apps/plugins/mikmod/mlutil.c new file mode 100644 index 0000000000..6d3a05f45d --- /dev/null +++ b/apps/plugins/mikmod/mlutil.c | |||
@@ -0,0 +1,336 @@ | |||
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: mlutil.c,v 1.3 2007/12/06 17:43:10 denis111 Exp $ | ||
24 | |||
25 | Utility functions for the module loader | ||
26 | |||
27 | ==============================================================================*/ | ||
28 | |||
29 | #ifdef HAVE_CONFIG_H | ||
30 | #include "config.h" | ||
31 | #endif | ||
32 | |||
33 | #ifdef HAVE_MEMORY_H | ||
34 | #include <memory.h> | ||
35 | #endif | ||
36 | #include <string.h> | ||
37 | |||
38 | #include "mikmod_internals.h" | ||
39 | |||
40 | #ifdef SUNOS | ||
41 | extern int fprintf(FILE *, const char *, ...); | ||
42 | #endif | ||
43 | |||
44 | /*========== Shared tracker identifiers */ | ||
45 | |||
46 | CHAR *STM_Signatures[STM_NTRACKERS] = { | ||
47 | "!Scream!", | ||
48 | "BMOD2STM", | ||
49 | "WUZAMOD!" | ||
50 | }; | ||
51 | |||
52 | CHAR *STM_Version[STM_NTRACKERS] = { | ||
53 | "Screamtracker 2", | ||
54 | "Converted by MOD2STM (STM format)", | ||
55 | "Wuzamod (STM format)" | ||
56 | }; | ||
57 | |||
58 | /*========== Shared loader variables */ | ||
59 | |||
60 | SBYTE remap[UF_MAXCHAN]; /* for removing empty channels */ | ||
61 | UBYTE* poslookup=NULL; /* lookup table for pattern jumps after blank | ||
62 | pattern removal */ | ||
63 | UWORD poslookupcnt; | ||
64 | UWORD* origpositions=NULL; | ||
65 | |||
66 | int filters; /* resonant filters in use */ | ||
67 | UBYTE activemacro; /* active midi macro number for Sxx,xx<80h */ | ||
68 | UBYTE filtermacros[UF_MAXMACRO]; /* midi macro settings */ | ||
69 | FILTER filtersettings[UF_MAXFILTER]; /* computed filter settings */ | ||
70 | |||
71 | /*========== Linear periods stuff */ | ||
72 | |||
73 | int* noteindex=NULL; /* remap value for linear period modules */ | ||
74 | static int noteindexcount=0; | ||
75 | |||
76 | int *AllocLinear(void) | ||
77 | { | ||
78 | if(of.numsmp>noteindexcount) { | ||
79 | noteindexcount=of.numsmp; | ||
80 | noteindex=MikMod_realloc(noteindex,noteindexcount*sizeof(int)); | ||
81 | } | ||
82 | return noteindex; | ||
83 | } | ||
84 | |||
85 | void FreeLinear(void) | ||
86 | { | ||
87 | if(noteindex) { | ||
88 | MikMod_free(noteindex); | ||
89 | noteindex=NULL; | ||
90 | } | ||
91 | noteindexcount=0; | ||
92 | } | ||
93 | |||
94 | int speed_to_finetune(ULONG speed,int sample) | ||
95 | { | ||
96 | int ctmp=0,tmp,note=1,finetune=0; | ||
97 | |||
98 | speed>>=1; | ||
99 | while((tmp=getfrequency(of.flags,getlinearperiod(note<<1,0)))<speed) { | ||
100 | ctmp=tmp; | ||
101 | note++; | ||
102 | } | ||
103 | |||
104 | if(tmp!=speed) { | ||
105 | if((tmp-speed)<(speed-ctmp)) | ||
106 | while(tmp>speed) | ||
107 | tmp=getfrequency(of.flags,getlinearperiod(note<<1,--finetune)); | ||
108 | else { | ||
109 | note--; | ||
110 | while(ctmp<speed) | ||
111 | ctmp=getfrequency(of.flags,getlinearperiod(note<<1,++finetune)); | ||
112 | } | ||
113 | } | ||
114 | |||
115 | noteindex[sample]=note-4*OCTAVE; | ||
116 | return finetune; | ||
117 | } | ||
118 | |||
119 | /*========== Order stuff */ | ||
120 | |||
121 | /* handles S3M and IT orders */ | ||
122 | void S3MIT_CreateOrders(int curious) | ||
123 | { | ||
124 | int t; | ||
125 | |||
126 | of.numpos = 0; | ||
127 | memset(of.positions,0,poslookupcnt*sizeof(UWORD)); | ||
128 | memset(poslookup,-1,256); | ||
129 | for(t=0;t<poslookupcnt;t++) { | ||
130 | int order=origpositions[t]; | ||
131 | if(order==255) order=LAST_PATTERN; | ||
132 | of.positions[of.numpos]=order; | ||
133 | poslookup[t]=of.numpos; /* bug fix for freaky S3Ms / ITs */ | ||
134 | if(origpositions[t]<254) of.numpos++; | ||
135 | else | ||
136 | /* end of song special order */ | ||
137 | if((order==LAST_PATTERN)&&(!(curious--))) break; | ||
138 | } | ||
139 | } | ||
140 | |||
141 | /*========== Effect stuff */ | ||
142 | |||
143 | /* handles S3M and IT effects */ | ||
144 | void S3MIT_ProcessCmd(UBYTE cmd,UBYTE inf,unsigned int flags) | ||
145 | { | ||
146 | UBYTE hi,lo; | ||
147 | |||
148 | lo=inf&0xf; | ||
149 | hi=inf>>4; | ||
150 | |||
151 | /* process S3M / IT specific command structure */ | ||
152 | |||
153 | if(cmd!=255) { | ||
154 | switch(cmd) { | ||
155 | case 1: /* Axx set speed to xx */ | ||
156 | UniEffect(UNI_S3MEFFECTA,inf); | ||
157 | break; | ||
158 | case 2: /* Bxx position jump */ | ||
159 | if (inf<poslookupcnt) { | ||
160 | /* switch to curious mode if necessary, for example | ||
161 | sympex.it, deep joy.it */ | ||
162 | if(((SBYTE)poslookup[inf]<0)&&(origpositions[inf]!=255)) | ||
163 | S3MIT_CreateOrders(1); | ||
164 | |||
165 | if(!((SBYTE)poslookup[inf]<0)) | ||
166 | UniPTEffect(0xb,poslookup[inf]); | ||
167 | } | ||
168 | break; | ||
169 | case 3: /* Cxx patternbreak to row xx */ | ||
170 | if ((flags & S3MIT_OLDSTYLE) && !(flags & S3MIT_IT)) | ||
171 | UniPTEffect(0xd,(inf>>4)*10+(inf&0xf)); | ||
172 | else | ||
173 | UniPTEffect(0xd,inf); | ||
174 | break; | ||
175 | case 4: /* Dxy volumeslide */ | ||
176 | UniEffect(UNI_S3MEFFECTD,inf); | ||
177 | break; | ||
178 | case 5: /* Exy toneslide down */ | ||
179 | UniEffect(UNI_S3MEFFECTE,inf); | ||
180 | break; | ||
181 | case 6: /* Fxy toneslide up */ | ||
182 | UniEffect(UNI_S3MEFFECTF,inf); | ||
183 | break; | ||
184 | case 7: /* Gxx Tone portamento, speed xx */ | ||
185 | if (flags & S3MIT_OLDSTYLE) | ||
186 | UniPTEffect(0x3,inf); | ||
187 | else | ||
188 | UniEffect(UNI_ITEFFECTG,inf); | ||
189 | break; | ||
190 | case 8: /* Hxy vibrato */ | ||
191 | if (flags & S3MIT_OLDSTYLE) | ||
192 | UniPTEffect(0x4,inf); | ||
193 | else | ||
194 | UniEffect(UNI_ITEFFECTH,inf); | ||
195 | break; | ||
196 | case 9: /* Ixy tremor, ontime x, offtime y */ | ||
197 | if (flags & S3MIT_OLDSTYLE) | ||
198 | UniEffect(UNI_S3MEFFECTI,inf); | ||
199 | else | ||
200 | UniEffect(UNI_ITEFFECTI,inf); | ||
201 | break; | ||
202 | case 0xa: /* Jxy arpeggio */ | ||
203 | UniPTEffect(0x0,inf); | ||
204 | break; | ||
205 | case 0xb: /* Kxy Dual command H00 & Dxy */ | ||
206 | if (flags & S3MIT_OLDSTYLE) | ||
207 | UniPTEffect(0x4,0); | ||
208 | else | ||
209 | UniEffect(UNI_ITEFFECTH,0); | ||
210 | UniEffect(UNI_S3MEFFECTD,inf); | ||
211 | break; | ||
212 | case 0xc: /* Lxy Dual command G00 & Dxy */ | ||
213 | if (flags & S3MIT_OLDSTYLE) | ||
214 | UniPTEffect(0x3,0); | ||
215 | else | ||
216 | UniEffect(UNI_ITEFFECTG,0); | ||
217 | UniEffect(UNI_S3MEFFECTD,inf); | ||
218 | break; | ||
219 | case 0xd: /* Mxx Set Channel Volume */ | ||
220 | UniEffect(UNI_ITEFFECTM,inf); | ||
221 | break; | ||
222 | case 0xe: /* Nxy Slide Channel Volume */ | ||
223 | UniEffect(UNI_ITEFFECTN,inf); | ||
224 | break; | ||
225 | case 0xf: /* Oxx set sampleoffset xx00h */ | ||
226 | UniPTEffect(0x9,inf); | ||
227 | break; | ||
228 | case 0x10: /* Pxy Slide Panning Commands */ | ||
229 | UniEffect(UNI_ITEFFECTP,inf); | ||
230 | break; | ||
231 | case 0x11: /* Qxy Retrig (+volumeslide) */ | ||
232 | UniWriteByte(UNI_S3MEFFECTQ); | ||
233 | if(inf && !lo && !(flags & S3MIT_OLDSTYLE)) | ||
234 | UniWriteByte(1); | ||
235 | else | ||
236 | UniWriteByte(inf); | ||
237 | break; | ||
238 | case 0x12: /* Rxy tremolo speed x, depth y */ | ||
239 | UniEffect(UNI_S3MEFFECTR,inf); | ||
240 | break; | ||
241 | case 0x13: /* Sxx special commands */ | ||
242 | if (inf>=0xf0) { | ||
243 | /* change resonant filter settings if necessary */ | ||
244 | if((filters)&&((inf&0xf)!=activemacro)) { | ||
245 | activemacro=inf&0xf; | ||
246 | for(inf=0;inf<0x80;inf++) | ||
247 | filtersettings[inf].filter=filtermacros[activemacro]; | ||
248 | } | ||
249 | } else { | ||
250 | /* Scream Tracker does not have samples larger than | ||
251 | 64 Kb, thus doesn't need the SAx effect */ | ||
252 | if ((flags & S3MIT_SCREAM) && ((inf & 0xf0) == 0xa0)) | ||
253 | break; | ||
254 | |||
255 | UniEffect(UNI_ITEFFECTS0,inf); | ||
256 | } | ||
257 | break; | ||
258 | case 0x14: /* Txx tempo */ | ||
259 | if(inf>=0x20) | ||
260 | UniEffect(UNI_S3MEFFECTT,inf); | ||
261 | else { | ||
262 | if(!(flags & S3MIT_OLDSTYLE)) | ||
263 | /* IT Tempo slide */ | ||
264 | UniEffect(UNI_ITEFFECTT,inf); | ||
265 | } | ||
266 | break; | ||
267 | case 0x15: /* Uxy Fine Vibrato speed x, depth y */ | ||
268 | if(flags & S3MIT_OLDSTYLE) | ||
269 | UniEffect(UNI_S3MEFFECTU,inf); | ||
270 | else | ||
271 | UniEffect(UNI_ITEFFECTU,inf); | ||
272 | break; | ||
273 | case 0x16: /* Vxx Set Global Volume */ | ||
274 | UniEffect(UNI_XMEFFECTG,inf); | ||
275 | break; | ||
276 | case 0x17: /* Wxy Global Volume Slide */ | ||
277 | UniEffect(UNI_ITEFFECTW,inf); | ||
278 | break; | ||
279 | case 0x18: /* Xxx amiga command 8xx */ | ||
280 | if(flags & S3MIT_OLDSTYLE) { | ||
281 | if(inf>128) | ||
282 | UniEffect(UNI_ITEFFECTS0,0x91); /* surround */ | ||
283 | else | ||
284 | UniPTEffect(0x8,(inf==128)?255:(inf<<1)); | ||
285 | } else | ||
286 | UniPTEffect(0x8,inf); | ||
287 | break; | ||
288 | case 0x19: /* Yxy Panbrello speed x, depth y */ | ||
289 | UniEffect(UNI_ITEFFECTY,inf); | ||
290 | break; | ||
291 | case 0x1a: /* Zxx midi/resonant filters */ | ||
292 | if(filtersettings[inf].filter) { | ||
293 | UniWriteByte(UNI_ITEFFECTZ); | ||
294 | UniWriteByte(filtersettings[inf].filter); | ||
295 | UniWriteByte(filtersettings[inf].inf); | ||
296 | } | ||
297 | break; | ||
298 | } | ||
299 | } | ||
300 | } | ||
301 | |||
302 | /*========== Unitrk stuff */ | ||
303 | |||
304 | /* Generic effect writing routine */ | ||
305 | void UniEffect(UWORD eff,UWORD dat) | ||
306 | { | ||
307 | if((!eff)||(eff>=UNI_LAST)) return; | ||
308 | |||
309 | UniWriteByte(eff); | ||
310 | if(unioperands[eff]==2) | ||
311 | UniWriteWord(dat); | ||
312 | else | ||
313 | UniWriteByte(dat); | ||
314 | } | ||
315 | |||
316 | /* Appends UNI_PTEFFECTX opcode to the unitrk stream. */ | ||
317 | void UniPTEffect(UBYTE eff, UBYTE dat) | ||
318 | { | ||
319 | #ifdef MIKMOD_DEBUG | ||
320 | if (eff>=0x10) | ||
321 | fprintf(stderr,"UniPTEffect called with incorrect eff value %d\n",eff); | ||
322 | else | ||
323 | #endif | ||
324 | if((eff)||(dat)||(of.flags&UF_ARPMEM)) UniEffect(UNI_PTEFFECT0+eff,dat); | ||
325 | } | ||
326 | |||
327 | /* Appends UNI_VOLEFFECT + effect/dat to unistream. */ | ||
328 | void UniVolEffect(UWORD eff,UBYTE dat) | ||
329 | { | ||
330 | if((eff)||(dat)) { /* don't write empty effect */ | ||
331 | UniWriteByte(UNI_VOLEFFECTS); | ||
332 | UniWriteByte(eff);UniWriteByte(dat); | ||
333 | } | ||
334 | } | ||
335 | |||
336 | /* ex:set ts=4: */ | ||
diff --git a/apps/plugins/mikmod/mmalloc.c b/apps/plugins/mikmod/mmalloc.c new file mode 100644 index 0000000000..7d505dff93 --- /dev/null +++ b/apps/plugins/mikmod/mmalloc.c | |||
@@ -0,0 +1,179 @@ | |||
1 | /* MikMod sound library | ||
2 | (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for | ||
3 | 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: mmalloc.c,v 1.3 2007/12/03 20:42:58 denis111 Exp $ | ||
24 | |||
25 | Dynamic memory routines | ||
26 | |||
27 | ==============================================================================*/ | ||
28 | |||
29 | #ifdef HAVE_CONFIG_H | ||
30 | #include "config.h" | ||
31 | #endif | ||
32 | |||
33 | #include "mikmod_internals.h" | ||
34 | |||
35 | #define ALIGN_STRIDE 16 | ||
36 | |||
37 | static void * align_pointer(char *ptr, size_t stride) | ||
38 | { | ||
39 | char *pptr = ptr + sizeof(void*); | ||
40 | char *fptr; | ||
41 | size_t err = ((size_t)pptr)&(stride-1); | ||
42 | if (err) | ||
43 | fptr = pptr + (stride - err); | ||
44 | else | ||
45 | fptr = pptr; | ||
46 | *(size_t*)(fptr - sizeof(void*)) = (size_t)ptr; | ||
47 | return fptr; | ||
48 | } | ||
49 | |||
50 | static void *get_pointer(void *data) | ||
51 | { | ||
52 | unsigned char *_pptr = (unsigned char*)data - sizeof(void*); | ||
53 | size_t _ptr = *(size_t*)_pptr; | ||
54 | return (void*)_ptr; | ||
55 | } | ||
56 | |||
57 | |||
58 | void* MikMod_realloc(void *data, size_t size) | ||
59 | { | ||
60 | return realloc(data, size); | ||
61 | |||
62 | #if 0 | ||
63 | if (data) | ||
64 | { | ||
65 | #if defined __MACH__ | ||
66 | void *d = realloc(data, size); | ||
67 | if (d) | ||
68 | { | ||
69 | return d; | ||
70 | } | ||
71 | return 0; | ||
72 | #elif (defined _WIN32 || defined _WIN64) && !defined(_WIN32_WCE) | ||
73 | return _aligned_realloc(data, size, ALIGN_STRIDE); | ||
74 | #else | ||
75 | unsigned char *newPtr = (unsigned char *)realloc(get_pointer(data), size + ALIGN_STRIDE + sizeof(void*)); | ||
76 | return align_pointer(newPtr, ALIGN_STRIDE); | ||
77 | #endif | ||
78 | } | ||
79 | return MikMod_malloc(size); | ||
80 | #endif | ||
81 | } | ||
82 | |||
83 | |||
84 | /* Same as malloc, but sets error variable _mm_error when fails. Returns a 16-byte aligned pointer */ | ||
85 | void* MikMod_malloc(size_t size) | ||
86 | { | ||
87 | void *d; | ||
88 | if(!(d=calloc(1,size))) { | ||
89 | _mm_errno = MMERR_OUT_OF_MEMORY; | ||
90 | if(_mm_errorhandler) _mm_errorhandler(); | ||
91 | } | ||
92 | return d; | ||
93 | |||
94 | #if 0 | ||
95 | #if defined __MACH__ | ||
96 | void *d = calloc(1, size); | ||
97 | if (d) | ||
98 | { | ||
99 | return d; | ||
100 | } | ||
101 | return 0; | ||
102 | #elif (defined _WIN32 || defined _WIN64) && !defined(_WIN32_WCE) | ||
103 | void * d = _aligned_malloc(size, ALIGN_STRIDE); | ||
104 | if (d) | ||
105 | { | ||
106 | ZeroMemory(d, size); | ||
107 | return d; | ||
108 | } | ||
109 | return 0; | ||
110 | #else | ||
111 | void *d = calloc(1, size + ALIGN_STRIDE + sizeof(void*)); | ||
112 | |||
113 | if(!d) { | ||
114 | _mm_errno = MMERR_OUT_OF_MEMORY; | ||
115 | if(_mm_errorhandler) _mm_errorhandler(); | ||
116 | } | ||
117 | return align_pointer(d, ALIGN_STRIDE); | ||
118 | #endif | ||
119 | #endif | ||
120 | } | ||
121 | |||
122 | /* Same as calloc, but sets error variable _mm_error when fails */ | ||
123 | void* MikMod_calloc(size_t nitems,size_t size) | ||
124 | { | ||
125 | void *d; | ||
126 | |||
127 | if(!(d=calloc(nitems,size))) { | ||
128 | _mm_errno = MMERR_OUT_OF_MEMORY; | ||
129 | if(_mm_errorhandler) _mm_errorhandler(); | ||
130 | } | ||
131 | return d; | ||
132 | |||
133 | #if 0 | ||
134 | #if defined __MACH__ | ||
135 | void *d = calloc(nitems, size); | ||
136 | if (d) | ||
137 | { | ||
138 | return d; | ||
139 | } | ||
140 | return 0; | ||
141 | #elif (defined _WIN32 || defined _WIN64) && !defined(_WIN32_WCE) | ||
142 | void * d = _aligned_malloc(size * nitems, ALIGN_STRIDE); | ||
143 | if (d) | ||
144 | { | ||
145 | ZeroMemory(d, size * nitems); | ||
146 | return d; | ||
147 | } | ||
148 | return 0; | ||
149 | #else | ||
150 | void *d = calloc(nitems, size + ALIGN_STRIDE + sizeof(void*)); | ||
151 | |||
152 | if(!d) { | ||
153 | _mm_errno = MMERR_OUT_OF_MEMORY; | ||
154 | if(_mm_errorhandler) _mm_errorhandler(); | ||
155 | } | ||
156 | return align_pointer(d, ALIGN_STRIDE); | ||
157 | #endif | ||
158 | #endif | ||
159 | } | ||
160 | |||
161 | void MikMod_free(void *data) | ||
162 | { | ||
163 | free(data); | ||
164 | |||
165 | #if 0 | ||
166 | if (data) | ||
167 | { | ||
168 | #if defined __MACH__ | ||
169 | free(data); | ||
170 | #elif (defined _WIN32 || defined _WIN64) && !defined(_WIN32_WCE) | ||
171 | _aligned_free(data); | ||
172 | #else | ||
173 | free(get_pointer(data)); | ||
174 | #endif | ||
175 | } | ||
176 | #endif | ||
177 | } | ||
178 | |||
179 | /* ex:set ts=4: */ | ||
diff --git a/apps/plugins/mikmod/mmerror.c b/apps/plugins/mikmod/mmerror.c new file mode 100644 index 0000000000..bd703f6c26 --- /dev/null +++ b/apps/plugins/mikmod/mmerror.c | |||
@@ -0,0 +1,213 @@ | |||
1 | /* MikMod sound library | ||
2 | (c) 1998, 1999, 2000 Miodrag Vallat and others - see file AUTHORS for | ||
3 | 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: mmerror.c,v 1.2 2005/03/30 19:10:41 realtech Exp $ | ||
24 | |||
25 | Error handling functions. | ||
26 | Register an error handler with _mm_RegisterErrorHandler() and you're all set. | ||
27 | |||
28 | ==============================================================================*/ | ||
29 | |||
30 | /* | ||
31 | |||
32 | The global variables _mm_errno, and _mm_critical are set before the error | ||
33 | handler in called. See below for the values of these variables. | ||
34 | |||
35 | */ | ||
36 | |||
37 | #ifdef HAVE_CONFIG_H | ||
38 | #include "config.h" | ||
39 | #endif | ||
40 | |||
41 | #include "mikmod_internals.h" | ||
42 | |||
43 | CHAR *_mm_errmsg[MMERR_MAX+1] = | ||
44 | { | ||
45 | /* No error */ | ||
46 | |||
47 | "No error", | ||
48 | |||
49 | /* Generic errors */ | ||
50 | |||
51 | "Could not open requested file", | ||
52 | "Out of memory", | ||
53 | "Dynamic linking failed", | ||
54 | |||
55 | /* Sample errors */ | ||
56 | |||
57 | "Out of memory to load sample", | ||
58 | "Out of sample handles to load sample", | ||
59 | "Sample format not recognized", | ||
60 | |||
61 | /* Module errors */ | ||
62 | |||
63 | "Failure loading module pattern", | ||
64 | "Failure loading module track", | ||
65 | "Failure loading module header", | ||
66 | "Failure loading sampleinfo", | ||
67 | "Module format not recognized", | ||
68 | "Module sample format not recognized", | ||
69 | "Synthsounds not supported in MED files", | ||
70 | "Compressed sample is invalid", | ||
71 | |||
72 | /* Driver errors: */ | ||
73 | |||
74 | "Sound device not detected", | ||
75 | "Device number out of range", | ||
76 | "Software mixer failure", | ||
77 | "Could not open sound device", | ||
78 | "This driver supports 8 bit linear output only", | ||
79 | "This driver supports 16 bit linear output only", | ||
80 | "This driver supports stereo output only", | ||
81 | "This driver supports uLaw output (8 bit mono, 8 kHz) only", | ||
82 | "Unable to set non-blocking mode for audio device", | ||
83 | |||
84 | /* AudioFile driver errors */ | ||
85 | |||
86 | "Cannot find suitable AudioFile audio port", | ||
87 | |||
88 | /* AIX driver errors */ | ||
89 | |||
90 | "Configuration (init step) of audio device failed", | ||
91 | "Configuration (control step) of audio device failed", | ||
92 | "Configuration (start step) of audio device failed", | ||
93 | |||
94 | /* ALSA driver errors */ | ||
95 | |||
96 | /* EsounD driver errors */ | ||
97 | |||
98 | /* Ultrasound driver errors */ | ||
99 | |||
100 | "Ultrasound driver only works in 16 bit stereo 44 KHz", | ||
101 | "Ultrasound card could not be reset", | ||
102 | "Could not start Ultrasound timer", | ||
103 | |||
104 | /* HP driver errors */ | ||
105 | |||
106 | "Unable to select 16bit-linear sample format", | ||
107 | "Could not select requested sample-rate", | ||
108 | "Could not select requested number of channels", | ||
109 | "Unable to select audio output", | ||
110 | "Unable to get audio description", | ||
111 | "Could not set transmission buffer size", | ||
112 | |||
113 | /* Open Sound System driver errors */ | ||
114 | |||
115 | "Could not set fragment size", | ||
116 | "Could not set sample size", | ||
117 | "Could not set mono/stereo setting", | ||
118 | "Could not set sample rate", | ||
119 | |||
120 | /* SGI driver errors */ | ||
121 | |||
122 | "Unsupported sample rate", | ||
123 | "Hardware does not support 16 bit sound", | ||
124 | "Hardware does not support 8 bit sound", | ||
125 | "Hardware does not support stereo sound", | ||
126 | "Hardware does not support mono sound", | ||
127 | |||
128 | /* Sun driver errors */ | ||
129 | |||
130 | "Sound device initialization failed", | ||
131 | |||
132 | /* OS/2 drivers errors */ | ||
133 | |||
134 | "Could not set mixing parameters", | ||
135 | "Could not create playback semaphores", | ||
136 | "Could not create playback timer", | ||
137 | "Could not create playback thread", | ||
138 | |||
139 | /* DirectSound driver errors */ | ||
140 | |||
141 | "Could not set playback priority", | ||
142 | "Could not create playback buffers", | ||
143 | "Could not set playback format", | ||
144 | "Could not register callback", | ||
145 | "Could not register event", | ||
146 | "Could not create playback thread", | ||
147 | "Could not initialize playback thread", | ||
148 | |||
149 | /* Windows Multimedia API driver errors */ | ||
150 | |||
151 | "Invalid device handle", | ||
152 | "The resource is already allocated", | ||
153 | "Invalid device identifier", | ||
154 | "Unsupported output format", | ||
155 | "Unknown error", | ||
156 | |||
157 | /* Macintosh driver errors */ | ||
158 | |||
159 | "Unsupported sample rate", | ||
160 | "Could not start playback", | ||
161 | |||
162 | /* MacOS X/Darwin driver errors */ | ||
163 | |||
164 | "Unknown device", | ||
165 | "Bad property", | ||
166 | "Could not set playback format", | ||
167 | "Could not set mono/stereo setting", | ||
168 | "Could not create playback buffers", | ||
169 | "Could not create playback thread", | ||
170 | "Could not start audio device", | ||
171 | "Could not create buffer thread", | ||
172 | |||
173 | /* DOS driver errors */ | ||
174 | |||
175 | "WSS_STARTDMA", | ||
176 | "SB_STARTDMA", | ||
177 | |||
178 | /* Invalid error */ | ||
179 | |||
180 | "Invalid error code" | ||
181 | }; | ||
182 | |||
183 | MIKMODAPI char *MikMod_strerror(int code) | ||
184 | { | ||
185 | if ((code<0)||(code>MMERR_MAX)) code=MMERR_MAX+1; | ||
186 | return _mm_errmsg[code]; | ||
187 | } | ||
188 | |||
189 | /* User installed error callback */ | ||
190 | MikMod_handler_t _mm_errorhandler = NULL; | ||
191 | MIKMODAPI int _mm_errno = 0; | ||
192 | MIKMODAPI int _mm_critical = 0; | ||
193 | |||
194 | MikMod_handler_t _mm_registererrorhandler(MikMod_handler_t proc) | ||
195 | { | ||
196 | MikMod_handler_t oldproc=_mm_errorhandler; | ||
197 | |||
198 | _mm_errorhandler = proc; | ||
199 | return oldproc; | ||
200 | } | ||
201 | |||
202 | MIKMODAPI MikMod_handler_t MikMod_RegisterErrorHandler(MikMod_handler_t proc) | ||
203 | { | ||
204 | MikMod_handler_t result; | ||
205 | |||
206 | MUTEX_LOCK(vars); | ||
207 | result=_mm_registererrorhandler(proc); | ||
208 | MUTEX_UNLOCK(vars); | ||
209 | |||
210 | return result; | ||
211 | } | ||
212 | |||
213 | /* ex:set ts=4: */ | ||
diff --git a/apps/plugins/mikmod/mmio.c b/apps/plugins/mikmod/mmio.c new file mode 100644 index 0000000000..344833e632 --- /dev/null +++ b/apps/plugins/mikmod/mmio.c | |||
@@ -0,0 +1,517 @@ | |||
1 | /* MikMod sound library | ||
2 | (c) 1998, 1999, 2000 Miodrag Vallat and others - see file AUTHORS for | ||
3 | 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: mmio.c,v 1.3 2005/03/30 19:10:58 realtech Exp $ | ||
24 | |||
25 | Portable file I/O routines | ||
26 | |||
27 | ==============================================================================*/ | ||
28 | |||
29 | /* | ||
30 | |||
31 | The way this module works: | ||
32 | |||
33 | - _mm_fopen will call the errorhandler [see mmerror.c] in addition to | ||
34 | setting _mm_errno on exit. | ||
35 | - _mm_iobase is for internal use. It is used by Player_LoadFP to | ||
36 | ensure that it works properly with wad files. | ||
37 | - _mm_read_I_* and _mm_read_M_* differ : the first is for reading data | ||
38 | written by a little endian (intel) machine, and the second is for reading | ||
39 | big endian (Mac, RISC, Alpha) machine data. | ||
40 | - _mm_write functions work the same as the _mm_read functions. | ||
41 | - _mm_read_string is for reading binary strings. It is basically the same | ||
42 | as an fread of bytes. | ||
43 | |||
44 | */ | ||
45 | |||
46 | #ifdef HAVE_CONFIG_H | ||
47 | #include "config.h" | ||
48 | #endif | ||
49 | |||
50 | #ifdef HAVE_UNISTD_H | ||
51 | #include <unistd.h> | ||
52 | #endif | ||
53 | |||
54 | #include <stdio.h> | ||
55 | #include <string.h> | ||
56 | |||
57 | #include "mikmod.h" | ||
58 | #include "mikmod_internals.h" | ||
59 | |||
60 | #ifdef SUNOS | ||
61 | extern int fclose(FILE *); | ||
62 | extern int fgetc(FILE *); | ||
63 | extern int fputc(int, FILE *); | ||
64 | extern size_t fread(void *, size_t, size_t, FILE *); | ||
65 | extern int fseek(FILE *, long, int); | ||
66 | extern size_t fwrite(const void *, size_t, size_t, FILE *); | ||
67 | #endif | ||
68 | |||
69 | #define COPY_BUFSIZE 1024 | ||
70 | |||
71 | /* some prototypes */ | ||
72 | static int _mm_MemReader_Eof(MREADER* reader); | ||
73 | static int _mm_MemReader_Read(MREADER* reader,void* ptr,size_t size); | ||
74 | static int _mm_MemReader_Get(MREADER* reader); | ||
75 | static int _mm_MemReader_Seek(MREADER* reader,long offset,int whence); | ||
76 | static long _mm_MemReader_Tell(MREADER* reader); | ||
77 | |||
78 | //static long _mm_iobase=0,temp_iobase=0; | ||
79 | |||
80 | int _mm_fopen(CHAR* fname,CHAR* attrib) | ||
81 | { | ||
82 | int fp; | ||
83 | |||
84 | //if(!(fp=fopen(fname,attrib))) { | ||
85 | // _mm_errno = MMERR_OPENING_FILE; | ||
86 | // if(_mm_errorhandler) _mm_errorhandler(); | ||
87 | //} | ||
88 | fp = open(fname, O_RDONLY); | ||
89 | if( fp < 0 ) { | ||
90 | _mm_errno = MMERR_OPENING_FILE; | ||
91 | if(_mm_errorhandler) _mm_errorhandler(); | ||
92 | } | ||
93 | return fp; | ||
94 | } | ||
95 | |||
96 | int _mm_FileExists(CHAR* fname) | ||
97 | { | ||
98 | int fp; | ||
99 | |||
100 | //if(!(fp=fopen(fname,"r"))) return 0; | ||
101 | //fclose(fp); | ||
102 | fp = open(fname, O_RDONLY); | ||
103 | if ( fp < 0 ) return 0; | ||
104 | close(fp); | ||
105 | |||
106 | return 1; | ||
107 | } | ||
108 | |||
109 | int _mm_fclose(int fp) | ||
110 | { | ||
111 | //return fclose(fp); | ||
112 | return close(fp); | ||
113 | } | ||
114 | |||
115 | /* Sets the current file-position as the new iobase */ | ||
116 | void _mm_iobase_setcur(MREADER* reader) | ||
117 | { | ||
118 | reader->prev_iobase=reader->iobase; /* store old value in case of revert */ | ||
119 | reader->iobase=reader->Tell(reader); | ||
120 | } | ||
121 | |||
122 | /* Reverts to the last known iobase value. */ | ||
123 | void _mm_iobase_revert(MREADER* reader) | ||
124 | { | ||
125 | reader->iobase=reader->prev_iobase; | ||
126 | } | ||
127 | |||
128 | /*========== File Reader */ | ||
129 | |||
130 | typedef struct MFILEREADER { | ||
131 | MREADER core; | ||
132 | int file; | ||
133 | } MFILEREADER; | ||
134 | |||
135 | static int _mm_FileReader_Eof(MREADER* reader) | ||
136 | { | ||
137 | //return feof(((MFILEREADER*)reader)->file); | ||
138 | int size = filesize(((MFILEREADER*)reader)->file); | ||
139 | int offset = lseek(((MFILEREADER*)reader)->file, 0, SEEK_CUR); | ||
140 | return offset < 0; | ||
141 | return (size <= 0 || offset < 0 || offset >= size) ? 1 : 0; | ||
142 | } | ||
143 | |||
144 | static int _mm_FileReader_Read(MREADER* reader,void* ptr,size_t size) | ||
145 | { | ||
146 | //return !!fread(ptr,size,1,((MFILEREADER*)reader)->file); | ||
147 | return read(((MFILEREADER*)reader)->file, ptr, size); | ||
148 | } | ||
149 | |||
150 | static int _mm_FileReader_Get(MREADER* reader) | ||
151 | { | ||
152 | //return fgetc(((MFILEREADER*)reader)->file); | ||
153 | unsigned char c; | ||
154 | if ( read(((MFILEREADER*)reader)->file, &c, 1) ) | ||
155 | return c; | ||
156 | else | ||
157 | return EOF; | ||
158 | } | ||
159 | |||
160 | static int _mm_FileReader_Seek(MREADER* reader,long offset,int whence) | ||
161 | { | ||
162 | //return fseek(((MFILEREADER*)reader)->file, | ||
163 | // (whence==SEEK_SET)?offset+reader->iobase:offset,whence); | ||
164 | return lseek(((MFILEREADER*)reader)->file, | ||
165 | (whence==SEEK_SET)?offset+reader->iobase:offset,whence); | ||
166 | } | ||
167 | |||
168 | static long _mm_FileReader_Tell(MREADER* reader) | ||
169 | { | ||
170 | //return ftell(((MFILEREADER*)reader)->file)-reader->iobase; | ||
171 | return lseek( (((MFILEREADER*)reader)->file)-reader->iobase, 0, SEEK_CUR ); | ||
172 | } | ||
173 | |||
174 | MREADER *_mm_new_file_reader(int fp) | ||
175 | { | ||
176 | MFILEREADER* reader=(MFILEREADER*)MikMod_malloc(sizeof(MFILEREADER)); | ||
177 | if (reader) { | ||
178 | reader->core.Eof =&_mm_FileReader_Eof; | ||
179 | reader->core.Read=&_mm_FileReader_Read; | ||
180 | reader->core.Get =&_mm_FileReader_Get; | ||
181 | reader->core.Seek=&_mm_FileReader_Seek; | ||
182 | reader->core.Tell=&_mm_FileReader_Tell; | ||
183 | reader->file=fp; | ||
184 | } | ||
185 | return (MREADER*)reader; | ||
186 | } | ||
187 | |||
188 | void _mm_delete_file_reader (MREADER* reader) | ||
189 | { | ||
190 | if(reader) MikMod_free(reader); | ||
191 | } | ||
192 | |||
193 | /*========== File Writer */ | ||
194 | |||
195 | typedef struct MFILEWRITER { | ||
196 | MWRITER core; | ||
197 | int file; | ||
198 | } MFILEWRITER; | ||
199 | |||
200 | static int _mm_FileWriter_Seek(MWRITER* writer,long offset,int whence) | ||
201 | { | ||
202 | //return fseek(((MFILEWRITER*)writer)->file,offset,whence); | ||
203 | return lseek(((MFILEREADER*)writer)->file,offset,whence); | ||
204 | } | ||
205 | |||
206 | static long _mm_FileWriter_Tell(MWRITER* writer) | ||
207 | { | ||
208 | //return ftell(((MFILEWRITER*)writer)->file); | ||
209 | return lseek(((MFILEWRITER*)writer)->file, 0, SEEK_CUR); | ||
210 | } | ||
211 | |||
212 | static int _mm_FileWriter_Write(MWRITER* writer,void* ptr,size_t size) | ||
213 | { | ||
214 | //return (fwrite(ptr,size,1,((MFILEWRITER*)writer)->file)==size); | ||
215 | return (write(ptr,size,((MFILEWRITER*)writer)->file)==size); | ||
216 | } | ||
217 | |||
218 | static int _mm_FileWriter_Put(MWRITER* writer,int value) | ||
219 | { | ||
220 | //return fputc(value,((MFILEWRITER*)writer)->file); | ||
221 | return 1; // TODO | ||
222 | } | ||
223 | |||
224 | MWRITER *_mm_new_file_writer(int fp) | ||
225 | { | ||
226 | MFILEWRITER* writer=(MFILEWRITER*)MikMod_malloc(sizeof(MFILEWRITER)); | ||
227 | if (writer) { | ||
228 | writer->core.Seek =&_mm_FileWriter_Seek; | ||
229 | writer->core.Tell =&_mm_FileWriter_Tell; | ||
230 | writer->core.Write=&_mm_FileWriter_Write; | ||
231 | writer->core.Put =&_mm_FileWriter_Put; | ||
232 | writer->file=fp; | ||
233 | } | ||
234 | return (MWRITER*) writer; | ||
235 | } | ||
236 | |||
237 | void _mm_delete_file_writer (MWRITER* writer) | ||
238 | { | ||
239 | if(writer) MikMod_free (writer); | ||
240 | } | ||
241 | |||
242 | /*========== Memory Reader */ | ||
243 | |||
244 | |||
245 | typedef struct MMEMREADER { | ||
246 | MREADER core; | ||
247 | const void *buffer; | ||
248 | long len; | ||
249 | long pos; | ||
250 | } MMEMREADER; | ||
251 | |||
252 | void _mm_delete_mem_reader(MREADER* reader) | ||
253 | { | ||
254 | if (reader) { MikMod_free(reader); } | ||
255 | } | ||
256 | |||
257 | MREADER *_mm_new_mem_reader(const void *buffer, int len) | ||
258 | { | ||
259 | MMEMREADER* reader=(MMEMREADER*)MikMod_malloc(sizeof(MMEMREADER)); | ||
260 | if (reader) | ||
261 | { | ||
262 | reader->core.Eof =&_mm_MemReader_Eof; | ||
263 | reader->core.Read=&_mm_MemReader_Read; | ||
264 | reader->core.Get =&_mm_MemReader_Get; | ||
265 | reader->core.Seek=&_mm_MemReader_Seek; | ||
266 | reader->core.Tell=&_mm_MemReader_Tell; | ||
267 | reader->buffer = buffer; | ||
268 | reader->len = len; | ||
269 | reader->pos = 0; | ||
270 | } | ||
271 | return (MREADER*)reader; | ||
272 | } | ||
273 | |||
274 | static int _mm_MemReader_Eof(MREADER* reader) | ||
275 | { | ||
276 | if (!reader) { return 1; } | ||
277 | if ( ((MMEMREADER*)reader)->pos > ((MMEMREADER*)reader)->len ) { | ||
278 | return 1; | ||
279 | } | ||
280 | return 0; | ||
281 | } | ||
282 | |||
283 | static int _mm_MemReader_Read(MREADER* reader,void* ptr,size_t size) | ||
284 | { | ||
285 | unsigned char *d=ptr; | ||
286 | const unsigned char *s; | ||
287 | |||
288 | if (!reader) { return 0; } | ||
289 | |||
290 | if (reader->Eof(reader)) { return 0; } | ||
291 | |||
292 | s = ((MMEMREADER*)reader)->buffer; | ||
293 | s += ((MMEMREADER*)reader)->pos; | ||
294 | |||
295 | if ( ((MMEMREADER*)reader)->pos + size > ((MMEMREADER*)reader)->len) | ||
296 | { | ||
297 | ((MMEMREADER*)reader)->pos = ((MMEMREADER*)reader)->len; | ||
298 | return 0; /* not enough remaining bytes */ | ||
299 | } | ||
300 | |||
301 | ((MMEMREADER*)reader)->pos += (long)size; | ||
302 | |||
303 | while (size--) | ||
304 | { | ||
305 | *d = *s; | ||
306 | s++; | ||
307 | d++; | ||
308 | } | ||
309 | |||
310 | return 1; | ||
311 | } | ||
312 | |||
313 | static int _mm_MemReader_Get(MREADER* reader) | ||
314 | { | ||
315 | int pos; | ||
316 | |||
317 | if (reader->Eof(reader)) { return 0; } | ||
318 | |||
319 | pos = ((MMEMREADER*)reader)->pos; | ||
320 | ((MMEMREADER*)reader)->pos++; | ||
321 | |||
322 | return ((unsigned char*)(((MMEMREADER*)reader)->buffer))[pos]; | ||
323 | } | ||
324 | |||
325 | static int _mm_MemReader_Seek(MREADER* reader,long offset,int whence) | ||
326 | { | ||
327 | if (!reader) { return -1; } | ||
328 | |||
329 | switch(whence) | ||
330 | { | ||
331 | case SEEK_CUR: | ||
332 | ((MMEMREADER*)reader)->pos += offset; | ||
333 | break; | ||
334 | case SEEK_SET: | ||
335 | ((MMEMREADER*)reader)->pos = offset; | ||
336 | break; | ||
337 | case SEEK_END: | ||
338 | ((MMEMREADER*)reader)->pos = ((MMEMREADER*)reader)->len - offset - 1; | ||
339 | break; | ||
340 | } | ||
341 | if ( ((MMEMREADER*)reader)->pos < 0) { ((MMEMREADER*)reader)->pos = 0; } | ||
342 | if ( ((MMEMREADER*)reader)->pos > ((MMEMREADER*)reader)->len ) { | ||
343 | ((MMEMREADER*)reader)->pos = ((MMEMREADER*)reader)->len; | ||
344 | } | ||
345 | return 0; | ||
346 | } | ||
347 | |||
348 | static long _mm_MemReader_Tell(MREADER* reader) | ||
349 | { | ||
350 | if (reader) { | ||
351 | return ((MMEMREADER*)reader)->pos; | ||
352 | } | ||
353 | return 0; | ||
354 | } | ||
355 | |||
356 | /*========== Write functions */ | ||
357 | |||
358 | void _mm_write_string(CHAR* data,MWRITER* writer) | ||
359 | { | ||
360 | if(data) | ||
361 | _mm_write_UBYTES(data,strlen(data),writer); | ||
362 | } | ||
363 | |||
364 | void _mm_write_M_UWORD(UWORD data,MWRITER* writer) | ||
365 | { | ||
366 | _mm_write_UBYTE(data>>8,writer); | ||
367 | _mm_write_UBYTE(data&0xff,writer); | ||
368 | } | ||
369 | |||
370 | void _mm_write_I_UWORD(UWORD data,MWRITER* writer) | ||
371 | { | ||
372 | _mm_write_UBYTE(data&0xff,writer); | ||
373 | _mm_write_UBYTE(data>>8,writer); | ||
374 | } | ||
375 | |||
376 | void _mm_write_M_ULONG(ULONG data,MWRITER* writer) | ||
377 | { | ||
378 | _mm_write_M_UWORD(data>>16,writer); | ||
379 | _mm_write_M_UWORD(data&0xffff,writer); | ||
380 | } | ||
381 | |||
382 | void _mm_write_I_ULONG(ULONG data,MWRITER* writer) | ||
383 | { | ||
384 | _mm_write_I_UWORD(data&0xffff,writer); | ||
385 | _mm_write_I_UWORD(data>>16,writer); | ||
386 | } | ||
387 | |||
388 | void _mm_write_M_SWORD(SWORD data,MWRITER* writer) | ||
389 | { | ||
390 | _mm_write_M_UWORD((UWORD)data,writer); | ||
391 | } | ||
392 | |||
393 | void _mm_write_I_SWORD(SWORD data,MWRITER* writer) | ||
394 | { | ||
395 | _mm_write_I_UWORD((UWORD)data,writer); | ||
396 | } | ||
397 | |||
398 | void _mm_write_M_SLONG(SLONG data,MWRITER* writer) | ||
399 | { | ||
400 | _mm_write_M_ULONG((ULONG)data,writer); | ||
401 | } | ||
402 | |||
403 | void _mm_write_I_SLONG(SLONG data,MWRITER* writer) | ||
404 | { | ||
405 | _mm_write_I_ULONG((ULONG)data,writer); | ||
406 | } | ||
407 | |||
408 | #if defined __STDC__ || defined _MSC_VER || defined MPW_C | ||
409 | #define DEFINE_MULTIPLE_WRITE_FUNCTION(type_name,type) \ | ||
410 | void _mm_write_##type_name##S (type *buffer,int number,MWRITER* writer) \ | ||
411 | { \ | ||
412 | while(number-->0) \ | ||
413 | _mm_write_##type_name(*(buffer++),writer); \ | ||
414 | } | ||
415 | #else | ||
416 | #define DEFINE_MULTIPLE_WRITE_FUNCTION(type_name,type) \ | ||
417 | void _mm_write_/**/type_name/**/S (type *buffer,int number,MWRITER* writer) \ | ||
418 | { \ | ||
419 | while(number-->0) \ | ||
420 | _mm_write_/**/type_name(*(buffer++),writer); \ | ||
421 | } | ||
422 | #endif | ||
423 | |||
424 | DEFINE_MULTIPLE_WRITE_FUNCTION(M_SWORD,SWORD) | ||
425 | DEFINE_MULTIPLE_WRITE_FUNCTION(M_UWORD,UWORD) | ||
426 | DEFINE_MULTIPLE_WRITE_FUNCTION(I_SWORD,SWORD) | ||
427 | DEFINE_MULTIPLE_WRITE_FUNCTION(I_UWORD,UWORD) | ||
428 | |||
429 | DEFINE_MULTIPLE_WRITE_FUNCTION(M_SLONG,SLONG) | ||
430 | DEFINE_MULTIPLE_WRITE_FUNCTION(M_ULONG,ULONG) | ||
431 | DEFINE_MULTIPLE_WRITE_FUNCTION(I_SLONG,SLONG) | ||
432 | DEFINE_MULTIPLE_WRITE_FUNCTION(I_ULONG,ULONG) | ||
433 | |||
434 | /*========== Read functions */ | ||
435 | |||
436 | int _mm_read_string(CHAR* buffer,int number,MREADER* reader) | ||
437 | { | ||
438 | return reader->Read(reader,buffer,number); | ||
439 | } | ||
440 | |||
441 | UWORD _mm_read_M_UWORD(MREADER* reader) | ||
442 | { | ||
443 | UWORD result=((UWORD)_mm_read_UBYTE(reader))<<8; | ||
444 | result|=_mm_read_UBYTE(reader); | ||
445 | return result; | ||
446 | } | ||
447 | |||
448 | UWORD _mm_read_I_UWORD(MREADER* reader) | ||
449 | { | ||
450 | UWORD result=_mm_read_UBYTE(reader); | ||
451 | result|=((UWORD)_mm_read_UBYTE(reader))<<8; | ||
452 | return result; | ||
453 | } | ||
454 | |||
455 | ULONG _mm_read_M_ULONG(MREADER* reader) | ||
456 | { | ||
457 | ULONG result=((ULONG)_mm_read_M_UWORD(reader))<<16; | ||
458 | result|=_mm_read_M_UWORD(reader); | ||
459 | return result; | ||
460 | } | ||
461 | |||
462 | ULONG _mm_read_I_ULONG(MREADER* reader) | ||
463 | { | ||
464 | ULONG result=_mm_read_I_UWORD(reader); | ||
465 | result|=((ULONG)_mm_read_I_UWORD(reader))<<16; | ||
466 | return result; | ||
467 | } | ||
468 | |||
469 | SWORD _mm_read_M_SWORD(MREADER* reader) | ||
470 | { | ||
471 | return((SWORD)_mm_read_M_UWORD(reader)); | ||
472 | } | ||
473 | |||
474 | SWORD _mm_read_I_SWORD(MREADER* reader) | ||
475 | { | ||
476 | return((SWORD)_mm_read_I_UWORD(reader)); | ||
477 | } | ||
478 | |||
479 | SLONG _mm_read_M_SLONG(MREADER* reader) | ||
480 | { | ||
481 | return((SLONG)_mm_read_M_ULONG(reader)); | ||
482 | } | ||
483 | |||
484 | SLONG _mm_read_I_SLONG(MREADER* reader) | ||
485 | { | ||
486 | return((SLONG)_mm_read_I_ULONG(reader)); | ||
487 | } | ||
488 | |||
489 | #if defined __STDC__ || defined _MSC_VER || defined MPW_C | ||
490 | #define DEFINE_MULTIPLE_READ_FUNCTION(type_name,type) \ | ||
491 | int _mm_read_##type_name##S (type *buffer,int number,MREADER* reader) \ | ||
492 | { \ | ||
493 | while(number-->0) \ | ||
494 | *(buffer++)=_mm_read_##type_name(reader); \ | ||
495 | return !reader->Eof(reader); \ | ||
496 | } | ||
497 | #else | ||
498 | #define DEFINE_MULTIPLE_READ_FUNCTION(type_name,type) \ | ||
499 | int _mm_read_/**/type_name/**/S (type *buffer,int number,MREADER* reader) \ | ||
500 | { \ | ||
501 | while(number-->0) \ | ||
502 | *(buffer++)=_mm_read_/**/type_name(reader); \ | ||
503 | return !reader->Eof(reader); \ | ||
504 | } | ||
505 | #endif | ||
506 | |||
507 | DEFINE_MULTIPLE_READ_FUNCTION(M_SWORD,SWORD) | ||
508 | DEFINE_MULTIPLE_READ_FUNCTION(M_UWORD,UWORD) | ||
509 | DEFINE_MULTIPLE_READ_FUNCTION(I_SWORD,SWORD) | ||
510 | DEFINE_MULTIPLE_READ_FUNCTION(I_UWORD,UWORD) | ||
511 | |||
512 | DEFINE_MULTIPLE_READ_FUNCTION(M_SLONG,SLONG) | ||
513 | DEFINE_MULTIPLE_READ_FUNCTION(M_ULONG,ULONG) | ||
514 | DEFINE_MULTIPLE_READ_FUNCTION(I_SLONG,SLONG) | ||
515 | DEFINE_MULTIPLE_READ_FUNCTION(I_ULONG,ULONG) | ||
516 | |||
517 | /* ex:set ts=4: */ | ||
diff --git a/apps/plugins/mikmod/mplayer.c b/apps/plugins/mikmod/mplayer.c new file mode 100644 index 0000000000..92585f0320 --- /dev/null +++ b/apps/plugins/mikmod/mplayer.c | |||
@@ -0,0 +1,3409 @@ | |||
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: mplayer.c,v 1.4 2006/08/08 00:06:31 realtech Exp $ | ||
24 | |||
25 | The Protracker Player Driver | ||
26 | |||
27 | The protracker driver supports all base Protracker 3.x commands and features. | ||
28 | |||
29 | ==============================================================================*/ | ||
30 | |||
31 | #ifdef HAVE_CONFIG_H | ||
32 | #include "config.h" | ||
33 | #endif | ||
34 | |||
35 | #include <string.h> | ||
36 | #include <stdarg.h> | ||
37 | #ifdef SRANDOM_IN_MATH_H | ||
38 | #include <math.h> | ||
39 | #else | ||
40 | #include <stdlib.h> | ||
41 | #endif | ||
42 | |||
43 | #include "mikmod_internals.h" | ||
44 | |||
45 | #ifdef SUNOS | ||
46 | extern int fprintf(FILE *, const char *, ...); | ||
47 | extern long int random(void); | ||
48 | #endif | ||
49 | |||
50 | /* The currently playing module */ | ||
51 | MODULE *pf = NULL; | ||
52 | |||
53 | #define HIGH_OCTAVE 2 /* number of above-range octaves */ | ||
54 | |||
55 | static UWORD oldperiods[OCTAVE*2]={ | ||
56 | 0x6b00, 0x6800, 0x6500, 0x6220, 0x5f50, 0x5c80, | ||
57 | 0x5a00, 0x5740, 0x54d0, 0x5260, 0x5010, 0x4dc0, | ||
58 | 0x4b90, 0x4960, 0x4750, 0x4540, 0x4350, 0x4160, | ||
59 | 0x3f90, 0x3dc0, 0x3c10, 0x3a40, 0x38b0, 0x3700 | ||
60 | }; | ||
61 | |||
62 | static UBYTE VibratoTable[32]={ | ||
63 | 0, 24, 49, 74, 97,120,141,161,180,197,212,224,235,244,250,253, | ||
64 | 255,253,250,244,235,224,212,197,180,161,141,120, 97, 74, 49, 24 | ||
65 | }; | ||
66 | |||
67 | static UBYTE avibtab[128]={ | ||
68 | 0, 1, 3, 4, 6, 7, 9,10,12,14,15,17,18,20,21,23, | ||
69 | 24,25,27,28,30,31,32,34,35,36,38,39,40,41,42,44, | ||
70 | 45,46,47,48,49,50,51,52,53,54,54,55,56,57,57,58, | ||
71 | 59,59,60,60,61,61,62,62,62,63,63,63,63,63,63,63, | ||
72 | 64,63,63,63,63,63,63,63,62,62,62,61,61,60,60,59, | ||
73 | 59,58,57,57,56,55,54,54,53,52,51,50,49,48,47,46, | ||
74 | 45,44,42,41,40,39,38,36,35,34,32,31,30,28,27,25, | ||
75 | 24,23,21,20,18,17,15,14,12,10, 9, 7, 6, 4, 3, 1 | ||
76 | }; | ||
77 | |||
78 | /* Triton's linear periods to frequency translation table (for XM modules) */ | ||
79 | static ULONG lintab[768]={ | ||
80 | 535232,534749,534266,533784,533303,532822,532341,531861, | ||
81 | 531381,530902,530423,529944,529466,528988,528511,528034, | ||
82 | 527558,527082,526607,526131,525657,525183,524709,524236, | ||
83 | 523763,523290,522818,522346,521875,521404,520934,520464, | ||
84 | 519994,519525,519057,518588,518121,517653,517186,516720, | ||
85 | 516253,515788,515322,514858,514393,513929,513465,513002, | ||
86 | 512539,512077,511615,511154,510692,510232,509771,509312, | ||
87 | 508852,508393,507934,507476,507018,506561,506104,505647, | ||
88 | 505191,504735,504280,503825,503371,502917,502463,502010, | ||
89 | 501557,501104,500652,500201,499749,499298,498848,498398, | ||
90 | 497948,497499,497050,496602,496154,495706,495259,494812, | ||
91 | 494366,493920,493474,493029,492585,492140,491696,491253, | ||
92 | 490809,490367,489924,489482,489041,488600,488159,487718, | ||
93 | 487278,486839,486400,485961,485522,485084,484647,484210, | ||
94 | 483773,483336,482900,482465,482029,481595,481160,480726, | ||
95 | 480292,479859,479426,478994,478562,478130,477699,477268, | ||
96 | 476837,476407,475977,475548,475119,474690,474262,473834, | ||
97 | 473407,472979,472553,472126,471701,471275,470850,470425, | ||
98 | 470001,469577,469153,468730,468307,467884,467462,467041, | ||
99 | 466619,466198,465778,465358,464938,464518,464099,463681, | ||
100 | 463262,462844,462427,462010,461593,461177,460760,460345, | ||
101 | 459930,459515,459100,458686,458272,457859,457446,457033, | ||
102 | 456621,456209,455797,455386,454975,454565,454155,453745, | ||
103 | 453336,452927,452518,452110,451702,451294,450887,450481, | ||
104 | 450074,449668,449262,448857,448452,448048,447644,447240, | ||
105 | 446836,446433,446030,445628,445226,444824,444423,444022, | ||
106 | 443622,443221,442821,442422,442023,441624,441226,440828, | ||
107 | 440430,440033,439636,439239,438843,438447,438051,437656, | ||
108 | 437261,436867,436473,436079,435686,435293,434900,434508, | ||
109 | 434116,433724,433333,432942,432551,432161,431771,431382, | ||
110 | 430992,430604,430215,429827,429439,429052,428665,428278, | ||
111 | 427892,427506,427120,426735,426350,425965,425581,425197, | ||
112 | 424813,424430,424047,423665,423283,422901,422519,422138, | ||
113 | 421757,421377,420997,420617,420237,419858,419479,419101, | ||
114 | 418723,418345,417968,417591,417214,416838,416462,416086, | ||
115 | 415711,415336,414961,414586,414212,413839,413465,413092, | ||
116 | 412720,412347,411975,411604,411232,410862,410491,410121, | ||
117 | 409751,409381,409012,408643,408274,407906,407538,407170, | ||
118 | 406803,406436,406069,405703,405337,404971,404606,404241, | ||
119 | 403876,403512,403148,402784,402421,402058,401695,401333, | ||
120 | 400970,400609,400247,399886,399525,399165,398805,398445, | ||
121 | 398086,397727,397368,397009,396651,396293,395936,395579, | ||
122 | 395222,394865,394509,394153,393798,393442,393087,392733, | ||
123 | 392378,392024,391671,391317,390964,390612,390259,389907, | ||
124 | 389556,389204,388853,388502,388152,387802,387452,387102, | ||
125 | 386753,386404,386056,385707,385359,385012,384664,384317, | ||
126 | 383971,383624,383278,382932,382587,382242,381897,381552, | ||
127 | 381208,380864,380521,380177,379834,379492,379149,378807, | ||
128 | 378466,378124,377783,377442,377102,376762,376422,376082, | ||
129 | 375743,375404,375065,374727,374389,374051,373714,373377, | ||
130 | 373040,372703,372367,372031,371695,371360,371025,370690, | ||
131 | 370356,370022,369688,369355,369021,368688,368356,368023, | ||
132 | 367691,367360,367028,366697,366366,366036,365706,365376, | ||
133 | 365046,364717,364388,364059,363731,363403,363075,362747, | ||
134 | 362420,362093,361766,361440,361114,360788,360463,360137, | ||
135 | 359813,359488,359164,358840,358516,358193,357869,357547, | ||
136 | 357224,356902,356580,356258,355937,355616,355295,354974, | ||
137 | 354654,354334,354014,353695,353376,353057,352739,352420, | ||
138 | 352103,351785,351468,351150,350834,350517,350201,349885, | ||
139 | 349569,349254,348939,348624,348310,347995,347682,347368, | ||
140 | 347055,346741,346429,346116,345804,345492,345180,344869, | ||
141 | 344558,344247,343936,343626,343316,343006,342697,342388, | ||
142 | 342079,341770,341462,341154,340846,340539,340231,339924, | ||
143 | 339618,339311,339005,338700,338394,338089,337784,337479, | ||
144 | 337175,336870,336566,336263,335959,335656,335354,335051, | ||
145 | 334749,334447,334145,333844,333542,333242,332941,332641, | ||
146 | 332341,332041,331741,331442,331143,330844,330546,330247, | ||
147 | 329950,329652,329355,329057,328761,328464,328168,327872, | ||
148 | 327576,327280,326985,326690,326395,326101,325807,325513, | ||
149 | 325219,324926,324633,324340,324047,323755,323463,323171, | ||
150 | 322879,322588,322297,322006,321716,321426,321136,320846, | ||
151 | 320557,320267,319978,319690,319401,319113,318825,318538, | ||
152 | 318250,317963,317676,317390,317103,316817,316532,316246, | ||
153 | 315961,315676,315391,315106,314822,314538,314254,313971, | ||
154 | 313688,313405,313122,312839,312557,312275,311994,311712, | ||
155 | 311431,311150,310869,310589,310309,310029,309749,309470, | ||
156 | 309190,308911,308633,308354,308076,307798,307521,307243, | ||
157 | 306966,306689,306412,306136,305860,305584,305308,305033, | ||
158 | 304758,304483,304208,303934,303659,303385,303112,302838, | ||
159 | 302565,302292,302019,301747,301475,301203,300931,300660, | ||
160 | 300388,300117,299847,299576,299306,299036,298766,298497, | ||
161 | 298227,297958,297689,297421,297153,296884,296617,296349, | ||
162 | 296082,295815,295548,295281,295015,294749,294483,294217, | ||
163 | 293952,293686,293421,293157,292892,292628,292364,292100, | ||
164 | 291837,291574,291311,291048,290785,290523,290261,289999, | ||
165 | 289737,289476,289215,288954,288693,288433,288173,287913, | ||
166 | 287653,287393,287134,286875,286616,286358,286099,285841, | ||
167 | 285583,285326,285068,284811,284554,284298,284041,283785, | ||
168 | 283529,283273,283017,282762,282507,282252,281998,281743, | ||
169 | 281489,281235,280981,280728,280475,280222,279969,279716, | ||
170 | 279464,279212,278960,278708,278457,278206,277955,277704, | ||
171 | 277453,277203,276953,276703,276453,276204,275955,275706, | ||
172 | 275457,275209,274960,274712,274465,274217,273970,273722, | ||
173 | 273476,273229,272982,272736,272490,272244,271999,271753, | ||
174 | 271508,271263,271018,270774,270530,270286,270042,269798, | ||
175 | 269555,269312,269069,268826,268583,268341,268099,267857 | ||
176 | }; | ||
177 | |||
178 | #define LOGFAC 2*16 | ||
179 | static UWORD logtab[104]={ | ||
180 | LOGFAC*907,LOGFAC*900,LOGFAC*894,LOGFAC*887, | ||
181 | LOGFAC*881,LOGFAC*875,LOGFAC*868,LOGFAC*862, | ||
182 | LOGFAC*856,LOGFAC*850,LOGFAC*844,LOGFAC*838, | ||
183 | LOGFAC*832,LOGFAC*826,LOGFAC*820,LOGFAC*814, | ||
184 | LOGFAC*808,LOGFAC*802,LOGFAC*796,LOGFAC*791, | ||
185 | LOGFAC*785,LOGFAC*779,LOGFAC*774,LOGFAC*768, | ||
186 | LOGFAC*762,LOGFAC*757,LOGFAC*752,LOGFAC*746, | ||
187 | LOGFAC*741,LOGFAC*736,LOGFAC*730,LOGFAC*725, | ||
188 | LOGFAC*720,LOGFAC*715,LOGFAC*709,LOGFAC*704, | ||
189 | LOGFAC*699,LOGFAC*694,LOGFAC*689,LOGFAC*684, | ||
190 | LOGFAC*678,LOGFAC*675,LOGFAC*670,LOGFAC*665, | ||
191 | LOGFAC*660,LOGFAC*655,LOGFAC*651,LOGFAC*646, | ||
192 | LOGFAC*640,LOGFAC*636,LOGFAC*632,LOGFAC*628, | ||
193 | LOGFAC*623,LOGFAC*619,LOGFAC*614,LOGFAC*610, | ||
194 | LOGFAC*604,LOGFAC*601,LOGFAC*597,LOGFAC*592, | ||
195 | LOGFAC*588,LOGFAC*584,LOGFAC*580,LOGFAC*575, | ||
196 | LOGFAC*570,LOGFAC*567,LOGFAC*563,LOGFAC*559, | ||
197 | LOGFAC*555,LOGFAC*551,LOGFAC*547,LOGFAC*543, | ||
198 | LOGFAC*538,LOGFAC*535,LOGFAC*532,LOGFAC*528, | ||
199 | LOGFAC*524,LOGFAC*520,LOGFAC*516,LOGFAC*513, | ||
200 | LOGFAC*508,LOGFAC*505,LOGFAC*502,LOGFAC*498, | ||
201 | LOGFAC*494,LOGFAC*491,LOGFAC*487,LOGFAC*484, | ||
202 | LOGFAC*480,LOGFAC*477,LOGFAC*474,LOGFAC*470, | ||
203 | LOGFAC*467,LOGFAC*463,LOGFAC*460,LOGFAC*457, | ||
204 | LOGFAC*453,LOGFAC*450,LOGFAC*447,LOGFAC*443, | ||
205 | LOGFAC*440,LOGFAC*437,LOGFAC*434,LOGFAC*431 | ||
206 | }; | ||
207 | |||
208 | static SBYTE PanbrelloTable[256]={ | ||
209 | 0, 2, 3, 5, 6, 8, 9, 11, 12, 14, 16, 17, 19, 20, 22, 23, | ||
210 | 24, 26, 27, 29, 30, 32, 33, 34, 36, 37, 38, 39, 41, 42, 43, 44, | ||
211 | 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 56, 57, 58, 59, | ||
212 | 59, 60, 60, 61, 61, 62, 62, 62, 63, 63, 63, 64, 64, 64, 64, 64, | ||
213 | 64, 64, 64, 64, 64, 64, 63, 63, 63, 62, 62, 62, 61, 61, 60, 60, | ||
214 | 59, 59, 58, 57, 56, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, | ||
215 | 45, 44, 43, 42, 41, 39, 38, 37, 36, 34, 33, 32, 30, 29, 27, 26, | ||
216 | 24, 23, 22, 20, 19, 17, 16, 14, 12, 11, 9, 8, 6, 5, 3, 2, | ||
217 | 0,- 2,- 3,- 5,- 6,- 8,- 9,-11,-12,-14,-16,-17,-19,-20,-22,-23, | ||
218 | -24,-26,-27,-29,-30,-32,-33,-34,-36,-37,-38,-39,-41,-42,-43,-44, | ||
219 | -45,-46,-47,-48,-49,-50,-51,-52,-53,-54,-55,-56,-56,-57,-58,-59, | ||
220 | -59,-60,-60,-61,-61,-62,-62,-62,-63,-63,-63,-64,-64,-64,-64,-64, | ||
221 | -64,-64,-64,-64,-64,-64,-63,-63,-63,-62,-62,-62,-61,-61,-60,-60, | ||
222 | -59,-59,-58,-57,-56,-56,-55,-54,-53,-52,-51,-50,-49,-48,-47,-46, | ||
223 | -45,-44,-43,-42,-41,-39,-38,-37,-36,-34,-33,-32,-30,-29,-27,-26, | ||
224 | -24,-23,-22,-20,-19,-17,-16,-14,-12,-11,- 9,- 8,- 6,- 5,- 3,- 2 | ||
225 | }; | ||
226 | |||
227 | /* returns a random value between 0 and ceil-1, ceil must be a power of two */ | ||
228 | static int getrandom(int ceil) | ||
229 | { | ||
230 | #ifdef HAVE_SRANDOM | ||
231 | return random()&(ceil-1); | ||
232 | #else | ||
233 | return (rand()*ceil)/(RAND_MAX+1.0); | ||
234 | #endif | ||
235 | } | ||
236 | |||
237 | /* New Note Action Scoring System : | ||
238 | -------------------------------- | ||
239 | 1) total-volume (fadevol, chanvol, volume) is the main scorer. | ||
240 | 2) a looping sample is a bonus x2 | ||
241 | 3) a foreground channel is a bonus x4 | ||
242 | 4) an active envelope with keyoff is a handicap -x2 | ||
243 | */ | ||
244 | static int MP_FindEmptyChannel(MODULE *mod) | ||
245 | { | ||
246 | MP_VOICE *a; | ||
247 | ULONG t,k,tvol,pp; | ||
248 | |||
249 | for (t=0;t<md_sngchn;t++) | ||
250 | if (((mod->voice[t].main.kick==KICK_ABSENT)|| | ||
251 | (mod->voice[t].main.kick==KICK_ENV))&& | ||
252 | Voice_Stopped_internal(t)) | ||
253 | return t; | ||
254 | |||
255 | tvol=0xffffffUL;t=-1;a=mod->voice; | ||
256 | for (k=0;k<md_sngchn;k++,a++) { | ||
257 | /* allow us to take over a nonexisting sample */ | ||
258 | if (!a->main.s) | ||
259 | return k; | ||
260 | |||
261 | if ((a->main.kick==KICK_ABSENT)||(a->main.kick==KICK_ENV)) { | ||
262 | pp=a->totalvol<<((a->main.s->flags&SF_LOOP)?1:0); | ||
263 | if ((a->master)&&(a==a->master->slave)) | ||
264 | pp<<=2; | ||
265 | |||
266 | if (pp<tvol) { | ||
267 | tvol=pp; | ||
268 | t=k; | ||
269 | } | ||
270 | } | ||
271 | } | ||
272 | |||
273 | if (tvol>8000*7) return -1; | ||
274 | return t; | ||
275 | } | ||
276 | |||
277 | static SWORD Interpolate(SWORD p,SWORD p1,SWORD p2,SWORD v1,SWORD v2) | ||
278 | { | ||
279 | if ((p1==p2)||(p==p1)) return v1; | ||
280 | return v1+((SLONG)((p-p1)*(v2-v1))/(p2-p1)); | ||
281 | } | ||
282 | |||
283 | UWORD getlinearperiod(UWORD note,ULONG fine) | ||
284 | { | ||
285 | UWORD t; | ||
286 | |||
287 | t=((20L+2*HIGH_OCTAVE)*OCTAVE+2-note)*32L-(fine>>1); | ||
288 | return t; | ||
289 | } | ||
290 | |||
291 | static UWORD getlogperiod(UWORD note,ULONG fine) | ||
292 | { | ||
293 | UWORD n,o; | ||
294 | UWORD p1,p2; | ||
295 | ULONG i; | ||
296 | |||
297 | n=note%(2*OCTAVE); | ||
298 | o=note/(2*OCTAVE); | ||
299 | i=(n<<2)+(fine>>4); /* n*8 + fine/16 */ | ||
300 | |||
301 | p1=logtab[i]; | ||
302 | p2=logtab[i+1]; | ||
303 | |||
304 | return (Interpolate(fine>>4,0,15,p1,p2)>>o); | ||
305 | } | ||
306 | |||
307 | static UWORD getoldperiod(UWORD note,ULONG speed) | ||
308 | { | ||
309 | UWORD n,o; | ||
310 | |||
311 | /* This happens sometimes on badly converted AMF, and old MOD */ | ||
312 | if (!speed) { | ||
313 | #ifdef MIKMOD_DEBUG | ||
314 | fprintf(stderr,"\rmplayer: getoldperiod() called with note=%d, speed=0 !\n",note); | ||
315 | #endif | ||
316 | return 4242; /* <- prevent divide overflow.. (42 hehe) */ | ||
317 | } | ||
318 | |||
319 | n=note%(2*OCTAVE); | ||
320 | o=note/(2*OCTAVE); | ||
321 | return ((8363L*(ULONG)oldperiods[n])>>o)/speed; | ||
322 | } | ||
323 | |||
324 | static UWORD GetPeriod(UWORD flags, UWORD note, ULONG speed) | ||
325 | { | ||
326 | if (flags & UF_XMPERIODS) { | ||
327 | if (flags & UF_LINEAR) | ||
328 | return getlinearperiod(note, speed); | ||
329 | else | ||
330 | return getlogperiod(note, speed); | ||
331 | } else | ||
332 | return getoldperiod(note, speed); | ||
333 | } | ||
334 | |||
335 | static SWORD InterpolateEnv(SWORD p,ENVPT *a,ENVPT *b) | ||
336 | { | ||
337 | return (Interpolate(p,a->pos,b->pos,a->val,b->val)); | ||
338 | } | ||
339 | |||
340 | static SWORD DoPan(SWORD envpan,SWORD pan) | ||
341 | { | ||
342 | int newpan; | ||
343 | |||
344 | newpan=pan+(((envpan-PAN_CENTER)*(128-abs(pan-PAN_CENTER)))/128); | ||
345 | |||
346 | return (newpan<PAN_LEFT)?PAN_LEFT:(newpan>PAN_RIGHT?PAN_RIGHT:newpan); | ||
347 | } | ||
348 | |||
349 | static SWORD StartEnvelope(ENVPR *t,UBYTE flg,UBYTE pts,UBYTE susbeg,UBYTE susend,UBYTE beg,UBYTE end,ENVPT *p,UBYTE keyoff) | ||
350 | { | ||
351 | t->flg=flg; | ||
352 | t->pts=pts; | ||
353 | t->susbeg=susbeg; | ||
354 | t->susend=susend; | ||
355 | t->beg=beg; | ||
356 | t->end=end; | ||
357 | t->env=p; | ||
358 | t->p=0; | ||
359 | t->a=0; | ||
360 | t->b=((t->flg&EF_SUSTAIN)&&(!(keyoff&KEY_OFF)))?0:1; | ||
361 | |||
362 | /* Imago Orpheus sometimes stores an extra initial point in the envelope */ | ||
363 | if ((t->pts>=2)&&(t->env[0].pos==t->env[1].pos)) { | ||
364 | t->a++;t->b++; | ||
365 | } | ||
366 | |||
367 | /* Fit in the envelope, still */ | ||
368 | if (t->a >= t->pts) | ||
369 | t->a = t->pts - 1; | ||
370 | if (t->b >= t->pts) | ||
371 | t->b = t->pts-1; | ||
372 | |||
373 | return t->env[t->a].val; | ||
374 | } | ||
375 | |||
376 | /* This procedure processes all envelope types, include volume, pitch, and | ||
377 | panning. Envelopes are defined by a set of points, each with a magnitude | ||
378 | [relating either to volume, panning position, or pitch modifier] and a tick | ||
379 | position. | ||
380 | |||
381 | Envelopes work in the following manner: | ||
382 | |||
383 | (a) Each tick the envelope is moved a point further in its progression. For | ||
384 | an accurate progression, magnitudes between two envelope points are | ||
385 | interpolated. | ||
386 | |||
387 | (b) When progression reaches a defined point on the envelope, values are | ||
388 | shifted to interpolate between this point and the next, and checks for | ||
389 | loops or envelope end are done. | ||
390 | |||
391 | Misc: | ||
392 | Sustain loops are loops that are only active as long as the keyoff flag is | ||
393 | clear. When a volume envelope terminates, so does the current fadeout. | ||
394 | */ | ||
395 | static SWORD ProcessEnvelope(MP_VOICE *aout, ENVPR *t, SWORD v) | ||
396 | { | ||
397 | if (t->flg & EF_ON) { | ||
398 | UBYTE a, b; /* actual points in the envelope */ | ||
399 | UWORD p; /* the 'tick counter' - real point being played */ | ||
400 | |||
401 | a = t->a; | ||
402 | b = t->b; | ||
403 | p = t->p; | ||
404 | |||
405 | /* | ||
406 | * Sustain loop on one point (XM type). | ||
407 | * Not processed if KEYOFF. | ||
408 | * Don't move and don't interpolate when the point is reached | ||
409 | */ | ||
410 | if ((t->flg & EF_SUSTAIN) && t->susbeg == t->susend && | ||
411 | (!(aout->main.keyoff & KEY_OFF) && p == t->env[t->susbeg].pos)) { | ||
412 | v = t->env[t->susbeg].val; | ||
413 | } else { | ||
414 | /* | ||
415 | * All following situations will require interpolation between | ||
416 | * two envelope points. | ||
417 | */ | ||
418 | |||
419 | /* | ||
420 | * Sustain loop between two points (IT type). | ||
421 | * Not processed if KEYOFF. | ||
422 | */ | ||
423 | /* if we were on a loop point, loop now */ | ||
424 | if ((t->flg & EF_SUSTAIN) && !(aout->main.keyoff & KEY_OFF) && | ||
425 | a >= t->susend) { | ||
426 | a = t->susbeg; | ||
427 | b = (t->susbeg==t->susend)?a:a+1; | ||
428 | p = t->env[a].pos; | ||
429 | v = t->env[a].val; | ||
430 | } else | ||
431 | /* | ||
432 | * Regular loop. | ||
433 | * Be sure to correctly handle single point loops. | ||
434 | */ | ||
435 | if ((t->flg & EF_LOOP) && a >= t->end) { | ||
436 | a = t->beg; | ||
437 | b = t->beg == t->end ? a : a + 1; | ||
438 | p = t->env[a].pos; | ||
439 | v = t->env[a].val; | ||
440 | } else | ||
441 | /* | ||
442 | * Non looping situations. | ||
443 | */ | ||
444 | if (a != b) | ||
445 | v = InterpolateEnv(p, &t->env[a], &t->env[b]); | ||
446 | else | ||
447 | v = t->env[a].val; | ||
448 | |||
449 | /* | ||
450 | * Start to fade if the volume envelope is finished. | ||
451 | */ | ||
452 | if (p >= t->env[t->pts - 1].pos) { | ||
453 | if (t->flg & EF_VOLENV) { | ||
454 | aout->main.keyoff |= KEY_FADE; | ||
455 | if (!v) | ||
456 | aout->main.fadevol = 0; | ||
457 | } | ||
458 | } else { | ||
459 | p++; | ||
460 | /* did pointer reach point b? */ | ||
461 | if (p >= t->env[b].pos) | ||
462 | a = b++; /* shift points a and b */ | ||
463 | } | ||
464 | t->a = a; | ||
465 | t->b = b; | ||
466 | t->p = p; | ||
467 | } | ||
468 | } | ||
469 | return v; | ||
470 | } | ||
471 | |||
472 | /* XM linear period to frequency conversion */ | ||
473 | ULONG getfrequency(UWORD flags,ULONG period) | ||
474 | { | ||
475 | if (flags & UF_LINEAR) { | ||
476 | SLONG shift = ((SLONG)period / 768) - HIGH_OCTAVE; | ||
477 | |||
478 | if (shift >= 0) | ||
479 | return lintab[period % 768] >> shift; | ||
480 | else | ||
481 | return lintab[period % 768] << (-shift); | ||
482 | } else | ||
483 | return (8363L*1712L)/(period?period:1); | ||
484 | } | ||
485 | |||
486 | /*========== Protracker effects */ | ||
487 | |||
488 | static void DoArpeggio(UWORD tick, UWORD flags, MP_CONTROL *a, UBYTE style) | ||
489 | { | ||
490 | UBYTE note=a->main.note; | ||
491 | |||
492 | if (a->arpmem) { | ||
493 | switch (style) { | ||
494 | case 0: /* mod style: N, N+x, N+y */ | ||
495 | switch (tick % 3) { | ||
496 | /* case 0: unchanged */ | ||
497 | case 1: | ||
498 | note += (a->arpmem >> 4); | ||
499 | break; | ||
500 | case 2: | ||
501 | note += (a->arpmem & 0xf); | ||
502 | break; | ||
503 | } | ||
504 | break; | ||
505 | case 3: /* okt arpeggio 3: N-x, N, N+y */ | ||
506 | switch (tick % 3) { | ||
507 | case 0: | ||
508 | note -= (a->arpmem >> 4); | ||
509 | break; | ||
510 | /* case 1: unchanged */ | ||
511 | case 2: | ||
512 | note += (a->arpmem & 0xf); | ||
513 | break; | ||
514 | } | ||
515 | break; | ||
516 | case 4: /* okt arpeggio 4: N, N+y, N, N-x */ | ||
517 | switch (tick % 4) { | ||
518 | /* case 0, case 2: unchanged */ | ||
519 | case 1: | ||
520 | note += (a->arpmem & 0xf); | ||
521 | break; | ||
522 | case 3: | ||
523 | note -= (a->arpmem >> 4); | ||
524 | break; | ||
525 | } | ||
526 | break; | ||
527 | case 5: /* okt arpeggio 5: N-x, N+y, N, and nothing at tick 0 */ | ||
528 | if (!tick) | ||
529 | break; | ||
530 | switch (tick % 3) { | ||
531 | /* case 0: unchanged */ | ||
532 | case 1: | ||
533 | note -= (a->arpmem >> 4); | ||
534 | break; | ||
535 | case 2: | ||
536 | note += (a->arpmem & 0xf); | ||
537 | break; | ||
538 | } | ||
539 | break; | ||
540 | } | ||
541 | a->main.period = GetPeriod(flags, (UWORD)note << 1, a->speed); | ||
542 | a->ownper = 1; | ||
543 | } | ||
544 | } | ||
545 | |||
546 | static int DoPTEffect0(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
547 | { | ||
548 | UBYTE dat; | ||
549 | |||
550 | dat = UniGetByte(); | ||
551 | if (!tick) { | ||
552 | if (!dat && (flags & UF_ARPMEM)) | ||
553 | dat=a->arpmem; | ||
554 | else | ||
555 | a->arpmem=dat; | ||
556 | } | ||
557 | if (a->main.period) | ||
558 | DoArpeggio(tick, flags, a, 0); | ||
559 | |||
560 | return 0; | ||
561 | } | ||
562 | |||
563 | static int DoPTEffect1(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
564 | { | ||
565 | UBYTE dat; | ||
566 | |||
567 | dat = UniGetByte(); | ||
568 | if (!tick && dat) | ||
569 | a->slidespeed = (UWORD)dat << 2; | ||
570 | if (a->main.period) | ||
571 | if (tick) | ||
572 | a->tmpperiod -= a->slidespeed; | ||
573 | |||
574 | return 0; | ||
575 | } | ||
576 | |||
577 | static int DoPTEffect2(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
578 | { | ||
579 | UBYTE dat; | ||
580 | |||
581 | dat = UniGetByte(); | ||
582 | if (!tick && dat) | ||
583 | a->slidespeed = (UWORD)dat << 2; | ||
584 | if (a->main.period) | ||
585 | if (tick) | ||
586 | a->tmpperiod += a->slidespeed; | ||
587 | |||
588 | return 0; | ||
589 | } | ||
590 | |||
591 | static void DoToneSlide(UWORD tick, MP_CONTROL *a) | ||
592 | { | ||
593 | if (!a->main.fadevol) | ||
594 | a->main.kick = (a->main.kick == KICK_NOTE)? KICK_NOTE : KICK_KEYOFF; | ||
595 | else | ||
596 | a->main.kick = (a->main.kick == KICK_NOTE)? KICK_ENV : KICK_ABSENT; | ||
597 | |||
598 | if (tick != 0) { | ||
599 | int dist; | ||
600 | |||
601 | /* We have to slide a->main.period towards a->wantedperiod, so compute | ||
602 | the difference between those two values */ | ||
603 | dist=a->main.period-a->wantedperiod; | ||
604 | |||
605 | /* if they are equal or if portamentospeed is too big ...*/ | ||
606 | if (dist == 0 || a->portspeed > abs(dist)) | ||
607 | /* ...make tmpperiod equal tperiod */ | ||
608 | a->tmpperiod=a->main.period=a->wantedperiod; | ||
609 | else if (dist>0) { | ||
610 | a->tmpperiod-=a->portspeed; | ||
611 | a->main.period-=a->portspeed; /* dist>0, slide up */ | ||
612 | } else { | ||
613 | a->tmpperiod+=a->portspeed; | ||
614 | a->main.period+=a->portspeed; /* dist<0, slide down */ | ||
615 | } | ||
616 | } else | ||
617 | a->tmpperiod=a->main.period; | ||
618 | a->ownper = 1; | ||
619 | } | ||
620 | |||
621 | static int DoPTEffect3(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
622 | { | ||
623 | UBYTE dat; | ||
624 | |||
625 | dat=UniGetByte(); | ||
626 | if ((!tick)&&(dat)) a->portspeed=(UWORD)dat<<2; | ||
627 | if (a->main.period) | ||
628 | DoToneSlide(tick, a); | ||
629 | |||
630 | return 0; | ||
631 | } | ||
632 | |||
633 | static void DoVibrato(UWORD tick, MP_CONTROL *a) | ||
634 | { | ||
635 | UBYTE q; | ||
636 | UWORD temp = 0; /* silence warning */ | ||
637 | |||
638 | if (!tick) | ||
639 | return; | ||
640 | |||
641 | q=(a->vibpos>>2)&0x1f; | ||
642 | |||
643 | switch (a->wavecontrol&3) { | ||
644 | case 0: /* sine */ | ||
645 | temp=VibratoTable[q]; | ||
646 | break; | ||
647 | case 1: /* ramp down */ | ||
648 | q<<=3; | ||
649 | if (a->vibpos<0) q=255-q; | ||
650 | temp=q; | ||
651 | break; | ||
652 | case 2: /* square wave */ | ||
653 | temp=255; | ||
654 | break; | ||
655 | case 3: /* random wave */ | ||
656 | temp=getrandom(256); | ||
657 | break; | ||
658 | } | ||
659 | |||
660 | temp*=a->vibdepth; | ||
661 | temp>>=7;temp<<=2; | ||
662 | |||
663 | if (a->vibpos>=0) | ||
664 | a->main.period=a->tmpperiod+temp; | ||
665 | else | ||
666 | a->main.period=a->tmpperiod-temp; | ||
667 | a->ownper = 1; | ||
668 | |||
669 | if (tick != 0) | ||
670 | a->vibpos+=a->vibspd; | ||
671 | } | ||
672 | |||
673 | static int DoPTEffect4(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
674 | { | ||
675 | UBYTE dat; | ||
676 | |||
677 | dat=UniGetByte(); | ||
678 | if (!tick) { | ||
679 | if (dat&0x0f) a->vibdepth=dat&0xf; | ||
680 | if (dat&0xf0) a->vibspd=(dat&0xf0)>>2; | ||
681 | } | ||
682 | if (a->main.period) | ||
683 | DoVibrato(tick, a); | ||
684 | |||
685 | return 0; | ||
686 | } | ||
687 | |||
688 | static void DoVolSlide(MP_CONTROL *a, UBYTE dat) | ||
689 | { | ||
690 | if (dat&0xf) { | ||
691 | a->tmpvolume-=(dat&0x0f); | ||
692 | if (a->tmpvolume<0) | ||
693 | a->tmpvolume=0; | ||
694 | } else { | ||
695 | a->tmpvolume+=(dat>>4); | ||
696 | if (a->tmpvolume>64) | ||
697 | a->tmpvolume=64; | ||
698 | } | ||
699 | } | ||
700 | |||
701 | static int DoPTEffect5(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
702 | { | ||
703 | UBYTE dat; | ||
704 | |||
705 | dat=UniGetByte(); | ||
706 | if (a->main.period) | ||
707 | DoToneSlide(tick, a); | ||
708 | |||
709 | if (tick) | ||
710 | DoVolSlide(a, dat); | ||
711 | |||
712 | return 0; | ||
713 | } | ||
714 | |||
715 | /* DoPTEffect6 after DoPTEffectA */ | ||
716 | |||
717 | static int DoPTEffect7(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
718 | { | ||
719 | UBYTE dat; | ||
720 | UBYTE q; | ||
721 | UWORD temp = 0; /* silence warning */ | ||
722 | |||
723 | dat=UniGetByte(); | ||
724 | if (!tick) { | ||
725 | if (dat&0x0f) a->trmdepth=dat&0xf; | ||
726 | if (dat&0xf0) a->trmspd=(dat&0xf0)>>2; | ||
727 | } | ||
728 | if (a->main.period) { | ||
729 | q=(a->trmpos>>2)&0x1f; | ||
730 | |||
731 | switch ((a->wavecontrol>>4)&3) { | ||
732 | case 0: /* sine */ | ||
733 | temp=VibratoTable[q]; | ||
734 | break; | ||
735 | case 1: /* ramp down */ | ||
736 | q<<=3; | ||
737 | if (a->trmpos<0) q=255-q; | ||
738 | temp=q; | ||
739 | break; | ||
740 | case 2: /* square wave */ | ||
741 | temp=255; | ||
742 | break; | ||
743 | case 3: /* random wave */ | ||
744 | temp=getrandom(256); | ||
745 | break; | ||
746 | } | ||
747 | temp*=a->trmdepth; | ||
748 | temp>>=6; | ||
749 | |||
750 | if (a->trmpos>=0) { | ||
751 | a->volume=a->tmpvolume+temp; | ||
752 | if (a->volume>64) a->volume=64; | ||
753 | } else { | ||
754 | a->volume=a->tmpvolume-temp; | ||
755 | if (a->volume<0) a->volume=0; | ||
756 | } | ||
757 | a->ownvol = 1; | ||
758 | |||
759 | if (tick) | ||
760 | a->trmpos+=a->trmspd; | ||
761 | } | ||
762 | |||
763 | return 0; | ||
764 | } | ||
765 | |||
766 | static int DoPTEffect8(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
767 | { | ||
768 | UBYTE dat; | ||
769 | |||
770 | dat = UniGetByte(); | ||
771 | if (mod->panflag) | ||
772 | a->main.panning = mod->panning[channel] = dat; | ||
773 | |||
774 | return 0; | ||
775 | } | ||
776 | |||
777 | static int DoPTEffect9(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
778 | { | ||
779 | UBYTE dat; | ||
780 | |||
781 | dat=UniGetByte(); | ||
782 | if (!tick) { | ||
783 | if (dat) a->soffset=(UWORD)dat<<8; | ||
784 | a->main.start=a->hioffset|a->soffset; | ||
785 | |||
786 | if ((a->main.s)&&(a->main.start>a->main.s->length)) | ||
787 | a->main.start=a->main.s->flags&(SF_LOOP|SF_BIDI)? | ||
788 | a->main.s->loopstart:a->main.s->length; | ||
789 | } | ||
790 | |||
791 | return 0; | ||
792 | } | ||
793 | |||
794 | static int DoPTEffectA(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
795 | { | ||
796 | UBYTE dat; | ||
797 | |||
798 | dat=UniGetByte(); | ||
799 | if (tick) | ||
800 | DoVolSlide(a, dat); | ||
801 | |||
802 | return 0; | ||
803 | } | ||
804 | |||
805 | static int DoPTEffect6(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
806 | { | ||
807 | if (a->main.period) | ||
808 | DoVibrato(tick, a); | ||
809 | DoPTEffectA(tick, flags, a, mod, channel); | ||
810 | |||
811 | return 0; | ||
812 | } | ||
813 | |||
814 | static int DoPTEffectB(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
815 | { | ||
816 | UBYTE dat; | ||
817 | |||
818 | dat=UniGetByte(); | ||
819 | |||
820 | if (tick || mod->patdly2) | ||
821 | return 0; | ||
822 | |||
823 | /* Vincent Voois uses a nasty trick in "Universal Bolero" */ | ||
824 | if (dat == mod->sngpos && mod->patbrk == mod->patpos) | ||
825 | return 0; | ||
826 | |||
827 | if (!mod->loop && !mod->patbrk && | ||
828 | (dat < mod->sngpos || | ||
829 | (mod->sngpos == (mod->numpos - 1) && !mod->patbrk) || | ||
830 | (dat == mod->sngpos && (flags & UF_NOWRAP)) | ||
831 | )) { | ||
832 | /* if we don't loop, better not to skip the end of the | ||
833 | pattern, after all... so: | ||
834 | mod->patbrk=0; */ | ||
835 | mod->posjmp=3; | ||
836 | } else { | ||
837 | /* if we were fading, adjust... */ | ||
838 | if (mod->sngpos == (mod->numpos-1)) | ||
839 | mod->volume=mod->initvolume>128?128:mod->initvolume; | ||
840 | mod->sngpos=dat; | ||
841 | mod->posjmp=2; | ||
842 | mod->patpos=0; | ||
843 | } | ||
844 | |||
845 | return 0; | ||
846 | } | ||
847 | |||
848 | static int DoPTEffectC(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
849 | { | ||
850 | UBYTE dat; | ||
851 | |||
852 | dat=UniGetByte(); | ||
853 | if (tick) return 0; | ||
854 | if (dat==(UBYTE)-1) a->anote=dat=0; /* note cut */ | ||
855 | else if (dat>64) dat=64; | ||
856 | a->tmpvolume=dat; | ||
857 | |||
858 | return 0; | ||
859 | } | ||
860 | |||
861 | static int DoPTEffectD(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
862 | { | ||
863 | UBYTE dat; | ||
864 | |||
865 | dat=UniGetByte(); | ||
866 | if ((tick)||(mod->patdly2)) return 0; | ||
867 | if ((mod->positions[mod->sngpos]!=LAST_PATTERN)&& | ||
868 | (dat>mod->pattrows[mod->positions[mod->sngpos]])) | ||
869 | dat=mod->pattrows[mod->positions[mod->sngpos]]; | ||
870 | mod->patbrk=dat; | ||
871 | if (!mod->posjmp) { | ||
872 | /* don't ask me to explain this code - it makes | ||
873 | backwards.s3m and children.xm (heretic's version) play | ||
874 | correctly, among others. Take that for granted, or write | ||
875 | the page of comments yourself... you might need some | ||
876 | aspirin - Miod */ | ||
877 | if ((mod->sngpos==mod->numpos-1)&&(dat)&&((mod->loop)|| | ||
878 | (mod->positions[mod->sngpos]==(mod->numpat-1) | ||
879 | && !(flags&UF_NOWRAP)))) { | ||
880 | mod->sngpos=0; | ||
881 | mod->posjmp=2; | ||
882 | } else | ||
883 | mod->posjmp=3; | ||
884 | } | ||
885 | |||
886 | return 0; | ||
887 | } | ||
888 | |||
889 | static void DoEEffects(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, | ||
890 | SWORD channel, UBYTE dat) | ||
891 | { | ||
892 | UBYTE nib = dat & 0xf; | ||
893 | |||
894 | switch (dat>>4) { | ||
895 | case 0x0: /* hardware filter toggle, not supported */ | ||
896 | break; | ||
897 | case 0x1: /* fineslide up */ | ||
898 | if (a->main.period) | ||
899 | if (!tick) | ||
900 | a->tmpperiod-=(nib<<2); | ||
901 | break; | ||
902 | case 0x2: /* fineslide dn */ | ||
903 | if (a->main.period) | ||
904 | if (!tick) | ||
905 | a->tmpperiod+=(nib<<2); | ||
906 | break; | ||
907 | case 0x3: /* glissando ctrl */ | ||
908 | a->glissando=nib; | ||
909 | break; | ||
910 | case 0x4: /* set vibrato waveform */ | ||
911 | a->wavecontrol&=0xf0; | ||
912 | a->wavecontrol|=nib; | ||
913 | break; | ||
914 | case 0x5: /* set finetune */ | ||
915 | if (a->main.period) { | ||
916 | if (flags&UF_XMPERIODS) | ||
917 | a->speed=nib+128; | ||
918 | else | ||
919 | a->speed=finetune[nib]; | ||
920 | a->tmpperiod=GetPeriod(flags, (UWORD)a->main.note<<1,a->speed); | ||
921 | } | ||
922 | break; | ||
923 | case 0x6: /* set patternloop */ | ||
924 | if (tick) | ||
925 | break; | ||
926 | if (nib) { /* set reppos or repcnt ? */ | ||
927 | /* set repcnt, so check if repcnt already is set, which means we | ||
928 | are already looping */ | ||
929 | if (a->pat_repcnt) | ||
930 | a->pat_repcnt--; /* already looping, decrease counter */ | ||
931 | else { | ||
932 | #if 0 | ||
933 | /* this would make walker.xm, shipped with Xsoundtracker, | ||
934 | play correctly, but it's better to remain compatible | ||
935 | with FT2 */ | ||
936 | if ((!(flags&UF_NOWRAP))||(a->pat_reppos!=POS_NONE)) | ||
937 | #endif | ||
938 | a->pat_repcnt=nib; /* not yet looping, so set repcnt */ | ||
939 | } | ||
940 | |||
941 | if (a->pat_repcnt) { /* jump to reppos if repcnt>0 */ | ||
942 | if (a->pat_reppos==POS_NONE) | ||
943 | a->pat_reppos=mod->patpos-1; | ||
944 | if (a->pat_reppos==-1) { | ||
945 | mod->pat_repcrazy=1; | ||
946 | mod->patpos=0; | ||
947 | } else | ||
948 | mod->patpos=a->pat_reppos; | ||
949 | } else a->pat_reppos=POS_NONE; | ||
950 | } else | ||
951 | a->pat_reppos=mod->patpos-1; /* set reppos - can be (-1) */ | ||
952 | break; | ||
953 | case 0x7: /* set tremolo waveform */ | ||
954 | a->wavecontrol&=0x0f; | ||
955 | a->wavecontrol|=nib<<4; | ||
956 | break; | ||
957 | case 0x8: /* set panning */ | ||
958 | if (mod->panflag) { | ||
959 | if (nib<=8) nib<<=4; | ||
960 | else nib*=17; | ||
961 | a->main.panning=mod->panning[channel]=nib; | ||
962 | } | ||
963 | break; | ||
964 | case 0x9: /* retrig note */ | ||
965 | /* do not retrigger on tick 0, until we are emulating FT2 and effect | ||
966 | data is zero */ | ||
967 | if (!tick && !((flags & UF_FT2QUIRKS) && (!nib))) | ||
968 | break; | ||
969 | /* only retrigger if data nibble > 0, or if tick 0 (FT2 compat) */ | ||
970 | if (nib || !tick) { | ||
971 | if (!a->retrig) { | ||
972 | /* when retrig counter reaches 0, reset counter and restart | ||
973 | the sample */ | ||
974 | if (a->main.period) a->main.kick=KICK_NOTE; | ||
975 | a->retrig=nib; | ||
976 | } | ||
977 | a->retrig--; /* countdown */ | ||
978 | } | ||
979 | break; | ||
980 | case 0xa: /* fine volume slide up */ | ||
981 | if (tick) | ||
982 | break; | ||
983 | a->tmpvolume+=nib; | ||
984 | if (a->tmpvolume>64) a->tmpvolume=64; | ||
985 | break; | ||
986 | case 0xb: /* fine volume slide dn */ | ||
987 | if (tick) | ||
988 | break; | ||
989 | a->tmpvolume-=nib; | ||
990 | if (a->tmpvolume<0)a->tmpvolume=0; | ||
991 | break; | ||
992 | case 0xc: /* cut note */ | ||
993 | /* When tick reaches the cut-note value, turn the volume to | ||
994 | zero (just like on the amiga) */ | ||
995 | if (tick>=nib) | ||
996 | a->tmpvolume=0; /* just turn the volume down */ | ||
997 | break; | ||
998 | case 0xd: /* note delay */ | ||
999 | /* delay the start of the sample until tick==nib */ | ||
1000 | if (!tick) | ||
1001 | a->main.notedelay=nib; | ||
1002 | else if (a->main.notedelay) | ||
1003 | a->main.notedelay--; | ||
1004 | break; | ||
1005 | case 0xe: /* pattern delay */ | ||
1006 | if (!tick) | ||
1007 | if (!mod->patdly2) | ||
1008 | mod->patdly=nib+1; /* only once, when tick=0 */ | ||
1009 | break; | ||
1010 | case 0xf: /* invert loop, not supported */ | ||
1011 | break; | ||
1012 | } | ||
1013 | } | ||
1014 | |||
1015 | static int DoPTEffectE(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
1016 | { | ||
1017 | DoEEffects(tick, flags, a, mod, channel, UniGetByte()); | ||
1018 | |||
1019 | return 0; | ||
1020 | } | ||
1021 | |||
1022 | static int DoPTEffectF(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
1023 | { | ||
1024 | UBYTE dat; | ||
1025 | |||
1026 | dat=UniGetByte(); | ||
1027 | if (tick||mod->patdly2) return 0; | ||
1028 | if (mod->extspd&&(dat>=mod->bpmlimit)) | ||
1029 | mod->bpm=dat; | ||
1030 | else | ||
1031 | if (dat) { | ||
1032 | mod->sngspd=(dat>=mod->bpmlimit)?mod->bpmlimit-1:dat; | ||
1033 | mod->vbtick=0; | ||
1034 | } | ||
1035 | |||
1036 | return 0; | ||
1037 | } | ||
1038 | |||
1039 | /*========== Scream Tracker effects */ | ||
1040 | |||
1041 | static int DoS3MEffectA(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
1042 | { | ||
1043 | UBYTE speed; | ||
1044 | |||
1045 | speed = UniGetByte(); | ||
1046 | |||
1047 | if (tick || mod->patdly2) | ||
1048 | return 0; | ||
1049 | |||
1050 | if (speed > 128) | ||
1051 | speed -= 128; | ||
1052 | if (speed) { | ||
1053 | mod->sngspd = speed; | ||
1054 | mod->vbtick = 0; | ||
1055 | } | ||
1056 | |||
1057 | return 0; | ||
1058 | } | ||
1059 | |||
1060 | static void DoS3MVolSlide(UWORD tick, UWORD flags, MP_CONTROL *a, UBYTE inf) | ||
1061 | { | ||
1062 | UBYTE lo, hi; | ||
1063 | |||
1064 | if (inf) | ||
1065 | a->s3mvolslide=inf; | ||
1066 | else | ||
1067 | inf=a->s3mvolslide; | ||
1068 | |||
1069 | lo=inf&0xf; | ||
1070 | hi=inf>>4; | ||
1071 | |||
1072 | if (!lo) { | ||
1073 | if ((tick)||(flags&UF_S3MSLIDES)) a->tmpvolume+=hi; | ||
1074 | } else | ||
1075 | if (!hi) { | ||
1076 | if ((tick)||(flags&UF_S3MSLIDES)) a->tmpvolume-=lo; | ||
1077 | } else | ||
1078 | if (lo==0xf) { | ||
1079 | if (!tick) a->tmpvolume+=(hi?hi:0xf); | ||
1080 | } else | ||
1081 | if (hi==0xf) { | ||
1082 | if (!tick) a->tmpvolume-=(lo?lo:0xf); | ||
1083 | } else | ||
1084 | return; | ||
1085 | |||
1086 | if (a->tmpvolume<0) | ||
1087 | a->tmpvolume=0; | ||
1088 | else if (a->tmpvolume>64) | ||
1089 | a->tmpvolume=64; | ||
1090 | } | ||
1091 | |||
1092 | static int DoS3MEffectD(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
1093 | { | ||
1094 | DoS3MVolSlide(tick, flags, a, UniGetByte()); | ||
1095 | |||
1096 | return 1; | ||
1097 | } | ||
1098 | |||
1099 | static void DoS3MSlideDn(UWORD tick, MP_CONTROL *a, UBYTE inf) | ||
1100 | { | ||
1101 | UBYTE hi,lo; | ||
1102 | |||
1103 | if (inf) | ||
1104 | a->slidespeed=inf; | ||
1105 | else | ||
1106 | inf=a->slidespeed; | ||
1107 | |||
1108 | hi=inf>>4; | ||
1109 | lo=inf&0xf; | ||
1110 | |||
1111 | if (hi==0xf) { | ||
1112 | if (!tick) a->tmpperiod+=(UWORD)lo<<2; | ||
1113 | } else | ||
1114 | if (hi==0xe) { | ||
1115 | if (!tick) a->tmpperiod+=lo; | ||
1116 | } else { | ||
1117 | if (tick) a->tmpperiod+=(UWORD)inf<<2; | ||
1118 | } | ||
1119 | } | ||
1120 | |||
1121 | static int DoS3MEffectE(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
1122 | { | ||
1123 | UBYTE dat; | ||
1124 | |||
1125 | dat=UniGetByte(); | ||
1126 | if (a->main.period) | ||
1127 | DoS3MSlideDn(tick, a,dat); | ||
1128 | |||
1129 | return 0; | ||
1130 | } | ||
1131 | |||
1132 | static void DoS3MSlideUp(UWORD tick, MP_CONTROL *a, UBYTE inf) | ||
1133 | { | ||
1134 | UBYTE hi,lo; | ||
1135 | |||
1136 | if (inf) a->slidespeed=inf; | ||
1137 | else inf=a->slidespeed; | ||
1138 | |||
1139 | hi=inf>>4; | ||
1140 | lo=inf&0xf; | ||
1141 | |||
1142 | if (hi==0xf) { | ||
1143 | if (!tick) a->tmpperiod-=(UWORD)lo<<2; | ||
1144 | } else | ||
1145 | if (hi==0xe) { | ||
1146 | if (!tick) a->tmpperiod-=lo; | ||
1147 | } else { | ||
1148 | if (tick) a->tmpperiod-=(UWORD)inf<<2; | ||
1149 | } | ||
1150 | } | ||
1151 | |||
1152 | static int DoS3MEffectF(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
1153 | { | ||
1154 | UBYTE dat; | ||
1155 | |||
1156 | dat=UniGetByte(); | ||
1157 | if (a->main.period) | ||
1158 | DoS3MSlideUp(tick, a,dat); | ||
1159 | |||
1160 | return 0; | ||
1161 | } | ||
1162 | |||
1163 | static int DoS3MEffectI(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
1164 | { | ||
1165 | UBYTE inf, on, off; | ||
1166 | |||
1167 | inf = UniGetByte(); | ||
1168 | if (inf) | ||
1169 | a->s3mtronof = inf; | ||
1170 | else { | ||
1171 | inf = a->s3mtronof; | ||
1172 | if (!inf) | ||
1173 | return 0; | ||
1174 | } | ||
1175 | |||
1176 | if (!tick) | ||
1177 | return 0; | ||
1178 | |||
1179 | on=(inf>>4)+1; | ||
1180 | off=(inf&0xf)+1; | ||
1181 | a->s3mtremor%=(on+off); | ||
1182 | a->volume=(a->s3mtremor<on)?a->tmpvolume:0; | ||
1183 | a->ownvol=1; | ||
1184 | a->s3mtremor++; | ||
1185 | |||
1186 | return 0; | ||
1187 | } | ||
1188 | |||
1189 | static int DoS3MEffectQ(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
1190 | { | ||
1191 | UBYTE inf; | ||
1192 | |||
1193 | inf = UniGetByte(); | ||
1194 | if (a->main.period) { | ||
1195 | if (inf) { | ||
1196 | a->s3mrtgslide=inf>>4; | ||
1197 | a->s3mrtgspeed=inf&0xf; | ||
1198 | } | ||
1199 | |||
1200 | /* only retrigger if low nibble > 0 */ | ||
1201 | if (a->s3mrtgspeed>0) { | ||
1202 | if (!a->retrig) { | ||
1203 | /* when retrig counter reaches 0, reset counter and restart the | ||
1204 | sample */ | ||
1205 | if (a->main.kick!=KICK_NOTE) a->main.kick=KICK_KEYOFF; | ||
1206 | a->retrig=a->s3mrtgspeed; | ||
1207 | |||
1208 | if ((tick)||(flags&UF_S3MSLIDES)) { | ||
1209 | switch (a->s3mrtgslide) { | ||
1210 | case 1: | ||
1211 | case 2: | ||
1212 | case 3: | ||
1213 | case 4: | ||
1214 | case 5: | ||
1215 | a->tmpvolume-=(1<<(a->s3mrtgslide-1)); | ||
1216 | break; | ||
1217 | case 6: | ||
1218 | a->tmpvolume=(2*a->tmpvolume)/3; | ||
1219 | break; | ||
1220 | case 7: | ||
1221 | a->tmpvolume>>=1; | ||
1222 | break; | ||
1223 | case 9: | ||
1224 | case 0xa: | ||
1225 | case 0xb: | ||
1226 | case 0xc: | ||
1227 | case 0xd: | ||
1228 | a->tmpvolume+=(1<<(a->s3mrtgslide-9)); | ||
1229 | break; | ||
1230 | case 0xe: | ||
1231 | a->tmpvolume=(3*a->tmpvolume)>>1; | ||
1232 | break; | ||
1233 | case 0xf: | ||
1234 | a->tmpvolume=a->tmpvolume<<1; | ||
1235 | break; | ||
1236 | } | ||
1237 | if (a->tmpvolume<0) | ||
1238 | a->tmpvolume=0; | ||
1239 | else if (a->tmpvolume>64) | ||
1240 | a->tmpvolume=64; | ||
1241 | } | ||
1242 | } | ||
1243 | a->retrig--; /* countdown */ | ||
1244 | } | ||
1245 | } | ||
1246 | |||
1247 | return 0; | ||
1248 | } | ||
1249 | |||
1250 | static int DoS3MEffectR(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
1251 | { | ||
1252 | UBYTE dat, q; | ||
1253 | UWORD temp=0; /* silence warning */ | ||
1254 | |||
1255 | dat = UniGetByte(); | ||
1256 | if (!tick) { | ||
1257 | if (dat&0x0f) a->trmdepth=dat&0xf; | ||
1258 | if (dat&0xf0) a->trmspd=(dat&0xf0)>>2; | ||
1259 | } | ||
1260 | |||
1261 | q=(a->trmpos>>2)&0x1f; | ||
1262 | |||
1263 | switch ((a->wavecontrol>>4)&3) { | ||
1264 | case 0: /* sine */ | ||
1265 | temp=VibratoTable[q]; | ||
1266 | break; | ||
1267 | case 1: /* ramp down */ | ||
1268 | q<<=3; | ||
1269 | if (a->trmpos<0) q=255-q; | ||
1270 | temp=q; | ||
1271 | break; | ||
1272 | case 2: /* square wave */ | ||
1273 | temp=255; | ||
1274 | break; | ||
1275 | case 3: /* random */ | ||
1276 | temp=getrandom(256); | ||
1277 | break; | ||
1278 | } | ||
1279 | |||
1280 | temp*=a->trmdepth; | ||
1281 | temp>>=7; | ||
1282 | |||
1283 | if (a->trmpos>=0) { | ||
1284 | a->volume=a->tmpvolume+temp; | ||
1285 | if (a->volume>64) a->volume=64; | ||
1286 | } else { | ||
1287 | a->volume=a->tmpvolume-temp; | ||
1288 | if (a->volume<0) a->volume=0; | ||
1289 | } | ||
1290 | a->ownvol = 1; | ||
1291 | |||
1292 | if (tick) | ||
1293 | a->trmpos+=a->trmspd; | ||
1294 | |||
1295 | return 0; | ||
1296 | } | ||
1297 | |||
1298 | static int DoS3MEffectT(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
1299 | { | ||
1300 | UBYTE tempo; | ||
1301 | |||
1302 | tempo = UniGetByte(); | ||
1303 | |||
1304 | if (tick || mod->patdly2) | ||
1305 | return 0; | ||
1306 | |||
1307 | mod->bpm = (tempo < 32) ? 32 : tempo; | ||
1308 | |||
1309 | return 0; | ||
1310 | } | ||
1311 | |||
1312 | static int DoS3MEffectU(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
1313 | { | ||
1314 | UBYTE dat, q; | ||
1315 | UWORD temp = 0; /* silence warning */ | ||
1316 | |||
1317 | dat = UniGetByte(); | ||
1318 | if (!tick) { | ||
1319 | if (dat&0x0f) a->vibdepth=dat&0xf; | ||
1320 | if (dat&0xf0) a->vibspd=(dat&0xf0)>>2; | ||
1321 | } else | ||
1322 | if (a->main.period) { | ||
1323 | q=(a->vibpos>>2)&0x1f; | ||
1324 | |||
1325 | switch (a->wavecontrol&3) { | ||
1326 | case 0: /* sine */ | ||
1327 | temp=VibratoTable[q]; | ||
1328 | break; | ||
1329 | case 1: /* ramp down */ | ||
1330 | q<<=3; | ||
1331 | if (a->vibpos<0) q=255-q; | ||
1332 | temp=q; | ||
1333 | break; | ||
1334 | case 2: /* square wave */ | ||
1335 | temp=255; | ||
1336 | break; | ||
1337 | case 3: /* random */ | ||
1338 | temp=getrandom(256); | ||
1339 | break; | ||
1340 | } | ||
1341 | |||
1342 | temp*=a->vibdepth; | ||
1343 | temp>>=8; | ||
1344 | |||
1345 | if (a->vibpos>=0) | ||
1346 | a->main.period=a->tmpperiod+temp; | ||
1347 | else | ||
1348 | a->main.period=a->tmpperiod-temp; | ||
1349 | a->ownper = 1; | ||
1350 | |||
1351 | a->vibpos+=a->vibspd; | ||
1352 | } | ||
1353 | |||
1354 | return 0; | ||
1355 | } | ||
1356 | |||
1357 | /*========== Envelope helpers */ | ||
1358 | |||
1359 | static int DoKeyOff(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
1360 | { | ||
1361 | a->main.keyoff|=KEY_OFF; | ||
1362 | if ((!(a->main.volflg&EF_ON))||(a->main.volflg&EF_LOOP)) | ||
1363 | a->main.keyoff=KEY_KILL; | ||
1364 | |||
1365 | return 0; | ||
1366 | } | ||
1367 | |||
1368 | static int DoKeyFade(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
1369 | { | ||
1370 | UBYTE dat; | ||
1371 | |||
1372 | dat=UniGetByte(); | ||
1373 | if ((tick>=dat)||(tick==mod->sngspd-1)) { | ||
1374 | a->main.keyoff=KEY_KILL; | ||
1375 | if (!(a->main.volflg&EF_ON)) | ||
1376 | a->main.fadevol=0; | ||
1377 | } | ||
1378 | |||
1379 | return 0; | ||
1380 | } | ||
1381 | |||
1382 | /*========== Fast Tracker effects */ | ||
1383 | |||
1384 | /* DoXMEffect6 after DoXMEffectA */ | ||
1385 | |||
1386 | static int DoXMEffectA(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
1387 | { | ||
1388 | UBYTE inf, lo, hi; | ||
1389 | |||
1390 | inf = UniGetByte(); | ||
1391 | if (inf) | ||
1392 | a->s3mvolslide = inf; | ||
1393 | else | ||
1394 | inf = a->s3mvolslide; | ||
1395 | |||
1396 | if (tick) { | ||
1397 | lo=inf&0xf; | ||
1398 | hi=inf>>4; | ||
1399 | |||
1400 | if (!hi) { | ||
1401 | a->tmpvolume-=lo; | ||
1402 | if (a->tmpvolume<0) a->tmpvolume=0; | ||
1403 | } else { | ||
1404 | a->tmpvolume+=hi; | ||
1405 | if (a->tmpvolume>64) a->tmpvolume=64; | ||
1406 | } | ||
1407 | } | ||
1408 | |||
1409 | return 0; | ||
1410 | } | ||
1411 | |||
1412 | static int DoXMEffect6(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
1413 | { | ||
1414 | if (a->main.period) | ||
1415 | DoVibrato(tick, a); | ||
1416 | |||
1417 | return DoXMEffectA(tick, flags, a, mod, channel); | ||
1418 | } | ||
1419 | |||
1420 | static int DoXMEffectE1(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
1421 | { | ||
1422 | UBYTE dat; | ||
1423 | |||
1424 | dat=UniGetByte(); | ||
1425 | if (!tick) { | ||
1426 | if (dat) a->fportupspd=dat; | ||
1427 | if (a->main.period) | ||
1428 | a->tmpperiod-=(a->fportupspd<<2); | ||
1429 | } | ||
1430 | |||
1431 | return 0; | ||
1432 | } | ||
1433 | |||
1434 | static int DoXMEffectE2(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
1435 | { | ||
1436 | UBYTE dat; | ||
1437 | |||
1438 | dat=UniGetByte(); | ||
1439 | if (!tick) { | ||
1440 | if (dat) a->fportdnspd=dat; | ||
1441 | if (a->main.period) | ||
1442 | a->tmpperiod+=(a->fportdnspd<<2); | ||
1443 | } | ||
1444 | |||
1445 | return 0; | ||
1446 | } | ||
1447 | |||
1448 | static int DoXMEffectEA(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
1449 | { | ||
1450 | UBYTE dat; | ||
1451 | |||
1452 | dat=UniGetByte(); | ||
1453 | if (!tick) | ||
1454 | if (dat) a->fslideupspd=dat; | ||
1455 | a->tmpvolume+=a->fslideupspd; | ||
1456 | if (a->tmpvolume>64) a->tmpvolume=64; | ||
1457 | |||
1458 | return 0; | ||
1459 | } | ||
1460 | |||
1461 | static int DoXMEffectEB(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
1462 | { | ||
1463 | UBYTE dat; | ||
1464 | |||
1465 | dat=UniGetByte(); | ||
1466 | if (!tick) | ||
1467 | if (dat) a->fslidednspd=dat; | ||
1468 | a->tmpvolume-=a->fslidednspd; | ||
1469 | if (a->tmpvolume<0) a->tmpvolume=0; | ||
1470 | |||
1471 | return 0; | ||
1472 | } | ||
1473 | |||
1474 | static int DoXMEffectG(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
1475 | { | ||
1476 | mod->volume=UniGetByte()<<1; | ||
1477 | if (mod->volume>128) mod->volume=128; | ||
1478 | |||
1479 | return 0; | ||
1480 | } | ||
1481 | |||
1482 | static int DoXMEffectH(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
1483 | { | ||
1484 | UBYTE inf; | ||
1485 | |||
1486 | inf = UniGetByte(); | ||
1487 | |||
1488 | if (tick) { | ||
1489 | if (inf) mod->globalslide=inf; | ||
1490 | else inf=mod->globalslide; | ||
1491 | if (inf & 0xf0) inf&=0xf0; | ||
1492 | mod->volume=mod->volume+((inf>>4)-(inf&0xf))*2; | ||
1493 | |||
1494 | if (mod->volume<0) | ||
1495 | mod->volume=0; | ||
1496 | else if (mod->volume>128) | ||
1497 | mod->volume=128; | ||
1498 | } | ||
1499 | |||
1500 | return 0; | ||
1501 | } | ||
1502 | |||
1503 | static int DoXMEffectL(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
1504 | { | ||
1505 | UBYTE dat; | ||
1506 | |||
1507 | dat=UniGetByte(); | ||
1508 | if ((!tick)&&(a->main.i)) { | ||
1509 | UWORD points; | ||
1510 | INSTRUMENT *i=a->main.i; | ||
1511 | MP_VOICE *aout; | ||
1512 | |||
1513 | if ((aout=a->slave)) { | ||
1514 | if (aout->venv.env) { | ||
1515 | points=i->volenv[i->volpts-1].pos; | ||
1516 | aout->venv.p=aout->venv.env[(dat>points)?points:dat].pos; | ||
1517 | } | ||
1518 | if (aout->penv.env) { | ||
1519 | points=i->panenv[i->panpts-1].pos; | ||
1520 | aout->penv.p=aout->penv.env[(dat>points)?points:dat].pos; | ||
1521 | } | ||
1522 | } | ||
1523 | } | ||
1524 | |||
1525 | return 0; | ||
1526 | } | ||
1527 | |||
1528 | static int DoXMEffectP(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
1529 | { | ||
1530 | UBYTE inf, lo, hi; | ||
1531 | SWORD pan; | ||
1532 | |||
1533 | inf = UniGetByte(); | ||
1534 | if (!mod->panflag) | ||
1535 | return 0; | ||
1536 | |||
1537 | if (inf) | ||
1538 | a->pansspd = inf; | ||
1539 | else | ||
1540 | inf =a->pansspd; | ||
1541 | |||
1542 | if (tick) { | ||
1543 | lo=inf&0xf; | ||
1544 | hi=inf>>4; | ||
1545 | |||
1546 | /* slide right has absolute priority */ | ||
1547 | if (hi) | ||
1548 | lo = 0; | ||
1549 | |||
1550 | pan=((a->main.panning==PAN_SURROUND)?PAN_CENTER:a->main.panning)+hi-lo; | ||
1551 | a->main.panning=(pan<PAN_LEFT)?PAN_LEFT:(pan>PAN_RIGHT?PAN_RIGHT:pan); | ||
1552 | } | ||
1553 | |||
1554 | return 0; | ||
1555 | } | ||
1556 | |||
1557 | static int DoXMEffectX1(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
1558 | { | ||
1559 | UBYTE dat; | ||
1560 | |||
1561 | dat = UniGetByte(); | ||
1562 | if (dat) | ||
1563 | a->ffportupspd = dat; | ||
1564 | else | ||
1565 | dat = a->ffportupspd; | ||
1566 | |||
1567 | if (a->main.period) | ||
1568 | if (!tick) { | ||
1569 | a->main.period-=dat; | ||
1570 | a->tmpperiod-=dat; | ||
1571 | a->ownper = 1; | ||
1572 | } | ||
1573 | |||
1574 | return 0; | ||
1575 | } | ||
1576 | |||
1577 | static int DoXMEffectX2(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
1578 | { | ||
1579 | UBYTE dat; | ||
1580 | |||
1581 | dat = UniGetByte(); | ||
1582 | if (dat) | ||
1583 | a->ffportdnspd=dat; | ||
1584 | else | ||
1585 | dat = a->ffportdnspd; | ||
1586 | |||
1587 | if (a->main.period) | ||
1588 | if (!tick) { | ||
1589 | a->main.period+=dat; | ||
1590 | a->tmpperiod+=dat; | ||
1591 | a->ownper = 1; | ||
1592 | } | ||
1593 | |||
1594 | return 0; | ||
1595 | } | ||
1596 | |||
1597 | /*========== Impulse Tracker effects */ | ||
1598 | |||
1599 | static void DoITToneSlide(UWORD tick, MP_CONTROL *a, UBYTE dat) | ||
1600 | { | ||
1601 | if (dat) | ||
1602 | a->portspeed = dat; | ||
1603 | |||
1604 | /* if we don't come from another note, ignore the slide and play the note | ||
1605 | as is */ | ||
1606 | if (!a->oldnote || !a->main.period) | ||
1607 | return; | ||
1608 | |||
1609 | if ((!tick)&&(a->newsamp)){ | ||
1610 | a->main.kick=KICK_NOTE; | ||
1611 | a->main.start=-1; | ||
1612 | } else | ||
1613 | a->main.kick=(a->main.kick==KICK_NOTE)?KICK_ENV:KICK_ABSENT; | ||
1614 | |||
1615 | if (tick) { | ||
1616 | int dist; | ||
1617 | |||
1618 | /* We have to slide a->main.period towards a->wantedperiod, compute the | ||
1619 | difference between those two values */ | ||
1620 | dist=a->main.period-a->wantedperiod; | ||
1621 | |||
1622 | /* if they are equal or if portamentospeed is too big... */ | ||
1623 | if ((!dist)||((a->portspeed<<2)>abs(dist))) | ||
1624 | /* ... make tmpperiod equal tperiod */ | ||
1625 | a->tmpperiod=a->main.period=a->wantedperiod; | ||
1626 | else | ||
1627 | if (dist>0) { | ||
1628 | a->tmpperiod-=a->portspeed<<2; | ||
1629 | a->main.period-=a->portspeed<<2; /* dist>0 slide up */ | ||
1630 | } else { | ||
1631 | a->tmpperiod+=a->portspeed<<2; | ||
1632 | a->main.period+=a->portspeed<<2; /* dist<0 slide down */ | ||
1633 | } | ||
1634 | } else | ||
1635 | a->tmpperiod=a->main.period; | ||
1636 | a->ownper=1; | ||
1637 | } | ||
1638 | |||
1639 | static int DoITEffectG(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
1640 | { | ||
1641 | DoITToneSlide(tick, a, UniGetByte()); | ||
1642 | |||
1643 | return 0; | ||
1644 | } | ||
1645 | |||
1646 | static void DoITVibrato(UWORD tick, MP_CONTROL *a, UBYTE dat) | ||
1647 | { | ||
1648 | UBYTE q; | ||
1649 | UWORD temp=0; | ||
1650 | |||
1651 | if (!tick) { | ||
1652 | if (dat&0x0f) a->vibdepth=dat&0xf; | ||
1653 | if (dat&0xf0) a->vibspd=(dat&0xf0)>>2; | ||
1654 | } | ||
1655 | if (!a->main.period) | ||
1656 | return; | ||
1657 | |||
1658 | q=(a->vibpos>>2)&0x1f; | ||
1659 | |||
1660 | switch (a->wavecontrol&3) { | ||
1661 | case 0: /* sine */ | ||
1662 | temp=VibratoTable[q]; | ||
1663 | break; | ||
1664 | case 1: /* square wave */ | ||
1665 | temp=255; | ||
1666 | break; | ||
1667 | case 2: /* ramp down */ | ||
1668 | q<<=3; | ||
1669 | if (a->vibpos<0) q=255-q; | ||
1670 | temp=q; | ||
1671 | break; | ||
1672 | case 3: /* random */ | ||
1673 | temp=getrandom(256); | ||
1674 | break; | ||
1675 | } | ||
1676 | |||
1677 | temp*=a->vibdepth; | ||
1678 | temp>>=8; | ||
1679 | temp<<=2; | ||
1680 | |||
1681 | if (a->vibpos>=0) | ||
1682 | a->main.period=a->tmpperiod+temp; | ||
1683 | else | ||
1684 | a->main.period=a->tmpperiod-temp; | ||
1685 | a->ownper=1; | ||
1686 | |||
1687 | a->vibpos+=a->vibspd; | ||
1688 | } | ||
1689 | |||
1690 | static int DoITEffectH(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
1691 | { | ||
1692 | DoITVibrato(tick, a, UniGetByte()); | ||
1693 | |||
1694 | return 0; | ||
1695 | } | ||
1696 | |||
1697 | static int DoITEffectI(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
1698 | { | ||
1699 | UBYTE inf, on, off; | ||
1700 | |||
1701 | inf = UniGetByte(); | ||
1702 | if (inf) | ||
1703 | a->s3mtronof = inf; | ||
1704 | else { | ||
1705 | inf = a->s3mtronof; | ||
1706 | if (!inf) | ||
1707 | return 0; | ||
1708 | } | ||
1709 | |||
1710 | on=(inf>>4); | ||
1711 | off=(inf&0xf); | ||
1712 | |||
1713 | a->s3mtremor%=(on+off); | ||
1714 | a->volume=(a->s3mtremor<on)?a->tmpvolume:0; | ||
1715 | a->ownvol = 1; | ||
1716 | a->s3mtremor++; | ||
1717 | |||
1718 | return 0; | ||
1719 | } | ||
1720 | |||
1721 | static int DoITEffectM(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
1722 | { | ||
1723 | a->main.chanvol=UniGetByte(); | ||
1724 | if (a->main.chanvol>64) | ||
1725 | a->main.chanvol=64; | ||
1726 | else if (a->main.chanvol<0) | ||
1727 | a->main.chanvol=0; | ||
1728 | |||
1729 | return 0; | ||
1730 | } | ||
1731 | |||
1732 | static int DoITEffectN(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
1733 | { | ||
1734 | UBYTE inf, lo, hi; | ||
1735 | |||
1736 | inf = UniGetByte(); | ||
1737 | |||
1738 | if (inf) | ||
1739 | a->chanvolslide = inf; | ||
1740 | else | ||
1741 | inf = a->chanvolslide; | ||
1742 | |||
1743 | lo=inf&0xf; | ||
1744 | hi=inf>>4; | ||
1745 | |||
1746 | if (!hi) | ||
1747 | a->main.chanvol-=lo; | ||
1748 | else | ||
1749 | if (!lo) { | ||
1750 | a->main.chanvol+=hi; | ||
1751 | } else | ||
1752 | if (hi==0xf) { | ||
1753 | if (!tick) a->main.chanvol-=lo; | ||
1754 | } else | ||
1755 | if (lo==0xf) { | ||
1756 | if (!tick) a->main.chanvol+=hi; | ||
1757 | } | ||
1758 | |||
1759 | if (a->main.chanvol<0) | ||
1760 | a->main.chanvol=0; | ||
1761 | else if (a->main.chanvol>64) | ||
1762 | a->main.chanvol=64; | ||
1763 | |||
1764 | return 0; | ||
1765 | } | ||
1766 | |||
1767 | static int DoITEffectP(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
1768 | { | ||
1769 | UBYTE inf, lo, hi; | ||
1770 | SWORD pan; | ||
1771 | |||
1772 | inf = UniGetByte(); | ||
1773 | if (inf) | ||
1774 | a->pansspd = inf; | ||
1775 | else | ||
1776 | inf = a->pansspd; | ||
1777 | |||
1778 | if (!mod->panflag) | ||
1779 | return 0; | ||
1780 | |||
1781 | lo=inf&0xf; | ||
1782 | hi=inf>>4; | ||
1783 | |||
1784 | pan=(a->main.panning==PAN_SURROUND)?PAN_CENTER:a->main.panning; | ||
1785 | |||
1786 | if (!hi) | ||
1787 | pan+=lo<<2; | ||
1788 | else | ||
1789 | if (!lo) { | ||
1790 | pan-=hi<<2; | ||
1791 | } else | ||
1792 | if (hi==0xf) { | ||
1793 | if (!tick) pan+=lo<<2; | ||
1794 | } else | ||
1795 | if (lo==0xf) { | ||
1796 | if (!tick) pan-=hi<<2; | ||
1797 | } | ||
1798 | a->main.panning= | ||
1799 | (pan<PAN_LEFT)?PAN_LEFT:(pan>PAN_RIGHT?PAN_RIGHT:pan); | ||
1800 | |||
1801 | return 0; | ||
1802 | } | ||
1803 | |||
1804 | static int DoITEffectT(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
1805 | { | ||
1806 | UBYTE tempo; | ||
1807 | SWORD temp; | ||
1808 | |||
1809 | tempo = UniGetByte(); | ||
1810 | |||
1811 | if (mod->patdly2) | ||
1812 | return 0; | ||
1813 | |||
1814 | temp = mod->bpm; | ||
1815 | if (tempo & 0x10) | ||
1816 | temp += (tempo & 0x0f); | ||
1817 | else | ||
1818 | temp -= tempo; | ||
1819 | |||
1820 | mod->bpm=(temp>255)?255:(temp<1?1:temp); | ||
1821 | |||
1822 | return 0; | ||
1823 | } | ||
1824 | |||
1825 | static int DoITEffectU(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
1826 | { | ||
1827 | UBYTE dat, q; | ||
1828 | UWORD temp = 0; /* silence warning */ | ||
1829 | |||
1830 | dat = UniGetByte(); | ||
1831 | if (!tick) { | ||
1832 | if (dat&0x0f) a->vibdepth=dat&0xf; | ||
1833 | if (dat&0xf0) a->vibspd=(dat&0xf0)>>2; | ||
1834 | } | ||
1835 | if (a->main.period) { | ||
1836 | q=(a->vibpos>>2)&0x1f; | ||
1837 | |||
1838 | switch (a->wavecontrol&3) { | ||
1839 | case 0: /* sine */ | ||
1840 | temp=VibratoTable[q]; | ||
1841 | break; | ||
1842 | case 1: /* square wave */ | ||
1843 | temp=255; | ||
1844 | break; | ||
1845 | case 2: /* ramp down */ | ||
1846 | q<<=3; | ||
1847 | if (a->vibpos<0) q=255-q; | ||
1848 | temp=q; | ||
1849 | break; | ||
1850 | case 3: /* random */ | ||
1851 | temp=getrandom(256); | ||
1852 | break; | ||
1853 | } | ||
1854 | |||
1855 | temp*=a->vibdepth; | ||
1856 | temp>>=8; | ||
1857 | |||
1858 | if (a->vibpos>=0) | ||
1859 | a->main.period=a->tmpperiod+temp; | ||
1860 | else | ||
1861 | a->main.period=a->tmpperiod-temp; | ||
1862 | a->ownper = 1; | ||
1863 | |||
1864 | a->vibpos+=a->vibspd; | ||
1865 | } | ||
1866 | |||
1867 | return 0; | ||
1868 | } | ||
1869 | |||
1870 | static int DoITEffectW(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
1871 | { | ||
1872 | UBYTE inf, lo, hi; | ||
1873 | |||
1874 | inf = UniGetByte(); | ||
1875 | |||
1876 | if (inf) | ||
1877 | mod->globalslide = inf; | ||
1878 | else | ||
1879 | inf = mod->globalslide; | ||
1880 | |||
1881 | lo=inf&0xf; | ||
1882 | hi=inf>>4; | ||
1883 | |||
1884 | if (!lo) { | ||
1885 | if (tick) mod->volume+=hi; | ||
1886 | } else | ||
1887 | if (!hi) { | ||
1888 | if (tick) mod->volume-=lo; | ||
1889 | } else | ||
1890 | if (lo==0xf) { | ||
1891 | if (!tick) mod->volume+=hi; | ||
1892 | } else | ||
1893 | if (hi==0xf) { | ||
1894 | if (!tick) mod->volume-=lo; | ||
1895 | } | ||
1896 | |||
1897 | if (mod->volume<0) | ||
1898 | mod->volume=0; | ||
1899 | else if (mod->volume>128) | ||
1900 | mod->volume=128; | ||
1901 | |||
1902 | return 0; | ||
1903 | } | ||
1904 | |||
1905 | static int DoITEffectY(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
1906 | { | ||
1907 | UBYTE dat, q; | ||
1908 | SLONG temp = 0; /* silence warning */ | ||
1909 | |||
1910 | |||
1911 | dat=UniGetByte(); | ||
1912 | if (!tick) { | ||
1913 | if (dat&0x0f) a->panbdepth=(dat&0xf); | ||
1914 | if (dat&0xf0) a->panbspd=(dat&0xf0)>>4; | ||
1915 | } | ||
1916 | if (mod->panflag) { | ||
1917 | q=a->panbpos; | ||
1918 | |||
1919 | switch (a->panbwave) { | ||
1920 | case 0: /* sine */ | ||
1921 | temp=PanbrelloTable[q]; | ||
1922 | break; | ||
1923 | case 1: /* square wave */ | ||
1924 | temp=(q<0x80)?64:0; | ||
1925 | break; | ||
1926 | case 2: /* ramp down */ | ||
1927 | q<<=3; | ||
1928 | temp=q; | ||
1929 | break; | ||
1930 | case 3: /* random */ | ||
1931 | temp=getrandom(256); | ||
1932 | break; | ||
1933 | } | ||
1934 | |||
1935 | temp*=a->panbdepth; | ||
1936 | temp=(temp/8)+mod->panning[channel]; | ||
1937 | |||
1938 | a->main.panning= | ||
1939 | (temp<PAN_LEFT)?PAN_LEFT:(temp>PAN_RIGHT?PAN_RIGHT:temp); | ||
1940 | a->panbpos+=a->panbspd; | ||
1941 | |||
1942 | } | ||
1943 | |||
1944 | return 0; | ||
1945 | } | ||
1946 | |||
1947 | static void DoNNAEffects(MODULE *, MP_CONTROL *, UBYTE); | ||
1948 | |||
1949 | /* Impulse/Scream Tracker Sxx effects. | ||
1950 | All Sxx effects share the same memory space. */ | ||
1951 | static int DoITEffectS0(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
1952 | { | ||
1953 | UBYTE dat, inf, c; | ||
1954 | |||
1955 | dat = UniGetByte(); | ||
1956 | inf=dat&0xf; | ||
1957 | c=dat>>4; | ||
1958 | |||
1959 | if (!dat) { | ||
1960 | c=a->sseffect; | ||
1961 | inf=a->ssdata; | ||
1962 | } else { | ||
1963 | a->sseffect=c; | ||
1964 | a->ssdata=inf; | ||
1965 | } | ||
1966 | |||
1967 | switch (c) { | ||
1968 | case SS_GLISSANDO: /* S1x set glissando voice */ | ||
1969 | DoEEffects(tick, flags, a, mod, channel, 0x30|inf); | ||
1970 | break; | ||
1971 | case SS_FINETUNE: /* S2x set finetune */ | ||
1972 | DoEEffects(tick, flags, a, mod, channel, 0x50|inf); | ||
1973 | break; | ||
1974 | case SS_VIBWAVE: /* S3x set vibrato waveform */ | ||
1975 | DoEEffects(tick, flags, a, mod, channel, 0x40|inf); | ||
1976 | break; | ||
1977 | case SS_TREMWAVE: /* S4x set tremolo waveform */ | ||
1978 | DoEEffects(tick, flags, a, mod, channel, 0x70|inf); | ||
1979 | break; | ||
1980 | case SS_PANWAVE: /* S5x panbrello */ | ||
1981 | a->panbwave=inf; | ||
1982 | break; | ||
1983 | case SS_FRAMEDELAY: /* S6x delay x number of frames (patdly) */ | ||
1984 | DoEEffects(tick, flags, a, mod, channel, 0xe0|inf); | ||
1985 | break; | ||
1986 | case SS_S7EFFECTS: /* S7x instrument / NNA commands */ | ||
1987 | DoNNAEffects(mod, a, inf); | ||
1988 | break; | ||
1989 | case SS_PANNING: /* S8x set panning position */ | ||
1990 | DoEEffects(tick, flags, a, mod, channel, 0x80 | inf); | ||
1991 | break; | ||
1992 | case SS_SURROUND: /* S9x set surround sound */ | ||
1993 | if (mod->panflag) | ||
1994 | a->main.panning = mod->panning[channel] = PAN_SURROUND; | ||
1995 | break; | ||
1996 | case SS_HIOFFSET: /* SAy set high order sample offset yxx00h */ | ||
1997 | if (!tick) { | ||
1998 | a->hioffset=inf<<16; | ||
1999 | a->main.start=a->hioffset|a->soffset; | ||
2000 | |||
2001 | if ((a->main.s)&&(a->main.start>a->main.s->length)) | ||
2002 | a->main.start=a->main.s->flags&(SF_LOOP|SF_BIDI)? | ||
2003 | a->main.s->loopstart:a->main.s->length; | ||
2004 | } | ||
2005 | break; | ||
2006 | case SS_PATLOOP: /* SBx pattern loop */ | ||
2007 | DoEEffects(tick, flags, a, mod, channel, 0x60|inf); | ||
2008 | break; | ||
2009 | case SS_NOTECUT: /* SCx notecut */ | ||
2010 | if (!inf) inf = 1; | ||
2011 | DoEEffects(tick, flags, a, mod, channel, 0xC0|inf); | ||
2012 | break; | ||
2013 | case SS_NOTEDELAY: /* SDx notedelay */ | ||
2014 | DoEEffects(tick, flags, a, mod, channel, 0xD0|inf); | ||
2015 | break; | ||
2016 | case SS_PATDELAY: /* SEx patterndelay */ | ||
2017 | DoEEffects(tick, flags, a, mod, channel, 0xE0|inf); | ||
2018 | break; | ||
2019 | } | ||
2020 | |||
2021 | return 0; | ||
2022 | } | ||
2023 | |||
2024 | /*========== Impulse Tracker Volume/Pan Column effects */ | ||
2025 | |||
2026 | /* | ||
2027 | * All volume/pan column effects share the same memory space. | ||
2028 | */ | ||
2029 | |||
2030 | static int DoVolEffects(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
2031 | { | ||
2032 | UBYTE c, inf; | ||
2033 | |||
2034 | c = UniGetByte(); | ||
2035 | inf = UniGetByte(); | ||
2036 | |||
2037 | if ((!c)&&(!inf)) { | ||
2038 | c=a->voleffect; | ||
2039 | inf=a->voldata; | ||
2040 | } else { | ||
2041 | a->voleffect=c; | ||
2042 | a->voldata=inf; | ||
2043 | } | ||
2044 | |||
2045 | if (c) | ||
2046 | switch (c) { | ||
2047 | case VOL_VOLUME: | ||
2048 | if (tick) break; | ||
2049 | if (inf>64) inf=64; | ||
2050 | a->tmpvolume=inf; | ||
2051 | break; | ||
2052 | case VOL_PANNING: | ||
2053 | if (mod->panflag) | ||
2054 | a->main.panning=inf; | ||
2055 | break; | ||
2056 | case VOL_VOLSLIDE: | ||
2057 | DoS3MVolSlide(tick, flags, a, inf); | ||
2058 | return 1; | ||
2059 | case VOL_PITCHSLIDEDN: | ||
2060 | if (a->main.period) | ||
2061 | DoS3MSlideDn(tick, a, inf); | ||
2062 | break; | ||
2063 | case VOL_PITCHSLIDEUP: | ||
2064 | if (a->main.period) | ||
2065 | DoS3MSlideUp(tick, a, inf); | ||
2066 | break; | ||
2067 | case VOL_PORTAMENTO: | ||
2068 | DoITToneSlide(tick, a, inf); | ||
2069 | break; | ||
2070 | case VOL_VIBRATO: | ||
2071 | DoITVibrato(tick, a, inf); | ||
2072 | break; | ||
2073 | } | ||
2074 | |||
2075 | return 0; | ||
2076 | } | ||
2077 | |||
2078 | /*========== UltraTracker effects */ | ||
2079 | |||
2080 | static int DoULTEffect9(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
2081 | { | ||
2082 | UWORD offset=UniGetWord(); | ||
2083 | |||
2084 | if (offset) | ||
2085 | a->ultoffset=offset; | ||
2086 | |||
2087 | a->main.start=a->ultoffset<<2; | ||
2088 | if ((a->main.s)&&(a->main.start>a->main.s->length)) | ||
2089 | a->main.start=a->main.s->flags&(SF_LOOP|SF_BIDI)? | ||
2090 | a->main.s->loopstart:a->main.s->length; | ||
2091 | |||
2092 | return 0; | ||
2093 | } | ||
2094 | |||
2095 | /*========== OctaMED effects */ | ||
2096 | |||
2097 | static int DoMEDSpeed(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
2098 | { | ||
2099 | UWORD speed=UniGetWord(); | ||
2100 | |||
2101 | mod->bpm=speed; | ||
2102 | |||
2103 | return 0; | ||
2104 | } | ||
2105 | |||
2106 | static int DoMEDEffectF1(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
2107 | { | ||
2108 | DoEEffects(tick, flags, a, mod, channel, 0x90|(mod->sngspd/2)); | ||
2109 | |||
2110 | return 0; | ||
2111 | } | ||
2112 | |||
2113 | static int DoMEDEffectF2(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
2114 | { | ||
2115 | DoEEffects(tick, flags, a, mod, channel, 0xd0|(mod->sngspd/2)); | ||
2116 | |||
2117 | return 0; | ||
2118 | } | ||
2119 | |||
2120 | static int DoMEDEffectF3(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
2121 | { | ||
2122 | DoEEffects(tick, flags, a, mod, channel, 0x90|(mod->sngspd/3)); | ||
2123 | |||
2124 | return 0; | ||
2125 | } | ||
2126 | |||
2127 | /*========== Oktalyzer effects */ | ||
2128 | |||
2129 | static int DoOktArp(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
2130 | { | ||
2131 | UBYTE dat, dat2; | ||
2132 | |||
2133 | dat2 = UniGetByte(); /* arpeggio style */ | ||
2134 | dat = UniGetByte(); | ||
2135 | if (!tick) { | ||
2136 | if (!dat && (flags & UF_ARPMEM)) | ||
2137 | dat=a->arpmem; | ||
2138 | else | ||
2139 | a->arpmem=dat; | ||
2140 | } | ||
2141 | if (a->main.period) | ||
2142 | DoArpeggio(tick, flags, a, dat2); | ||
2143 | |||
2144 | return 0; | ||
2145 | } | ||
2146 | |||
2147 | /*========== General player functions */ | ||
2148 | |||
2149 | static int DoNothing(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel) | ||
2150 | { | ||
2151 | UniSkipOpcode(); | ||
2152 | |||
2153 | return 0; | ||
2154 | } | ||
2155 | |||
2156 | typedef int (*effect_func) (UWORD, UWORD, MP_CONTROL *, MODULE *, SWORD); | ||
2157 | |||
2158 | static effect_func effects[UNI_LAST] = { | ||
2159 | DoNothing, /* 0 */ | ||
2160 | DoNothing, /* UNI_NOTE */ | ||
2161 | DoNothing, /* UNI_INSTRUMENT */ | ||
2162 | DoPTEffect0, /* UNI_PTEFFECT0 */ | ||
2163 | DoPTEffect1, /* UNI_PTEFFECT1 */ | ||
2164 | DoPTEffect2, /* UNI_PTEFFECT2 */ | ||
2165 | DoPTEffect3, /* UNI_PTEFFECT3 */ | ||
2166 | DoPTEffect4, /* UNI_PTEFFECT4 */ | ||
2167 | DoPTEffect5, /* UNI_PTEFFECT5 */ | ||
2168 | DoPTEffect6, /* UNI_PTEFFECT6 */ | ||
2169 | DoPTEffect7, /* UNI_PTEFFECT7 */ | ||
2170 | DoPTEffect8, /* UNI_PTEFFECT8 */ | ||
2171 | DoPTEffect9, /* UNI_PTEFFECT9 */ | ||
2172 | DoPTEffectA, /* UNI_PTEFFECTA */ | ||
2173 | DoPTEffectB, /* UNI_PTEFFECTB */ | ||
2174 | DoPTEffectC, /* UNI_PTEFFECTC */ | ||
2175 | DoPTEffectD, /* UNI_PTEFFECTD */ | ||
2176 | DoPTEffectE, /* UNI_PTEFFECTE */ | ||
2177 | DoPTEffectF, /* UNI_PTEFFECTF */ | ||
2178 | DoS3MEffectA, /* UNI_S3MEFFECTA */ | ||
2179 | DoS3MEffectD, /* UNI_S3MEFFECTD */ | ||
2180 | DoS3MEffectE, /* UNI_S3MEFFECTE */ | ||
2181 | DoS3MEffectF, /* UNI_S3MEFFECTF */ | ||
2182 | DoS3MEffectI, /* UNI_S3MEFFECTI */ | ||
2183 | DoS3MEffectQ, /* UNI_S3MEFFECTQ */ | ||
2184 | DoS3MEffectR, /* UNI_S3MEFFECTR */ | ||
2185 | DoS3MEffectT, /* UNI_S3MEFFECTT */ | ||
2186 | DoS3MEffectU, /* UNI_S3MEFFECTU */ | ||
2187 | DoKeyOff, /* UNI_KEYOFF */ | ||
2188 | DoKeyFade, /* UNI_KEYFADE */ | ||
2189 | DoVolEffects, /* UNI_VOLEFFECTS */ | ||
2190 | DoPTEffect4, /* UNI_XMEFFECT4 */ | ||
2191 | DoXMEffect6, /* UNI_XMEFFECT6 */ | ||
2192 | DoXMEffectA, /* UNI_XMEFFECTA */ | ||
2193 | DoXMEffectE1, /* UNI_XMEFFECTE1 */ | ||
2194 | DoXMEffectE2, /* UNI_XMEFFECTE2 */ | ||
2195 | DoXMEffectEA, /* UNI_XMEFFECTEA */ | ||
2196 | DoXMEffectEB, /* UNI_XMEFFECTEB */ | ||
2197 | DoXMEffectG, /* UNI_XMEFFECTG */ | ||
2198 | DoXMEffectH, /* UNI_XMEFFECTH */ | ||
2199 | DoXMEffectL, /* UNI_XMEFFECTL */ | ||
2200 | DoXMEffectP, /* UNI_XMEFFECTP */ | ||
2201 | DoXMEffectX1, /* UNI_XMEFFECTX1 */ | ||
2202 | DoXMEffectX2, /* UNI_XMEFFECTX2 */ | ||
2203 | DoITEffectG, /* UNI_ITEFFECTG */ | ||
2204 | DoITEffectH, /* UNI_ITEFFECTH */ | ||
2205 | DoITEffectI, /* UNI_ITEFFECTI */ | ||
2206 | DoITEffectM, /* UNI_ITEFFECTM */ | ||
2207 | DoITEffectN, /* UNI_ITEFFECTN */ | ||
2208 | DoITEffectP, /* UNI_ITEFFECTP */ | ||
2209 | DoITEffectT, /* UNI_ITEFFECTT */ | ||
2210 | DoITEffectU, /* UNI_ITEFFECTU */ | ||
2211 | DoITEffectW, /* UNI_ITEFFECTW */ | ||
2212 | DoITEffectY, /* UNI_ITEFFECTY */ | ||
2213 | DoNothing, /* UNI_ITEFFECTZ */ | ||
2214 | DoITEffectS0, /* UNI_ITEFFECTS0 */ | ||
2215 | DoULTEffect9, /* UNI_ULTEFFECT9 */ | ||
2216 | DoMEDSpeed, /* UNI_MEDSPEED */ | ||
2217 | DoMEDEffectF1, /* UNI_MEDEFFECTF1 */ | ||
2218 | DoMEDEffectF2, /* UNI_MEDEFFECTF2 */ | ||
2219 | DoMEDEffectF3, /* UNI_MEDEFFECTF3 */ | ||
2220 | DoOktArp, /* UNI_OKTARP */ | ||
2221 | }; | ||
2222 | |||
2223 | static int pt_playeffects(MODULE *mod, SWORD channel, MP_CONTROL *a) | ||
2224 | { | ||
2225 | UWORD tick = mod->vbtick; | ||
2226 | UWORD flags = mod->flags; | ||
2227 | UBYTE c; | ||
2228 | int explicitslides = 0; | ||
2229 | effect_func f; | ||
2230 | |||
2231 | while((c=UniGetByte())) { | ||
2232 | f = effects[c]; | ||
2233 | if (f != DoNothing) | ||
2234 | a->sliding = 0; | ||
2235 | explicitslides |= f(tick, flags, a, mod, channel); | ||
2236 | } | ||
2237 | return explicitslides; | ||
2238 | } | ||
2239 | |||
2240 | static void DoNNAEffects(MODULE *mod, MP_CONTROL *a, UBYTE dat) | ||
2241 | { | ||
2242 | int t; | ||
2243 | MP_VOICE *aout; | ||
2244 | |||
2245 | dat&=0xf; | ||
2246 | aout=(a->slave)?a->slave:NULL; | ||
2247 | |||
2248 | switch (dat) { | ||
2249 | case 0x0: /* past note cut */ | ||
2250 | for (t=0;t<md_sngchn;t++) | ||
2251 | if (mod->voice[t].master==a) | ||
2252 | mod->voice[t].main.fadevol=0; | ||
2253 | break; | ||
2254 | case 0x1: /* past note off */ | ||
2255 | for (t=0;t<md_sngchn;t++) | ||
2256 | if (mod->voice[t].master==a) { | ||
2257 | mod->voice[t].main.keyoff|=KEY_OFF; | ||
2258 | if ((!(mod->voice[t].venv.flg & EF_ON))|| | ||
2259 | (mod->voice[t].venv.flg & EF_LOOP)) | ||
2260 | mod->voice[t].main.keyoff=KEY_KILL; | ||
2261 | } | ||
2262 | break; | ||
2263 | case 0x2: /* past note fade */ | ||
2264 | for (t=0;t<md_sngchn;t++) | ||
2265 | if (mod->voice[t].master==a) | ||
2266 | mod->voice[t].main.keyoff|=KEY_FADE; | ||
2267 | break; | ||
2268 | case 0x3: /* set NNA note cut */ | ||
2269 | a->main.nna=(a->main.nna&~NNA_MASK)|NNA_CUT; | ||
2270 | break; | ||
2271 | case 0x4: /* set NNA note continue */ | ||
2272 | a->main.nna=(a->main.nna&~NNA_MASK)|NNA_CONTINUE; | ||
2273 | break; | ||
2274 | case 0x5: /* set NNA note off */ | ||
2275 | a->main.nna=(a->main.nna&~NNA_MASK)|NNA_OFF; | ||
2276 | break; | ||
2277 | case 0x6: /* set NNA note fade */ | ||
2278 | a->main.nna=(a->main.nna&~NNA_MASK)|NNA_FADE; | ||
2279 | break; | ||
2280 | case 0x7: /* disable volume envelope */ | ||
2281 | if (aout) | ||
2282 | aout->main.volflg&=~EF_ON; | ||
2283 | break; | ||
2284 | case 0x8: /* enable volume envelope */ | ||
2285 | if (aout) | ||
2286 | aout->main.volflg|=EF_ON; | ||
2287 | break; | ||
2288 | case 0x9: /* disable panning envelope */ | ||
2289 | if (aout) | ||
2290 | aout->main.panflg&=~EF_ON; | ||
2291 | break; | ||
2292 | case 0xa: /* enable panning envelope */ | ||
2293 | if (aout) | ||
2294 | aout->main.panflg|=EF_ON; | ||
2295 | break; | ||
2296 | case 0xb: /* disable pitch envelope */ | ||
2297 | if (aout) | ||
2298 | aout->main.pitflg&=~EF_ON; | ||
2299 | break; | ||
2300 | case 0xc: /* enable pitch envelope */ | ||
2301 | if (aout) | ||
2302 | aout->main.pitflg|=EF_ON; | ||
2303 | break; | ||
2304 | } | ||
2305 | } | ||
2306 | |||
2307 | void pt_UpdateVoices(MODULE *mod, int max_volume) | ||
2308 | { | ||
2309 | SWORD envpan,envvol,envpit,channel; | ||
2310 | UWORD playperiod; | ||
2311 | SLONG vibval,vibdpt; | ||
2312 | ULONG tmpvol; | ||
2313 | |||
2314 | MP_VOICE *aout; | ||
2315 | INSTRUMENT *i; | ||
2316 | SAMPLE *s; | ||
2317 | |||
2318 | mod->totalchn=mod->realchn=0; | ||
2319 | for (channel=0;channel<md_sngchn;channel++) { | ||
2320 | aout=&mod->voice[channel]; | ||
2321 | i=aout->main.i; | ||
2322 | s=aout->main.s; | ||
2323 | |||
2324 | if (!s || !s->length) continue; | ||
2325 | |||
2326 | if (aout->main.period<40) | ||
2327 | aout->main.period=40; | ||
2328 | else if (aout->main.period>50000) | ||
2329 | aout->main.period=50000; | ||
2330 | |||
2331 | if ((aout->main.kick==KICK_NOTE)||(aout->main.kick==KICK_KEYOFF)) { | ||
2332 | Voice_Play_internal(channel,s,(aout->main.start==-1)? | ||
2333 | ((s->flags&SF_UST_LOOP)?s->loopstart:0):aout->main.start); | ||
2334 | aout->main.fadevol=32768; | ||
2335 | aout->aswppos=0; | ||
2336 | } | ||
2337 | |||
2338 | envvol = 256; | ||
2339 | envpan = PAN_CENTER; | ||
2340 | envpit = 32; | ||
2341 | if (i && ((aout->main.kick==KICK_NOTE)||(aout->main.kick==KICK_ENV))) { | ||
2342 | if (aout->main.volflg & EF_ON) | ||
2343 | envvol = StartEnvelope(&aout->venv,aout->main.volflg, | ||
2344 | i->volpts,i->volsusbeg,i->volsusend, | ||
2345 | i->volbeg,i->volend,i->volenv,aout->main.keyoff); | ||
2346 | if (aout->main.panflg & EF_ON) | ||
2347 | envpan = StartEnvelope(&aout->penv,aout->main.panflg, | ||
2348 | i->panpts,i->pansusbeg,i->pansusend, | ||
2349 | i->panbeg,i->panend,i->panenv,aout->main.keyoff); | ||
2350 | if (aout->main.pitflg & EF_ON) | ||
2351 | envpit = StartEnvelope(&aout->cenv,aout->main.pitflg, | ||
2352 | i->pitpts,i->pitsusbeg,i->pitsusend, | ||
2353 | i->pitbeg,i->pitend,i->pitenv,aout->main.keyoff); | ||
2354 | |||
2355 | if (aout->cenv.flg & EF_ON) | ||
2356 | aout->masterperiod=GetPeriod(mod->flags, | ||
2357 | (UWORD)aout->main.note<<1, aout->master->speed); | ||
2358 | } else { | ||
2359 | if (aout->main.volflg & EF_ON) | ||
2360 | envvol = ProcessEnvelope(aout,&aout->venv,256); | ||
2361 | if (aout->main.panflg & EF_ON) | ||
2362 | envpan = ProcessEnvelope(aout,&aout->penv,PAN_CENTER); | ||
2363 | if (aout->main.pitflg & EF_ON) | ||
2364 | envpit = ProcessEnvelope(aout,&aout->cenv,32); | ||
2365 | } | ||
2366 | if (aout->main.kick == KICK_NOTE) { | ||
2367 | aout->main.kick_flag = 1; | ||
2368 | } | ||
2369 | aout->main.kick=KICK_ABSENT; | ||
2370 | |||
2371 | tmpvol = aout->main.fadevol; /* max 32768 */ | ||
2372 | tmpvol *= aout->main.chanvol; /* * max 64 */ | ||
2373 | tmpvol *= aout->main.outvolume; /* * max 256 */ | ||
2374 | tmpvol /= (256 * 64); /* tmpvol is max 32768 again */ | ||
2375 | aout->totalvol = tmpvol >> 2; /* used to determine samplevolume */ | ||
2376 | tmpvol *= envvol; /* * max 256 */ | ||
2377 | tmpvol *= mod->volume; /* * max 128 */ | ||
2378 | tmpvol /= (128 * 256 * 128); | ||
2379 | |||
2380 | /* fade out */ | ||
2381 | if (mod->sngpos>=mod->numpos) | ||
2382 | tmpvol=0; | ||
2383 | else | ||
2384 | tmpvol=(tmpvol*max_volume)/128; | ||
2385 | |||
2386 | if ((aout->masterchn!=-1)&& mod->control[aout->masterchn].muted) | ||
2387 | Voice_SetVolume_internal(channel,0); | ||
2388 | else { | ||
2389 | Voice_SetVolume_internal(channel,tmpvol); | ||
2390 | if ((tmpvol)&&(aout->master)&&(aout->master->slave==aout)) | ||
2391 | mod->realchn++; | ||
2392 | mod->totalchn++; | ||
2393 | } | ||
2394 | |||
2395 | if (aout->main.panning==PAN_SURROUND) | ||
2396 | Voice_SetPanning_internal(channel,PAN_SURROUND); | ||
2397 | else | ||
2398 | if ((mod->panflag)&&(aout->penv.flg & EF_ON)) | ||
2399 | Voice_SetPanning_internal(channel, | ||
2400 | DoPan(envpan,aout->main.panning)); | ||
2401 | else | ||
2402 | Voice_SetPanning_internal(channel,aout->main.panning); | ||
2403 | |||
2404 | if (aout->main.period && s->vibdepth) | ||
2405 | switch (s->vibtype) { | ||
2406 | case 0: | ||
2407 | vibval=avibtab[s->avibpos&127]; | ||
2408 | if (aout->avibpos & 0x80) vibval=-vibval; | ||
2409 | break; | ||
2410 | case 1: | ||
2411 | vibval=64; | ||
2412 | if (aout->avibpos & 0x80) vibval=-vibval; | ||
2413 | break; | ||
2414 | case 2: | ||
2415 | vibval=63-(((aout->avibpos+128)&255)>>1); | ||
2416 | break; | ||
2417 | default: | ||
2418 | vibval=(((aout->avibpos+128)&255)>>1)-64; | ||
2419 | break; | ||
2420 | } | ||
2421 | else | ||
2422 | vibval=0; | ||
2423 | |||
2424 | if (s->vibflags & AV_IT) { | ||
2425 | if ((aout->aswppos>>8)<s->vibdepth) { | ||
2426 | aout->aswppos += s->vibsweep; | ||
2427 | vibdpt=aout->aswppos; | ||
2428 | } else | ||
2429 | vibdpt=s->vibdepth<<8; | ||
2430 | vibval=(vibval*vibdpt)>>16; | ||
2431 | if (aout->mflag) { | ||
2432 | if (!(mod->flags&UF_LINEAR)) vibval>>=1; | ||
2433 | aout->main.period-=vibval; | ||
2434 | } | ||
2435 | } else { | ||
2436 | /* do XM style auto-vibrato */ | ||
2437 | if (!(aout->main.keyoff & KEY_OFF)) { | ||
2438 | if (aout->aswppos<s->vibsweep) { | ||
2439 | vibdpt=(aout->aswppos*s->vibdepth)/s->vibsweep; | ||
2440 | aout->aswppos++; | ||
2441 | } else | ||
2442 | vibdpt=s->vibdepth; | ||
2443 | } else { | ||
2444 | /* keyoff -> depth becomes 0 if final depth wasn't reached or | ||
2445 | stays at final level if depth WAS reached */ | ||
2446 | if (aout->aswppos>=s->vibsweep) | ||
2447 | vibdpt=s->vibdepth; | ||
2448 | else | ||
2449 | vibdpt=0; | ||
2450 | } | ||
2451 | vibval=(vibval*vibdpt)>>8; | ||
2452 | aout->main.period-=vibval; | ||
2453 | } | ||
2454 | |||
2455 | /* update vibrato position */ | ||
2456 | aout->avibpos=(aout->avibpos+s->vibrate)&0xff; | ||
2457 | |||
2458 | /* process pitch envelope */ | ||
2459 | playperiod=aout->main.period; | ||
2460 | |||
2461 | if ((aout->main.pitflg&EF_ON)&&(envpit!=32)) { | ||
2462 | long p1; | ||
2463 | |||
2464 | envpit-=32; | ||
2465 | if ((aout->main.note<<1)+envpit<=0) envpit=-(aout->main.note<<1); | ||
2466 | |||
2467 | p1=GetPeriod(mod->flags, ((UWORD)aout->main.note<<1)+envpit, | ||
2468 | aout->master->speed)-aout->masterperiod; | ||
2469 | if (p1>0) { | ||
2470 | if ((UWORD)(playperiod+p1)<=playperiod) { | ||
2471 | p1=0; | ||
2472 | aout->main.keyoff|=KEY_OFF; | ||
2473 | } | ||
2474 | } else if (p1<0) { | ||
2475 | if ((UWORD)(playperiod+p1)>=playperiod) { | ||
2476 | p1=0; | ||
2477 | aout->main.keyoff|=KEY_OFF; | ||
2478 | } | ||
2479 | } | ||
2480 | playperiod+=p1; | ||
2481 | } | ||
2482 | |||
2483 | if (!aout->main.fadevol) { /* check for a dead note (fadevol=0) */ | ||
2484 | Voice_Stop_internal(channel); | ||
2485 | mod->totalchn--; | ||
2486 | if ((tmpvol)&&(aout->master)&&(aout->master->slave==aout)) | ||
2487 | mod->realchn--; | ||
2488 | } else { | ||
2489 | Voice_SetFrequency_internal(channel, | ||
2490 | getfrequency(mod->flags,playperiod)); | ||
2491 | |||
2492 | /* if keyfade, start substracting fadeoutspeed from fadevol: */ | ||
2493 | if ((i)&&(aout->main.keyoff&KEY_FADE)) { | ||
2494 | if (aout->main.fadevol>=i->volfade) | ||
2495 | aout->main.fadevol-=i->volfade; | ||
2496 | else | ||
2497 | aout->main.fadevol=0; | ||
2498 | } | ||
2499 | } | ||
2500 | |||
2501 | md_bpm=mod->bpm+mod->relspd; | ||
2502 | if (md_bpm<32) | ||
2503 | md_bpm=32; | ||
2504 | else if ((!(mod->flags&UF_HIGHBPM)) && md_bpm>255) | ||
2505 | md_bpm=255; | ||
2506 | } | ||
2507 | } | ||
2508 | |||
2509 | /* Handles new notes or instruments */ | ||
2510 | void pt_Notes(MODULE *mod) | ||
2511 | { | ||
2512 | SWORD channel; | ||
2513 | MP_CONTROL *a; | ||
2514 | UBYTE c,inst; | ||
2515 | int tr,funky; /* funky is set to indicate note or instrument change */ | ||
2516 | |||
2517 | for (channel=0;channel<mod->numchn;channel++) { | ||
2518 | a=&mod->control[channel]; | ||
2519 | |||
2520 | if (mod->sngpos>=mod->numpos) { | ||
2521 | tr=mod->numtrk; | ||
2522 | mod->numrow=0; | ||
2523 | } else { | ||
2524 | tr=mod->patterns[(mod->positions[mod->sngpos]*mod->numchn)+channel]; | ||
2525 | mod->numrow=mod->pattrows[mod->positions[mod->sngpos]]; | ||
2526 | } | ||
2527 | |||
2528 | a->row=(tr<mod->numtrk)?UniFindRow(mod->tracks[tr],mod->patpos):NULL; | ||
2529 | a->newsamp=0; | ||
2530 | if (!mod->vbtick) a->main.notedelay=0; | ||
2531 | |||
2532 | if (!a->row) continue; | ||
2533 | UniSetRow(a->row); | ||
2534 | funky=0; | ||
2535 | |||
2536 | while((c=UniGetByte())) | ||
2537 | switch (c) { | ||
2538 | case UNI_NOTE: | ||
2539 | funky|=1; | ||
2540 | a->oldnote=a->anote,a->anote=UniGetByte(); | ||
2541 | a->main.kick =KICK_NOTE; | ||
2542 | a->main.start=-1; | ||
2543 | a->sliding=0; | ||
2544 | |||
2545 | /* retrig tremolo and vibrato waves ? */ | ||
2546 | if (!(a->wavecontrol & 0x80)) a->trmpos=0; | ||
2547 | if (!(a->wavecontrol & 0x08)) a->vibpos=0; | ||
2548 | if (!a->panbwave) a->panbpos=0; | ||
2549 | break; | ||
2550 | case UNI_INSTRUMENT: | ||
2551 | inst=UniGetByte(); | ||
2552 | if (inst>=mod->numins) break; /* safety valve */ | ||
2553 | funky|=2; | ||
2554 | a->main.i=(mod->flags & UF_INST)?&mod->instruments[inst]:NULL; | ||
2555 | a->retrig=0; | ||
2556 | a->s3mtremor=0; | ||
2557 | a->ultoffset=0; | ||
2558 | a->main.sample=inst; | ||
2559 | break; | ||
2560 | default: | ||
2561 | UniSkipOpcode(); | ||
2562 | break; | ||
2563 | } | ||
2564 | |||
2565 | if (funky) { | ||
2566 | INSTRUMENT *i; | ||
2567 | SAMPLE *s; | ||
2568 | |||
2569 | if ((i=a->main.i)) { | ||
2570 | if (i->samplenumber[a->anote] >= mod->numsmp) continue; | ||
2571 | s=&mod->samples[i->samplenumber[a->anote]]; | ||
2572 | a->main.note=i->samplenote[a->anote]; | ||
2573 | } else { | ||
2574 | a->main.note=a->anote; | ||
2575 | s=&mod->samples[a->main.sample]; | ||
2576 | } | ||
2577 | |||
2578 | if (a->main.s!=s) { | ||
2579 | a->main.s=s; | ||
2580 | a->newsamp=a->main.period; | ||
2581 | } | ||
2582 | |||
2583 | /* channel or instrument determined panning ? */ | ||
2584 | a->main.panning=mod->panning[channel]; | ||
2585 | if (s->flags & SF_OWNPAN) | ||
2586 | a->main.panning=s->panning; | ||
2587 | else if ((i)&&(i->flags & IF_OWNPAN)) | ||
2588 | a->main.panning=i->panning; | ||
2589 | |||
2590 | a->main.handle=s->handle; | ||
2591 | a->speed=s->speed; | ||
2592 | |||
2593 | if (i) { | ||
2594 | if ((mod->panflag)&&(i->flags & IF_PITCHPAN) | ||
2595 | &&(a->main.panning!=PAN_SURROUND)){ | ||
2596 | a->main.panning+= | ||
2597 | ((a->anote-i->pitpancenter)*i->pitpansep)/8; | ||
2598 | if (a->main.panning<PAN_LEFT) | ||
2599 | a->main.panning=PAN_LEFT; | ||
2600 | else if (a->main.panning>PAN_RIGHT) | ||
2601 | a->main.panning=PAN_RIGHT; | ||
2602 | } | ||
2603 | a->main.pitflg=i->pitflg; | ||
2604 | a->main.volflg=i->volflg; | ||
2605 | a->main.panflg=i->panflg; | ||
2606 | a->main.nna=i->nnatype; | ||
2607 | a->dca=i->dca; | ||
2608 | a->dct=i->dct; | ||
2609 | } else { | ||
2610 | a->main.pitflg=a->main.volflg=a->main.panflg=0; | ||
2611 | a->main.nna=a->dca=0; | ||
2612 | a->dct=DCT_OFF; | ||
2613 | } | ||
2614 | |||
2615 | if (funky&2) /* instrument change */ { | ||
2616 | /* IT random volume variations: 0:8 bit fixed, and one bit for | ||
2617 | sign. */ | ||
2618 | a->volume=a->tmpvolume=s->volume; | ||
2619 | if ((s)&&(i)) { | ||
2620 | if (i->rvolvar) { | ||
2621 | a->volume=a->tmpvolume=s->volume+ | ||
2622 | ((s->volume*((SLONG)i->rvolvar*(SLONG)getrandom(512) | ||
2623 | ))/25600); | ||
2624 | if (a->volume<0) | ||
2625 | a->volume=a->tmpvolume=0; | ||
2626 | else if (a->volume>64) | ||
2627 | a->volume=a->tmpvolume=64; | ||
2628 | } | ||
2629 | if ((mod->panflag)&&(a->main.panning!=PAN_SURROUND)) { | ||
2630 | a->main.panning+=((a->main.panning*((SLONG)i->rpanvar* | ||
2631 | (SLONG)getrandom(512)))/25600); | ||
2632 | if (a->main.panning<PAN_LEFT) | ||
2633 | a->main.panning=PAN_LEFT; | ||
2634 | else if (a->main.panning>PAN_RIGHT) | ||
2635 | a->main.panning=PAN_RIGHT; | ||
2636 | } | ||
2637 | } | ||
2638 | } | ||
2639 | |||
2640 | a->wantedperiod=a->tmpperiod= | ||
2641 | GetPeriod(mod->flags, (UWORD)a->main.note<<1,a->speed); | ||
2642 | a->main.keyoff=KEY_KICK; | ||
2643 | } | ||
2644 | } | ||
2645 | } | ||
2646 | |||
2647 | /* Handles effects */ | ||
2648 | void pt_EffectsPass1(MODULE *mod) | ||
2649 | { | ||
2650 | SWORD channel; | ||
2651 | MP_CONTROL *a; | ||
2652 | MP_VOICE *aout; | ||
2653 | int explicitslides; | ||
2654 | |||
2655 | for (channel=0;channel<mod->numchn;channel++) { | ||
2656 | a=&mod->control[channel]; | ||
2657 | |||
2658 | if ((aout=a->slave)) { | ||
2659 | a->main.fadevol=aout->main.fadevol; | ||
2660 | a->main.period=aout->main.period; | ||
2661 | if (a->main.kick==KICK_KEYOFF) | ||
2662 | a->main.keyoff=aout->main.keyoff; | ||
2663 | } | ||
2664 | |||
2665 | if (!a->row) continue; | ||
2666 | UniSetRow(a->row); | ||
2667 | |||
2668 | a->ownper=a->ownvol=0; | ||
2669 | explicitslides = pt_playeffects(mod, channel, a); | ||
2670 | |||
2671 | /* continue volume slide if necessary for XM and IT */ | ||
2672 | if (mod->flags&UF_BGSLIDES) { | ||
2673 | if (!explicitslides && a->sliding) | ||
2674 | DoS3MVolSlide(mod->vbtick, mod->flags, a, 0); | ||
2675 | else if (a->tmpvolume) | ||
2676 | a->sliding = explicitslides; | ||
2677 | } | ||
2678 | |||
2679 | if (!a->ownper) | ||
2680 | a->main.period=a->tmpperiod; | ||
2681 | if (!a->ownvol) | ||
2682 | a->volume=a->tmpvolume; | ||
2683 | |||
2684 | if (a->main.s) { | ||
2685 | if (a->main.i) | ||
2686 | a->main.outvolume= | ||
2687 | (a->volume*a->main.s->globvol*a->main.i->globvol)>>10; | ||
2688 | else | ||
2689 | a->main.outvolume=(a->volume*a->main.s->globvol)>>4; | ||
2690 | if (a->main.outvolume>256) | ||
2691 | a->main.outvolume=256; | ||
2692 | else if (a->main.outvolume<0) | ||
2693 | a->main.outvolume=0; | ||
2694 | } | ||
2695 | } | ||
2696 | } | ||
2697 | |||
2698 | /* NNA management */ | ||
2699 | void pt_NNA(MODULE *mod) | ||
2700 | { | ||
2701 | SWORD channel; | ||
2702 | MP_CONTROL *a; | ||
2703 | |||
2704 | for (channel=0;channel<mod->numchn;channel++) { | ||
2705 | a=&mod->control[channel]; | ||
2706 | |||
2707 | if (a->main.kick==KICK_NOTE) { | ||
2708 | int kill=0; | ||
2709 | |||
2710 | if (a->slave) { | ||
2711 | MP_VOICE *aout; | ||
2712 | |||
2713 | aout=a->slave; | ||
2714 | if (aout->main.nna & NNA_MASK) { | ||
2715 | /* Make sure the old MP_VOICE channel knows it has no | ||
2716 | master now ! */ | ||
2717 | a->slave=NULL; | ||
2718 | /* assume the channel is taken by NNA */ | ||
2719 | aout->mflag=0; | ||
2720 | |||
2721 | switch (aout->main.nna) { | ||
2722 | case NNA_CONTINUE: /* continue note, do nothing */ | ||
2723 | break; | ||
2724 | case NNA_OFF: /* note off */ | ||
2725 | aout->main.keyoff|=KEY_OFF; | ||
2726 | if ((!(aout->main.volflg & EF_ON))|| | ||
2727 | (aout->main.volflg & EF_LOOP)) | ||
2728 | aout->main.keyoff=KEY_KILL; | ||
2729 | break; | ||
2730 | case NNA_FADE: | ||
2731 | aout->main.keyoff |= KEY_FADE; | ||
2732 | break; | ||
2733 | } | ||
2734 | } | ||
2735 | } | ||
2736 | |||
2737 | if (a->dct!=DCT_OFF) { | ||
2738 | int t; | ||
2739 | |||
2740 | for (t=0;t<md_sngchn;t++) | ||
2741 | if ((!Voice_Stopped_internal(t))&& | ||
2742 | (mod->voice[t].masterchn==channel)&& | ||
2743 | (a->main.sample==mod->voice[t].main.sample)) { | ||
2744 | kill=0; | ||
2745 | switch (a->dct) { | ||
2746 | case DCT_NOTE: | ||
2747 | if (a->main.note==mod->voice[t].main.note) | ||
2748 | kill=1; | ||
2749 | break; | ||
2750 | case DCT_SAMPLE: | ||
2751 | if (a->main.handle==mod->voice[t].main.handle) | ||
2752 | kill=1; | ||
2753 | break; | ||
2754 | case DCT_INST: | ||
2755 | kill=1; | ||
2756 | break; | ||
2757 | } | ||
2758 | if (kill) | ||
2759 | switch (a->dca) { | ||
2760 | case DCA_CUT: | ||
2761 | mod->voice[t].main.fadevol=0; | ||
2762 | break; | ||
2763 | case DCA_OFF: | ||
2764 | mod->voice[t].main.keyoff|=KEY_OFF; | ||
2765 | if ((!(mod->voice[t].main.volflg&EF_ON))|| | ||
2766 | (mod->voice[t].main.volflg&EF_LOOP)) | ||
2767 | mod->voice[t].main.keyoff=KEY_KILL; | ||
2768 | break; | ||
2769 | case DCA_FADE: | ||
2770 | mod->voice[t].main.keyoff|=KEY_FADE; | ||
2771 | break; | ||
2772 | } | ||
2773 | } | ||
2774 | } | ||
2775 | } /* if (a->main.kick==KICK_NOTE) */ | ||
2776 | } | ||
2777 | } | ||
2778 | |||
2779 | /* Setup module and NNA voices */ | ||
2780 | void pt_SetupVoices(MODULE *mod) | ||
2781 | { | ||
2782 | SWORD channel; | ||
2783 | MP_CONTROL *a; | ||
2784 | MP_VOICE *aout; | ||
2785 | |||
2786 | for (channel=0;channel<mod->numchn;channel++) { | ||
2787 | a=&mod->control[channel]; | ||
2788 | |||
2789 | if (a->main.notedelay) continue; | ||
2790 | if (a->main.kick==KICK_NOTE) { | ||
2791 | /* if no channel was cut above, find an empty or quiet channel | ||
2792 | here */ | ||
2793 | if (mod->flags&UF_NNA) { | ||
2794 | if (!a->slave) { | ||
2795 | int newchn; | ||
2796 | |||
2797 | if ((newchn=MP_FindEmptyChannel(mod))!=-1) | ||
2798 | a->slave=&mod->voice[a->slavechn=newchn]; | ||
2799 | } | ||
2800 | } else | ||
2801 | a->slave=&mod->voice[a->slavechn=channel]; | ||
2802 | |||
2803 | /* assign parts of MP_VOICE only done for a KICK_NOTE */ | ||
2804 | if ((aout=a->slave)) { | ||
2805 | if (aout->mflag && aout->master) aout->master->slave=NULL; | ||
2806 | aout->master=a; | ||
2807 | a->slave=aout; | ||
2808 | aout->masterchn=channel; | ||
2809 | aout->mflag=1; | ||
2810 | } | ||
2811 | } else | ||
2812 | aout=a->slave; | ||
2813 | |||
2814 | if (aout) | ||
2815 | aout->main=a->main; | ||
2816 | a->main.kick=KICK_ABSENT; | ||
2817 | } | ||
2818 | } | ||
2819 | |||
2820 | /* second effect pass */ | ||
2821 | void pt_EffectsPass2(MODULE *mod) | ||
2822 | { | ||
2823 | SWORD channel; | ||
2824 | MP_CONTROL *a; | ||
2825 | UBYTE c; | ||
2826 | |||
2827 | for (channel=0;channel<mod->numchn;channel++) { | ||
2828 | a=&mod->control[channel]; | ||
2829 | |||
2830 | if (!a->row) continue; | ||
2831 | UniSetRow(a->row); | ||
2832 | |||
2833 | while((c=UniGetByte())) | ||
2834 | if (c==UNI_ITEFFECTS0) { | ||
2835 | c=UniGetByte(); | ||
2836 | if ((c>>4)==SS_S7EFFECTS) | ||
2837 | DoNNAEffects(mod, a, c&0xf); | ||
2838 | } else | ||
2839 | UniSkipOpcode(); | ||
2840 | } | ||
2841 | } | ||
2842 | |||
2843 | void Player_HandleTick(void) | ||
2844 | { | ||
2845 | SWORD channel; | ||
2846 | int max_volume; | ||
2847 | |||
2848 | #if 0 | ||
2849 | /* don't handle the very first ticks, this allows the other hardware to | ||
2850 | settle down so we don't loose any starting notes */ | ||
2851 | if (isfirst) { | ||
2852 | isfirst--; | ||
2853 | return; | ||
2854 | } | ||
2855 | #endif | ||
2856 | |||
2857 | if ((!pf)||(pf->forbid)||(pf->sngpos>=pf->numpos)) return; | ||
2858 | |||
2859 | /* update time counter (sngtime is in milliseconds (in fact 2^-10)) */ | ||
2860 | pf->sngremainder+=(1<<9)*5; /* thus 2.5*(1<<10), since fps=0.4xtempo */ | ||
2861 | pf->sngtime+=pf->sngremainder/pf->bpm; | ||
2862 | pf->sngremainder%=pf->bpm; | ||
2863 | |||
2864 | if (++pf->vbtick>=pf->sngspd) { | ||
2865 | if (pf->pat_repcrazy) | ||
2866 | pf->pat_repcrazy=0; /* play 2 times row 0 */ | ||
2867 | else | ||
2868 | pf->patpos++; | ||
2869 | pf->vbtick=0; | ||
2870 | |||
2871 | /* process pattern-delay. pf->patdly2 is the counter and pf->patdly is | ||
2872 | the command memory. */ | ||
2873 | if (pf->patdly) | ||
2874 | pf->patdly2=pf->patdly,pf->patdly=0; | ||
2875 | if (pf->patdly2) { | ||
2876 | /* patterndelay active */ | ||
2877 | if (--pf->patdly2) | ||
2878 | /* so turn back pf->patpos by 1 */ | ||
2879 | if (pf->patpos) pf->patpos--; | ||
2880 | } | ||
2881 | |||
2882 | /* do we have to get a new patternpointer ? (when pf->patpos reaches the | ||
2883 | pattern size, or when a patternbreak is active) */ | ||
2884 | if (((pf->patpos>=pf->numrow)&&(pf->numrow>0))&&(!pf->posjmp)) | ||
2885 | pf->posjmp=3; | ||
2886 | |||
2887 | if (pf->posjmp) { | ||
2888 | pf->patpos=pf->numrow?(pf->patbrk%pf->numrow):0; | ||
2889 | pf->pat_repcrazy=0; | ||
2890 | pf->sngpos+=(pf->posjmp-2); | ||
2891 | for (channel=0;channel<pf->numchn;channel++) | ||
2892 | pf->control[channel].pat_reppos=-1; | ||
2893 | |||
2894 | pf->patbrk=pf->posjmp=0; | ||
2895 | /* handle the "---" (end of song) pattern since it can occur | ||
2896 | *inside* the module in some formats */ | ||
2897 | if ((pf->sngpos>=pf->numpos)|| | ||
2898 | (pf->positions[pf->sngpos]==LAST_PATTERN)) { | ||
2899 | if (!pf->wrap) return; | ||
2900 | if (!(pf->sngpos=pf->reppos)) { | ||
2901 | pf->volume=pf->initvolume>128?128:pf->initvolume; | ||
2902 | if(pf->initspeed!=0) | ||
2903 | pf->sngspd=pf->initspeed<32?pf->initspeed:32; | ||
2904 | else | ||
2905 | pf->sngspd=6; | ||
2906 | pf->bpm=pf->inittempo<32?32:pf->inittempo; | ||
2907 | } | ||
2908 | } | ||
2909 | if (pf->sngpos<0) pf->sngpos=pf->numpos-1; | ||
2910 | } | ||
2911 | |||
2912 | if (!pf->patdly2) | ||
2913 | pt_Notes(pf); | ||
2914 | } | ||
2915 | |||
2916 | /* Fade global volume if enabled and we're playing the last pattern */ | ||
2917 | if (((pf->sngpos==pf->numpos-1)|| | ||
2918 | (pf->positions[pf->sngpos+1]==LAST_PATTERN))&& | ||
2919 | (pf->fadeout)) | ||
2920 | max_volume=pf->numrow?((pf->numrow-pf->patpos)*128)/pf->numrow:0; | ||
2921 | else | ||
2922 | max_volume=128; | ||
2923 | |||
2924 | pt_EffectsPass1(pf); | ||
2925 | if (pf->flags&UF_NNA) | ||
2926 | pt_NNA(pf); | ||
2927 | pt_SetupVoices(pf); | ||
2928 | pt_EffectsPass2(pf); | ||
2929 | |||
2930 | /* now set up the actual hardware channel playback information */ | ||
2931 | pt_UpdateVoices(pf, max_volume); | ||
2932 | } | ||
2933 | |||
2934 | static void Player_Init_internal(MODULE* mod) | ||
2935 | { | ||
2936 | int t; | ||
2937 | |||
2938 | for (t=0;t<mod->numchn;t++) { | ||
2939 | mod->control[t].main.chanvol=mod->chanvol[t]; | ||
2940 | mod->control[t].main.panning=mod->panning[t]; | ||
2941 | } | ||
2942 | |||
2943 | mod->sngtime=0; | ||
2944 | mod->sngremainder=0; | ||
2945 | |||
2946 | mod->pat_repcrazy=0; | ||
2947 | mod->sngpos=0; | ||
2948 | if(mod->initspeed!=0) | ||
2949 | mod->sngspd=mod->initspeed<32?mod->initspeed:32; | ||
2950 | else | ||
2951 | mod->sngspd=6; | ||
2952 | mod->volume=mod->initvolume>128?128:mod->initvolume; | ||
2953 | |||
2954 | mod->vbtick=mod->sngspd; | ||
2955 | mod->patdly=0; | ||
2956 | mod->patdly2=0; | ||
2957 | mod->bpm=mod->inittempo<32?32:mod->inittempo; | ||
2958 | mod->realchn=0; | ||
2959 | |||
2960 | mod->patpos=0; | ||
2961 | mod->posjmp=2; /* make sure the player fetches the first note */ | ||
2962 | mod->numrow=-1; | ||
2963 | mod->patbrk=0; | ||
2964 | } | ||
2965 | |||
2966 | int Player_Init(MODULE* mod) | ||
2967 | { | ||
2968 | mod->extspd=1; | ||
2969 | mod->panflag=1; | ||
2970 | mod->wrap=0; | ||
2971 | mod->loop=1; | ||
2972 | mod->fadeout=0; | ||
2973 | |||
2974 | mod->relspd=0; | ||
2975 | |||
2976 | /* make sure the player doesn't start with garbage */ | ||
2977 | if (!(mod->control=(MP_CONTROL*)MikMod_calloc(mod->numchn,sizeof(MP_CONTROL)))) | ||
2978 | return 1; | ||
2979 | if (!(mod->voice=(MP_VOICE*)MikMod_calloc(md_sngchn,sizeof(MP_VOICE)))) | ||
2980 | return 1; | ||
2981 | |||
2982 | Player_Init_internal(mod); | ||
2983 | return 0; | ||
2984 | } | ||
2985 | |||
2986 | void Player_Exit_internal(MODULE* mod) | ||
2987 | { | ||
2988 | if (!mod) | ||
2989 | return; | ||
2990 | |||
2991 | /* Stop playback if necessary */ | ||
2992 | if (mod==pf) { | ||
2993 | Player_Stop_internal(); | ||
2994 | pf=NULL; | ||
2995 | } | ||
2996 | |||
2997 | if (mod->control) | ||
2998 | MikMod_free(mod->control); | ||
2999 | if (mod->voice) | ||
3000 | MikMod_free(mod->voice); | ||
3001 | mod->control=NULL; | ||
3002 | mod->voice=NULL; | ||
3003 | } | ||
3004 | |||
3005 | void Player_Exit(MODULE* mod) | ||
3006 | { | ||
3007 | MUTEX_LOCK(vars); | ||
3008 | Player_Exit_internal(mod); | ||
3009 | MUTEX_UNLOCK(vars); | ||
3010 | } | ||
3011 | |||
3012 | MIKMODAPI void Player_SetVolume(SWORD volume) | ||
3013 | { | ||
3014 | MUTEX_LOCK(vars); | ||
3015 | if (pf) | ||
3016 | pf->volume=(volume<0)?0:(volume>128)?128:volume; | ||
3017 | MUTEX_UNLOCK(vars); | ||
3018 | } | ||
3019 | |||
3020 | MIKMODAPI MODULE* Player_GetModule(void) | ||
3021 | { | ||
3022 | MODULE* result; | ||
3023 | |||
3024 | MUTEX_LOCK(vars); | ||
3025 | result=pf; | ||
3026 | MUTEX_UNLOCK(vars); | ||
3027 | |||
3028 | return result; | ||
3029 | } | ||
3030 | |||
3031 | MIKMODAPI void Player_Start(MODULE *mod) | ||
3032 | { | ||
3033 | int t; | ||
3034 | |||
3035 | if (!mod) | ||
3036 | return; | ||
3037 | |||
3038 | if (!MikMod_Active()) | ||
3039 | MikMod_EnableOutput(); | ||
3040 | |||
3041 | mod->forbid=0; | ||
3042 | |||
3043 | MUTEX_LOCK(vars); | ||
3044 | if (pf!=mod) { | ||
3045 | /* new song is being started, so completely stop out the old one. */ | ||
3046 | if (pf) pf->forbid=1; | ||
3047 | for (t=0;t<md_sngchn;t++) Voice_Stop_internal(t); | ||
3048 | } | ||
3049 | pf=mod; | ||
3050 | MUTEX_UNLOCK(vars); | ||
3051 | } | ||
3052 | |||
3053 | void Player_Stop_internal(void) | ||
3054 | { | ||
3055 | if (!md_sfxchn) MikMod_DisableOutput_internal(); | ||
3056 | if (pf) pf->forbid=1; | ||
3057 | pf=NULL; | ||
3058 | } | ||
3059 | |||
3060 | MIKMODAPI void Player_Stop(void) | ||
3061 | { | ||
3062 | MUTEX_LOCK(vars); | ||
3063 | Player_Stop_internal(); | ||
3064 | MUTEX_UNLOCK(vars); | ||
3065 | } | ||
3066 | |||
3067 | MIKMODAPI int Player_Active(void) | ||
3068 | { | ||
3069 | int result=0; | ||
3070 | |||
3071 | MUTEX_LOCK(vars); | ||
3072 | if (pf) | ||
3073 | result=(!(pf->sngpos>=pf->numpos)); | ||
3074 | MUTEX_UNLOCK(vars); | ||
3075 | |||
3076 | return result; | ||
3077 | } | ||
3078 | |||
3079 | MIKMODAPI void Player_NextPosition(void) | ||
3080 | { | ||
3081 | MUTEX_LOCK(vars); | ||
3082 | if (pf) { | ||
3083 | int t; | ||
3084 | |||
3085 | pf->forbid=1; | ||
3086 | pf->posjmp=3; | ||
3087 | pf->patbrk=0; | ||
3088 | pf->vbtick=pf->sngspd; | ||
3089 | |||
3090 | for (t=0;t<md_sngchn;t++) { | ||
3091 | Voice_Stop_internal(t); | ||
3092 | pf->voice[t].main.i=NULL; | ||
3093 | pf->voice[t].main.s=NULL; | ||
3094 | } | ||
3095 | for (t=0;t<pf->numchn;t++) { | ||
3096 | pf->control[t].main.i=NULL; | ||
3097 | pf->control[t].main.s=NULL; | ||
3098 | } | ||
3099 | pf->forbid=0; | ||
3100 | } | ||
3101 | MUTEX_UNLOCK(vars); | ||
3102 | } | ||
3103 | |||
3104 | MIKMODAPI void Player_PrevPosition(void) | ||
3105 | { | ||
3106 | MUTEX_LOCK(vars); | ||
3107 | if (pf) { | ||
3108 | int t; | ||
3109 | |||
3110 | pf->forbid=1; | ||
3111 | pf->posjmp=1; | ||
3112 | pf->patbrk=0; | ||
3113 | pf->vbtick=pf->sngspd; | ||
3114 | |||
3115 | for (t=0;t<md_sngchn;t++) { | ||
3116 | Voice_Stop_internal(t); | ||
3117 | pf->voice[t].main.i=NULL; | ||
3118 | pf->voice[t].main.s=NULL; | ||
3119 | } | ||
3120 | for (t=0;t<pf->numchn;t++) { | ||
3121 | pf->control[t].main.i=NULL; | ||
3122 | pf->control[t].main.s=NULL; | ||
3123 | } | ||
3124 | pf->forbid=0; | ||
3125 | } | ||
3126 | MUTEX_UNLOCK(vars); | ||
3127 | } | ||
3128 | |||
3129 | MIKMODAPI void Player_SetPosition(UWORD pos) | ||
3130 | { | ||
3131 | MUTEX_LOCK(vars); | ||
3132 | if (pf) { | ||
3133 | int t; | ||
3134 | |||
3135 | pf->forbid=1; | ||
3136 | if (pos>=pf->numpos) pos=pf->numpos; | ||
3137 | pf->posjmp=2; | ||
3138 | pf->patbrk=0; | ||
3139 | pf->sngpos=pos; | ||
3140 | pf->vbtick=pf->sngspd; | ||
3141 | |||
3142 | for (t=0;t<md_sngchn;t++) { | ||
3143 | Voice_Stop_internal(t); | ||
3144 | pf->voice[t].main.i=NULL; | ||
3145 | pf->voice[t].main.s=NULL; | ||
3146 | } | ||
3147 | for (t=0;t<pf->numchn;t++) { | ||
3148 | pf->control[t].main.i=NULL; | ||
3149 | pf->control[t].main.s=NULL; | ||
3150 | } | ||
3151 | pf->forbid=0; | ||
3152 | |||
3153 | if (!pos) | ||
3154 | Player_Init_internal(pf); | ||
3155 | } | ||
3156 | MUTEX_UNLOCK(vars); | ||
3157 | } | ||
3158 | |||
3159 | static void Player_Unmute_internal(SLONG arg1,va_list ap) | ||
3160 | { | ||
3161 | SLONG t,arg2,arg3=0; | ||
3162 | |||
3163 | if (pf) { | ||
3164 | switch (arg1) { | ||
3165 | case MUTE_INCLUSIVE: | ||
3166 | if (((!(arg2=va_arg(ap,SLONG)))&&(!(arg3=va_arg(ap,SLONG))))|| | ||
3167 | (arg2>arg3)||(arg3>=pf->numchn)) | ||
3168 | return; | ||
3169 | for (;arg2<pf->numchn && arg2<=arg3;arg2++) | ||
3170 | pf->control[arg2].muted=0; | ||
3171 | break; | ||
3172 | case MUTE_EXCLUSIVE: | ||
3173 | if (((!(arg2=va_arg(ap,SLONG)))&&(!(arg3=va_arg(ap,SLONG))))|| | ||
3174 | (arg2>arg3)||(arg3>=pf->numchn)) | ||
3175 | return; | ||
3176 | for (t=0;t<pf->numchn;t++) { | ||
3177 | if ((t>=arg2) && (t<=arg3)) | ||
3178 | continue; | ||
3179 | pf->control[t].muted=0; | ||
3180 | } | ||
3181 | break; | ||
3182 | default: | ||
3183 | if (arg1<pf->numchn) pf->control[arg1].muted=0; | ||
3184 | break; | ||
3185 | } | ||
3186 | } | ||
3187 | } | ||
3188 | |||
3189 | MIKMODAPI void Player_Unmute(SLONG arg1, ...) | ||
3190 | { | ||
3191 | va_list args; | ||
3192 | |||
3193 | va_start(args,arg1); | ||
3194 | MUTEX_LOCK(vars); | ||
3195 | Player_Unmute_internal(arg1,args); | ||
3196 | MUTEX_UNLOCK(vars); | ||
3197 | va_end(args); | ||
3198 | } | ||
3199 | |||
3200 | static void Player_Mute_internal(SLONG arg1,va_list ap) | ||
3201 | { | ||
3202 | SLONG t,arg2,arg3=0; | ||
3203 | |||
3204 | if (pf) { | ||
3205 | switch (arg1) { | ||
3206 | case MUTE_INCLUSIVE: | ||
3207 | if (((!(arg2=va_arg(ap,SLONG)))&&(!(arg3=va_arg(ap,SLONG))))|| | ||
3208 | (arg2>arg3)||(arg3>=pf->numchn)) | ||
3209 | return; | ||
3210 | for (;arg2<pf->numchn && arg2<=arg3;arg2++) | ||
3211 | pf->control[arg2].muted=1; | ||
3212 | break; | ||
3213 | case MUTE_EXCLUSIVE: | ||
3214 | if (((!(arg2=va_arg(ap,SLONG)))&&(!(arg3=va_arg(ap,SLONG))))|| | ||
3215 | (arg2>arg3)||(arg3>=pf->numchn)) | ||
3216 | return; | ||
3217 | for (t=0;t<pf->numchn;t++) { | ||
3218 | if ((t>=arg2) && (t<=arg3)) | ||
3219 | continue; | ||
3220 | pf->control[t].muted=1; | ||
3221 | } | ||
3222 | break; | ||
3223 | default: | ||
3224 | if (arg1<pf->numchn) | ||
3225 | pf->control[arg1].muted=1; | ||
3226 | break; | ||
3227 | } | ||
3228 | } | ||
3229 | } | ||
3230 | |||
3231 | MIKMODAPI void Player_Mute(SLONG arg1,...) | ||
3232 | { | ||
3233 | va_list args; | ||
3234 | |||
3235 | va_start(args,arg1); | ||
3236 | MUTEX_LOCK(vars); | ||
3237 | Player_Mute_internal(arg1,args); | ||
3238 | MUTEX_UNLOCK(vars); | ||
3239 | va_end(args); | ||
3240 | } | ||
3241 | |||
3242 | static void Player_ToggleMute_internal(SLONG arg1,va_list ap) | ||
3243 | { | ||
3244 | SLONG arg2,arg3=0; | ||
3245 | ULONG t; | ||
3246 | |||
3247 | if (pf) { | ||
3248 | switch (arg1) { | ||
3249 | case MUTE_INCLUSIVE: | ||
3250 | if (((!(arg2=va_arg(ap,SLONG)))&&(!(arg3=va_arg(ap,SLONG))))|| | ||
3251 | (arg2>arg3)||(arg3>=pf->numchn)) | ||
3252 | return; | ||
3253 | for (;arg2<pf->numchn && arg2<=arg3;arg2++) | ||
3254 | pf->control[arg2].muted=1-pf->control[arg2].muted; | ||
3255 | break; | ||
3256 | case MUTE_EXCLUSIVE: | ||
3257 | if (((!(arg2=va_arg(ap,SLONG)))&&(!(arg3=va_arg(ap,SLONG))))|| | ||
3258 | (arg2>arg3)||(arg3>=pf->numchn)) | ||
3259 | return; | ||
3260 | for (t=0;t<pf->numchn;t++) { | ||
3261 | if ((t>=arg2) && (t<=arg3)) | ||
3262 | continue; | ||
3263 | pf->control[t].muted=1-pf->control[t].muted; | ||
3264 | } | ||
3265 | break; | ||
3266 | default: | ||
3267 | if (arg1<pf->numchn) | ||
3268 | pf->control[arg1].muted=1-pf->control[arg1].muted; | ||
3269 | break; | ||
3270 | } | ||
3271 | } | ||
3272 | } | ||
3273 | |||
3274 | MIKMODAPI void Player_ToggleMute(SLONG arg1,...) | ||
3275 | { | ||
3276 | va_list args; | ||
3277 | |||
3278 | va_start(args,arg1); | ||
3279 | MUTEX_LOCK(vars); | ||
3280 | Player_ToggleMute_internal(arg1,args); | ||
3281 | MUTEX_UNLOCK(vars); | ||
3282 | va_end(args); | ||
3283 | } | ||
3284 | |||
3285 | MIKMODAPI int Player_Muted(UBYTE chan) | ||
3286 | { | ||
3287 | int result=1; | ||
3288 | |||
3289 | MUTEX_LOCK(vars); | ||
3290 | if (pf) | ||
3291 | result=(chan<pf->numchn)?pf->control[chan].muted:1; | ||
3292 | MUTEX_UNLOCK(vars); | ||
3293 | |||
3294 | return result; | ||
3295 | } | ||
3296 | |||
3297 | MIKMODAPI int Player_GetChannelVoice(UBYTE chan) | ||
3298 | { | ||
3299 | int result=0; | ||
3300 | |||
3301 | MUTEX_LOCK(vars); | ||
3302 | if (pf) | ||
3303 | result=(chan<pf->numchn)?pf->control[chan].slavechn:-1; | ||
3304 | MUTEX_UNLOCK(vars); | ||
3305 | |||
3306 | return result; | ||
3307 | } | ||
3308 | |||
3309 | MIKMODAPI UWORD Player_GetChannelPeriod(UBYTE chan) | ||
3310 | { | ||
3311 | UWORD result=0; | ||
3312 | |||
3313 | MUTEX_LOCK(vars); | ||
3314 | if (pf) | ||
3315 | result=(chan<pf->numchn)?pf->control[chan].main.period:0; | ||
3316 | MUTEX_UNLOCK(vars); | ||
3317 | |||
3318 | return result; | ||
3319 | } | ||
3320 | |||
3321 | int Player_Paused_internal(void) | ||
3322 | { | ||
3323 | return pf?pf->forbid:1; | ||
3324 | } | ||
3325 | |||
3326 | MIKMODAPI int Player_Paused(void) | ||
3327 | { | ||
3328 | int result; | ||
3329 | |||
3330 | MUTEX_LOCK(vars); | ||
3331 | result=Player_Paused_internal(); | ||
3332 | MUTEX_UNLOCK(vars); | ||
3333 | |||
3334 | return result; | ||
3335 | } | ||
3336 | |||
3337 | MIKMODAPI void Player_TogglePause(void) | ||
3338 | { | ||
3339 | MUTEX_LOCK(vars); | ||
3340 | if (pf) | ||
3341 | pf->forbid=1-pf->forbid; | ||
3342 | MUTEX_UNLOCK(vars); | ||
3343 | } | ||
3344 | |||
3345 | MIKMODAPI void Player_SetSpeed(UWORD speed) | ||
3346 | { | ||
3347 | MUTEX_LOCK(vars); | ||
3348 | if (pf) | ||
3349 | pf->sngspd=speed?(speed<32?speed:32):1; | ||
3350 | MUTEX_UNLOCK(vars); | ||
3351 | } | ||
3352 | |||
3353 | MIKMODAPI void Player_SetTempo(UWORD tempo) | ||
3354 | { | ||
3355 | if (tempo<32) tempo=32; | ||
3356 | MUTEX_LOCK(vars); | ||
3357 | if (pf) { | ||
3358 | if ((!(pf->flags&UF_HIGHBPM))&&(tempo>255)) tempo=255; | ||
3359 | pf->bpm=tempo; | ||
3360 | } | ||
3361 | MUTEX_UNLOCK(vars); | ||
3362 | } | ||
3363 | |||
3364 | MIKMODAPI int Player_QueryVoices(UWORD numvoices, VOICEINFO *vinfo) | ||
3365 | { | ||
3366 | int i; | ||
3367 | |||
3368 | if (numvoices > md_sngchn) | ||
3369 | numvoices = md_sngchn; | ||
3370 | |||
3371 | MUTEX_LOCK(vars); | ||
3372 | if (pf) | ||
3373 | for (i = 0; i < md_sngchn; i++) { | ||
3374 | vinfo [i].i = pf->voice[i].main.i; | ||
3375 | vinfo [i].s = pf->voice[i].main.s; | ||
3376 | vinfo [i].panning = pf->voice [i].main.panning; | ||
3377 | vinfo [i].volume = pf->voice [i].main.chanvol; | ||
3378 | vinfo [i].period = pf->voice [i].main.period; | ||
3379 | vinfo [i].kick = pf->voice [i].main.kick_flag; | ||
3380 | pf->voice [i].main.kick_flag = 0; | ||
3381 | } | ||
3382 | MUTEX_UNLOCK(vars); | ||
3383 | |||
3384 | return numvoices; | ||
3385 | } | ||
3386 | |||
3387 | |||
3388 | // Get current module order | ||
3389 | MIKMODAPI int Player_GetOrder(void) | ||
3390 | { | ||
3391 | int ret; | ||
3392 | MUTEX_LOCK(vars); | ||
3393 | ret = pf ? pf->sngpos :0; // pf->positions[pf->sngpos ? pf->sngpos-1 : 0]: 0; | ||
3394 | MUTEX_UNLOCK(vars); | ||
3395 | return ret; | ||
3396 | } | ||
3397 | |||
3398 | // Get current module row | ||
3399 | MIKMODAPI int Player_GetRow(void) | ||
3400 | { | ||
3401 | int ret; | ||
3402 | MUTEX_LOCK(vars); | ||
3403 | ret = pf ? pf->patpos : 0; | ||
3404 | MUTEX_UNLOCK(vars); | ||
3405 | return ret; | ||
3406 | } | ||
3407 | |||
3408 | |||
3409 | /* ex:set ts=4: */ | ||
diff --git a/apps/plugins/mikmod/munitrk.c b/apps/plugins/mikmod/munitrk.c new file mode 100644 index 0000000000..f0a8f58af7 --- /dev/null +++ b/apps/plugins/mikmod/munitrk.c | |||
@@ -0,0 +1,303 @@ | |||
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: munitrk.c,v 1.2 2005/03/30 19:11:46 realtech Exp $ | ||
24 | |||
25 | All routines dealing with the manipulation of UNITRK streams | ||
26 | |||
27 | ==============================================================================*/ | ||
28 | |||
29 | #ifdef HAVE_CONFIG_H | ||
30 | #include "config.h" | ||
31 | #endif | ||
32 | |||
33 | #include "mikmod_internals.h" | ||
34 | |||
35 | #include <string.h> | ||
36 | |||
37 | /* Unibuffer chunk size */ | ||
38 | #define BUFPAGE 128 | ||
39 | |||
40 | UWORD unioperands[UNI_LAST]={ | ||
41 | 0, /* not used */ | ||
42 | 1, /* UNI_NOTE */ | ||
43 | 1, /* UNI_INSTRUMENT */ | ||
44 | 1, /* UNI_PTEFFECT0 */ | ||
45 | 1, /* UNI_PTEFFECT1 */ | ||
46 | 1, /* UNI_PTEFFECT2 */ | ||
47 | 1, /* UNI_PTEFFECT3 */ | ||
48 | 1, /* UNI_PTEFFECT4 */ | ||
49 | 1, /* UNI_PTEFFECT5 */ | ||
50 | 1, /* UNI_PTEFFECT6 */ | ||
51 | 1, /* UNI_PTEFFECT7 */ | ||
52 | 1, /* UNI_PTEFFECT8 */ | ||
53 | 1, /* UNI_PTEFFECT9 */ | ||
54 | 1, /* UNI_PTEFFECTA */ | ||
55 | 1, /* UNI_PTEFFECTB */ | ||
56 | 1, /* UNI_PTEFFECTC */ | ||
57 | 1, /* UNI_PTEFFECTD */ | ||
58 | 1, /* UNI_PTEFFECTE */ | ||
59 | 1, /* UNI_PTEFFECTF */ | ||
60 | 1, /* UNI_S3MEFFECTA */ | ||
61 | 1, /* UNI_S3MEFFECTD */ | ||
62 | 1, /* UNI_S3MEFFECTE */ | ||
63 | 1, /* UNI_S3MEFFECTF */ | ||
64 | 1, /* UNI_S3MEFFECTI */ | ||
65 | 1, /* UNI_S3MEFFECTQ */ | ||
66 | 1, /* UNI_S3MEFFECTR */ | ||
67 | 1, /* UNI_S3MEFFECTT */ | ||
68 | 1, /* UNI_S3MEFFECTU */ | ||
69 | 0, /* UNI_KEYOFF */ | ||
70 | 1, /* UNI_KEYFADE */ | ||
71 | 2, /* UNI_VOLEFFECTS */ | ||
72 | 1, /* UNI_XMEFFECT4 */ | ||
73 | 1, /* UNI_XMEFFECT6 */ | ||
74 | 1, /* UNI_XMEFFECTA */ | ||
75 | 1, /* UNI_XMEFFECTE1 */ | ||
76 | 1, /* UNI_XMEFFECTE2 */ | ||
77 | 1, /* UNI_XMEFFECTEA */ | ||
78 | 1, /* UNI_XMEFFECTEB */ | ||
79 | 1, /* UNI_XMEFFECTG */ | ||
80 | 1, /* UNI_XMEFFECTH */ | ||
81 | 1, /* UNI_XMEFFECTL */ | ||
82 | 1, /* UNI_XMEFFECTP */ | ||
83 | 1, /* UNI_XMEFFECTX1 */ | ||
84 | 1, /* UNI_XMEFFECTX2 */ | ||
85 | 1, /* UNI_ITEFFECTG */ | ||
86 | 1, /* UNI_ITEFFECTH */ | ||
87 | 1, /* UNI_ITEFFECTI */ | ||
88 | 1, /* UNI_ITEFFECTM */ | ||
89 | 1, /* UNI_ITEFFECTN */ | ||
90 | 1, /* UNI_ITEFFECTP */ | ||
91 | 1, /* UNI_ITEFFECTT */ | ||
92 | 1, /* UNI_ITEFFECTU */ | ||
93 | 1, /* UNI_ITEFFECTW */ | ||
94 | 1, /* UNI_ITEFFECTY */ | ||
95 | 2, /* UNI_ITEFFECTZ */ | ||
96 | 1, /* UNI_ITEFFECTS0 */ | ||
97 | 2, /* UNI_ULTEFFECT9 */ | ||
98 | 2, /* UNI_MEDSPEED */ | ||
99 | 0, /* UNI_MEDEFFECTF1 */ | ||
100 | 0, /* UNI_MEDEFFECTF2 */ | ||
101 | 0, /* UNI_MEDEFFECTF3 */ | ||
102 | 2, /* UNI_OKTARP */ | ||
103 | }; | ||
104 | |||
105 | /* Sparse description of the internal module format | ||
106 | ------------------------------------------------ | ||
107 | |||
108 | A UNITRK stream is an array of bytes representing a single track of a pattern. | ||
109 | It's made up of 'repeat/length' bytes, opcodes and operands (sort of a assembly | ||
110 | language): | ||
111 | |||
112 | rrrlllll | ||
113 | [REP/LEN][OPCODE][OPERAND][OPCODE][OPERAND] [REP/LEN][OPCODE][OPERAND].. | ||
114 | ^ ^ ^ | ||
115 | |-------ROWS 0 - 0+REP of a track---------| |-------ROWS xx - xx+REP of a track... | ||
116 | |||
117 | The rep/len byte contains the number of bytes in the current row, _including_ | ||
118 | the length byte itself (So the LENGTH byte of row 0 in the previous example | ||
119 | would have a value of 5). This makes it easy to search through a stream for a | ||
120 | particular row. A track is concluded by a 0-value length byte. | ||
121 | |||
122 | The upper 3 bits of the rep/len byte contain the number of times -1 this row | ||
123 | is repeated for this track. (so a value of 7 means this row is repeated 8 times) | ||
124 | |||
125 | Opcodes can range from 1 to 255 but currently only opcodes 1 to 62 are being | ||
126 | used. Each opcode can have a different number of operands. You can find the | ||
127 | number of operands to a particular opcode by using the opcode as an index into | ||
128 | the 'unioperands' table. | ||
129 | |||
130 | */ | ||
131 | |||
132 | /*========== Reading routines */ | ||
133 | |||
134 | static UBYTE *rowstart; /* startadress of a row */ | ||
135 | static UBYTE *rowend; /* endaddress of a row (exclusive) */ | ||
136 | static UBYTE *rowpc; /* current unimod(tm) programcounter */ | ||
137 | |||
138 | static UBYTE lastbyte; /* for UniSkipOpcode() */ | ||
139 | |||
140 | void UniSetRow(UBYTE* t) | ||
141 | { | ||
142 | rowstart = t; | ||
143 | rowpc = rowstart; | ||
144 | rowend = t?rowstart+(*(rowpc++)&0x1f):t; | ||
145 | } | ||
146 | |||
147 | UBYTE UniGetByte(void) | ||
148 | { | ||
149 | return lastbyte = (rowpc<rowend)?*(rowpc++):0; | ||
150 | } | ||
151 | |||
152 | UWORD UniGetWord(void) | ||
153 | { | ||
154 | return ((UWORD)UniGetByte()<<8)|UniGetByte(); | ||
155 | } | ||
156 | |||
157 | void UniSkipOpcode(void) | ||
158 | { | ||
159 | if (lastbyte < UNI_LAST) { | ||
160 | UWORD t = unioperands[lastbyte]; | ||
161 | |||
162 | while (t--) | ||
163 | UniGetByte(); | ||
164 | } | ||
165 | } | ||
166 | |||
167 | /* Finds the address of row number 'row' in the UniMod(tm) stream 't' returns | ||
168 | NULL if the row can't be found. */ | ||
169 | UBYTE *UniFindRow(UBYTE* t,UWORD row) | ||
170 | { | ||
171 | UBYTE c,l; | ||
172 | |||
173 | if(t) | ||
174 | while(1) { | ||
175 | c = *t; /* get rep/len byte */ | ||
176 | if(!c) return NULL; /* zero ? -> end of track.. */ | ||
177 | l = (c>>5)+1; /* extract repeat value */ | ||
178 | if(l>row) break; /* reached wanted row? -> return pointer */ | ||
179 | row -= l; /* haven't reached row yet.. update row */ | ||
180 | t += c&0x1f; /* point t to the next row */ | ||
181 | } | ||
182 | return t; | ||
183 | } | ||
184 | |||
185 | /*========== Writing routines */ | ||
186 | |||
187 | static UBYTE *unibuf; /* pointer to the temporary unitrk buffer */ | ||
188 | static UWORD unimax; /* buffer size */ | ||
189 | |||
190 | static UWORD unipc; /* buffer cursor */ | ||
191 | static UWORD unitt; /* current row index */ | ||
192 | static UWORD lastp; /* previous row index */ | ||
193 | |||
194 | /* Resets index-pointers to create a new track. */ | ||
195 | void UniReset(void) | ||
196 | { | ||
197 | unitt = 0; /* reset index to rep/len byte */ | ||
198 | unipc = 1; /* first opcode will be written to index 1 */ | ||
199 | lastp = 0; /* no previous row yet */ | ||
200 | unibuf[0] = 0; /* clear rep/len byte */ | ||
201 | } | ||
202 | |||
203 | /* Expands the buffer */ | ||
204 | static int UniExpand(int wanted) | ||
205 | { | ||
206 | if ((unipc+wanted)>=unimax) { | ||
207 | UBYTE *newbuf; | ||
208 | |||
209 | /* Expand the buffer by BUFPAGE bytes */ | ||
210 | newbuf=(UBYTE*)MikMod_realloc(unibuf,(unimax+BUFPAGE)*sizeof(UBYTE)); | ||
211 | |||
212 | /* Check if MikMod_realloc succeeded */ | ||
213 | if(newbuf) { | ||
214 | unibuf = newbuf; | ||
215 | unimax+=BUFPAGE; | ||
216 | return 1; | ||
217 | } else | ||
218 | return 0; | ||
219 | } | ||
220 | return 1; | ||
221 | } | ||
222 | |||
223 | /* Appends one byte of data to the current row of a track. */ | ||
224 | void UniWriteByte(UBYTE data) | ||
225 | { | ||
226 | if (UniExpand(1)) | ||
227 | /* write byte to current position and update */ | ||
228 | unibuf[unipc++]=data; | ||
229 | } | ||
230 | |||
231 | void UniWriteWord(UWORD data) | ||
232 | { | ||
233 | if (UniExpand(2)) { | ||
234 | unibuf[unipc++]=data>>8; | ||
235 | unibuf[unipc++]=data&0xff; | ||
236 | } | ||
237 | } | ||
238 | |||
239 | static int MyCmp(UBYTE* a,UBYTE* b,UWORD l) | ||
240 | { | ||
241 | UWORD t; | ||
242 | |||
243 | for(t=0;t<l;t++) | ||
244 | if(*(a++)!=*(b++)) return 0; | ||
245 | return 1; | ||
246 | } | ||
247 | |||
248 | /* Closes the current row of a unitrk stream (updates the rep/len byte) and sets | ||
249 | pointers to start a new row. */ | ||
250 | void UniNewline(void) | ||
251 | { | ||
252 | UWORD n,l,len; | ||
253 | |||
254 | n = (unibuf[lastp]>>5)+1; /* repeat of previous row */ | ||
255 | l = (unibuf[lastp]&0x1f); /* length of previous row */ | ||
256 | |||
257 | len = unipc-unitt; /* length of current row */ | ||
258 | |||
259 | /* Now, check if the previous and the current row are identical.. when they | ||
260 | are, just increase the repeat field of the previous row */ | ||
261 | if(n<8 && len==l && MyCmp(&unibuf[lastp+1],&unibuf[unitt+1],len-1)) { | ||
262 | unibuf[lastp]+=0x20; | ||
263 | unipc = unitt+1; | ||
264 | } else { | ||
265 | if (UniExpand(unitt-unipc)) { | ||
266 | /* current and previous row aren't equal... update the pointers */ | ||
267 | unibuf[unitt] = len; | ||
268 | lastp = unitt; | ||
269 | unitt = unipc++; | ||
270 | } | ||
271 | } | ||
272 | } | ||
273 | |||
274 | /* Terminates the current unitrk stream and returns a pointer to a copy of the | ||
275 | stream. */ | ||
276 | UBYTE* UniDup(void) | ||
277 | { | ||
278 | UBYTE *d; | ||
279 | |||
280 | if (!UniExpand(unitt-unipc)) return NULL; | ||
281 | unibuf[unitt] = 0; | ||
282 | |||
283 | if(!(d=(UBYTE *)MikMod_malloc(unipc))) return NULL; | ||
284 | memcpy(d,unibuf,unipc); | ||
285 | |||
286 | return d; | ||
287 | } | ||
288 | |||
289 | int UniInit(void) | ||
290 | { | ||
291 | unimax = BUFPAGE; | ||
292 | |||
293 | if(!(unibuf=(UBYTE*)MikMod_malloc(unimax*sizeof(UBYTE)))) return 0; | ||
294 | return 1; | ||
295 | } | ||
296 | |||
297 | void UniCleanup(void) | ||
298 | { | ||
299 | if(unibuf) MikMod_free(unibuf); | ||
300 | unibuf = NULL; | ||
301 | } | ||
302 | |||
303 | /* ex:set ts=4: */ | ||
diff --git a/apps/plugins/mikmod/npertab.c b/apps/plugins/mikmod/npertab.c new file mode 100644 index 0000000000..4aa5ef9a17 --- /dev/null +++ b/apps/plugins/mikmod/npertab.c | |||
@@ -0,0 +1,48 @@ | |||
1 | /* MikMod sound library | ||
2 | (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for | ||
3 | 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: npertab.c,v 1.2 2005/03/30 19:11:47 realtech Exp $ | ||
24 | |||
25 | MOD format period table. Used by both the MOD and M15 (15-inst mod) Loaders. | ||
26 | |||
27 | ==============================================================================*/ | ||
28 | |||
29 | #ifdef HAVE_CONFIG_H | ||
30 | #include "config.h" | ||
31 | #endif | ||
32 | |||
33 | #include "mikmod_internals.h" | ||
34 | |||
35 | UWORD npertab[7 * OCTAVE] = { | ||
36 | /* Octaves 6 -> 0 */ | ||
37 | /* C C# D D# E F F# G G# A A# B */ | ||
38 | 0x6b0,0x650,0x5f4,0x5a0,0x54c,0x500,0x4b8,0x474,0x434,0x3f8,0x3c0,0x38a, | ||
39 | 0x358,0x328,0x2fa,0x2d0,0x2a6,0x280,0x25c,0x23a,0x21a,0x1fc,0x1e0,0x1c5, | ||
40 | 0x1ac,0x194,0x17d,0x168,0x153,0x140,0x12e,0x11d,0x10d,0x0fe,0x0f0,0x0e2, | ||
41 | 0x0d6,0x0ca,0x0be,0x0b4,0x0aa,0x0a0,0x097,0x08f,0x087,0x07f,0x078,0x071, | ||
42 | 0x06b,0x065,0x05f,0x05a,0x055,0x050,0x04b,0x047,0x043,0x03f,0x03c,0x038, | ||
43 | 0x035,0x032,0x02f,0x02d,0x02a,0x028,0x025,0x023,0x021,0x01f,0x01e,0x01c, | ||
44 | 0x01b,0x019,0x018,0x016,0x015,0x014,0x013,0x012,0x011,0x010,0x00f,0x00e | ||
45 | }; | ||
46 | |||
47 | /* ex:set ts=4: */ | ||
48 | |||
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: */ | ||
diff --git a/apps/plugins/mikmod/strdup.c b/apps/plugins/mikmod/strdup.c new file mode 100644 index 0000000000..f8c1438bee --- /dev/null +++ b/apps/plugins/mikmod/strdup.c | |||
@@ -0,0 +1,23 @@ | |||
1 | #ifdef HAVE_CONFIG_H | ||
2 | #include "config.h" | ||
3 | #endif | ||
4 | |||
5 | #include <stdlib.h> | ||
6 | #include <string.h> | ||
7 | #include "mikmod.h" | ||
8 | |||
9 | #undef strdup | ||
10 | |||
11 | char* strdup(const char *__s) | ||
12 | { | ||
13 | char *charptr; | ||
14 | |||
15 | if (!__s) | ||
16 | return NULL; | ||
17 | |||
18 | charptr=(char *)MikMod_malloc(sizeof(char) * (strlen(__s) + 1)); | ||
19 | if (charptr) | ||
20 | strcpy(charptr, __s); | ||
21 | |||
22 | return charptr; | ||
23 | } | ||
diff --git a/apps/plugins/mikmod/strstr.c b/apps/plugins/mikmod/strstr.c new file mode 100644 index 0000000000..c2cf97ecde --- /dev/null +++ b/apps/plugins/mikmod/strstr.c | |||
@@ -0,0 +1,21 @@ | |||
1 | #ifdef HAVE_CONFIG_H | ||
2 | #include "config.h" | ||
3 | #endif | ||
4 | |||
5 | #include <string.h> | ||
6 | |||
7 | #include "mikmod_supp.h" | ||
8 | |||
9 | char *strstr(const char *haystack, const char *needle) | ||
10 | { | ||
11 | const char *scan; | ||
12 | size_t len; | ||
13 | char firstc; | ||
14 | |||
15 | firstc = *needle; | ||
16 | len = strlen(needle); | ||
17 | for (scan = haystack; *scan != firstc || strncmp(scan, needle, len); ) | ||
18 | if (!*scan++) | ||
19 | return NULL; | ||
20 | return (char *)scan; | ||
21 | } | ||
diff --git a/apps/plugins/mikmod/virtch.c b/apps/plugins/mikmod/virtch.c new file mode 100644 index 0000000000..43a61a3c2c --- /dev/null +++ b/apps/plugins/mikmod/virtch.c | |||
@@ -0,0 +1,1319 @@ | |||
1 | /* MikMod sound library | ||
2 | (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file | ||
3 | AUTHORS 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: virtch.c,v 1.4 2005/05/18 13:42:23 raphassenat Exp $ | ||
24 | |||
25 | Sample mixing routines, using a 32 bits mixing buffer. | ||
26 | |||
27 | ==============================================================================*/ | ||
28 | |||
29 | /* | ||
30 | |||
31 | Optional features include: | ||
32 | (a) 4-step reverb (for 16 bit output only) | ||
33 | (b) Interpolation of sample data during mixing | ||
34 | (c) Dolby Surround Sound | ||
35 | */ | ||
36 | #if 0 | ||
37 | #include <assert.h> | ||
38 | #endif | ||
39 | |||
40 | #ifdef HAVE_CONFIG_H | ||
41 | #include "config.h" | ||
42 | #endif | ||
43 | |||
44 | #include <stddef.h> | ||
45 | #ifdef HAVE_MEMORY_H | ||
46 | #include <memory.h> | ||
47 | #endif | ||
48 | #include <string.h> | ||
49 | |||
50 | #include "mikmod_internals.h" | ||
51 | #include "mikmod.h" | ||
52 | |||
53 | /* | ||
54 | Constant definitions | ||
55 | ==================== | ||
56 | |||
57 | BITSHIFT | ||
58 | Controls the maximum volume of the sound output. All data is shifted | ||
59 | right by BITSHIFT after being mixed. Higher values result in quieter | ||
60 | sound and less chance of distortion. | ||
61 | |||
62 | REVERBERATION | ||
63 | Controls the duration of the reverb. Larger values represent a shorter | ||
64 | reverb loop. Smaller values extend the reverb but can result in more of | ||
65 | an echo-ish sound. | ||
66 | |||
67 | */ | ||
68 | |||
69 | #define BITSHIFT 9 | ||
70 | #define REVERBERATION 110000L | ||
71 | |||
72 | #define FRACBITS 11 | ||
73 | #define FRACMASK ((1L<<FRACBITS)-1L) | ||
74 | |||
75 | #define TICKLSIZE 8192 | ||
76 | #define TICKWSIZE (TICKLSIZE<<1) | ||
77 | #define TICKBSIZE (TICKWSIZE<<1) | ||
78 | |||
79 | #define CLICK_SHIFT 6 | ||
80 | #define CLICK_BUFFER (1L<<CLICK_SHIFT) | ||
81 | |||
82 | #ifndef MIN | ||
83 | #define MIN(a,b) (((a)<(b)) ? (a) : (b)) | ||
84 | #endif | ||
85 | |||
86 | typedef struct VINFO { | ||
87 | UBYTE kick; /* =1 -> sample has to be restarted */ | ||
88 | UBYTE active; /* =1 -> sample is playing */ | ||
89 | UWORD flags; /* 16/8 bits looping/one-shot */ | ||
90 | SWORD handle; /* identifies the sample */ | ||
91 | ULONG start; /* start index */ | ||
92 | ULONG size; /* samplesize */ | ||
93 | ULONG reppos; /* loop start */ | ||
94 | ULONG repend; /* loop end */ | ||
95 | ULONG frq; /* current frequency */ | ||
96 | int vol; /* current volume */ | ||
97 | int pan; /* current panning position */ | ||
98 | |||
99 | int rampvol; | ||
100 | int lvolsel,rvolsel; /* Volume factor in range 0-255 */ | ||
101 | int oldlvol,oldrvol; | ||
102 | |||
103 | SLONGLONG current; /* current index in the sample */ | ||
104 | SLONGLONG increment; /* increment value */ | ||
105 | } VINFO; | ||
106 | |||
107 | static SWORD **Samples; | ||
108 | static VINFO *vinf=NULL,*vnf; | ||
109 | static long tickleft,samplesthatfit,vc_memory=0; | ||
110 | static int vc_softchn; | ||
111 | static SLONGLONG idxsize,idxlpos,idxlend; | ||
112 | static SLONG *vc_tickbuf=NULL; | ||
113 | static UWORD vc_mode; | ||
114 | |||
115 | /* Reverb control variables */ | ||
116 | |||
117 | static int RVc1, RVc2, RVc3, RVc4, RVc5, RVc6, RVc7, RVc8; | ||
118 | static ULONG RVRindex; | ||
119 | |||
120 | /* For Mono or Left Channel */ | ||
121 | static SLONG *RVbufL1=NULL,*RVbufL2=NULL,*RVbufL3=NULL,*RVbufL4=NULL, | ||
122 | *RVbufL5=NULL,*RVbufL6=NULL,*RVbufL7=NULL,*RVbufL8=NULL; | ||
123 | |||
124 | /* For Stereo only (Right Channel) */ | ||
125 | static SLONG *RVbufR1=NULL,*RVbufR2=NULL,*RVbufR3=NULL,*RVbufR4=NULL, | ||
126 | *RVbufR5=NULL,*RVbufR6=NULL,*RVbufR7=NULL,*RVbufR8=NULL; | ||
127 | |||
128 | #ifdef NATIVE_64BIT_INT | ||
129 | #define NATIVE SLONGLONG | ||
130 | #else | ||
131 | #define NATIVE SLONG | ||
132 | #endif | ||
133 | #if defined HAVE_SSE2 || defined HAVE_ALTIVEC | ||
134 | |||
135 | static size_t MixSIMDMonoNormal(const SWORD* srce,SLONG* dest,size_t index, size_t increment,size_t todo) | ||
136 | { | ||
137 | // TODO: | ||
138 | SWORD sample; | ||
139 | SLONG lvolsel = vnf->lvolsel; | ||
140 | |||
141 | while(todo--) { | ||
142 | sample = srce[index >> FRACBITS]; | ||
143 | index += increment; | ||
144 | |||
145 | *dest++ += lvolsel * sample; | ||
146 | } | ||
147 | return index; | ||
148 | } | ||
149 | |||
150 | static size_t MixSIMDStereoNormal(const SWORD* srce, SLONG* dest, size_t index, size_t increment,size_t todo) | ||
151 | { | ||
152 | SWORD vol[8] = {vnf->lvolsel, vnf->rvolsel}; | ||
153 | SWORD sample; | ||
154 | SLONG remain = todo; | ||
155 | |||
156 | // Dest can be misaligned ... | ||
157 | while(!IS_ALIGNED_16(dest)) { | ||
158 | sample=srce[(index += increment) >> FRACBITS]; | ||
159 | *dest++ += vol[0] * sample; | ||
160 | *dest++ += vol[1] * sample; | ||
161 | todo--; | ||
162 | } | ||
163 | |||
164 | // Srce is always aligned ... | ||
165 | |||
166 | #if defined HAVE_SSE2 | ||
167 | remain = todo&3; | ||
168 | { | ||
169 | __m128i v0 = _mm_set_epi16(0, vol[1], | ||
170 | 0, vol[0], | ||
171 | 0, vol[1], | ||
172 | 0, vol[0]); | ||
173 | for(todo>>=2;todo; todo--) | ||
174 | { | ||
175 | SWORD s0 = srce[(index += increment) >> FRACBITS]; | ||
176 | SWORD s1 = srce[(index += increment) >> FRACBITS]; | ||
177 | SWORD s2 = srce[(index += increment) >> FRACBITS]; | ||
178 | SWORD s3 = srce[(index += increment) >> FRACBITS]; | ||
179 | __m128i v1 = _mm_set_epi16(0, s1, 0, s1, 0, s0, 0, s0); | ||
180 | __m128i v2 = _mm_set_epi16(0, s3, 0, s3, 0, s2, 0, s2); | ||
181 | __m128i v3 = _mm_load_si128((__m128i*)(dest+0)); | ||
182 | __m128i v4 = _mm_load_si128((__m128i*)(dest+4)); | ||
183 | _mm_store_si128((__m128i*)(dest+0), _mm_add_epi32(v3, _mm_madd_epi16(v0, v1))); | ||
184 | _mm_store_si128((__m128i*)(dest+4), _mm_add_epi32(v4, _mm_madd_epi16(v0, v2))); | ||
185 | dest+=8; | ||
186 | } | ||
187 | } | ||
188 | |||
189 | #elif defined HAVE_ALTIVEC | ||
190 | remain = todo&3; | ||
191 | { | ||
192 | vector signed short r0 = vec_ld(0, vol); | ||
193 | vector signed short v0 = vec_perm(r0, r0, (vector unsigned char)(0, 1, // l | ||
194 | 0, 1, // l | ||
195 | 2, 3, // r | ||
196 | 2, 1, // r | ||
197 | 0, 1, // l | ||
198 | 0, 1, // l | ||
199 | 2, 3, // r | ||
200 | 2, 3 // r | ||
201 | )); | ||
202 | SWORD s[8]; | ||
203 | |||
204 | for(todo>>=2;todo; todo--) | ||
205 | { | ||
206 | // Load constants | ||
207 | s[0] = srce[(index += increment) >> FRACBITS]; | ||
208 | s[1] = srce[(index += increment) >> FRACBITS]; | ||
209 | s[2] = srce[(index += increment) >> FRACBITS]; | ||
210 | s[3] = srce[(index += increment) >> FRACBITS]; | ||
211 | s[4] = 0; | ||
212 | |||
213 | vector short int r1 = vec_ld(0, s); | ||
214 | vector signed short v1 = vec_perm(r1, r1, (vector unsigned char)(0*2, 0*2+1, // s0 | ||
215 | 4*2, 4*2+1, // 0 | ||
216 | 0*2, 0*2+1, // s0 | ||
217 | 4*2, 4*2+1, // 0 | ||
218 | 1*2, 1*2+1, // s1 | ||
219 | 4*2, 4*2+1, // 0 | ||
220 | 1*2, 1*2+1, // s1 | ||
221 | 4*2, 4*2+1 // 0 | ||
222 | )); | ||
223 | |||
224 | vector signed short v2 = vec_perm(r1, r1, (vector unsigned char)(2*2, 2*2+1, // s2 | ||
225 | 4*2, 4*2+1, // 0 | ||
226 | 2*2, 2*2+1, // s2 | ||
227 | 4*2, 4*2+1, // 0 | ||
228 | 3*2, 3*2+1, // s3 | ||
229 | 4*2, 4*2+1, // 0 | ||
230 | 3*2, 3*2+1, // s3 | ||
231 | 4*2, 4*2+1 // 0 | ||
232 | )); | ||
233 | vector signed int v3 = vec_ld(0, dest); | ||
234 | vector signed int v4 = vec_ld(0, dest + 4); | ||
235 | vector signed int v5 = vec_mule(v0, v1); | ||
236 | vector signed int v6 = vec_mule(v0, v2); | ||
237 | |||
238 | vec_st(vec_add(v3, v5), 0, dest); | ||
239 | vec_st(vec_add(v4, v6), 0x10, dest); | ||
240 | |||
241 | dest+=8; | ||
242 | } | ||
243 | } | ||
244 | #endif // HAVE_ALTIVEC | ||
245 | |||
246 | // Remaining bits ... | ||
247 | while(remain--) { | ||
248 | sample=srce[(index += increment) >> FRACBITS]; | ||
249 | |||
250 | *dest++ += vol[0] * sample; | ||
251 | *dest++ += vol[1] * sample; | ||
252 | } | ||
253 | return index; | ||
254 | } | ||
255 | #endif | ||
256 | |||
257 | /*========== 32 bit sample mixers - only for 32 bit platforms */ | ||
258 | #ifndef NATIVE_64BIT_INT | ||
259 | |||
260 | static SLONG Mix32MonoNormal(const SWORD* srce,SLONG* dest,SLONG index,SLONG increment,SLONG todo) | ||
261 | { | ||
262 | #if defined HAVE_ALTIVEC || defined HAVE_SSE2 | ||
263 | if (md_mode & DMODE_SIMDMIXER) | ||
264 | { | ||
265 | return MixSIMDMonoNormal(srce, dest, index, increment, todo); | ||
266 | } | ||
267 | else | ||
268 | #endif | ||
269 | { | ||
270 | SWORD sample; | ||
271 | SLONG lvolsel = vnf->lvolsel; | ||
272 | |||
273 | while(todo--) { | ||
274 | sample = srce[index >> FRACBITS]; | ||
275 | index += increment; | ||
276 | |||
277 | *dest++ += lvolsel * sample; | ||
278 | } | ||
279 | } | ||
280 | return index; | ||
281 | } | ||
282 | |||
283 | // FIXME: This mixer should works also on 64-bit platform | ||
284 | // Hint : changes SLONG / SLONGLONG mess with size_t | ||
285 | static SLONG Mix32StereoNormal(const SWORD* srce,SLONG* dest,SLONG index,SLONG increment,SLONG todo) | ||
286 | { | ||
287 | #if defined HAVE_ALTIVEC || defined HAVE_SSE2 | ||
288 | if (md_mode & DMODE_SIMDMIXER) | ||
289 | { | ||
290 | return MixSIMDStereoNormal(srce, dest, index, increment, todo); | ||
291 | } | ||
292 | else | ||
293 | #endif | ||
294 | { | ||
295 | SWORD sample; | ||
296 | SLONG lvolsel = vnf->lvolsel; | ||
297 | SLONG rvolsel = vnf->rvolsel; | ||
298 | |||
299 | while(todo--) { | ||
300 | sample=srce[(index += increment) >> FRACBITS]; | ||
301 | |||
302 | *dest++ += lvolsel * sample; | ||
303 | *dest++ += rvolsel * sample; | ||
304 | } | ||
305 | } | ||
306 | return index; | ||
307 | } | ||
308 | |||
309 | |||
310 | static SLONG Mix32SurroundNormal(const SWORD* srce,SLONG* dest,SLONG index,SLONG increment,SLONG todo) | ||
311 | { | ||
312 | SWORD sample; | ||
313 | SLONG lvolsel = vnf->lvolsel; | ||
314 | SLONG rvolsel = vnf->rvolsel; | ||
315 | |||
316 | if (lvolsel>=rvolsel) { | ||
317 | while(todo--) { | ||
318 | sample = srce[index >> FRACBITS]; | ||
319 | index += increment; | ||
320 | |||
321 | *dest++ += lvolsel*sample; | ||
322 | *dest++ -= lvolsel*sample; | ||
323 | } | ||
324 | } else { | ||
325 | while(todo--) { | ||
326 | sample = srce[index >> FRACBITS]; | ||
327 | index += increment; | ||
328 | |||
329 | *dest++ -= rvolsel*sample; | ||
330 | *dest++ += rvolsel*sample; | ||
331 | } | ||
332 | } | ||
333 | return index; | ||
334 | } | ||
335 | |||
336 | static SLONG Mix32MonoInterp(const SWORD* srce,SLONG* dest,SLONG index,SLONG increment,SLONG todo) | ||
337 | { | ||
338 | SLONG sample; | ||
339 | SLONG lvolsel = vnf->lvolsel; | ||
340 | SLONG rampvol = vnf->rampvol; | ||
341 | |||
342 | if (rampvol) { | ||
343 | SLONG oldlvol = vnf->oldlvol - lvolsel; | ||
344 | while(todo--) { | ||
345 | sample=(SLONG)srce[index>>FRACBITS]+ | ||
346 | ((SLONG)(srce[(index>>FRACBITS)+1]-srce[index>>FRACBITS]) | ||
347 | *(index&FRACMASK)>>FRACBITS); | ||
348 | index += increment; | ||
349 | |||
350 | *dest++ += ((lvolsel << CLICK_SHIFT) + oldlvol * rampvol) | ||
351 | * sample >> CLICK_SHIFT; | ||
352 | if (!--rampvol) | ||
353 | break; | ||
354 | } | ||
355 | vnf->rampvol = rampvol; | ||
356 | if (todo < 0) | ||
357 | return index; | ||
358 | } | ||
359 | |||
360 | while(todo--) { | ||
361 | sample=(SLONG)srce[index>>FRACBITS]+ | ||
362 | ((SLONG)(srce[(index>>FRACBITS)+1]-srce[index>>FRACBITS]) | ||
363 | *(index&FRACMASK)>>FRACBITS); | ||
364 | index += increment; | ||
365 | |||
366 | *dest++ += lvolsel * sample; | ||
367 | } | ||
368 | return index; | ||
369 | } | ||
370 | |||
371 | static SLONG Mix32StereoInterp(const SWORD* srce,SLONG* dest,SLONG index,SLONG increment,SLONG todo) | ||
372 | { | ||
373 | SLONG sample; | ||
374 | SLONG lvolsel = vnf->lvolsel; | ||
375 | SLONG rvolsel = vnf->rvolsel; | ||
376 | SLONG rampvol = vnf->rampvol; | ||
377 | |||
378 | if (rampvol) { | ||
379 | SLONG oldlvol = vnf->oldlvol - lvolsel; | ||
380 | SLONG oldrvol = vnf->oldrvol - rvolsel; | ||
381 | while(todo--) { | ||
382 | sample=(SLONG)srce[index>>FRACBITS]+ | ||
383 | ((SLONG)(srce[(index>>FRACBITS)+1]-srce[index>>FRACBITS]) | ||
384 | *(index&FRACMASK)>>FRACBITS); | ||
385 | index += increment; | ||
386 | |||
387 | *dest++ += ((lvolsel << CLICK_SHIFT) + oldlvol * rampvol) | ||
388 | * sample >> CLICK_SHIFT; | ||
389 | *dest++ += ((rvolsel << CLICK_SHIFT) + oldrvol * rampvol) | ||
390 | * sample >> CLICK_SHIFT; | ||
391 | if (!--rampvol) | ||
392 | break; | ||
393 | } | ||
394 | vnf->rampvol = rampvol; | ||
395 | if (todo < 0) | ||
396 | return index; | ||
397 | } | ||
398 | |||
399 | while(todo--) { | ||
400 | sample=(SLONG)srce[index>>FRACBITS]+ | ||
401 | ((SLONG)(srce[(index>>FRACBITS)+1]-srce[index>>FRACBITS]) | ||
402 | *(index&FRACMASK)>>FRACBITS); | ||
403 | index += increment; | ||
404 | |||
405 | *dest++ += lvolsel * sample; | ||
406 | *dest++ += rvolsel * sample; | ||
407 | } | ||
408 | return index; | ||
409 | } | ||
410 | |||
411 | static SLONG Mix32SurroundInterp(const SWORD* srce,SLONG* dest,SLONG index,SLONG increment,SLONG todo) | ||
412 | { | ||
413 | SLONG sample; | ||
414 | SLONG lvolsel = vnf->lvolsel; | ||
415 | SLONG rvolsel = vnf->rvolsel; | ||
416 | SLONG rampvol = vnf->rampvol; | ||
417 | SLONG oldvol, vol; | ||
418 | |||
419 | if (lvolsel >= rvolsel) { | ||
420 | vol = lvolsel; | ||
421 | oldvol = vnf->oldlvol; | ||
422 | } else { | ||
423 | vol = rvolsel; | ||
424 | oldvol = vnf->oldrvol; | ||
425 | } | ||
426 | |||
427 | if (rampvol) { | ||
428 | oldvol -= vol; | ||
429 | while(todo--) { | ||
430 | sample=(SLONG)srce[index>>FRACBITS]+ | ||
431 | ((SLONG)(srce[(index>>FRACBITS)+1]-srce[index>>FRACBITS]) | ||
432 | *(index&FRACMASK)>>FRACBITS); | ||
433 | index += increment; | ||
434 | |||
435 | sample=((vol << CLICK_SHIFT) + oldvol * rampvol) | ||
436 | * sample >> CLICK_SHIFT; | ||
437 | *dest++ += sample; | ||
438 | *dest++ -= sample; | ||
439 | |||
440 | if (!--rampvol) | ||
441 | break; | ||
442 | } | ||
443 | vnf->rampvol = rampvol; | ||
444 | if (todo < 0) | ||
445 | return index; | ||
446 | } | ||
447 | |||
448 | while(todo--) { | ||
449 | sample=(SLONG)srce[index>>FRACBITS]+ | ||
450 | ((SLONG)(srce[(index>>FRACBITS)+1]-srce[index>>FRACBITS]) | ||
451 | *(index&FRACMASK)>>FRACBITS); | ||
452 | index += increment; | ||
453 | |||
454 | *dest++ += vol*sample; | ||
455 | *dest++ -= vol*sample; | ||
456 | } | ||
457 | return index; | ||
458 | } | ||
459 | #endif | ||
460 | |||
461 | /*========== 64 bit sample mixers - all platforms */ | ||
462 | |||
463 | static SLONGLONG MixMonoNormal(const SWORD* srce,SLONG* dest,SLONGLONG index,SLONGLONG increment,SLONG todo) | ||
464 | { | ||
465 | SWORD sample; | ||
466 | SLONG lvolsel = vnf->lvolsel; | ||
467 | |||
468 | while(todo--) { | ||
469 | sample = srce[index >> FRACBITS]; | ||
470 | index += increment; | ||
471 | |||
472 | *dest++ += lvolsel * sample; | ||
473 | } | ||
474 | return index; | ||
475 | } | ||
476 | |||
477 | static SLONGLONG MixStereoNormal(const SWORD* srce,SLONG* dest,SLONGLONG index,SLONGLONG increment,SLONG todo) | ||
478 | { | ||
479 | SWORD sample; | ||
480 | SLONG lvolsel = vnf->lvolsel; | ||
481 | SLONG rvolsel = vnf->rvolsel; | ||
482 | |||
483 | while(todo--) { | ||
484 | sample=srce[index >> FRACBITS]; | ||
485 | index += increment; | ||
486 | |||
487 | *dest++ += lvolsel * sample; | ||
488 | *dest++ += rvolsel * sample; | ||
489 | } | ||
490 | return index; | ||
491 | } | ||
492 | |||
493 | static SLONGLONG MixSurroundNormal(const SWORD* srce,SLONG* dest,SLONGLONG index,SLONGLONG increment,SLONG todo) | ||
494 | { | ||
495 | SWORD sample; | ||
496 | SLONG lvolsel = vnf->lvolsel; | ||
497 | SLONG rvolsel = vnf->rvolsel; | ||
498 | |||
499 | if(vnf->lvolsel>=vnf->rvolsel) { | ||
500 | while(todo--) { | ||
501 | sample = srce[index >> FRACBITS]; | ||
502 | index += increment; | ||
503 | |||
504 | *dest++ += lvolsel*sample; | ||
505 | *dest++ -= lvolsel*sample; | ||
506 | } | ||
507 | } else { | ||
508 | while(todo--) { | ||
509 | sample = srce[index >> FRACBITS]; | ||
510 | index += increment; | ||
511 | |||
512 | *dest++ -= rvolsel*sample; | ||
513 | *dest++ += rvolsel*sample; | ||
514 | } | ||
515 | } | ||
516 | return index; | ||
517 | } | ||
518 | |||
519 | static SLONGLONG MixMonoInterp(const SWORD* srce,SLONG* dest,SLONGLONG index,SLONGLONG increment,SLONG todo) | ||
520 | { | ||
521 | SLONG sample; | ||
522 | SLONG lvolsel = vnf->lvolsel; | ||
523 | SLONG rampvol = vnf->rampvol; | ||
524 | |||
525 | if (rampvol) { | ||
526 | SLONG oldlvol = vnf->oldlvol - lvolsel; | ||
527 | while(todo--) { | ||
528 | sample=(SLONG)srce[index>>FRACBITS]+ | ||
529 | ((SLONG)(srce[(index>>FRACBITS)+1]-srce[index>>FRACBITS]) | ||
530 | *(index&FRACMASK)>>FRACBITS); | ||
531 | index += increment; | ||
532 | |||
533 | *dest++ += ((lvolsel << CLICK_SHIFT) + oldlvol * rampvol) | ||
534 | * sample >> CLICK_SHIFT; | ||
535 | if (!--rampvol) | ||
536 | break; | ||
537 | } | ||
538 | vnf->rampvol = rampvol; | ||
539 | if (todo < 0) | ||
540 | return index; | ||
541 | } | ||
542 | |||
543 | while(todo--) { | ||
544 | sample=(SLONG)srce[index>>FRACBITS]+ | ||
545 | ((SLONG)(srce[(index>>FRACBITS)+1]-srce[index>>FRACBITS]) | ||
546 | *(index&FRACMASK)>>FRACBITS); | ||
547 | index += increment; | ||
548 | |||
549 | *dest++ += lvolsel * sample; | ||
550 | } | ||
551 | return index; | ||
552 | } | ||
553 | |||
554 | static SLONGLONG MixStereoInterp(const SWORD* srce,SLONG* dest,SLONGLONG index,SLONGLONG increment,SLONG todo) | ||
555 | { | ||
556 | SLONG sample; | ||
557 | SLONG lvolsel = vnf->lvolsel; | ||
558 | SLONG rvolsel = vnf->rvolsel; | ||
559 | SLONG rampvol = vnf->rampvol; | ||
560 | |||
561 | if (rampvol) { | ||
562 | SLONG oldlvol = vnf->oldlvol - lvolsel; | ||
563 | SLONG oldrvol = vnf->oldrvol - rvolsel; | ||
564 | while(todo--) { | ||
565 | sample=(SLONG)srce[index>>FRACBITS]+ | ||
566 | ((SLONG)(srce[(index>>FRACBITS)+1]-srce[index>>FRACBITS]) | ||
567 | *(index&FRACMASK)>>FRACBITS); | ||
568 | index += increment; | ||
569 | |||
570 | *dest++ +=((lvolsel << CLICK_SHIFT) + oldlvol * rampvol) | ||
571 | * sample >> CLICK_SHIFT; | ||
572 | *dest++ +=((rvolsel << CLICK_SHIFT) + oldrvol * rampvol) | ||
573 | * sample >> CLICK_SHIFT; | ||
574 | if (!--rampvol) | ||
575 | break; | ||
576 | } | ||
577 | vnf->rampvol = rampvol; | ||
578 | if (todo < 0) | ||
579 | return index; | ||
580 | } | ||
581 | |||
582 | while(todo--) { | ||
583 | sample=(SLONG)srce[index>>FRACBITS]+ | ||
584 | ((SLONG)(srce[(index>>FRACBITS)+1]-srce[index>>FRACBITS]) | ||
585 | *(index&FRACMASK)>>FRACBITS); | ||
586 | index += increment; | ||
587 | |||
588 | *dest++ += lvolsel * sample; | ||
589 | *dest++ += rvolsel * sample; | ||
590 | } | ||
591 | return index; | ||
592 | } | ||
593 | |||
594 | static SLONGLONG MixSurroundInterp(const SWORD* srce,SLONG* dest,SLONGLONG index,SLONGLONG increment,SLONG todo) | ||
595 | { | ||
596 | SLONG sample; | ||
597 | SLONG lvolsel = vnf->lvolsel; | ||
598 | SLONG rvolsel = vnf->rvolsel; | ||
599 | SLONG rampvol = vnf->rampvol; | ||
600 | SLONG oldvol, vol; | ||
601 | |||
602 | if (lvolsel >= rvolsel) { | ||
603 | vol = lvolsel; | ||
604 | oldvol = vnf->oldlvol; | ||
605 | } else { | ||
606 | vol = rvolsel; | ||
607 | oldvol = vnf->oldrvol; | ||
608 | } | ||
609 | |||
610 | if (rampvol) { | ||
611 | oldvol -= vol; | ||
612 | while(todo--) { | ||
613 | sample=(SLONG)srce[index>>FRACBITS]+ | ||
614 | ((SLONG)(srce[(index>>FRACBITS)+1]-srce[index>>FRACBITS]) | ||
615 | *(index&FRACMASK)>>FRACBITS); | ||
616 | index += increment; | ||
617 | |||
618 | sample=((vol << CLICK_SHIFT) + oldvol * rampvol) | ||
619 | * sample >> CLICK_SHIFT; | ||
620 | *dest++ += sample; | ||
621 | *dest++ -= sample; | ||
622 | if (!--rampvol) | ||
623 | break; | ||
624 | } | ||
625 | vnf->rampvol = rampvol; | ||
626 | if (todo < 0) | ||
627 | return index; | ||
628 | } | ||
629 | |||
630 | while(todo--) { | ||
631 | sample=(SLONG)srce[index>>FRACBITS]+ | ||
632 | ((SLONG)(srce[(index>>FRACBITS)+1]-srce[index>>FRACBITS]) | ||
633 | *(index&FRACMASK)>>FRACBITS); | ||
634 | index += increment; | ||
635 | |||
636 | *dest++ += vol*sample; | ||
637 | *dest++ -= vol*sample; | ||
638 | } | ||
639 | return index; | ||
640 | } | ||
641 | |||
642 | static void (*MixReverb)(SLONG* srce,NATIVE count); | ||
643 | |||
644 | /* Reverb macros */ | ||
645 | #define COMPUTE_LOC(n) loc##n = RVRindex % RVc##n | ||
646 | #define COMPUTE_LECHO(n) RVbufL##n [loc##n ]=speedup+((ReverbPct*RVbufL##n [loc##n ])>>7) | ||
647 | #define COMPUTE_RECHO(n) RVbufR##n [loc##n ]=speedup+((ReverbPct*RVbufR##n [loc##n ])>>7) | ||
648 | |||
649 | static void MixReverb_Normal(SLONG* srce,NATIVE count) | ||
650 | { | ||
651 | unsigned int speedup; | ||
652 | int ReverbPct; | ||
653 | unsigned int loc1,loc2,loc3,loc4; | ||
654 | unsigned int loc5,loc6,loc7,loc8; | ||
655 | |||
656 | ReverbPct=58+(md_reverb<<2); | ||
657 | |||
658 | COMPUTE_LOC(1); COMPUTE_LOC(2); COMPUTE_LOC(3); COMPUTE_LOC(4); | ||
659 | COMPUTE_LOC(5); COMPUTE_LOC(6); COMPUTE_LOC(7); COMPUTE_LOC(8); | ||
660 | |||
661 | while(count--) { | ||
662 | /* Compute the left channel echo buffers */ | ||
663 | speedup = *srce >> 3; | ||
664 | |||
665 | COMPUTE_LECHO(1); COMPUTE_LECHO(2); COMPUTE_LECHO(3); COMPUTE_LECHO(4); | ||
666 | COMPUTE_LECHO(5); COMPUTE_LECHO(6); COMPUTE_LECHO(7); COMPUTE_LECHO(8); | ||
667 | |||
668 | /* Prepare to compute actual finalized data */ | ||
669 | RVRindex++; | ||
670 | |||
671 | COMPUTE_LOC(1); COMPUTE_LOC(2); COMPUTE_LOC(3); COMPUTE_LOC(4); | ||
672 | COMPUTE_LOC(5); COMPUTE_LOC(6); COMPUTE_LOC(7); COMPUTE_LOC(8); | ||
673 | |||
674 | /* left channel */ | ||
675 | *srce++ +=RVbufL1[loc1]-RVbufL2[loc2]+RVbufL3[loc3]-RVbufL4[loc4]+ | ||
676 | RVbufL5[loc5]-RVbufL6[loc6]+RVbufL7[loc7]-RVbufL8[loc8]; | ||
677 | } | ||
678 | } | ||
679 | |||
680 | static void MixReverb_Stereo(SLONG* srce,NATIVE count) | ||
681 | { | ||
682 | unsigned int speedup; | ||
683 | int ReverbPct; | ||
684 | unsigned int loc1, loc2, loc3, loc4; | ||
685 | unsigned int loc5, loc6, loc7, loc8; | ||
686 | |||
687 | ReverbPct = 92+(md_reverb<<1); | ||
688 | |||
689 | COMPUTE_LOC(1); COMPUTE_LOC(2); COMPUTE_LOC(3); COMPUTE_LOC(4); | ||
690 | COMPUTE_LOC(5); COMPUTE_LOC(6); COMPUTE_LOC(7); COMPUTE_LOC(8); | ||
691 | |||
692 | while(count--) { | ||
693 | /* Compute the left channel echo buffers */ | ||
694 | speedup = *srce >> 3; | ||
695 | |||
696 | COMPUTE_LECHO(1); COMPUTE_LECHO(2); COMPUTE_LECHO(3); COMPUTE_LECHO(4); | ||
697 | COMPUTE_LECHO(5); COMPUTE_LECHO(6); COMPUTE_LECHO(7); COMPUTE_LECHO(8); | ||
698 | |||
699 | /* Compute the right channel echo buffers */ | ||
700 | speedup = srce[1] >> 3; | ||
701 | |||
702 | COMPUTE_RECHO(1); COMPUTE_RECHO(2); COMPUTE_RECHO(3); COMPUTE_RECHO(4); | ||
703 | COMPUTE_RECHO(5); COMPUTE_RECHO(6); COMPUTE_RECHO(7); COMPUTE_RECHO(8); | ||
704 | |||
705 | /* Prepare to compute actual finalized data */ | ||
706 | RVRindex++; | ||
707 | |||
708 | COMPUTE_LOC(1); COMPUTE_LOC(2); COMPUTE_LOC(3); COMPUTE_LOC(4); | ||
709 | COMPUTE_LOC(5); COMPUTE_LOC(6); COMPUTE_LOC(7); COMPUTE_LOC(8); | ||
710 | |||
711 | /* left channel then right channel */ | ||
712 | *srce++ +=RVbufL1[loc1]-RVbufL2[loc2]+RVbufL3[loc3]-RVbufL4[loc4]+ | ||
713 | RVbufL5[loc5]-RVbufL6[loc6]+RVbufL7[loc7]-RVbufL8[loc8]; | ||
714 | |||
715 | *srce++ +=RVbufR1[loc1]-RVbufR2[loc2]+RVbufR3[loc3]-RVbufR4[loc4]+ | ||
716 | RVbufR5[loc5]-RVbufR6[loc6]+RVbufR7[loc7]-RVbufR8[loc8]; | ||
717 | } | ||
718 | } | ||
719 | |||
720 | static void (*MixLowPass)(SLONG* srce,NATIVE count); | ||
721 | |||
722 | static int nLeftNR, nRightNR; | ||
723 | |||
724 | static void MixLowPass_Stereo(SLONG* srce,NATIVE count) | ||
725 | { | ||
726 | int n1 = nLeftNR, n2 = nRightNR; | ||
727 | SLONG *pnr = srce; | ||
728 | int nr=count; | ||
729 | for (; nr; nr--) | ||
730 | { | ||
731 | int vnr = pnr[0] >> 1; | ||
732 | pnr[0] = vnr + n1; | ||
733 | n1 = vnr; | ||
734 | vnr = pnr[1] >> 1; | ||
735 | pnr[1] = vnr + n2; | ||
736 | n2 = vnr; | ||
737 | pnr += 2; | ||
738 | } | ||
739 | nLeftNR = n1; | ||
740 | nRightNR = n2; | ||
741 | } | ||
742 | |||
743 | static void MixLowPass_Normal(SLONG* srce,NATIVE count) | ||
744 | { | ||
745 | int n1 = nLeftNR; | ||
746 | SLONG *pnr = srce; | ||
747 | int nr=count; | ||
748 | for (; nr; nr--) | ||
749 | { | ||
750 | int vnr = pnr[0] >> 1; | ||
751 | pnr[0] = vnr + n1; | ||
752 | n1 = vnr; | ||
753 | pnr ++; | ||
754 | } | ||
755 | nLeftNR = n1; | ||
756 | } | ||
757 | |||
758 | /* shifting fudge factor for FP scaling, should be 0 < FP_SHIFT < BITSHIFT */ | ||
759 | #define FP_SHIFT 4 | ||
760 | |||
761 | /* Mixing macros */ | ||
762 | #define EXTRACT_SAMPLE_FP(var,size) var=(*srce++>>(BITSHIFT-size)) * ((1.0f / 32768.0f) / (1 << size)) | ||
763 | #define CHECK_SAMPLE_FP(var,bound) var=(var>bound)?bound:(var<-bound)?-bound:var | ||
764 | #define PUT_SAMPLE_FP(var) *dste++=var | ||
765 | |||
766 | static void Mix32ToFP(float* dste,const SLONG *srce,NATIVE count) | ||
767 | { | ||
768 | float x1,x2,x3,x4; | ||
769 | int remain; | ||
770 | |||
771 | remain=count&3; | ||
772 | for(count>>=2;count;count--) { | ||
773 | EXTRACT_SAMPLE_FP(x1,FP_SHIFT); EXTRACT_SAMPLE_FP(x2,FP_SHIFT); | ||
774 | EXTRACT_SAMPLE_FP(x3,FP_SHIFT); EXTRACT_SAMPLE_FP(x4,FP_SHIFT); | ||
775 | |||
776 | CHECK_SAMPLE_FP(x1,1.0f); CHECK_SAMPLE_FP(x2,1.0f); | ||
777 | CHECK_SAMPLE_FP(x3,1.0f); CHECK_SAMPLE_FP(x4,1.0f); | ||
778 | |||
779 | PUT_SAMPLE_FP(x1); PUT_SAMPLE_FP(x2); | ||
780 | PUT_SAMPLE_FP(x3); PUT_SAMPLE_FP(x4); | ||
781 | } | ||
782 | while(remain--) { | ||
783 | EXTRACT_SAMPLE_FP(x1,FP_SHIFT); | ||
784 | CHECK_SAMPLE_FP(x1,1.0f); | ||
785 | PUT_SAMPLE_FP(x1); | ||
786 | } | ||
787 | } | ||
788 | |||
789 | |||
790 | /* Mixing macros */ | ||
791 | #define EXTRACT_SAMPLE(var,size) var=*srce++>>(BITSHIFT+16-size) | ||
792 | #define CHECK_SAMPLE(var,bound) var=(var>=bound)?bound-1:(var<-bound)?-bound:var | ||
793 | #define PUT_SAMPLE(var) *dste++=var | ||
794 | |||
795 | static void Mix32To16(SWORD* dste,const SLONG *srce,NATIVE count) | ||
796 | { | ||
797 | SLONG x1,x2,x3,x4; | ||
798 | int remain; | ||
799 | |||
800 | remain=count&3; | ||
801 | for(count>>=2;count;count--) { | ||
802 | EXTRACT_SAMPLE(x1,16); EXTRACT_SAMPLE(x2,16); | ||
803 | EXTRACT_SAMPLE(x3,16); EXTRACT_SAMPLE(x4,16); | ||
804 | |||
805 | CHECK_SAMPLE(x1,32768); CHECK_SAMPLE(x2,32768); | ||
806 | CHECK_SAMPLE(x3,32768); CHECK_SAMPLE(x4,32768); | ||
807 | |||
808 | PUT_SAMPLE(x1); PUT_SAMPLE(x2); PUT_SAMPLE(x3); PUT_SAMPLE(x4); | ||
809 | } | ||
810 | while(remain--) { | ||
811 | EXTRACT_SAMPLE(x1,16); | ||
812 | CHECK_SAMPLE(x1,32768); | ||
813 | PUT_SAMPLE(x1); | ||
814 | } | ||
815 | } | ||
816 | |||
817 | static void Mix32To8(SBYTE* dste,const SLONG *srce,NATIVE count) | ||
818 | { | ||
819 | SWORD x1,x2,x3,x4; | ||
820 | int remain; | ||
821 | |||
822 | remain=count&3; | ||
823 | for(count>>=2;count;count--) { | ||
824 | EXTRACT_SAMPLE(x1,8); EXTRACT_SAMPLE(x2,8); | ||
825 | EXTRACT_SAMPLE(x3,8); EXTRACT_SAMPLE(x4,8); | ||
826 | |||
827 | CHECK_SAMPLE(x1,128); CHECK_SAMPLE(x2,128); | ||
828 | CHECK_SAMPLE(x3,128); CHECK_SAMPLE(x4,128); | ||
829 | |||
830 | PUT_SAMPLE(x1+128); PUT_SAMPLE(x2+128); | ||
831 | PUT_SAMPLE(x3+128); PUT_SAMPLE(x4+128); | ||
832 | } | ||
833 | while(remain--) { | ||
834 | EXTRACT_SAMPLE(x1,8); | ||
835 | CHECK_SAMPLE(x1,128); | ||
836 | PUT_SAMPLE(x1+128); | ||
837 | } | ||
838 | } | ||
839 | |||
840 | #if defined HAVE_ALTIVEC || defined HAVE_SSE2 | ||
841 | |||
842 | // Mix 32bit input to floating point. 32 samples per iteration | ||
843 | // PC: ?, Mac OK | ||
844 | static void Mix32ToFP_SIMD(float* dste,SLONG* srce,NATIVE count) | ||
845 | { | ||
846 | int remain=count; | ||
847 | |||
848 | while(!IS_ALIGNED_16(dste) || !IS_ALIGNED_16(srce)) | ||
849 | { | ||
850 | float x1; | ||
851 | EXTRACT_SAMPLE_FP(x1,FP_SHIFT); | ||
852 | CHECK_SAMPLE_FP(x1,1.0f); | ||
853 | PUT_SAMPLE_FP(x1); | ||
854 | count--; | ||
855 | if (!count) | ||
856 | { | ||
857 | return; | ||
858 | } | ||
859 | } | ||
860 | |||
861 | remain = count&7; | ||
862 | |||
863 | const float k = ((1.0f / 32768.0f) / (1 << FP_SHIFT)); | ||
864 | simd_m128 x1, x2; | ||
865 | simd_m128 xk = LOAD_PS1_SIMD(&k); // Scale factor | ||
866 | |||
867 | for(count>>=3;count;count--) { | ||
868 | EXTRACT_SAMPLE_SIMD_F(srce, x1, FP_SHIFT, xk); // Load 4 samples | ||
869 | EXTRACT_SAMPLE_SIMD_F(srce+4, x2, FP_SHIFT, xk); // Load 4 samples | ||
870 | PUT_SAMPLE_SIMD_F(dste, x1); // Store 4 samples | ||
871 | PUT_SAMPLE_SIMD_F(dste+4, x2); // Store 4 samples | ||
872 | srce+=8; | ||
873 | dste+=8; | ||
874 | } | ||
875 | |||
876 | if (remain&4) { | ||
877 | EXTRACT_SAMPLE_SIMD_F(srce, x1, FP_SHIFT, xk); // Load 4 samples | ||
878 | PUT_SAMPLE_SIMD_F(dste, x1); // Store 4 samples | ||
879 | srce+=4; | ||
880 | dste+=4; | ||
881 | remain &= 3; | ||
882 | } | ||
883 | |||
884 | while(remain--) { | ||
885 | float x1; | ||
886 | EXTRACT_SAMPLE_FP(x1,FP_SHIFT); | ||
887 | CHECK_SAMPLE_FP(x1,1.0f); | ||
888 | PUT_SAMPLE_FP(x1); | ||
889 | } | ||
890 | } | ||
891 | // PC: Ok, Mac Ok | ||
892 | static void Mix32To16_SIMD(SWORD* dste,SLONG* srce,NATIVE count) | ||
893 | { | ||
894 | int remain = count; | ||
895 | |||
896 | while(!IS_ALIGNED_16(dste) || !IS_ALIGNED_16(srce)) | ||
897 | { | ||
898 | SLONG x1; | ||
899 | EXTRACT_SAMPLE(x1,16); | ||
900 | CHECK_SAMPLE(x1,32768); | ||
901 | PUT_SAMPLE(x1); | ||
902 | count--; | ||
903 | if (!count) | ||
904 | { | ||
905 | return; | ||
906 | } | ||
907 | } | ||
908 | |||
909 | remain = count&7; | ||
910 | |||
911 | for(count>>=3;count;count--) | ||
912 | { | ||
913 | simd_m128i x1,x2; | ||
914 | EXTRACT_SAMPLE_SIMD_16(srce, x1); // Load 4 samples | ||
915 | EXTRACT_SAMPLE_SIMD_16(srce+4, x2); // Load 4 samples | ||
916 | PUT_SAMPLE_SIMD_W(dste, x1, x2); // Store 8 samples | ||
917 | srce+=8; | ||
918 | dste+=8; | ||
919 | } | ||
920 | |||
921 | if (remain) | ||
922 | Mix32To16(dste, srce, remain); | ||
923 | } | ||
924 | |||
925 | // Mix 32bit input to 8bit. 128 samples per iteration | ||
926 | // PC:OK, Mac: Ok | ||
927 | static void Mix32To8_SIMD(SBYTE* dste,SLONG* srce,NATIVE count) | ||
928 | { | ||
929 | int remain=count; | ||
930 | |||
931 | while(!IS_ALIGNED_16(dste) || !IS_ALIGNED_16(srce)) | ||
932 | { | ||
933 | SWORD x1; | ||
934 | EXTRACT_SAMPLE(x1,8); | ||
935 | CHECK_SAMPLE(x1,128); | ||
936 | PUT_SAMPLE(x1+128); | ||
937 | count--; | ||
938 | if (!count) | ||
939 | { | ||
940 | return; | ||
941 | } | ||
942 | } | ||
943 | |||
944 | remain = count&15; | ||
945 | |||
946 | for(count>>=4;count;count--) { | ||
947 | simd_m128i x1,x2,x3,x4; | ||
948 | EXTRACT_SAMPLE_SIMD_8(srce, x1); // Load 4 samples | ||
949 | EXTRACT_SAMPLE_SIMD_8(srce+4, x2); // Load 4 samples | ||
950 | EXTRACT_SAMPLE_SIMD_8(srce+8, x3); // Load 4 samples | ||
951 | EXTRACT_SAMPLE_SIMD_8(srce+12, x4); // Load 4 samples | ||
952 | PUT_SAMPLE_SIMD_B(dste, x1, x2, x3, x4); // Store 16 samples | ||
953 | srce+=16; | ||
954 | dste+=16; | ||
955 | } | ||
956 | if (remain) | ||
957 | Mix32To8(dste, srce, remain); | ||
958 | } | ||
959 | |||
960 | #endif | ||
961 | |||
962 | |||
963 | |||
964 | static void AddChannel(SLONG* ptr,NATIVE todo) | ||
965 | { | ||
966 | SLONGLONG end,done; | ||
967 | SWORD *s; | ||
968 | |||
969 | if(!(s=Samples[vnf->handle])) { | ||
970 | vnf->current = vnf->active = 0; | ||
971 | return; | ||
972 | } | ||
973 | |||
974 | /* update the 'current' index so the sample loops, or stops playing if it | ||
975 | reached the end of the sample */ | ||
976 | while(todo>0) { | ||
977 | SLONGLONG endpos; | ||
978 | |||
979 | if(vnf->flags & SF_REVERSE) { | ||
980 | /* The sample is playing in reverse */ | ||
981 | if((vnf->flags&SF_LOOP)&&(vnf->current<idxlpos)) { | ||
982 | /* the sample is looping and has reached the loopstart index */ | ||
983 | if(vnf->flags & SF_BIDI) { | ||
984 | /* sample is doing bidirectional loops, so 'bounce' the | ||
985 | current index against the idxlpos */ | ||
986 | vnf->current = idxlpos+(idxlpos-vnf->current); | ||
987 | vnf->flags &= ~SF_REVERSE; | ||
988 | vnf->increment = -vnf->increment; | ||
989 | } else | ||
990 | /* normal backwards looping, so set the current position to | ||
991 | loopend index */ | ||
992 | vnf->current=idxlend-(idxlpos-vnf->current); | ||
993 | } else { | ||
994 | /* the sample is not looping, so check if it reached index 0 */ | ||
995 | if(vnf->current < 0) { | ||
996 | /* playing index reached 0, so stop playing this sample */ | ||
997 | vnf->current = vnf->active = 0; | ||
998 | break; | ||
999 | } | ||
1000 | } | ||
1001 | } else { | ||
1002 | /* The sample is playing forward */ | ||
1003 | if((vnf->flags & SF_LOOP) && | ||
1004 | (vnf->current >= idxlend)) { | ||
1005 | /* the sample is looping, check the loopend index */ | ||
1006 | if(vnf->flags & SF_BIDI) { | ||
1007 | /* sample is doing bidirectional loops, so 'bounce' the | ||
1008 | current index against the idxlend */ | ||
1009 | vnf->flags |= SF_REVERSE; | ||
1010 | vnf->increment = -vnf->increment; | ||
1011 | vnf->current = idxlend-(vnf->current-idxlend); | ||
1012 | } else | ||
1013 | /* normal backwards looping, so set the current position | ||
1014 | to loopend index */ | ||
1015 | vnf->current=idxlpos+(vnf->current-idxlend); | ||
1016 | } else { | ||
1017 | /* sample is not looping, so check if it reached the last | ||
1018 | position */ | ||
1019 | if(vnf->current >= idxsize) { | ||
1020 | /* yes, so stop playing this sample */ | ||
1021 | vnf->current = vnf->active = 0; | ||
1022 | break; | ||
1023 | } | ||
1024 | } | ||
1025 | } | ||
1026 | |||
1027 | end=(vnf->flags&SF_REVERSE)?(vnf->flags&SF_LOOP)?idxlpos:0: | ||
1028 | (vnf->flags&SF_LOOP)?idxlend:idxsize; | ||
1029 | |||
1030 | /* if the sample is not blocked... */ | ||
1031 | if((end==vnf->current)||(!vnf->increment)) | ||
1032 | done=0; | ||
1033 | else { | ||
1034 | done=MIN((end-vnf->current)/vnf->increment+1,todo); | ||
1035 | if(done<0) done=0; | ||
1036 | } | ||
1037 | |||
1038 | if(!done) { | ||
1039 | vnf->active = 0; | ||
1040 | break; | ||
1041 | } | ||
1042 | |||
1043 | endpos=vnf->current+done*vnf->increment; | ||
1044 | |||
1045 | if(vnf->vol) { | ||
1046 | #ifndef NATIVE_64BIT_INT | ||
1047 | /* use the 32 bit mixers as often as we can (they're much faster) */ | ||
1048 | if((vnf->current<0x7fffffff)&&(endpos<0x7fffffff)) { | ||
1049 | if((md_mode & DMODE_INTERP)) { | ||
1050 | if(vc_mode & DMODE_STEREO) { | ||
1051 | if((vnf->pan==PAN_SURROUND)&&(md_mode&DMODE_SURROUND)) | ||
1052 | vnf->current=Mix32SurroundInterp | ||
1053 | (s,ptr,vnf->current,vnf->increment,done); | ||
1054 | else | ||
1055 | vnf->current=Mix32StereoInterp | ||
1056 | (s,ptr,vnf->current,vnf->increment,done); | ||
1057 | } else | ||
1058 | vnf->current=Mix32MonoInterp | ||
1059 | (s,ptr,vnf->current,vnf->increment,done); | ||
1060 | } else if(vc_mode & DMODE_STEREO) { | ||
1061 | if((vnf->pan==PAN_SURROUND)&&(md_mode&DMODE_SURROUND)) | ||
1062 | vnf->current=Mix32SurroundNormal | ||
1063 | (s,ptr,vnf->current,vnf->increment,done); | ||
1064 | else | ||
1065 | { | ||
1066 | #if defined HAVE_ALTIVEC || defined HAVE_SSE2 | ||
1067 | if (md_mode & DMODE_SIMDMIXER) | ||
1068 | vnf->current=MixSIMDStereoNormal | ||
1069 | (s,ptr,vnf->current,vnf->increment,done); | ||
1070 | |||
1071 | else | ||
1072 | #endif | ||
1073 | vnf->current=Mix32StereoNormal | ||
1074 | (s,ptr,vnf->current,vnf->increment,done); | ||
1075 | } | ||
1076 | } else | ||
1077 | vnf->current=Mix32MonoNormal | ||
1078 | (s,ptr,vnf->current,vnf->increment,done); | ||
1079 | } else | ||
1080 | #endif | ||
1081 | { | ||
1082 | if((md_mode & DMODE_INTERP)) { | ||
1083 | if(vc_mode & DMODE_STEREO) { | ||
1084 | if((vnf->pan==PAN_SURROUND)&&(md_mode&DMODE_SURROUND)) | ||
1085 | vnf->current=MixSurroundInterp | ||
1086 | (s,ptr,vnf->current,vnf->increment,done); | ||
1087 | else | ||
1088 | vnf->current=MixStereoInterp | ||
1089 | (s,ptr,vnf->current,vnf->increment,done); | ||
1090 | } else | ||
1091 | vnf->current=MixMonoInterp | ||
1092 | (s,ptr,vnf->current,vnf->increment,done); | ||
1093 | } else if(vc_mode & DMODE_STEREO) { | ||
1094 | if((vnf->pan==PAN_SURROUND)&&(md_mode&DMODE_SURROUND)) | ||
1095 | vnf->current=MixSurroundNormal | ||
1096 | (s,ptr,vnf->current,vnf->increment,done); | ||
1097 | else | ||
1098 | { | ||
1099 | #if defined HAVE_ALTIVEC || defined HAVE_SSE2 | ||
1100 | if (md_mode & DMODE_SIMDMIXER) | ||
1101 | vnf->current=MixSIMDStereoNormal | ||
1102 | (s,ptr,vnf->current,vnf->increment,done); | ||
1103 | |||
1104 | else | ||
1105 | #endif | ||
1106 | vnf->current=MixStereoNormal | ||
1107 | (s,ptr,vnf->current,vnf->increment,done); | ||
1108 | } | ||
1109 | } else | ||
1110 | vnf->current=MixMonoNormal | ||
1111 | (s,ptr,vnf->current,vnf->increment,done); | ||
1112 | } | ||
1113 | } else | ||
1114 | /* update sample position */ | ||
1115 | vnf->current=endpos; | ||
1116 | |||
1117 | todo-=done; | ||
1118 | ptr +=(vc_mode & DMODE_STEREO)?(done<<1):done; | ||
1119 | } | ||
1120 | } | ||
1121 | |||
1122 | #define _IN_VIRTCH_ | ||
1123 | #include "virtch_common.c" | ||
1124 | #undef _IN_VIRTCH_ | ||
1125 | |||
1126 | void VC1_WriteSamples(SBYTE* buf,ULONG todo) | ||
1127 | { | ||
1128 | int left,portion=0,count; | ||
1129 | SBYTE *buffer; | ||
1130 | int t, pan, vol; | ||
1131 | |||
1132 | while(todo) { | ||
1133 | if(!tickleft) { | ||
1134 | if(vc_mode & DMODE_SOFT_MUSIC) md_player(); | ||
1135 | tickleft=(md_mixfreq*125L)/(md_bpm*50L); | ||
1136 | } | ||
1137 | left = MIN(tickleft, todo); | ||
1138 | buffer = buf; | ||
1139 | tickleft -= left; | ||
1140 | todo -= left; | ||
1141 | buf += samples2bytes(left); | ||
1142 | |||
1143 | while(left) { | ||
1144 | portion = MIN(left, samplesthatfit); | ||
1145 | count = (vc_mode & DMODE_STEREO)?(portion<<1):portion; | ||
1146 | memset(vc_tickbuf, 0, count<<2); | ||
1147 | for(t=0;t<vc_softchn;t++) { | ||
1148 | vnf = &vinf[t]; | ||
1149 | |||
1150 | if(vnf->kick) { | ||
1151 | vnf->current=((SLONGLONG)vnf->start)<<FRACBITS; | ||
1152 | vnf->kick =0; | ||
1153 | vnf->active =1; | ||
1154 | } | ||
1155 | |||
1156 | if(!vnf->frq) vnf->active = 0; | ||
1157 | |||
1158 | if(vnf->active) { | ||
1159 | vnf->increment=((SLONGLONG)(vnf->frq<<FRACBITS))/md_mixfreq; | ||
1160 | if(vnf->flags&SF_REVERSE) vnf->increment=-vnf->increment; | ||
1161 | vol = vnf->vol; pan = vnf->pan; | ||
1162 | |||
1163 | vnf->oldlvol=vnf->lvolsel;vnf->oldrvol=vnf->rvolsel; | ||
1164 | if(vc_mode & DMODE_STEREO) { | ||
1165 | if(pan != PAN_SURROUND) { | ||
1166 | vnf->lvolsel=(vol*(PAN_RIGHT-pan))>>8; | ||
1167 | vnf->rvolsel=(vol*pan)>>8; | ||
1168 | } else | ||
1169 | vnf->lvolsel=vnf->rvolsel=vol/2; | ||
1170 | } else | ||
1171 | vnf->lvolsel=vol; | ||
1172 | |||
1173 | idxsize = (vnf->size)? ((SLONGLONG)vnf->size << FRACBITS)-1 : 0; | ||
1174 | idxlend = (vnf->repend)? ((SLONGLONG)vnf->repend << FRACBITS)-1 : 0; | ||
1175 | idxlpos = (SLONGLONG)vnf->reppos << FRACBITS; | ||
1176 | AddChannel(vc_tickbuf, portion); | ||
1177 | } | ||
1178 | } | ||
1179 | |||
1180 | if(md_mode & DMODE_NOISEREDUCTION) { | ||
1181 | MixLowPass(vc_tickbuf, portion); | ||
1182 | } | ||
1183 | |||
1184 | if(md_reverb) { | ||
1185 | if(md_reverb>15) md_reverb=15; | ||
1186 | MixReverb(vc_tickbuf, portion); | ||
1187 | } | ||
1188 | |||
1189 | if (vc_callback) { | ||
1190 | vc_callback((unsigned char*)vc_tickbuf, portion); | ||
1191 | } | ||
1192 | |||
1193 | |||
1194 | #if defined HAVE_ALTIVEC || defined HAVE_SSE2 | ||
1195 | if (md_mode & DMODE_SIMDMIXER) | ||
1196 | { | ||
1197 | if(vc_mode & DMODE_FLOAT) | ||
1198 | Mix32ToFP_SIMD((float*) buffer, vc_tickbuf, count); | ||
1199 | else if(vc_mode & DMODE_16BITS) | ||
1200 | Mix32To16_SIMD((SWORD*) buffer, vc_tickbuf, count); | ||
1201 | else | ||
1202 | Mix32To8_SIMD((SBYTE*) buffer, vc_tickbuf, count); | ||
1203 | } | ||
1204 | else | ||
1205 | #endif | ||
1206 | { | ||
1207 | if(vc_mode & DMODE_FLOAT) | ||
1208 | Mix32ToFP((float*) buffer, vc_tickbuf, count); | ||
1209 | else if(vc_mode & DMODE_16BITS) | ||
1210 | Mix32To16((SWORD*) buffer, vc_tickbuf, count); | ||
1211 | else | ||
1212 | Mix32To8((SBYTE*) buffer, vc_tickbuf, count); | ||
1213 | } | ||
1214 | buffer += samples2bytes(portion); | ||
1215 | left -= portion; | ||
1216 | } | ||
1217 | } | ||
1218 | } | ||
1219 | |||
1220 | int VC1_Init(void) | ||
1221 | { | ||
1222 | VC_SetupPointers(); | ||
1223 | |||
1224 | //if (md_mode&DMODE_HQMIXER) | ||
1225 | // return VC2_Init(); | ||
1226 | |||
1227 | if(!(Samples=(SWORD**)MikMod_calloc(MAXSAMPLEHANDLES,sizeof(SWORD*)))) { | ||
1228 | _mm_errno = MMERR_INITIALIZING_MIXER; | ||
1229 | return 1; | ||
1230 | } | ||
1231 | if(!vc_tickbuf) | ||
1232 | if(!(vc_tickbuf=(SLONG*)MikMod_malloc((TICKLSIZE+32)*sizeof(SLONG)))) { | ||
1233 | _mm_errno = MMERR_INITIALIZING_MIXER; | ||
1234 | return 1; | ||
1235 | } | ||
1236 | |||
1237 | MixReverb=(md_mode&DMODE_STEREO)?MixReverb_Stereo:MixReverb_Normal; | ||
1238 | MixLowPass=(md_mode&DMODE_STEREO)?MixLowPass_Stereo:MixLowPass_Normal; | ||
1239 | vc_mode = md_mode; | ||
1240 | return 0; | ||
1241 | } | ||
1242 | |||
1243 | int VC1_PlayStart(void) | ||
1244 | { | ||
1245 | samplesthatfit=TICKLSIZE; | ||
1246 | if(vc_mode & DMODE_STEREO) samplesthatfit >>= 1; | ||
1247 | tickleft = 0; | ||
1248 | |||
1249 | RVc1 = (5000L * md_mixfreq) / REVERBERATION; | ||
1250 | RVc2 = (5078L * md_mixfreq) / REVERBERATION; | ||
1251 | RVc3 = (5313L * md_mixfreq) / REVERBERATION; | ||
1252 | RVc4 = (5703L * md_mixfreq) / REVERBERATION; | ||
1253 | RVc5 = (6250L * md_mixfreq) / REVERBERATION; | ||
1254 | RVc6 = (6953L * md_mixfreq) / REVERBERATION; | ||
1255 | RVc7 = (7813L * md_mixfreq) / REVERBERATION; | ||
1256 | RVc8 = (8828L * md_mixfreq) / REVERBERATION; | ||
1257 | |||
1258 | if(!(RVbufL1=(SLONG*)MikMod_calloc((RVc1+1),sizeof(SLONG)))) return 1; | ||
1259 | if(!(RVbufL2=(SLONG*)MikMod_calloc((RVc2+1),sizeof(SLONG)))) return 1; | ||
1260 | if(!(RVbufL3=(SLONG*)MikMod_calloc((RVc3+1),sizeof(SLONG)))) return 1; | ||
1261 | if(!(RVbufL4=(SLONG*)MikMod_calloc((RVc4+1),sizeof(SLONG)))) return 1; | ||
1262 | if(!(RVbufL5=(SLONG*)MikMod_calloc((RVc5+1),sizeof(SLONG)))) return 1; | ||
1263 | if(!(RVbufL6=(SLONG*)MikMod_calloc((RVc6+1),sizeof(SLONG)))) return 1; | ||
1264 | if(!(RVbufL7=(SLONG*)MikMod_calloc((RVc7+1),sizeof(SLONG)))) return 1; | ||
1265 | if(!(RVbufL8=(SLONG*)MikMod_calloc((RVc8+1),sizeof(SLONG)))) return 1; | ||
1266 | |||
1267 | if(!(RVbufR1=(SLONG*)MikMod_calloc((RVc1+1),sizeof(SLONG)))) return 1; | ||
1268 | if(!(RVbufR2=(SLONG*)MikMod_calloc((RVc2+1),sizeof(SLONG)))) return 1; | ||
1269 | if(!(RVbufR3=(SLONG*)MikMod_calloc((RVc3+1),sizeof(SLONG)))) return 1; | ||
1270 | if(!(RVbufR4=(SLONG*)MikMod_calloc((RVc4+1),sizeof(SLONG)))) return 1; | ||
1271 | if(!(RVbufR5=(SLONG*)MikMod_calloc((RVc5+1),sizeof(SLONG)))) return 1; | ||
1272 | if(!(RVbufR6=(SLONG*)MikMod_calloc((RVc6+1),sizeof(SLONG)))) return 1; | ||
1273 | if(!(RVbufR7=(SLONG*)MikMod_calloc((RVc7+1),sizeof(SLONG)))) return 1; | ||
1274 | if(!(RVbufR8=(SLONG*)MikMod_calloc((RVc8+1),sizeof(SLONG)))) return 1; | ||
1275 | |||
1276 | RVRindex = 0; | ||
1277 | return 0; | ||
1278 | } | ||
1279 | |||
1280 | void VC1_PlayStop(void) | ||
1281 | { | ||
1282 | if(RVbufL1) MikMod_free(RVbufL1); | ||
1283 | if(RVbufL2) MikMod_free(RVbufL2); | ||
1284 | if(RVbufL3) MikMod_free(RVbufL3); | ||
1285 | if(RVbufL4) MikMod_free(RVbufL4); | ||
1286 | if(RVbufL5) MikMod_free(RVbufL5); | ||
1287 | if(RVbufL6) MikMod_free(RVbufL6); | ||
1288 | if(RVbufL7) MikMod_free(RVbufL7); | ||
1289 | if(RVbufL8) MikMod_free(RVbufL8); | ||
1290 | RVbufL1=RVbufL2=RVbufL3=RVbufL4=RVbufL5=RVbufL6=RVbufL7=RVbufL8=NULL; | ||
1291 | if(RVbufR1) MikMod_free(RVbufR1); | ||
1292 | if(RVbufR2) MikMod_free(RVbufR2); | ||
1293 | if(RVbufR3) MikMod_free(RVbufR3); | ||
1294 | if(RVbufR4) MikMod_free(RVbufR4); | ||
1295 | if(RVbufR5) MikMod_free(RVbufR5); | ||
1296 | if(RVbufR6) MikMod_free(RVbufR6); | ||
1297 | if(RVbufR7) MikMod_free(RVbufR7); | ||
1298 | if(RVbufR8) MikMod_free(RVbufR8); | ||
1299 | RVbufR1=RVbufR2=RVbufR3=RVbufR4=RVbufR5=RVbufR6=RVbufR7=RVbufR8=NULL; | ||
1300 | } | ||
1301 | |||
1302 | int VC1_SetNumVoices(void) | ||
1303 | { | ||
1304 | int t; | ||
1305 | |||
1306 | if(!(vc_softchn=md_softchn)) return 0; | ||
1307 | |||
1308 | if(vinf) MikMod_free(vinf); | ||
1309 | if(!(vinf= MikMod_calloc(sizeof(VINFO),vc_softchn))) return 1; | ||
1310 | |||
1311 | for(t=0;t<vc_softchn;t++) { | ||
1312 | vinf[t].frq=10000; | ||
1313 | vinf[t].pan=(t&1)?PAN_LEFT:PAN_RIGHT; | ||
1314 | } | ||
1315 | |||
1316 | return 0; | ||
1317 | } | ||
1318 | |||
1319 | /* ex:set ts=4: */ | ||
diff --git a/apps/plugins/mikmod/virtch_common.c b/apps/plugins/mikmod/virtch_common.c new file mode 100644 index 0000000000..522f4509f0 --- /dev/null +++ b/apps/plugins/mikmod/virtch_common.c | |||
@@ -0,0 +1,464 @@ | |||
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: virtch_common.c,v 1.2 2005/03/30 19:11:50 realtech Exp $ | ||
24 | |||
25 | Common source parts between the two software mixers. | ||
26 | This file is probably the ugliest part of libmikmod... | ||
27 | |||
28 | ==============================================================================*/ | ||
29 | |||
30 | #ifndef _IN_VIRTCH_ | ||
31 | |||
32 | #include "mikmod_internals.h" | ||
33 | |||
34 | extern int VC1_Init(void); | ||
35 | //extern int VC2_Init(void); | ||
36 | static int (*VC_Init_ptr)(void)=VC1_Init; | ||
37 | extern void VC1_Exit(void); | ||
38 | //extern void VC2_Exit(void); | ||
39 | static void (*VC_Exit_ptr)(void)=VC1_Exit; | ||
40 | extern int VC1_SetNumVoices(void); | ||
41 | //extern int VC2_SetNumVoices(void); | ||
42 | static int (*VC_SetNumVoices_ptr)(void); | ||
43 | extern ULONG VC1_SampleSpace(int); | ||
44 | //extern ULONG VC2_SampleSpace(int); | ||
45 | static ULONG (*VC_SampleSpace_ptr)(int); | ||
46 | extern ULONG VC1_SampleLength(int,SAMPLE*); | ||
47 | //extern ULONG VC2_SampleLength(int,SAMPLE*); | ||
48 | static ULONG (*VC_SampleLength_ptr)(int,SAMPLE*); | ||
49 | |||
50 | extern int VC1_PlayStart(void); | ||
51 | //extern int VC2_PlayStart(void); | ||
52 | static int (*VC_PlayStart_ptr)(void); | ||
53 | extern void VC1_PlayStop(void); | ||
54 | extern void VC2_PlayStop(void); | ||
55 | static void (*VC_PlayStop_ptr)(void); | ||
56 | |||
57 | extern SWORD VC1_SampleLoad(struct SAMPLOAD*,int); | ||
58 | //extern SWORD VC2_SampleLoad(struct SAMPLOAD*,int); | ||
59 | static SWORD (*VC_SampleLoad_ptr)(struct SAMPLOAD*,int); | ||
60 | extern void VC1_SampleUnload(SWORD); | ||
61 | //extern void VC2_SampleUnload(SWORD); | ||
62 | static void (*VC_SampleUnload_ptr)(SWORD); | ||
63 | |||
64 | extern ULONG VC1_WriteBytes(SBYTE*,ULONG); | ||
65 | //extern ULONG VC2_WriteBytes(SBYTE*,ULONG); | ||
66 | static ULONG (*VC_WriteBytes_ptr)(SBYTE*,ULONG); | ||
67 | extern ULONG VC1_SilenceBytes(SBYTE*,ULONG); | ||
68 | //extern ULONG VC2_SilenceBytes(SBYTE*,ULONG); | ||
69 | static ULONG (*VC_SilenceBytes_ptr)(SBYTE*,ULONG); | ||
70 | |||
71 | extern void VC1_VoiceSetVolume(UBYTE,UWORD); | ||
72 | //extern void VC2_VoiceSetVolume(UBYTE,UWORD); | ||
73 | static void (*VC_VoiceSetVolume_ptr)(UBYTE,UWORD); | ||
74 | extern UWORD VC1_VoiceGetVolume(UBYTE); | ||
75 | //extern UWORD VC2_VoiceGetVolume(UBYTE); | ||
76 | static UWORD (*VC_VoiceGetVolume_ptr)(UBYTE); | ||
77 | extern void VC1_VoiceSetFrequency(UBYTE,ULONG); | ||
78 | //extern void VC2_VoiceSetFrequency(UBYTE,ULONG); | ||
79 | static void (*VC_VoiceSetFrequency_ptr)(UBYTE,ULONG); | ||
80 | extern ULONG VC1_VoiceGetFrequency(UBYTE); | ||
81 | //extern ULONG VC2_VoiceGetFrequency(UBYTE); | ||
82 | static ULONG (*VC_VoiceGetFrequency_ptr)(UBYTE); | ||
83 | extern void VC1_VoiceSetPanning(UBYTE,ULONG); | ||
84 | //extern void VC2_VoiceSetPanning(UBYTE,ULONG); | ||
85 | static void (*VC_VoiceSetPanning_ptr)(UBYTE,ULONG); | ||
86 | extern ULONG VC1_VoiceGetPanning(UBYTE); | ||
87 | //extern ULONG VC2_VoiceGetPanning(UBYTE); | ||
88 | static ULONG (*VC_VoiceGetPanning_ptr)(UBYTE); | ||
89 | extern void VC1_VoicePlay(UBYTE,SWORD,ULONG,ULONG,ULONG,ULONG,UWORD); | ||
90 | //extern void VC2_VoicePlay(UBYTE,SWORD,ULONG,ULONG,ULONG,ULONG,UWORD); | ||
91 | static void (*VC_VoicePlay_ptr)(UBYTE,SWORD,ULONG,ULONG,ULONG,ULONG,UWORD); | ||
92 | |||
93 | extern void VC1_VoiceStop(UBYTE); | ||
94 | //extern void VC2_VoiceStop(UBYTE); | ||
95 | static void (*VC_VoiceStop_ptr)(UBYTE); | ||
96 | extern int VC1_VoiceStopped(UBYTE); | ||
97 | //extern int VC2_VoiceStopped(UBYTE); | ||
98 | static int (*VC_VoiceStopped_ptr)(UBYTE); | ||
99 | extern SLONG VC1_VoiceGetPosition(UBYTE); | ||
100 | //extern SLONG VC2_VoiceGetPosition(UBYTE); | ||
101 | static SLONG (*VC_VoiceGetPosition_ptr)(UBYTE); | ||
102 | extern ULONG VC1_VoiceRealVolume(UBYTE); | ||
103 | //extern ULONG VC2_VoiceRealVolume(UBYTE); | ||
104 | static ULONG (*VC_VoiceRealVolume_ptr)(UBYTE); | ||
105 | |||
106 | #if defined __STDC__ || defined _MSC_VER || defined MPW_C | ||
107 | #define VC_PROC0(suffix) \ | ||
108 | MIKMODAPI void VC_##suffix (void) { VC_##suffix##_ptr(); } | ||
109 | |||
110 | #define VC_FUNC0(suffix,ret) \ | ||
111 | MIKMODAPI ret VC_##suffix (void) { return VC_##suffix##_ptr(); } | ||
112 | |||
113 | #define VC_PROC1(suffix,typ1) \ | ||
114 | MIKMODAPI void VC_##suffix (typ1 a) { VC_##suffix##_ptr(a); } | ||
115 | |||
116 | #define VC_FUNC1(suffix,ret,typ1) \ | ||
117 | MIKMODAPI ret VC_##suffix (typ1 a) { return VC_##suffix##_ptr(a); } | ||
118 | |||
119 | #define VC_PROC2(suffix,typ1,typ2) \ | ||
120 | MIKMODAPI void VC_##suffix (typ1 a,typ2 b) { VC_##suffix##_ptr(a,b); } | ||
121 | |||
122 | #define VC_FUNC2(suffix,ret,typ1,typ2) \ | ||
123 | MIKMODAPI ret VC_##suffix (typ1 a,typ2 b) { return VC_##suffix##_ptr(a,b); } | ||
124 | #else | ||
125 | #define VC_PROC0(suffix) \ | ||
126 | MIKMODAPI void VC_/**/suffix (void) { VC_/**/suffix/**/_ptr(); } | ||
127 | |||
128 | #define VC_FUNC0(suffix,ret) \ | ||
129 | MIKMODAPI ret VC_/**/suffix (void) { return VC_/**/suffix/**/_ptr(); } | ||
130 | |||
131 | #define VC_PROC1(suffix,typ1) \ | ||
132 | MIKMODAPI void VC_/**/suffix (typ1 a) { VC_/**/suffix/**/_ptr(a); } | ||
133 | |||
134 | #define VC_FUNC1(suffix,ret,typ1) \ | ||
135 | MIKMODAPI ret VC_/**/suffix (typ1 a) { return VC_/**/suffix/**/_ptr(a); } | ||
136 | |||
137 | #define VC_PROC2(suffix,typ1,typ2) \ | ||
138 | MIKMODAPI void VC_/**/suffix (typ1 a,typ2 b) { VC_/**/suffix/**/_ptr(a,b); } | ||
139 | |||
140 | #define VC_FUNC2(suffix,ret,typ1,typ2) \ | ||
141 | MIKMODAPI ret VC_/**/suffix (typ1 a,typ2 b) { return VC_/**/suffix/**/_ptr(a,b); } | ||
142 | #endif | ||
143 | |||
144 | VC_FUNC0(Init,int) | ||
145 | VC_PROC0(Exit) | ||
146 | VC_FUNC0(SetNumVoices,int) | ||
147 | VC_FUNC1(SampleSpace,ULONG,int) | ||
148 | VC_FUNC2(SampleLength,ULONG,int,SAMPLE*) | ||
149 | VC_FUNC0(PlayStart,int) | ||
150 | VC_PROC0(PlayStop) | ||
151 | VC_FUNC2(SampleLoad,SWORD,struct SAMPLOAD*,int) | ||
152 | VC_PROC1(SampleUnload,SWORD) | ||
153 | VC_FUNC2(WriteBytes,ULONG,SBYTE*,ULONG) | ||
154 | VC_FUNC2(SilenceBytes,ULONG,SBYTE*,ULONG) | ||
155 | VC_PROC2(VoiceSetVolume,UBYTE,UWORD) | ||
156 | VC_FUNC1(VoiceGetVolume,UWORD,UBYTE) | ||
157 | VC_PROC2(VoiceSetFrequency,UBYTE,ULONG) | ||
158 | VC_FUNC1(VoiceGetFrequency,ULONG,UBYTE) | ||
159 | VC_PROC2(VoiceSetPanning,UBYTE,ULONG) | ||
160 | VC_FUNC1(VoiceGetPanning,ULONG,UBYTE) | ||
161 | |||
162 | void VC_VoicePlay(UBYTE a,SWORD b,ULONG c,ULONG d,ULONG e,ULONG f,UWORD g) | ||
163 | { VC_VoicePlay_ptr(a,b,c,d,e,f,g); } | ||
164 | |||
165 | VC_PROC1(VoiceStop,UBYTE) | ||
166 | VC_FUNC1(VoiceStopped,int,UBYTE) | ||
167 | VC_FUNC1(VoiceGetPosition,SLONG,UBYTE) | ||
168 | VC_FUNC1(VoiceRealVolume,ULONG,UBYTE) | ||
169 | |||
170 | void VC_SetupPointers(void) | ||
171 | { | ||
172 | /* | ||
173 | if (md_mode&DMODE_HQMIXER) { | ||
174 | VC_Init_ptr=VC2_Init; | ||
175 | VC_Exit_ptr=VC2_Exit; | ||
176 | VC_SetNumVoices_ptr=VC2_SetNumVoices; | ||
177 | VC_SampleSpace_ptr=VC2_SampleSpace; | ||
178 | VC_SampleLength_ptr=VC2_SampleLength; | ||
179 | VC_PlayStart_ptr=VC2_PlayStart; | ||
180 | VC_PlayStop_ptr=VC2_PlayStop; | ||
181 | VC_SampleLoad_ptr=VC2_SampleLoad; | ||
182 | VC_SampleUnload_ptr=VC2_SampleUnload; | ||
183 | VC_WriteBytes_ptr=VC2_WriteBytes; | ||
184 | VC_SilenceBytes_ptr=VC2_SilenceBytes; | ||
185 | VC_VoiceSetVolume_ptr=VC2_VoiceSetVolume; | ||
186 | VC_VoiceGetVolume_ptr=VC2_VoiceGetVolume; | ||
187 | VC_VoiceSetFrequency_ptr=VC2_VoiceSetFrequency; | ||
188 | VC_VoiceGetFrequency_ptr=VC2_VoiceGetFrequency; | ||
189 | VC_VoiceSetPanning_ptr=VC2_VoiceSetPanning; | ||
190 | VC_VoiceGetPanning_ptr=VC2_VoiceGetPanning; | ||
191 | VC_VoicePlay_ptr=VC2_VoicePlay; | ||
192 | VC_VoiceStop_ptr=VC2_VoiceStop; | ||
193 | VC_VoiceStopped_ptr=VC2_VoiceStopped; | ||
194 | VC_VoiceGetPosition_ptr=VC2_VoiceGetPosition; | ||
195 | VC_VoiceRealVolume_ptr=VC2_VoiceRealVolume; | ||
196 | } else { | ||
197 | */ | ||
198 | VC_Init_ptr=VC1_Init; | ||
199 | VC_Exit_ptr=VC1_Exit; | ||
200 | VC_SetNumVoices_ptr=VC1_SetNumVoices; | ||
201 | VC_SampleSpace_ptr=VC1_SampleSpace; | ||
202 | VC_SampleLength_ptr=VC1_SampleLength; | ||
203 | VC_PlayStart_ptr=VC1_PlayStart; | ||
204 | VC_PlayStop_ptr=VC1_PlayStop; | ||
205 | VC_SampleLoad_ptr=VC1_SampleLoad; | ||
206 | VC_SampleUnload_ptr=VC1_SampleUnload; | ||
207 | VC_WriteBytes_ptr=VC1_WriteBytes; | ||
208 | VC_SilenceBytes_ptr=VC1_SilenceBytes; | ||
209 | VC_VoiceSetVolume_ptr=VC1_VoiceSetVolume; | ||
210 | VC_VoiceGetVolume_ptr=VC1_VoiceGetVolume; | ||
211 | VC_VoiceSetFrequency_ptr=VC1_VoiceSetFrequency; | ||
212 | VC_VoiceGetFrequency_ptr=VC1_VoiceGetFrequency; | ||
213 | VC_VoiceSetPanning_ptr=VC1_VoiceSetPanning; | ||
214 | VC_VoiceGetPanning_ptr=VC1_VoiceGetPanning; | ||
215 | VC_VoicePlay_ptr=VC1_VoicePlay; | ||
216 | VC_VoiceStop_ptr=VC1_VoiceStop; | ||
217 | VC_VoiceStopped_ptr=VC1_VoiceStopped; | ||
218 | VC_VoiceGetPosition_ptr=VC1_VoiceGetPosition; | ||
219 | VC_VoiceRealVolume_ptr=VC1_VoiceRealVolume; | ||
220 | //} | ||
221 | } | ||
222 | |||
223 | #else | ||
224 | |||
225 | #ifndef _VIRTCH_COMMON_ | ||
226 | #define _VIRTCH_COMMON_ | ||
227 | |||
228 | static ULONG samples2bytes(ULONG samples) | ||
229 | { | ||
230 | if(vc_mode & DMODE_FLOAT) samples <<= 2; | ||
231 | else if(vc_mode & DMODE_16BITS) samples <<= 1; | ||
232 | if(vc_mode & DMODE_STEREO) samples <<= 1; | ||
233 | return samples; | ||
234 | } | ||
235 | |||
236 | static ULONG bytes2samples(ULONG bytes) | ||
237 | { | ||
238 | if(vc_mode & DMODE_FLOAT) bytes >>= 2; | ||
239 | else if(vc_mode & DMODE_16BITS) bytes >>= 1; | ||
240 | if(vc_mode & DMODE_STEREO) bytes >>= 1; | ||
241 | return bytes; | ||
242 | } | ||
243 | |||
244 | /* Fill the buffer with 'todo' bytes of silence (it depends on the mixing mode | ||
245 | how the buffer is filled) */ | ||
246 | ULONG VC1_SilenceBytes(SBYTE* buf,ULONG todo) | ||
247 | { | ||
248 | todo=samples2bytes(bytes2samples(todo)); | ||
249 | |||
250 | /* clear the buffer to zero (16 bits signed) or 0x80 (8 bits unsigned) */ | ||
251 | if(vc_mode & DMODE_FLOAT) | ||
252 | memset(buf,0,todo); | ||
253 | else if(vc_mode & DMODE_16BITS) | ||
254 | memset(buf,0,todo); | ||
255 | else | ||
256 | memset(buf,0x80,todo); | ||
257 | |||
258 | return todo; | ||
259 | } | ||
260 | |||
261 | void VC1_WriteSamples(SBYTE*,ULONG); | ||
262 | |||
263 | /* Writes 'todo' mixed SBYTES (!!) to 'buf'. It returns the number of SBYTES | ||
264 | actually written to 'buf' (which is rounded to number of samples that fit | ||
265 | into 'todo' bytes). */ | ||
266 | ULONG VC1_WriteBytes(SBYTE* buf,ULONG todo) | ||
267 | { | ||
268 | if(!vc_softchn) | ||
269 | return VC1_SilenceBytes(buf,todo); | ||
270 | |||
271 | todo = bytes2samples(todo); | ||
272 | VC1_WriteSamples(buf,todo); | ||
273 | |||
274 | return samples2bytes(todo); | ||
275 | } | ||
276 | |||
277 | void VC1_Exit(void) | ||
278 | { | ||
279 | if(vc_tickbuf) MikMod_free(vc_tickbuf); | ||
280 | if(vinf) MikMod_free(vinf); | ||
281 | if(Samples) MikMod_free(Samples); | ||
282 | |||
283 | vc_tickbuf = NULL; | ||
284 | vinf = NULL; | ||
285 | Samples = NULL; | ||
286 | |||
287 | VC_SetupPointers(); | ||
288 | } | ||
289 | |||
290 | UWORD VC1_VoiceGetVolume(UBYTE voice) | ||
291 | { | ||
292 | return vinf[voice].vol; | ||
293 | } | ||
294 | |||
295 | ULONG VC1_VoiceGetPanning(UBYTE voice) | ||
296 | { | ||
297 | return vinf[voice].pan; | ||
298 | } | ||
299 | |||
300 | void VC1_VoiceSetFrequency(UBYTE voice,ULONG frq) | ||
301 | { | ||
302 | vinf[voice].frq=frq; | ||
303 | } | ||
304 | |||
305 | ULONG VC1_VoiceGetFrequency(UBYTE voice) | ||
306 | { | ||
307 | return vinf[voice].frq; | ||
308 | } | ||
309 | |||
310 | void VC1_VoicePlay(UBYTE voice,SWORD handle,ULONG start,ULONG size,ULONG reppos,ULONG repend,UWORD flags) | ||
311 | { | ||
312 | vinf[voice].flags = flags; | ||
313 | vinf[voice].handle = handle; | ||
314 | vinf[voice].start = start; | ||
315 | vinf[voice].size = size; | ||
316 | vinf[voice].reppos = reppos; | ||
317 | vinf[voice].repend = repend; | ||
318 | vinf[voice].kick = 1; | ||
319 | } | ||
320 | |||
321 | void VC1_VoiceStop(UBYTE voice) | ||
322 | { | ||
323 | vinf[voice].active = 0; | ||
324 | } | ||
325 | |||
326 | int VC1_VoiceStopped(UBYTE voice) | ||
327 | { | ||
328 | return(vinf[voice].active==0); | ||
329 | } | ||
330 | |||
331 | SLONG VC1_VoiceGetPosition(UBYTE voice) | ||
332 | { | ||
333 | return (SLONG)(vinf[voice].current>>FRACBITS); | ||
334 | } | ||
335 | |||
336 | void VC1_VoiceSetVolume(UBYTE voice,UWORD vol) | ||
337 | { | ||
338 | /* protect against clicks if volume variation is too high */ | ||
339 | if(abs((int)vinf[voice].vol-(int)vol)>32) | ||
340 | vinf[voice].rampvol=CLICK_BUFFER; | ||
341 | vinf[voice].vol=vol; | ||
342 | } | ||
343 | |||
344 | void VC1_VoiceSetPanning(UBYTE voice,ULONG pan) | ||
345 | { | ||
346 | /* protect against clicks if panning variation is too high */ | ||
347 | if(abs((int)vinf[voice].pan-(int)pan)>48) | ||
348 | vinf[voice].rampvol=CLICK_BUFFER; | ||
349 | vinf[voice].pan=pan; | ||
350 | } | ||
351 | |||
352 | /*========== External mixer interface */ | ||
353 | |||
354 | void VC1_SampleUnload(SWORD handle) | ||
355 | { | ||
356 | if (handle<MAXSAMPLEHANDLES) { | ||
357 | if (Samples[handle]) | ||
358 | MikMod_free(Samples[handle]); | ||
359 | Samples[handle]=NULL; | ||
360 | } | ||
361 | } | ||
362 | |||
363 | SWORD VC1_SampleLoad(struct SAMPLOAD* sload,int type) | ||
364 | { | ||
365 | SAMPLE *s = sload->sample; | ||
366 | int handle; | ||
367 | ULONG t, length,loopstart,loopend; | ||
368 | |||
369 | if(type==MD_HARDWARE) return -1; | ||
370 | |||
371 | /* Find empty slot to put sample address in */ | ||
372 | for(handle=0;handle<MAXSAMPLEHANDLES;handle++) | ||
373 | if(!Samples[handle]) break; | ||
374 | |||
375 | if(handle==MAXSAMPLEHANDLES) { | ||
376 | _mm_errno = MMERR_OUT_OF_HANDLES; | ||
377 | return -1; | ||
378 | } | ||
379 | |||
380 | /* Reality check for loop settings */ | ||
381 | if (s->loopend > s->length) | ||
382 | s->loopend = s->length; | ||
383 | if (s->loopstart >= s->loopend) | ||
384 | s->flags &= ~SF_LOOP; | ||
385 | |||
386 | length = s->length; | ||
387 | loopstart = s->loopstart; | ||
388 | loopend = s->loopend; | ||
389 | |||
390 | SL_SampleSigned(sload); | ||
391 | SL_Sample8to16(sload); | ||
392 | |||
393 | if(!(Samples[handle]=(SWORD*)MikMod_malloc((length+20)<<1))) { | ||
394 | _mm_errno = MMERR_SAMPLE_TOO_BIG; | ||
395 | return -1; | ||
396 | } | ||
397 | |||
398 | /* read sample into buffer */ | ||
399 | if (SL_Load(Samples[handle],sload,length)) | ||
400 | return -1; | ||
401 | |||
402 | /* Unclick sample */ | ||
403 | if(s->flags & SF_LOOP) { | ||
404 | if(s->flags & SF_BIDI) | ||
405 | for(t=0;t<16;t++) | ||
406 | Samples[handle][loopend+t]=Samples[handle][(loopend-t)-1]; | ||
407 | else | ||
408 | for(t=0;t<16;t++) | ||
409 | Samples[handle][loopend+t]=Samples[handle][t+loopstart]; | ||
410 | } else | ||
411 | for(t=0;t<16;t++) | ||
412 | Samples[handle][t+length]=0; | ||
413 | |||
414 | return handle; | ||
415 | } | ||
416 | |||
417 | ULONG VC1_SampleSpace(int type) | ||
418 | { | ||
419 | return vc_memory; | ||
420 | } | ||
421 | |||
422 | ULONG VC1_SampleLength(int type,SAMPLE* s) | ||
423 | { | ||
424 | if (!s) return 0; | ||
425 | |||
426 | return (s->length*((s->flags&SF_16BITS)?2:1))+16; | ||
427 | } | ||
428 | |||
429 | ULONG VC1_VoiceRealVolume(UBYTE voice) | ||
430 | { | ||
431 | ULONG i,s,size; | ||
432 | int k,j; | ||
433 | SWORD *smp; | ||
434 | SLONG t; | ||
435 | |||
436 | t = (SLONG)(vinf[voice].current>>FRACBITS); | ||
437 | if(!vinf[voice].active) return 0; | ||
438 | |||
439 | s = vinf[voice].handle; | ||
440 | size = vinf[voice].size; | ||
441 | |||
442 | i=64; t-=64; k=0; j=0; | ||
443 | if(i>size) i = size; | ||
444 | if(t<0) t = 0; | ||
445 | if(t+i > size) t = size-i; | ||
446 | |||
447 | i &= ~1; /* make sure it's EVEN. */ | ||
448 | |||
449 | smp = &Samples[s][t]; | ||
450 | for(;i;i--,smp++) { | ||
451 | if(k<*smp) k = *smp; | ||
452 | if(j>*smp) j = *smp; | ||
453 | } | ||
454 | return abs(k-j); | ||
455 | } | ||
456 | |||
457 | |||
458 | #endif | ||
459 | |||
460 | MikMod_callback_t vc_callback; | ||
461 | |||
462 | #endif | ||
463 | |||
464 | /* ex:set ts=4: */ | ||
diff --git a/apps/plugins/viewers.config b/apps/plugins/viewers.config index 92e6d903d0..0170883817 100644 --- a/apps/plugins/viewers.config +++ b/apps/plugins/viewers.config | |||
@@ -33,6 +33,26 @@ gbc,viewers/rockboy,6 | |||
33 | sgb,viewers/rockboy,6 | 33 | sgb,viewers/rockboy,6 |
34 | mid,viewers/midi,7 | 34 | mid,viewers/midi,7 |
35 | rmi,viewers/midi,7 | 35 | rmi,viewers/midi,7 |
36 | 669,viewers/mikmod,7 | ||
37 | amf,viewers/mikmod,7 | ||
38 | asy,viewers/mikmod,7 | ||
39 | dsm,viewers/mikmod,7 | ||
40 | far,viewers/mikmod,7 | ||
41 | gdm,viewers/mikmod,7 | ||
42 | gt2,viewers/mikmod,7 | ||
43 | imf,viewers/mikmod,7 | ||
44 | it,viewers/mikmod,7 | ||
45 | m15,viewers/mikmod,7 | ||
46 | med,viewers/mikmod,7 | ||
47 | mod,viewers/mikmod,7 | ||
48 | mtm,viewers/mikmod,7 | ||
49 | okt,viewers/mikmod,7 | ||
50 | s3m,viewers/mikmod,7 | ||
51 | stm,viewers/mikmod,7 | ||
52 | stx,viewers/mikmod,7 | ||
53 | ult,viewers/mikmod,7 | ||
54 | uni,viewers/mikmod,7 | ||
55 | xm,viewers/mikmod,7 | ||
36 | pd,viewers/pdbox,2 | 56 | pd,viewers/pdbox,2 |
37 | rsp,viewers/searchengine,8 | 57 | rsp,viewers/searchengine,8 |
38 | sok,games/sokoban,1 | 58 | sok,games/sokoban,1 |