summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrank Gevaerts <frank@gevaerts.be>2010-12-12 15:03:30 +0000
committerFrank Gevaerts <frank@gevaerts.be>2010-12-12 15:03:30 +0000
commit26f2bfde03420edad4de1f22cb3d515dc063b20d (patch)
tree4a8c4abaf4795f38da70a4657c1a0fb3ba9debeb
parentd192bdf11e06e50645ecb5726658d4b691480a9a (diff)
downloadrockbox-26f2bfde03420edad4de1f22cb3d515dc063b20d.tar.gz
rockbox-26f2bfde03420edad4de1f22cb3d515dc063b20d.zip
Add MikMod plugin, ported by Jason Yu, with some minor work by Craig Mann and William Peters (FS#8806)
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@28810 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/plugins/CATEGORIES1
-rw-r--r--apps/plugins/SUBDIRS1
-rw-r--r--apps/plugins/mikmod/SOURCES39
-rw-r--r--apps/plugins/mikmod/drv_nos.c107
-rw-r--r--apps/plugins/mikmod/load_669.c368
-rw-r--r--apps/plugins/mikmod/load_amf.c569
-rw-r--r--apps/plugins/mikmod/load_asy.c398
-rw-r--r--apps/plugins/mikmod/load_dsm.c364
-rw-r--r--apps/plugins/mikmod/load_far.c346
-rw-r--r--apps/plugins/mikmod/load_gdm.c558
-rw-r--r--apps/plugins/mikmod/load_gt2.c374
-rw-r--r--apps/plugins/mikmod/load_imf.c738
-rw-r--r--apps/plugins/mikmod/load_it.c1013
-rw-r--r--apps/plugins/mikmod/load_m15.c505
-rw-r--r--apps/plugins/mikmod/load_med.c719
-rw-r--r--apps/plugins/mikmod/load_mod.c512
-rw-r--r--apps/plugins/mikmod/load_mtm.c285
-rw-r--r--apps/plugins/mikmod/load_okt.c460
-rw-r--r--apps/plugins/mikmod/load_s3m.c470
-rw-r--r--apps/plugins/mikmod/load_stm.c374
-rw-r--r--apps/plugins/mikmod/load_stx.c439
-rw-r--r--apps/plugins/mikmod/load_ult.c339
-rw-r--r--apps/plugins/mikmod/load_uni.c717
-rw-r--r--apps/plugins/mikmod/load_xm.c829
-rw-r--r--apps/plugins/mikmod/mdreg.c131
-rw-r--r--apps/plugins/mikmod/mdriver.c965
-rw-r--r--apps/plugins/mikmod/mikmod.c943
-rw-r--r--apps/plugins/mikmod/mikmod.h783
-rw-r--r--apps/plugins/mikmod/mikmod.make33
-rw-r--r--apps/plugins/mikmod/mikmod_internals.h806
-rw-r--r--apps/plugins/mikmod/mikmod_supp.h79
-rw-r--r--apps/plugins/mikmod/mloader.c615
-rw-r--r--apps/plugins/mikmod/mlreg.c66
-rw-r--r--apps/plugins/mikmod/mlutil.c336
-rw-r--r--apps/plugins/mikmod/mmalloc.c179
-rw-r--r--apps/plugins/mikmod/mmerror.c213
-rw-r--r--apps/plugins/mikmod/mmio.c517
-rw-r--r--apps/plugins/mikmod/mplayer.c3409
-rw-r--r--apps/plugins/mikmod/munitrk.c303
-rw-r--r--apps/plugins/mikmod/npertab.c48
-rw-r--r--apps/plugins/mikmod/sloader.c519
-rw-r--r--apps/plugins/mikmod/strdup.c23
-rw-r--r--apps/plugins/mikmod/strstr.c21
-rw-r--r--apps/plugins/mikmod/virtch.c1319
-rw-r--r--apps/plugins/mikmod/virtch_common.c464
-rw-r--r--apps/plugins/viewers.config20
-rw-r--r--docs/CREDITS4
47 files changed, 22320 insertions, 1 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
56metronome,apps 56metronome,apps
57midi2wav,viewers 57midi2wav,viewers
58midi,viewers 58midi,viewers
59mikmod,viewers
59minesweeper,games 60minesweeper,games
60mosaique,demos 61mosaique,demos
61mp3_encoder,apps 62mp3_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 */
68midi 68midi
69mikmod
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 @@
1drv_nos.c
2load_669.c
3load_amf.c
4load_asy.c
5load_dsm.c
6load_far.c
7load_gdm.c
8load_gt2.c
9load_imf.c
10load_it.c
11load_m15.c
12load_med.c
13load_mod.c
14load_mtm.c
15load_okt.c
16load_s3m.c
17load_stm.c
18load_stx.c
19load_ult.c
20load_uni.c
21load_xm.c
22mdreg.c
23mdriver.c
24mloader.c
25mlreg.c
26mlutil.c
27mmalloc.c
28mmerror.c
29mmio.c
30mplayer.c
31munitrk.c
32npertab.c
33sloader.c
34strdup.c
35strstr.c
36virtch.c
37virtch_common.c
38mikmod.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
49static int NS_IsThere(void)
50{
51 return 1;
52}
53
54static int NS_Init(void)
55{
56 //zerobuf=(SBYTE*)MikMod_malloc(ZEROLEN);
57 return VC_Init();
58}
59
60static void NS_Exit(void)
61{
62 VC_Exit();
63 //MikMod_free(zerobuf);
64}
65
66static void NS_Update(void)
67{
68 //if (zerobuf)
69 // VC_WriteBytes(zerobuf,ZEROLEN);
70}
71
72MIKMODAPI 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
46extern int fprintf(FILE *, const char *, ...);
47#endif
48
49/*========== Module structure */
50
51/* header */
52typedef 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 */
64typedef struct S69SAMPLE {
65 CHAR filename[13];
66 SLONG length;
67 SLONG loopbeg;
68 SLONG loopend;
69} S69SAMPLE;
70
71/* encoded note */
72typedef struct S69NOTE {
73 UBYTE a,b,c;
74} S69NOTE;
75
76/*========== Loader variables */
77
78/* current pattern */
79static S69NOTE* s69pat=NULL;
80/* Module header */
81static S69HEADER* mh=NULL;
82
83/* file type identification */
84static CHAR* S69_Version[]={
85 "Composer 669",
86 "Extended 669"
87};
88
89/*========== Loader code */
90
91int 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
125int 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
133void S69_Cleanup(void)
134{
135 MikMod_free(s69pat);
136 MikMod_free(mh);
137}
138
139static 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
248int 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
345CHAR *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
357MIKMODAPI 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
46extern int fprintf(FILE *, const char *, ...);
47#endif
48
49/*========== Module structure */
50
51typedef 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
64typedef 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
76typedef struct AMFNOTE {
77 UBYTE note,instr,volume,fxcnt;
78 UBYTE effect[3];
79 SBYTE parameter[3];
80} AMFNOTE;
81
82/*========== Loader variables */
83
84static AMFHEADER *mh = NULL;
85#define AMFTEXTLEN 22
86static CHAR AMF_Version[AMFTEXTLEN+1] = "DSMI Module Format 0.0";
87static AMFNOTE *track = NULL;
88
89/*========== Loader code */
90
91int 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
103int 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
111void AMF_Cleanup(void)
112{
113 MikMod_free(mh);
114 MikMod_free(track);
115}
116
117static 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
188static 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
333int 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
546CHAR *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
558MIKMODAPI 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
50typedef struct MSAMPINFO {
51 CHAR samplename[24];
52 UBYTE finetune;
53 UBYTE volume;
54 ULONG length;
55 ULONG reppos;
56 ULONG replen;
57} MSAMPINFO;
58
59typedef 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
67typedef struct MODTYPE {
68 CHAR id[5];
69 UBYTE channels;
70 CHAR *name;
71} MODTYPE;
72
73typedef 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 */
80UWORD 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
94static CHAR asylum[] = "Asylum 1.0";
95
96static MODULEHEADER *mh = NULL;
97static MODNOTE *patbuf = NULL;
98static int modtype = 0;
99
100/*========== Loader code */
101
102static 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
115static 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
132static int ASY_Init(void)
133{
134 if (!(mh = (MODULEHEADER *)MikMod_malloc(sizeof(MODULEHEADER))))
135 return 0;
136 return 1;
137}
138
139static void ASY_Cleanup(void)
140{
141 MikMod_free(mh);
142 MikMod_free(patbuf);
143}
144
145static 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
224static 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. */
238static 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
273static 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
378static CHAR *ASY_LoadTitle(void)
379{
380 CHAR *s = ""; // no titles
381
382 return (DupStr(s, 21, 1));
383}
384
385/*========== Loader information */
386
387MLOADER 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
46extern int fprintf(FILE *, const char *, ...);
47#endif
48
49/*========== Module structure */
50
51#define DSM_MAXCHAN (16)
52#define DSM_MAXORDERS (128)
53
54typedef 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
71typedef 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
84typedef struct DSMNOTE {
85 UBYTE note,ins,vol,cmd,inf;
86} DSMNOTE;
87
88#define DSM_SURROUND (0xa4)
89
90/*========== Loader variables */
91
92static CHAR* SONGID="SONG";
93static CHAR* INSTID="INST";
94static CHAR* PATTID="PATT";
95
96static UBYTE blockid[4];
97static ULONG blockln;
98static ULONG blocklp;
99static DSMSONG* mh=NULL;
100static DSMNOTE* dsmbuf=NULL;
101
102static CHAR DSM_Version[]="DSIK DSM-format";
103
104static unsigned char DSMSIG[4+4]={'R','I','F','F','D','S','M','F'};
105
106/*========== Loader code */
107
108int 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
118int 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
125void DSM_Cleanup(void)
126{
127 MikMod_free(dsmbuf);
128 MikMod_free(mh);
129}
130
131static 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
160static 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
193static 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
234int 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
340CHAR *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
352MIKMODAPI 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
46extern int fprintf(FILE *, const char *, ...);
47#endif
48
49/*========== Module structure */
50
51typedef 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
65typedef struct FARHEADER2 {
66 UBYTE orders[256];
67 UBYTE numpat;
68 UBYTE snglen;
69 UBYTE loopto;
70 UWORD patsiz[256];
71} FARHEADER2;
72
73typedef 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
84typedef struct FARNOTE {
85 UBYTE note,ins,vol,eff;
86} FARNOTE;
87
88/*========== Loader variables */
89
90static CHAR FAR_Version[] = "Farandole";
91static FARHEADER1 *mh1 = NULL;
92static FARHEADER2 *mh2 = NULL;
93static FARNOTE *pat = NULL;
94
95static unsigned char FARSIG[4+3]={'F','A','R',0xfe,13,10,26};
96
97/*========== Loader code */
98
99int 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
108int 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
117void FAR_Cleanup(void)
118{
119 MikMod_free(mh1);
120 MikMod_free(mh2);
121 MikMod_free(pat);
122}
123
124static 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
176int 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
323CHAR *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
335MIKMODAPI 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
54extern int fprintf(FILE *, const char *, ...);
55#endif
56
57typedef struct GDMNOTE {
58 UBYTE note;
59 UBYTE samp;
60 struct {
61 UBYTE effect;
62 UBYTE param;
63 } effect[4];
64} GDMNOTE;
65
66typedef GDMNOTE GDMTRACK[64];
67
68typedef 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
101typedef 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
114static GDMHEADER *mh=NULL; /* pointer to GDM header */
115static GDMNOTE *gdmbuf=NULL; /* pointer to a complete GDM pattern */
116
117CHAR GDM_Version[]="General DigiMusic 1.xx";
118
119int 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
137int 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
145void GDM_Cleanup(void)
146{
147 MikMod_free(mh);
148 MikMod_free(gdmbuf);
149}
150
151int 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
203UBYTE *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
340int 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
536CHAR *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
546MIKMODAPI 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
46typedef 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 */
54typedef 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 */
72typedef 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 */
80typedef 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 */
88typedef 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 */
97typedef 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 */
105typedef 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 */
118typedef 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
124typedef 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 */
130typedef 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
145typedef 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
163typedef 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
172typedef struct ENDC_CHUNK {
173 UBYTE id[4]; /* must be ENDC */
174 ULONG chunk_size;
175 ULONG total_module_size;
176} ENDC_CHUNK;
177
178
179typedef 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
195GT_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
315int GT2_Init(void)
316{
317 return 1;
318}
319
320int 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
332int 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
346void GT2_Cleanup(void)
347{
348}
349
350CHAR *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
362MIKMODAPI 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
46extern int fprintf(FILE *, const char *, ...);
47#endif
48
49/*========== Module structure */
50
51/* module header */
52typedef 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 */
66typedef 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)
77typedef 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 */
104typedef 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
115typedef struct IMFNOTE {
116 UBYTE note,ins,eff1,dat1,eff2,dat2;
117} IMFNOTE;
118
119/*========== Loader variables */
120
121static CHAR IMF_Version[]="Imago Orpheus";
122
123static IMFNOTE *imfpat=NULL;
124static IMFHEADER *mh=NULL;
125
126/*========== Loader code */
127
128int 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
138int 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
146void IMF_Cleanup(void)
147{
148 FreeLinear();
149
150 MikMod_free(imfpat);
151 MikMod_free(mh);
152}
153
154static 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
203static 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
353static 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
380int 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
715CHAR *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
727MIKMODAPI 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
47extern int fprintf(FILE *, const char *, ...);
48extern int toupper(int);
49#endif
50
51/*========== Module structure */
52
53/* header */
54typedef 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 */
79typedef 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
105typedef 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
156typedef struct ITNOTE {
157 UBYTE note,ins,volpan,cmd,inf;
158} ITNOTE;
159
160/*========== Loader data */
161
162static ULONG *paraptr=NULL; /* parapointer array (see IT docs) */
163static ITHEADER *mh=NULL;
164static ITNOTE *itpat=NULL; /* allocate to space for one full pattern */
165static UBYTE *mask=NULL; /* arrays allocated to 64 elements and used for */
166static ITNOTE *last=NULL; /* uncompressing IT's pattern information */
167static int numtrk=0;
168static unsigned int old_effect; /* if set, use S3M old-effects stuffs */
169
170static 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 */
180static UBYTE portatable[10]= {0,1,4,8,16,32,64,96,128,255};
181
182/*========== Loader code */
183
184int 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
193int 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
204void 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*/
226static 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
251static 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
325static 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
382static 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 */
397static 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
444int 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
990CHAR *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
1002MIKMODAPI 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
48extern int fprintf(FILE *, const char *, ...);
49#endif
50
51/*========== Module Structure */
52
53typedef 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
62typedef 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
70typedef struct MODNOTE {
71 UBYTE a,b,c,d;
72} MODNOTE;
73
74/*========== Loader variables */
75
76static MODULEHEADER *mh = NULL;
77static MODNOTE *patbuf = NULL;
78static 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
82static char *signatures[REJECT]={
83 "CAKEWALK", /* cakewalk midi files */
84 "SZDD" /* Microsoft compressed files */
85};
86static int siglen[REJECT]={8,4};
87
88/*========== Loader code */
89
90static 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 */
148static 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
177static 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
243static int M15_Init(void)
244{
245 if(!(mh=(MODULEHEADER*)MikMod_malloc(sizeof(MODULEHEADER)))) return 0;
246 return 1;
247}
248
249static void M15_Cleanup(void)
250{
251 MikMod_free(mh);
252 MikMod_free(patbuf);
253}
254
255/*
256Old (amiga) noteinfo:
257
258 _____byte 1_____ byte2_ _____byte 3_____ byte4_
259/ \ / \ / \ / \
2600000 0000-00000000 0000 0000-00000000
261
262Upper four 12 bits for Lower four Effect command.
263bits of sam- note period. bits of sam-
264ple number. ple number.
265*/
266
267static 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
358static 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. */
373static 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
398static 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
482static 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
494MIKMODAPI 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
46extern int fprintf(FILE *, const char *, ...);
47#endif
48
49/*========== Module information */
50
51typedef 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
72typedef 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
80typedef 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
95typedef 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
115typedef struct MMD0NOTE {
116 UBYTE a, b, c;
117} MMD0NOTE;
118
119typedef struct MMD1NOTE {
120 UBYTE a, b, c, d;
121} MMD1NOTE;
122
123typedef struct MEDINSTHEADER {
124 ULONG length;
125 SWORD type;
126 /* Followed by actual data */
127} MEDINSTHEADER;
128
129typedef struct MEDINSTEXT {
130 UBYTE hold;
131 UBYTE decay;
132 UBYTE suppress_midi_off;
133 SBYTE finetune;
134} MEDINSTEXT;
135
136typedef struct MEDINSTINFO {
137 UBYTE name[40];
138} MEDINSTINFO;
139
140/*========== Loader variables */
141
142#define MMD0_string 0x4D4D4430
143#define MMD1_string 0x4D4D4431
144
145static MEDHEADER *mh = NULL;
146static MEDSONG *ms = NULL;
147static MEDEXP *me = NULL;
148static ULONG *ba = NULL;
149static MMD0NOTE *mmd0pat = NULL;
150static MMD1NOTE *mmd1pat = NULL;
151
152static int decimalvolumes;
153static 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
158static CHAR MED_Version[] = "OctaMED (MMDx)";
159
160/*========== Loader code */
161
162int 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
173int 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
184void 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
194static 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
271static 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
296static 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
325static 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
376static 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
429int 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
683CHAR *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
708MIKMODAPI 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
47extern int fprintf(FILE *, const char *, ...);
48#endif
49
50/*========== Module structure */
51
52typedef 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
61typedef 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
70typedef struct MODTYPE {
71 CHAR id[5];
72 UBYTE channels;
73 CHAR *name;
74} MODTYPE;
75
76typedef struct MODNOTE {
77 UBYTE a, b, c, d;
78} MODNOTE;
79
80/*========== Loader variables */
81
82#define MODULEHEADERSIZE 0x438
83
84static CHAR protracker[] = "Protracker";
85static CHAR startrekker[] = "Startrekker";
86static CHAR fasttracker[] = "Fasttracker";
87static CHAR oktalyser[] = "Oktalyser";
88static CHAR oktalyzer[] = "Oktalyzer";
89static CHAR taketracker[] = "TakeTracker";
90static CHAR orpheus[] = "Imago Orpheus (MOD format)";
91
92static MODULEHEADER *mh = NULL;
93static MODNOTE *patbuf = NULL;
94static 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 */
100static 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
167static 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
182static int MOD_Init(void)
183{
184 if (!(mh = (MODULEHEADER *)MikMod_malloc(sizeof(MODULEHEADER))))
185 return 0;
186 return 1;
187}
188
189static void MOD_Cleanup(void)
190{
191 MikMod_free(mh);
192 MikMod_free(patbuf);
193}
194
195/*
196Old (amiga) noteinfo:
197
198_____byte 1_____ byte2_ _____byte 3_____ byte4_
199/ \ / \ / \ / \
2000000 0000-00000000 0000 0000-00000000
201
202Upper four 12 bits for Lower four Effect command.
203bits of sam- note period. bits of sam-
204ple number. ple number.
205
206*/
207
208static 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
295static 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. */
310static 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
363static 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
487static 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
501MIKMODAPI 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
46extern int fprintf(FILE *, const char *, ...);
47#endif
48
49/*========== Module structure */
50
51typedef 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
66typedef 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
76typedef struct MTMNOTE {
77 UBYTE a,b,c;
78} MTMNOTE;
79
80/*========== Loader variables */
81
82static MTMHEADER *mh = NULL;
83static MTMNOTE *mtmtrk = NULL;
84static UWORD pat[32];
85
86static CHAR MTM_Version[] = "MTM";
87
88/*========== Loader code */
89
90int 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
99int 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
107void MTM_Cleanup(void)
108{
109 MikMod_free(mtmtrk);
110 MikMod_free(mh);
111}
112
113static 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
143int 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
262CHAR *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
274MIKMODAPI 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
53extern int fprintf(FILE *, const char *, ...);
54#endif
55
56/*========== Module blocks */
57
58/* sample information */
59typedef struct OKTSAMPLE {
60 CHAR sampname[20];
61 ULONG len;
62 UWORD loopbeg;
63 UWORD looplen;
64 UBYTE volume;
65} OKTSAMPLE;
66
67typedef struct OKTNOTE {
68 UBYTE note, ins, eff, dat;
69} OKTNOTE;
70
71/*========== Loader variables */
72
73static OKTNOTE *okttrk = NULL;
74
75/*========== Loader code */
76
77int 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*/
101static 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 */
171static 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 */
191static 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 */
243static 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 */
251static void OKT_doSLEN(void)
252{
253 of.numpat = _mm_read_M_UWORD(modreader);
254}
255
256/* Read pattern length information */
257static void OKT_doPLEN(void)
258{
259 of.numpos = _mm_read_M_UWORD(modreader);
260}
261
262/* Read order table */
263static 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
279static 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
320static void OKT_doSBOD(int insnum)
321{
322 of.samples[insnum].seekpos = _mm_ftell(modreader);
323}
324
325int 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
442CHAR *OKT_LoadTitle(void)
443{
444 return StrDup("");
445}
446
447/*========== Loader information */
448
449MIKMODAPI 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
46extern int fprintf(FILE *, const char *, ...);
47#endif
48
49/*========== Module structure */
50
51/* header */
52typedef 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 */
76typedef 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
94typedef struct S3MNOTE {
95 UBYTE note,ins,vol,cmd,inf;
96} S3MNOTE;
97
98/*========== Loader variables */
99
100static S3MNOTE *s3mbuf = NULL; /* pointer to a complete S3M pattern */
101static S3MHEADER *mh = NULL;
102static UWORD *paraptr = NULL; /* parapointer array (see S3M docs) */
103static unsigned int tracker; /* tracker id */
104
105/* tracker identifiers */
106#define NUMTRACKERS 4
107static 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 */
116static int numeric[NUMTRACKERS]={14,14,16,16};
117
118/*========== Loader code */
119
120int 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
130int 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
140void 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. */
160static 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
183static 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
224static 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
253int 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
447CHAR *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
459MIKMODAPI 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
46extern int fprintf(FILE *, const char *, ...);
47#endif
48
49/*========== Module structure */
50
51/* sample information */
52typedef 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 */
68typedef 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
83typedef struct STMNOTE {
84 UBYTE note,insvol,volcmd,cmdinf;
85} STMNOTE;
86
87/*========== Loader variables */
88
89static STMNOTE *stmbuf = NULL;
90static STMHEADER *mh = NULL;
91
92/* tracker identifiers */
93static CHAR* STM_Version[STM_NTRACKERS] = {
94 "Screamtracker 2",
95 "Converted by MOD2STM (STM format)",
96 "Wuzamod (STM format)"
97};
98
99/*========== Loader code */
100
101int 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
121int 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
129static void STM_Cleanup(void)
130{
131 MikMod_free(mh);
132 MikMod_free(stmbuf);
133}
134
135static 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
212static 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
225static 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
252int 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
350CHAR *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
362MIKMODAPI 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
52extern int fprintf(FILE *, const char *, ...);
53#endif
54
55/*========== Module structure */
56
57/* header */
58typedef 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 */
82typedef 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
100typedef struct STXNOTE {
101 UBYTE note,ins,vol,cmd,inf;
102} STXNOTE;
103
104/*========== Loader variables */
105
106static STXNOTE *stxbuf = NULL; /* pointer to a complete STX pattern */
107static STXHEADER *mh = NULL;
108static UWORD *paraptr = NULL; /* parapointer array (see STX docs) */
109
110/*========== Loader code */
111
112static 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
130static 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
140static void STX_Cleanup(void)
141{
142 MikMod_free(stxbuf);
143 MikMod_free(paraptr);
144 MikMod_free(poslookup);
145 MikMod_free(mh);
146}
147
148static 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
189static 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
268static 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
416static 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
428MIKMODAPI 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
46extern int fprintf(FILE *, const char *, ...);
47#endif
48
49/*========== Module structure */
50
51/* header */
52typedef struct ULTHEADER {
53 CHAR id[16];
54 CHAR songtitle[32];
55 UBYTE reserved;
56} ULTHEADER;
57
58/* sample information */
59typedef 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
72typedef 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
83static CHAR ULT_Version[ULT_VERSION_LEN]="Ultra Tracker v1.x";
84
85static ULTEVENT ev;
86
87/*========== Loader code */
88
89int 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
99int ULT_Init(void)
100{
101 return 1;
102}
103
104void ULT_Cleanup(void)
105{
106}
107
108static 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
127int 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
315CHAR *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
327MIKMODAPI 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
46extern int fprintf(FILE *, const char *, ...);
47#endif
48
49/*========== Module structure */
50
51typedef 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
71typedef 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
89static UWORD universion;
90static UNIHEADER mh;
91
92#define UNI_SMPINCR 64
93static UNISMP05 *wh=NULL,*s=NULL;
94
95/*========== Loader code */
96
97static 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
111int 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
128int UNI_Init(void)
129{
130 return 1;
131}
132
133void UNI_Cleanup(void)
134{
135 MikMod_free(wh);
136 s=NULL;
137}
138
139static 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
221static 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
292static 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
359static 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
457static 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
501int 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
691CHAR *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
706MIKMODAPI 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
46extern int fprintf(FILE *, const char *, ...);
47#endif
48
49/*========== Module structure */
50
51typedef 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
68typedef 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)
78typedef 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
99typedef 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
116typedef 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
123typedef struct XMNOTE {
124 UBYTE note,ins,vol,eff,dat;
125} XMNOTE;
126
127/*========== Loader variables */
128
129static XMNOTE *xmpat=NULL;
130static XMHEADER *mh=NULL;
131
132/* increment unit for sample array MikMod_reallocation */
133#define XM_SMPINCR 64
134static ULONG *nextwav=NULL;
135static XMWAVHEADER *wh=NULL,*s=NULL;
136
137/*========== Loader code */
138
139int 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
149int XM_Init(void)
150{
151 if(!(mh=(XMHEADER *)MikMod_malloc(sizeof(XMHEADER)))) return 0;
152 return 1;
153}
154
155void XM_Cleanup(void)
156{
157 MikMod_free(mh);
158}
159
160static 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
184static 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
324static 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
406static 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
444static 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
660int 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
806CHAR *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
818MIKMODAPI 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
35void _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
124void 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
52extern int fprintf(FILE *, const char *, ...);
53#endif
54
55static MDRIVER *firstdriver=NULL;
56MIKMODAPI MDRIVER *md_driver=NULL;
57extern MODULE *pf; /* modfile being played */
58
59/* Initial global settings */
60MIKMODAPI UWORD md_device = 0; /* autodetect */
61MIKMODAPI UWORD md_mixfreq = 44100;
62MIKMODAPI UWORD md_mode = DMODE_STEREO | DMODE_16BITS |
63 DMODE_SURROUND |DMODE_SOFT_MUSIC |
64 DMODE_SOFT_SNDFX;
65MIKMODAPI UBYTE md_pansep = 128; /* 128 == 100% (full left/right) */
66MIKMODAPI UBYTE md_reverb = 0; /* no reverb */
67MIKMODAPI UBYTE md_volume = 128; /* global sound volume (0-128) */
68MIKMODAPI UBYTE md_musicvolume = 128; /* volume of song */
69MIKMODAPI 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;
77static volatile int isplaying=0, initialized = 0;
78static UBYTE *sfxinfo;
79static int sfxpool;
80
81static SAMPLE **md_sample = NULL;
82
83/* Previous driver in use */
84static 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. */
88static 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. */
122static 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. */
156ULONG 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
166ULONG 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
177MIKMODAPI 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
201void _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
221MIKMODAPI 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
233MIKMODAPI 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
253MIKMODAPI 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
269SWORD 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
285void MD_SampleUnload(SWORD handle)
286{
287 md_driver->SampleUnload(handle);
288}
289
290MIKMODAPI 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
302MIKMODAPI 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
316void 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
332MIKMODAPI void Voice_SetVolume(SBYTE voice,UWORD vol)
333{
334 MUTEX_LOCK(vars);
335 Voice_SetVolume_internal(voice,vol);
336 MUTEX_UNLOCK(vars);
337}
338
339MIKMODAPI 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
351void 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
359MIKMODAPI void Voice_SetFrequency(SBYTE voice,ULONG frq)
360{
361 MUTEX_LOCK(vars);
362 Voice_SetFrequency_internal(voice,frq);
363 MUTEX_UNLOCK(vars);
364}
365
366MIKMODAPI 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
378void 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
389MIKMODAPI 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
401MIKMODAPI 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
413void 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
429MIKMODAPI 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
438void 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
447MIKMODAPI void Voice_Stop(SBYTE voice)
448{
449 MUTEX_LOCK(vars);
450 Voice_Stop_internal(voice);
451 MUTEX_UNLOCK(vars);
452}
453
454int Voice_Stopped_internal(SBYTE voice)
455{
456 if((voice<0)||(voice>=md_numchn)) return 0;
457 return(md_driver->VoiceStopped(voice));
458}
459
460MIKMODAPI 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
471MIKMODAPI 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
487MIKMODAPI 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
499extern MikMod_callback_t vc_callback;
500
501MIKMODAPI void VC_SetCallback(MikMod_callback_t callback)
502{
503 vc_callback = callback;
504}
505
506static 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
564MIKMODAPI 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
577void 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
592MIKMODAPI 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. */
603static 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
637MIKMODAPI 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. */
651int 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
699MIKMODAPI 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
710int 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
721MIKMODAPI 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
732void MikMod_DisableOutput_internal(void)
733{
734 if(isplaying && md_driver) {
735 isplaying = 0;
736 md_driver->PlayStop();
737 }
738}
739
740MIKMODAPI void MikMod_DisableOutput(void)
741{
742 MUTEX_LOCK(vars);
743 MikMod_DisableOutput_internal();
744 MUTEX_UNLOCK(vars);
745}
746
747int MikMod_Active_internal(void)
748{
749 return isplaying;
750}
751
752MIKMODAPI 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. */
768SBYTE 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
807MIKMODAPI 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
818MIKMODAPI 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
839INIT_MUTEX(vars);
840INIT_MUTEX(lists);
841
842MIKMODAPI 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
869MIKMODAPI void MikMod_Unlock(void)
870{
871 MUTEX_UNLOCK(lists);
872 MUTEX_UNLOCK(vars);
873}
874
875MIKMODAPI void MikMod_Lock(void)
876{
877 MUTEX_LOCK(vars);
878 MUTEX_LOCK(lists);
879}
880
881/*========== Parameter extraction helper */
882
883CHAR *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... */
920int 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 */
942int 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
33static unsigned int thread_id;
34static struct event_queue thread_q;
35/* use long for aligning */
36unsigned long thread_stack[THREAD_STACK_SIZE/sizeof(long)];
37#endif
38
39/* the current full file name */
40static char np_file[MAX_PATH];
41static int curfile = 0, direction = DIR_NEXT, entries = 0;
42
43/* list of the mod files */
44static char **file_pt;
45
46
47/* The MP3 audio buffer which we will use as heap memory */
48static unsigned char* audio_buffer;
49/* amount of bytes left in audio_buffer */
50static size_t audio_buffer_free;
51
52
53/* The rockbox plugin interface */
54MEM_FUNCTION_WRAPPERS;
55
56bool quit;
57int playingtime IBSS_ATTR;
58MODULE *module IBSS_ATTR;
59char gmbuf[BUF_SIZE*NBUF];
60
61
62int textlines;
63int vscroll = 0;
64int hscroll = 0;
65bool screenupdated = false;
66
67enum {
68 DISPLAY_INFO = 0,
69 DISPLAY_SAMPLE,
70 DISPLAY_INST,
71 DISPLAY_COMMENTS,
72} display;
73
74
75/*
76* strncat wrapper
77*/
78char* 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*/
102int 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*/
117void 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() */
150static int compare(const void* p1, const void* p2)
151{
152 return rb->strcasecmp(*((char **)p1), *((char **)p2));
153}
154
155bool 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. */
185void 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
215int 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
253bool swap = false;
254bool lastswap = true;
255
256static 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
272void 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
293void 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
351void 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
370void 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
389void 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
428int 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
465struct mikmod_settings
466{
467 int pansep;
468 int reverb;
469 bool interp;
470 bool reverse;
471 bool surround;
472 bool boost;
473};
474
475static struct mikmod_settings settings =
476{
477 128,
478 0,
479 0,
480 0,
481 1,
482 1
483};
484
485static struct mikmod_settings old_settings;
486
487static 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
497void 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 */
525int 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 */
586int 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 */
619void 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
635void mm_errorhandler(void)
636{
637 rb->splashf(HZ, "%s", MikMod_strerror(MikMod_errno));
638 quit = true;
639}
640
641int 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*/
872enum 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
36extern "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
68MIKMODAPI 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
85typedef char CHAR;
86#endif
87#endif
88
89typedef char CHAR;
90
91
92#if defined(__arch64__) || defined(__alpha) || defined(__x86_64) || defined(__powerpc64__)
93/* 64 bit architectures */
94
95typedef signed char SBYTE; /* 1 byte, signed */
96typedef unsigned char UBYTE; /* 1 byte, unsigned */
97typedef signed short SWORD; /* 2 bytes, signed */
98typedef unsigned short UWORD; /* 2 bytes, unsigned */
99typedef signed int SLONG; /* 4 bytes, signed */
100typedef unsigned int ULONG; /* 4 bytes, unsigned */
101//typedef int BOOL; /* 0=false, <>0 true */
102
103#else
104/* 32 bit architectures */
105
106typedef signed char SBYTE; /* 1 byte, signed */
107typedef unsigned char UBYTE; /* 1 byte, unsigned */
108typedef signed short SWORD; /* 2 bytes, signed */
109typedef unsigned short UWORD; /* 2 bytes, unsigned */
110typedef signed long SLONG; /* 4 bytes, signed */
111#if !defined(__OS2__)&&!defined(__EMX__)&&!defined(WIN32)
112typedef 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
121enum {
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
220typedef void (MikMod_handler)(void);
221typedef MikMod_handler *MikMod_handler_t;
222
223MIKMODAPI extern int MikMod_errno;
224MIKMODAPI extern int MikMod_critical;
225MIKMODAPI extern char *MikMod_strerror(int);
226
227MIKMODAPI extern MikMod_handler_t MikMod_RegisterErrorHandler(MikMod_handler_t);
228
229/*
230 * ========== Library initialization and core functions
231 */
232
233struct MDRIVER;
234
235MIKMODAPI extern void MikMod_RegisterAllDrivers(void);
236
237MIKMODAPI extern CHAR* MikMod_InfoDriver(void);
238MIKMODAPI extern void MikMod_RegisterDriver(struct MDRIVER*);
239MIKMODAPI extern int MikMod_DriverFromAlias(CHAR*);
240MIKMODAPI extern struct MDRIVER *MikMod_DriverByOrdinal(int);
241
242MIKMODAPI extern int MikMod_Init(CHAR*);
243MIKMODAPI extern void MikMod_Exit(void);
244MIKMODAPI extern int MikMod_Reset(CHAR*);
245MIKMODAPI extern int MikMod_SetNumVoices(int,int);
246MIKMODAPI extern int MikMod_Active(void);
247MIKMODAPI extern int MikMod_EnableOutput(void);
248MIKMODAPI extern void MikMod_DisableOutput(void);
249MIKMODAPI extern void MikMod_Update(void);
250
251MIKMODAPI extern int MikMod_InitThreads(void);
252MIKMODAPI extern void MikMod_Lock(void);
253MIKMODAPI extern void MikMod_Unlock(void);
254
255MIKMODAPI extern void* MikMod_malloc(size_t);
256MIKMODAPI extern void* MikMod_realloc(void *, size_t);
257MIKMODAPI extern void* MikMod_calloc(size_t,size_t);
258MIKMODAPI extern void MikMod_free(void*);
259
260/*
261 * ========== Reader, Writer
262 */
263
264typedef 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
274typedef 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
322typedef 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
354MIKMODAPI extern SAMPLE *Sample_LoadRaw(CHAR *,ULONG rate, ULONG channel, ULONG flags);
355MIKMODAPI extern SAMPLE *Sample_LoadRawFP(int fp,ULONG rate,ULONG channel, ULONG flags);
356MIKMODAPI extern SAMPLE *Sample_LoadRawMem(const char *buf, int len, ULONG rate, ULONG channel, ULONG flags);
357MIKMODAPI extern SAMPLE *Sample_LoadRawGeneric(MREADER*reader,ULONG rate, ULONG channel, ULONG flags);
358
359MIKMODAPI extern SAMPLE *Sample_Load(CHAR*);
360MIKMODAPI extern SAMPLE *Sample_LoadFP(int);
361MIKMODAPI extern SAMPLE *Sample_LoadMem(const char *buf, int len);
362MIKMODAPI extern SAMPLE *Sample_LoadGeneric(MREADER*);
363MIKMODAPI extern void Sample_Free(SAMPLE*);
364MIKMODAPI extern SBYTE Sample_Play(SAMPLE*,ULONG,UBYTE);
365
366MIKMODAPI extern void Voice_SetVolume(SBYTE,UWORD);
367MIKMODAPI extern UWORD Voice_GetVolume(SBYTE);
368MIKMODAPI extern void Voice_SetFrequency(SBYTE,ULONG);
369MIKMODAPI extern ULONG Voice_GetFrequency(SBYTE);
370MIKMODAPI extern void Voice_SetPanning(SBYTE,ULONG);
371MIKMODAPI extern ULONG Voice_GetPanning(SBYTE);
372MIKMODAPI extern void Voice_Play(SBYTE,SAMPLE*,ULONG);
373MIKMODAPI extern void Voice_Stop(SBYTE);
374MIKMODAPI extern int Voice_Stopped(SBYTE);
375MIKMODAPI extern SLONG Voice_GetPosition(SBYTE);
376MIKMODAPI 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 */
391typedef struct ENVPT {
392 SWORD pos;
393 SWORD val;
394} ENVPT;
395
396/* Envelope point count */
397#define ENVPOINTS 32
398
399/* Instrument structure */
400typedef 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
445struct MP_CONTROL;
446struct 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
471typedef 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 */
484struct INSTRUMENT* instruments; /* all instruments */
485struct 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
524struct MP_CONTROL* control; /* Effects Channel info (size pf->numchn) */
525struct 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 */
538typedef 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
551struct MLOADER;
552
553MIKMODAPI extern CHAR* MikMod_InfoLoader(void);
554MIKMODAPI extern void MikMod_RegisterAllLoaders(void);
555MIKMODAPI extern void MikMod_RegisterLoader(struct MLOADER*);
556
557MIKMODAPI extern struct MLOADER load_669; /* 669 and Extended-669 (by Tran/Renaissance) */
558MIKMODAPI extern struct MLOADER load_amf; /* DMP Advanced Module Format (by Otto Chrons) */
559MIKMODAPI extern struct MLOADER load_asy; /* ASYLUM Music Format 1.0 */
560MIKMODAPI extern struct MLOADER load_dsm; /* DSIK internal module format */
561MIKMODAPI extern struct MLOADER load_far; /* Farandole Composer (by Daniel Potter) */
562MIKMODAPI extern struct MLOADER load_gdm; /* General DigiMusic (by Edward Schlunder) */
563MIKMODAPI extern struct MLOADER load_gt2; /* Graoumf tracker */
564MIKMODAPI extern struct MLOADER load_it; /* Impulse Tracker (by Jeffrey Lim) */
565MIKMODAPI extern struct MLOADER load_imf; /* Imago Orpheus (by Lutz Roeder) */
566MIKMODAPI extern struct MLOADER load_med; /* Amiga MED modules (by Teijo Kinnunen) */
567MIKMODAPI extern struct MLOADER load_m15; /* Soundtracker 15-instrument */
568MIKMODAPI extern struct MLOADER load_mod; /* Standard 31-instrument Module loader */
569MIKMODAPI extern struct MLOADER load_mtm; /* Multi-Tracker Module (by Renaissance) */
570MIKMODAPI extern struct MLOADER load_okt; /* Amiga Oktalyzer */
571MIKMODAPI extern struct MLOADER load_stm; /* ScreamTracker 2 (by Future Crew) */
572MIKMODAPI extern struct MLOADER load_stx; /* STMIK 0.2 (by Future Crew) */
573MIKMODAPI extern struct MLOADER load_s3m; /* ScreamTracker 3 (by Future Crew) */
574MIKMODAPI extern struct MLOADER load_ult; /* UltraTracker (by MAS) */
575MIKMODAPI extern struct MLOADER load_uni; /* MikMod and APlayer internal module format */
576MIKMODAPI extern struct MLOADER load_xm; /* FastTracker 2 (by Triton) */
577
578/*
579 * ========== Module player
580 */
581
582MIKMODAPI extern MODULE* Player_Load(CHAR*,int,int);
583MIKMODAPI extern MODULE* Player_LoadFP(int,int,int);
584MIKMODAPI extern MODULE* Player_LoadMem(const char *buffer,int len,int maxchan,int curious);
585MIKMODAPI extern MODULE* Player_LoadGeneric(MREADER*,int,int);
586MIKMODAPI extern CHAR* Player_LoadTitle(CHAR*);
587MIKMODAPI extern CHAR* Player_LoadTitleFP(int);
588MIKMODAPI extern CHAR* Player_LoadTitleMem(const char *buffer,int len);
589MIKMODAPI extern CHAR* Player_LoadTitleGeneric(MREADER*);
590
591MIKMODAPI extern void Player_Free(MODULE*);
592MIKMODAPI extern void Player_Start(MODULE*);
593MIKMODAPI extern int Player_Active(void);
594MIKMODAPI extern void Player_Stop(void);
595MIKMODAPI extern void Player_TogglePause(void);
596MIKMODAPI extern int Player_Paused(void);
597MIKMODAPI extern void Player_NextPosition(void);
598MIKMODAPI extern void Player_PrevPosition(void);
599MIKMODAPI extern void Player_SetPosition(UWORD);
600MIKMODAPI extern int Player_Muted(UBYTE);
601MIKMODAPI extern void Player_SetVolume(SWORD);
602MIKMODAPI extern MODULE* Player_GetModule(void);
603MIKMODAPI extern void Player_SetSpeed(UWORD);
604MIKMODAPI extern void Player_SetTempo(UWORD);
605MIKMODAPI extern void Player_Unmute(SLONG,...);
606MIKMODAPI extern void Player_Mute(SLONG,...);
607MIKMODAPI extern void Player_ToggleMute(SLONG,...);
608MIKMODAPI extern int Player_GetChannelVoice(UBYTE);
609MIKMODAPI extern UWORD Player_GetChannelPeriod(UBYTE);
610MIKMODAPI extern int Player_QueryVoices(UWORD numvoices, VOICEINFO *vinfo);
611MIKMODAPI extern int Player_GetRow(void);
612MIKMODAPI extern int Player_GetOrder(void);
613
614typedef void (*MikMod_player_t)(void);
615typedef void (*MikMod_callback_t)(unsigned char *data, size_t len);
616
617MIKMODAPI 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
626enum {
627 MD_MUSIC = 0,
628 MD_SNDFX
629};
630
631enum {
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
652struct SAMPLOAD;
653typedef struct MDRIVER {
654struct 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 */
692MIKMODAPI extern UBYTE md_volume; /* global sound volume (0-128) */
693MIKMODAPI extern UBYTE md_musicvolume; /* volume of song */
694MIKMODAPI extern UBYTE md_sndfxvolume; /* volume of sound effects */
695MIKMODAPI extern UBYTE md_reverb; /* 0 = none; 15 = chaos */
696MIKMODAPI 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). */
702MIKMODAPI extern UWORD md_device; /* device */
703MIKMODAPI extern UWORD md_mixfreq; /* mixing frequency */
704MIKMODAPI extern UWORD md_mode; /* mode. See DMODE_? flags above */
705
706/* The following variable should not be changed! */
707MIKMODAPI extern MDRIVER* md_driver; /* Current driver in use. */
708
709/* Known drivers list */
710
711MIKMODAPI extern struct MDRIVER drv_nos; /* no sound */
712#if 0
713MIKMODAPI extern struct MDRIVER drv_pipe; /* piped output */
714MIKMODAPI extern struct MDRIVER drv_raw; /* raw file disk writer [music.raw] */
715MIKMODAPI extern struct MDRIVER drv_stdout; /* output to stdout */
716MIKMODAPI extern struct MDRIVER drv_wav; /* RIFF WAVE file disk writer [music.wav] */
717MIKMODAPI extern struct MDRIVER drv_aiff; /* AIFF file disk writer [music.aiff] */
718
719MIKMODAPI extern struct MDRIVER drv_ultra; /* Linux Ultrasound driver */
720MIKMODAPI extern struct MDRIVER drv_sam9407; /* Linux sam9407 driver */
721
722MIKMODAPI extern struct MDRIVER drv_AF; /* Dec Alpha AudioFile */
723MIKMODAPI extern struct MDRIVER drv_aix; /* AIX audio device */
724MIKMODAPI extern struct MDRIVER drv_alsa; /* Advanced Linux Sound Architecture (ALSA) */
725MIKMODAPI extern struct MDRIVER drv_esd; /* Enlightened sound daemon (EsounD) */
726MIKMODAPI extern struct MDRIVER drv_hp; /* HP-UX audio device */
727MIKMODAPI extern struct MDRIVER drv_nas; /* Network Audio System (NAS) */
728MIKMODAPI extern struct MDRIVER drv_oss; /* OpenSound System (Linux,FreeBSD...) */
729MIKMODAPI extern struct MDRIVER drv_sgi; /* SGI audio library */
730MIKMODAPI extern struct MDRIVER drv_sun; /* Sun/NetBSD/OpenBSD audio device */
731
732MIKMODAPI extern struct MDRIVER drv_dart; /* OS/2 Direct Audio RealTime */
733MIKMODAPI extern struct MDRIVER drv_os2; /* OS/2 MMPM/2 */
734
735MIKMODAPI extern struct MDRIVER drv_ds; /* Win32 DirectSound driver */
736MIKMODAPI extern struct MDRIVER drv_win; /* Win32 multimedia API driver */
737
738MIKMODAPI extern struct MDRIVER drv_mac; /* Macintosh Sound Manager driver */
739MIKMODAPI extern struct MDRIVER drv_osx; /* MacOS X CoreAudio Driver */
740
741MIKMODAPI extern struct MDRIVER drv_gp32; /* GP32 Sound driver */
742
743MIKMODAPI extern struct MDRIVER drv_wss; /* DOS WSS driver */
744MIKMODAPI extern struct MDRIVER drv_sb; /* DOS SB driver */
745#endif
746/*========== Virtual channel mixer interface (for user-supplied drivers only) */
747
748MIKMODAPI extern int VC_Init(void);
749MIKMODAPI extern void VC_Exit(void);
750MIKMODAPI extern void VC_SetCallback(MikMod_callback_t callback);
751MIKMODAPI extern int VC_SetNumVoices(void);
752MIKMODAPI extern ULONG VC_SampleSpace(int);
753MIKMODAPI extern ULONG VC_SampleLength(int,SAMPLE*);
754
755MIKMODAPI extern int VC_PlayStart(void);
756MIKMODAPI extern void VC_PlayStop(void);
757
758MIKMODAPI extern SWORD VC_SampleLoad(struct SAMPLOAD*,int);
759MIKMODAPI extern void VC_SampleUnload(SWORD);
760
761MIKMODAPI extern ULONG VC_WriteBytes(SBYTE*,ULONG);
762MIKMODAPI extern ULONG VC_SilenceBytes(SBYTE*,ULONG);
763
764MIKMODAPI extern void VC_VoiceSetVolume(UBYTE,UWORD);
765MIKMODAPI extern UWORD VC_VoiceGetVolume(UBYTE);
766MIKMODAPI extern void VC_VoiceSetFrequency(UBYTE,ULONG);
767MIKMODAPI extern ULONG VC_VoiceGetFrequency(UBYTE);
768MIKMODAPI extern void VC_VoiceSetPanning(UBYTE,ULONG);
769MIKMODAPI extern ULONG VC_VoiceGetPanning(UBYTE);
770MIKMODAPI extern void VC_VoicePlay(UBYTE,SWORD,ULONG,ULONG,ULONG,ULONG,UWORD);
771
772MIKMODAPI extern void VC_VoiceStop(UBYTE);
773MIKMODAPI extern int VC_VoiceStopped(UBYTE);
774MIKMODAPI extern SLONG VC_VoiceGetPosition(UBYTE);
775MIKMODAPI 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
10MIKMODSRCDIR := $(APPSDIR)/plugins/mikmod
11MIKMODBUILDDIR := $(BUILDDIR)/apps/plugins/mikmod
12
13ROCKS += $(MIKMODBUILDDIR)/mikmod.rock
14
15MIKMOD_SRC := $(call preprocess, $(MIKMODSRCDIR)/SOURCES)
16MIKMOD_OBJ := $(call c2obj, $(MIKMOD_SRC))
17
18# add source files to OTHER_SRC to get automatic dependencies
19OTHER_SRC += $(MIKMOD_SRC)
20
21MIKMODCFLAGS = $(PLUGINFLAGS) -I$(MIKMODSRCDIR) -w
22ifeq ($(CPU),coldfire)
23 MIKMODCFLAGS += -O0
24else
25 MIKMODCFLAGS += -O2
26endif
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
33extern "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__)
49typedef long SLONGLONG;
50#define NATIVE_64BIT_INT
51#if 0
52#elif defined(__WATCOMC__)
53typedef __int64 SLONGLONG;
54#elif defined(WIN32) && !defined(__MWERKS__)
55typedef LONGLONG SLONGLONG;
56#elif macintosh && !TYPE_LONGLONG
57#include <Types.h>
58typedef SInt64 SLONGLONG;
59#endif
60#else
61typedef long long SLONGLONG;
62#endif
63
64/*========== Error handling */
65
66#define _mm_errno MikMod_errno
67#define _mm_critical MikMod_critical
68extern 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
106DECLARE_MUTEX(lists);
107DECLARE_MUTEX(vars);
108
109/*========== Portable file I/O */
110
111extern MREADER* _mm_new_mem_reader(const void *buffer, int len);
112extern void _mm_delete_mem_reader(MREADER *reader);
113
114extern MREADER* _mm_new_file_reader(int fp);
115extern void _mm_delete_file_reader(MREADER*);
116
117extern MWRITER* _mm_new_file_writer(int fp);
118extern void _mm_delete_file_writer(MWRITER*);
119
120extern 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
139extern void _mm_iobase_setcur(MREADER*);
140extern void _mm_iobase_revert(MREADER*);
141extern int _mm_fopen(CHAR*,CHAR*);
142extern int _mm_fclose(int);
143extern void _mm_write_string(CHAR*,MWRITER*);
144extern int _mm_read_string (CHAR*,int,MREADER*);
145
146extern SWORD _mm_read_M_SWORD(MREADER*);
147extern SWORD _mm_read_I_SWORD(MREADER*);
148extern UWORD _mm_read_M_UWORD(MREADER*);
149extern UWORD _mm_read_I_UWORD(MREADER*);
150
151extern SLONG _mm_read_M_SLONG(MREADER*);
152extern SLONG _mm_read_I_SLONG(MREADER*);
153extern ULONG _mm_read_M_ULONG(MREADER*);
154extern ULONG _mm_read_I_ULONG(MREADER*);
155
156extern int _mm_read_M_SWORDS(SWORD*,int,MREADER*);
157extern int _mm_read_I_SWORDS(SWORD*,int,MREADER*);
158extern int _mm_read_M_UWORDS(UWORD*,int,MREADER*);
159extern int _mm_read_I_UWORDS(UWORD*,int,MREADER*);
160
161extern int _mm_read_M_SLONGS(SLONG*,int,MREADER*);
162extern int _mm_read_I_SLONGS(SLONG*,int,MREADER*);
163extern int _mm_read_M_ULONGS(ULONG*,int,MREADER*);
164extern int _mm_read_I_ULONGS(ULONG*,int,MREADER*);
165
166extern void _mm_write_M_SWORD(SWORD,MWRITER*);
167extern void _mm_write_I_SWORD(SWORD,MWRITER*);
168extern void _mm_write_M_UWORD(UWORD,MWRITER*);
169extern void _mm_write_I_UWORD(UWORD,MWRITER*);
170
171extern void _mm_write_M_SLONG(SLONG,MWRITER*);
172extern void _mm_write_I_SLONG(SLONG,MWRITER*);
173extern void _mm_write_M_ULONG(ULONG,MWRITER*);
174extern void _mm_write_I_ULONG(ULONG,MWRITER*);
175
176extern void _mm_write_M_SWORDS(SWORD*,int,MWRITER*);
177extern void _mm_write_I_SWORDS(SWORD*,int,MWRITER*);
178extern void _mm_write_M_UWORDS(UWORD*,int,MWRITER*);
179extern void _mm_write_I_UWORDS(UWORD*,int,MWRITER*);
180
181extern void _mm_write_M_SLONGS(SLONG*,int,MWRITER*);
182extern void _mm_write_I_SLONGS(SLONG*,int,MWRITER*);
183extern void _mm_write_M_ULONGS(ULONG*,int,MWRITER*);
184extern 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. */
191typedef 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
205extern void SL_HalveSample(SAMPLOAD*,int);
206extern void SL_Sample8to16(SAMPLOAD*);
207extern void SL_Sample16to8(SAMPLOAD*);
208extern void SL_SampleSigned(SAMPLOAD*);
209extern void SL_SampleUnsigned(SAMPLOAD*);
210extern int SL_LoadSamples(void);
211extern SAMPLOAD* SL_RegisterSample(SAMPLE*,int,MREADER*);
212extern int SL_Load(void*,SAMPLOAD*,ULONG);
213extern int SL_Init(SAMPLOAD*);
214extern void SL_Exit(SAMPLOAD*);
215
216/*========== Internal module representation (UniMod) interface */
217
218/* number of notes in an octave */
219#define OCTAVE 12
220
221extern void UniSetRow(UBYTE*);
222extern UBYTE UniGetByte(void);
223extern UWORD UniGetWord(void);
224extern UBYTE* UniFindRow(UBYTE*,UWORD);
225extern void UniSkipOpcode(void);
226extern void UniReset(void);
227extern void UniWriteByte(UBYTE);
228extern void UniWriteWord(UWORD);
229extern void UniNewline(void);
230extern UBYTE* UniDup(void);
231extern int UniInit(void);
232extern void UniCleanup(void);
233extern void UniEffect(UWORD,UWORD);
234#define UniInstrument(x) UniEffect(UNI_INSTRUMENT,x)
235#define UniNote(x) UniEffect(UNI_NOTE,x)
236extern void UniPTEffect(UBYTE,UBYTE);
237extern void UniVolEffect(UWORD,UBYTE);
238
239/*========== Module Commands */
240
241enum {
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
316extern UWORD unioperands[UNI_LAST];
317
318/* IT / S3M Extended SS effects: */
319enum {
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 */
337enum {
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
355typedef 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
406typedef 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
419typedef 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
443typedef 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). */
518typedef 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
539typedef struct MLOADER {
540struct 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 */
551extern MREADER* modreader;
552extern UWORD finetune[16];
553extern MODULE of; /* static unimod loading space */
554extern UWORD npertab[7*OCTAVE]; /* used by the original MOD loaders */
555
556extern SBYTE remap[UF_MAXCHAN]; /* for removing empty channels */
557extern UBYTE* poslookup; /* lookup table for pattern jumps after
558 blank pattern removal */
559extern UWORD poslookupcnt;
560extern UWORD* origpositions;
561
562extern int filters; /* resonant filters in use */
563extern UBYTE activemacro; /* active midi macro number for Sxx */
564extern UBYTE filtermacros[UF_MAXMACRO]; /* midi macro settings */
565extern FILTER filtersettings[UF_MAXFILTER]; /* computed filter settings */
566
567extern int* noteindex;
568
569/*========== Internal loader interface */
570
571extern int ReadComment(UWORD);
572extern int ReadLinedComment(UWORD,UWORD);
573extern int AllocPositions(int);
574extern int AllocPatterns(void);
575extern int AllocTracks(void);
576extern int AllocInstruments(void);
577extern int AllocSamples(void);
578extern CHAR* DupStr(CHAR*,UWORD,int);
579extern CHAR* StrDup(CHAR *s);
580
581/* loader utility functions */
582extern int* AllocLinear(void);
583extern void FreeLinear(void);
584extern int speed_to_finetune(ULONG,int);
585extern void S3MIT_ProcessCmd(UBYTE,UBYTE,unsigned int);
586extern 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). */
594extern UWORD getlinearperiod(UWORD,ULONG);
595extern ULONG getfrequency(UWORD,ULONG);
596
597/* loader shared data */
598#define STM_NTRACKERS 3
599extern CHAR *STM_Signatures[STM_NTRACKERS];
600
601/*========== Player interface */
602
603extern int Player_Init(MODULE*);
604extern void Player_Exit(MODULE*);
605extern 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 */
613extern 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. */
618extern UBYTE md_numchn; /* number of song + sound effects voices */
619extern UBYTE md_sngchn; /* number of song voices */
620extern UBYTE md_sfxchn; /* number of sound effects voices */
621extern UBYTE md_hardchn; /* number of hardware mixed voices */
622extern 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. */
626extern void (*md_player)(void);
627
628extern SWORD MD_SampleLoad(SAMPLOAD*,int);
629extern void MD_SampleUnload(SWORD);
630extern ULONG MD_SampleSpace(int);
631extern ULONG MD_SampleLength(int,SAMPLE*);
632
633/* uLaw conversion */
634extern void unsignedtoulaw(char *,int);
635
636/* Parameter extraction helper */
637extern CHAR *MD_GetAtom(CHAR*,CHAR*,int);
638
639/* Internal software mixer stuff */
640extern void VC_SetupPointers(void);
641extern int VC1_Init(void);
642extern int VC2_Init(void);
643
644#if defined(unix) || defined(__APPLE__) && defined(__MACH__)
645/* POSIX helper functions */
646extern int MD_Access(CHAR *);
647extern 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
656extern void _mm_registerdriver(struct MDRIVER*);
657extern void _mm_registerloader(struct MLOADER*);
658extern int MikMod_Active_internal(void);
659extern void MikMod_DisableOutput_internal(void);
660extern int MikMod_EnableOutput_internal(void);
661extern void MikMod_Exit_internal(void);
662extern int MikMod_SetNumVoices_internal(int,int);
663extern void Player_Exit_internal(MODULE*);
664extern void Player_Stop_internal(void);
665extern int Player_Paused_internal(void);
666extern void Sample_Free_internal(SAMPLE*);
667extern void Voice_Play_internal(SBYTE,SAMPLE*,ULONG);
668extern void Voice_SetFrequency_internal(SBYTE,ULONG);
669extern void Voice_SetPanning_internal(SBYTE,ULONG);
670extern void Voice_SetVolume_internal(SBYTE,UWORD);
671extern void Voice_Stop_internal(SBYTE);
672extern 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
719static 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
725static 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
732static inline const vector float vec_setzero()
733{
734 return (const vector float) (0.);
735}
736
737static 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
755static 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).
761static 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
783static __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
52char* mmsupp_strncat(char *s1, const char *s2, size_t n);
53void mmsupp_printf(const char *fmt, ...);
54int mmsupp_sprintf(char *buf, const char *fmt, ... );
55
56extern 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
45extern int fprintf(FILE *, const char *, ...);
46#endif
47
48MREADER *modreader;
49MODULE of;
50
51static MLOADER *firstloader=NULL;
52
53UWORD finetune[16]={
54 8363,8413,8463,8529,8581,8651,8723,8757,
55 7895,7941,7985,8046,8107,8169,8232,8280
56};
57
58MIKMODAPI 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
79void _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
90MIKMODAPI 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
102int 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
123int 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
166int 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
176int 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
197int 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
207int 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
229int 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
248static 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. */
261CHAR *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
287CHAR *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
295static 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
302static void ML_XFreeInstrument(INSTRUMENT *i)
303{
304 if(i->insname) MikMod_free(i->insname);
305}
306
307static 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
338static MODULE *ML_AllocUniMod(void)
339{
340 MODULE *mf;
341
342 return (mf=MikMod_malloc(sizeof(MODULE)));
343}
344
345void Player_Free_internal(MODULE *mf)
346{
347 if(mf) {
348 Player_Exit_internal(mf);
349 ML_FreeEx(mf);
350 }
351}
352
353MIKMODAPI void Player_Free(MODULE *mf)
354{
355 MUTEX_LOCK(vars);
356 Player_Free_internal(mf);
357 MUTEX_UNLOCK(vars);
358}
359
360static 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
384MIKMODAPI 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
398MIKMODAPI 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
415MIKMODAPI 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
427MIKMODAPI 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 */
446MODULE* 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
562MIKMODAPI 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
575MIKMODAPI 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. */
589MIKMODAPI 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'. */
603MIKMODAPI 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
35void 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
60void 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
41extern int fprintf(FILE *, const char *, ...);
42#endif
43
44/*========== Shared tracker identifiers */
45
46CHAR *STM_Signatures[STM_NTRACKERS] = {
47 "!Scream!",
48 "BMOD2STM",
49 "WUZAMOD!"
50};
51
52CHAR *STM_Version[STM_NTRACKERS] = {
53 "Screamtracker 2",
54 "Converted by MOD2STM (STM format)",
55 "Wuzamod (STM format)"
56};
57
58/*========== Shared loader variables */
59
60SBYTE remap[UF_MAXCHAN]; /* for removing empty channels */
61UBYTE* poslookup=NULL; /* lookup table for pattern jumps after blank
62 pattern removal */
63UWORD poslookupcnt;
64UWORD* origpositions=NULL;
65
66int filters; /* resonant filters in use */
67UBYTE activemacro; /* active midi macro number for Sxx,xx<80h */
68UBYTE filtermacros[UF_MAXMACRO]; /* midi macro settings */
69FILTER filtersettings[UF_MAXFILTER]; /* computed filter settings */
70
71/*========== Linear periods stuff */
72
73int* noteindex=NULL; /* remap value for linear period modules */
74static int noteindexcount=0;
75
76int *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
85void FreeLinear(void)
86{
87 if(noteindex) {
88 MikMod_free(noteindex);
89 noteindex=NULL;
90 }
91 noteindexcount=0;
92}
93
94int 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 */
122void 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 */
144void 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 */
305void 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. */
317void 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. */
328void 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
37static 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
50static 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
58void* 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 */
85void* 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 */
123void* 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
161void 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
43CHAR *_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
183MIKMODAPI 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 */
190MikMod_handler_t _mm_errorhandler = NULL;
191MIKMODAPI int _mm_errno = 0;
192MIKMODAPI int _mm_critical = 0;
193
194MikMod_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
202MIKMODAPI 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
61extern int fclose(FILE *);
62extern int fgetc(FILE *);
63extern int fputc(int, FILE *);
64extern size_t fread(void *, size_t, size_t, FILE *);
65extern int fseek(FILE *, long, int);
66extern size_t fwrite(const void *, size_t, size_t, FILE *);
67#endif
68
69#define COPY_BUFSIZE 1024
70
71/* some prototypes */
72static int _mm_MemReader_Eof(MREADER* reader);
73static int _mm_MemReader_Read(MREADER* reader,void* ptr,size_t size);
74static int _mm_MemReader_Get(MREADER* reader);
75static int _mm_MemReader_Seek(MREADER* reader,long offset,int whence);
76static long _mm_MemReader_Tell(MREADER* reader);
77
78//static long _mm_iobase=0,temp_iobase=0;
79
80int _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
96int _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
109int _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 */
116void _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. */
123void _mm_iobase_revert(MREADER* reader)
124{
125 reader->iobase=reader->prev_iobase;
126}
127
128/*========== File Reader */
129
130typedef struct MFILEREADER {
131 MREADER core;
132 int file;
133} MFILEREADER;
134
135static 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
144static 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
150static 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
160static 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
168static 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
174MREADER *_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
188void _mm_delete_file_reader (MREADER* reader)
189{
190 if(reader) MikMod_free(reader);
191}
192
193/*========== File Writer */
194
195typedef struct MFILEWRITER {
196 MWRITER core;
197 int file;
198} MFILEWRITER;
199
200static 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
206static long _mm_FileWriter_Tell(MWRITER* writer)
207{
208 //return ftell(((MFILEWRITER*)writer)->file);
209 return lseek(((MFILEWRITER*)writer)->file, 0, SEEK_CUR);
210}
211
212static 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
218static int _mm_FileWriter_Put(MWRITER* writer,int value)
219{
220 //return fputc(value,((MFILEWRITER*)writer)->file);
221 return 1; // TODO
222}
223
224MWRITER *_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
237void _mm_delete_file_writer (MWRITER* writer)
238{
239 if(writer) MikMod_free (writer);
240}
241
242/*========== Memory Reader */
243
244
245typedef struct MMEMREADER {
246 MREADER core;
247 const void *buffer;
248 long len;
249 long pos;
250} MMEMREADER;
251
252void _mm_delete_mem_reader(MREADER* reader)
253{
254 if (reader) { MikMod_free(reader); }
255}
256
257MREADER *_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
274static 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
283static 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
313static 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
325static 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
348static 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
358void _mm_write_string(CHAR* data,MWRITER* writer)
359{
360 if(data)
361 _mm_write_UBYTES(data,strlen(data),writer);
362}
363
364void _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
370void _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
376void _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
382void _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
388void _mm_write_M_SWORD(SWORD data,MWRITER* writer)
389{
390 _mm_write_M_UWORD((UWORD)data,writer);
391}
392
393void _mm_write_I_SWORD(SWORD data,MWRITER* writer)
394{
395 _mm_write_I_UWORD((UWORD)data,writer);
396}
397
398void _mm_write_M_SLONG(SLONG data,MWRITER* writer)
399{
400 _mm_write_M_ULONG((ULONG)data,writer);
401}
402
403void _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) \
410void _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) \
417void _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
424DEFINE_MULTIPLE_WRITE_FUNCTION(M_SWORD,SWORD)
425DEFINE_MULTIPLE_WRITE_FUNCTION(M_UWORD,UWORD)
426DEFINE_MULTIPLE_WRITE_FUNCTION(I_SWORD,SWORD)
427DEFINE_MULTIPLE_WRITE_FUNCTION(I_UWORD,UWORD)
428
429DEFINE_MULTIPLE_WRITE_FUNCTION(M_SLONG,SLONG)
430DEFINE_MULTIPLE_WRITE_FUNCTION(M_ULONG,ULONG)
431DEFINE_MULTIPLE_WRITE_FUNCTION(I_SLONG,SLONG)
432DEFINE_MULTIPLE_WRITE_FUNCTION(I_ULONG,ULONG)
433
434/*========== Read functions */
435
436int _mm_read_string(CHAR* buffer,int number,MREADER* reader)
437{
438 return reader->Read(reader,buffer,number);
439}
440
441UWORD _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
448UWORD _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
455ULONG _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
462ULONG _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
469SWORD _mm_read_M_SWORD(MREADER* reader)
470{
471 return((SWORD)_mm_read_M_UWORD(reader));
472}
473
474SWORD _mm_read_I_SWORD(MREADER* reader)
475{
476 return((SWORD)_mm_read_I_UWORD(reader));
477}
478
479SLONG _mm_read_M_SLONG(MREADER* reader)
480{
481 return((SLONG)_mm_read_M_ULONG(reader));
482}
483
484SLONG _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) \
491int _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) \
499int _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
507DEFINE_MULTIPLE_READ_FUNCTION(M_SWORD,SWORD)
508DEFINE_MULTIPLE_READ_FUNCTION(M_UWORD,UWORD)
509DEFINE_MULTIPLE_READ_FUNCTION(I_SWORD,SWORD)
510DEFINE_MULTIPLE_READ_FUNCTION(I_UWORD,UWORD)
511
512DEFINE_MULTIPLE_READ_FUNCTION(M_SLONG,SLONG)
513DEFINE_MULTIPLE_READ_FUNCTION(M_ULONG,ULONG)
514DEFINE_MULTIPLE_READ_FUNCTION(I_SLONG,SLONG)
515DEFINE_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
46extern int fprintf(FILE *, const char *, ...);
47extern long int random(void);
48#endif
49
50/* The currently playing module */
51MODULE *pf = NULL;
52
53#define HIGH_OCTAVE 2 /* number of above-range octaves */
54
55static 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
62static 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
67static 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) */
79static 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
179static 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
208static 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 */
228static 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*/
244static 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
277static 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
283UWORD 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
291static 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
307static 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
324static 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
335static SWORD InterpolateEnv(SWORD p,ENVPT *a,ENVPT *b)
336{
337 return (Interpolate(p,a->pos,b->pos,a->val,b->val));
338}
339
340static 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
349static 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*/
395static 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 */
473ULONG 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
488static 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
546static 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
563static 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
577static 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
591static 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
621static 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
633static 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
673static 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
688static 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
701static 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
717static 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
766static 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
777static 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
794static 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
805static 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
814static 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
848static 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
861static 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
889static 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
1015static 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
1022static 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
1041static 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
1060static 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
1092static 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
1099static 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
1121static 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
1132static 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
1152static 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
1163static 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
1189static 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
1250static 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
1298static 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
1312static 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
1359static 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
1368static 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
1386static 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
1412static 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
1420static 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
1434static 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
1448static 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
1461static 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
1474static 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
1482static 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
1503static 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
1528static 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
1557static 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
1577static 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
1599static 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
1639static 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
1646static 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
1690static 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
1697static 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
1721static 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
1732static 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
1767static 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
1804static 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
1825static 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
1870static 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
1905static 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
1947static void DoNNAEffects(MODULE *, MP_CONTROL *, UBYTE);
1948
1949/* Impulse/Scream Tracker Sxx effects.
1950 All Sxx effects share the same memory space. */
1951static 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
2030static 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
2080static 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
2097static 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
2106static 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
2113static 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
2120static 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
2129static 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
2149static int DoNothing(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
2150{
2151 UniSkipOpcode();
2152
2153 return 0;
2154}
2155
2156typedef int (*effect_func) (UWORD, UWORD, MP_CONTROL *, MODULE *, SWORD);
2157
2158static 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
2223static 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
2240static 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
2307void 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 */
2510void 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 */
2648void 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 */
2699void 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 */
2780void 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 */
2821void 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
2843void 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
2934static 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
2966int 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
2986void 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
3005void Player_Exit(MODULE* mod)
3006{
3007 MUTEX_LOCK(vars);
3008 Player_Exit_internal(mod);
3009 MUTEX_UNLOCK(vars);
3010}
3011
3012MIKMODAPI 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
3020MIKMODAPI 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
3031MIKMODAPI 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
3053void Player_Stop_internal(void)
3054{
3055 if (!md_sfxchn) MikMod_DisableOutput_internal();
3056 if (pf) pf->forbid=1;
3057 pf=NULL;
3058}
3059
3060MIKMODAPI void Player_Stop(void)
3061{
3062 MUTEX_LOCK(vars);
3063 Player_Stop_internal();
3064 MUTEX_UNLOCK(vars);
3065}
3066
3067MIKMODAPI 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
3079MIKMODAPI 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
3104MIKMODAPI 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
3129MIKMODAPI 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
3159static 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
3189MIKMODAPI 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
3200static 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
3231MIKMODAPI 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
3242static 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
3274MIKMODAPI 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
3285MIKMODAPI 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
3297MIKMODAPI 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
3309MIKMODAPI 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
3321int Player_Paused_internal(void)
3322{
3323 return pf?pf->forbid:1;
3324}
3325
3326MIKMODAPI 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
3337MIKMODAPI void Player_TogglePause(void)
3338{
3339 MUTEX_LOCK(vars);
3340 if (pf)
3341 pf->forbid=1-pf->forbid;
3342 MUTEX_UNLOCK(vars);
3343}
3344
3345MIKMODAPI 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
3353MIKMODAPI 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
3364MIKMODAPI 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
3389MIKMODAPI 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
3399MIKMODAPI 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
40UWORD 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.
109It's made up of 'repeat/length' bytes, opcodes and operands (sort of a assembly
110language):
111
112rrrlllll
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_
118the length byte itself (So the LENGTH byte of row 0 in the previous example
119would have a value of 5). This makes it easy to search through a stream for a
120particular 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
123is 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
126used. Each opcode can have a different number of operands. You can find the
127number of operands to a particular opcode by using the opcode as an index into
128the 'unioperands' table.
129
130*/
131
132/*========== Reading routines */
133
134static UBYTE *rowstart; /* startadress of a row */
135static UBYTE *rowend; /* endaddress of a row (exclusive) */
136static UBYTE *rowpc; /* current unimod(tm) programcounter */
137
138static UBYTE lastbyte; /* for UniSkipOpcode() */
139
140void UniSetRow(UBYTE* t)
141{
142 rowstart = t;
143 rowpc = rowstart;
144 rowend = t?rowstart+(*(rowpc++)&0x1f):t;
145}
146
147UBYTE UniGetByte(void)
148{
149 return lastbyte = (rowpc<rowend)?*(rowpc++):0;
150}
151
152UWORD UniGetWord(void)
153{
154 return ((UWORD)UniGetByte()<<8)|UniGetByte();
155}
156
157void 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. */
169UBYTE *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
187static UBYTE *unibuf; /* pointer to the temporary unitrk buffer */
188static UWORD unimax; /* buffer size */
189
190static UWORD unipc; /* buffer cursor */
191static UWORD unitt; /* current row index */
192static UWORD lastp; /* previous row index */
193
194/* Resets index-pointers to create a new track. */
195void 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 */
204static 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. */
224void UniWriteByte(UBYTE data)
225{
226 if (UniExpand(1))
227 /* write byte to current position and update */
228 unibuf[unipc++]=data;
229}
230
231void UniWriteWord(UWORD data)
232{
233 if (UniExpand(2)) {
234 unibuf[unipc++]=data>>8;
235 unibuf[unipc++]=data&0xff;
236 }
237}
238
239static 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. */
250void 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. */
276UBYTE* 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
289int UniInit(void)
290{
291 unimax = BUFPAGE;
292
293 if(!(unibuf=(UBYTE*)MikMod_malloc(unimax*sizeof(UBYTE)))) return 0;
294 return 1;
295}
296
297void 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
35UWORD 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
40static int sl_rlength;
41static SWORD sl_old;
42static SWORD *sl_buffer=NULL;
43static SAMPLOAD *musiclist=NULL,*sndfxlist=NULL;
44
45/* size of the loader buffer in words */
46#define SLBUFSIZE 2048
47
48/* IT-Compressed status structure */
49typedef 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
56int 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
68void 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 */
78static 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 */
152static 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
225static 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
337int 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. */
344SAMPLOAD* 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
378static 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. */
390static 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
404static ULONG RealSpeed(SAMPLOAD *s)
405{
406 return(s->sample->speed/(s->scalefactor?s->scalefactor:1));
407}
408
409static 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
471int 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
484void SL_Sample16to8(SAMPLOAD* s)
485{
486 s->outfmt &= ~SF_16BITS;
487 s->sample->flags = (s->sample->flags&~SF_FORMATMASK) | s->outfmt;
488}
489
490void SL_Sample8to16(SAMPLOAD* s)
491{
492 s->outfmt |= SF_16BITS;
493 s->sample->flags = (s->sample->flags&~SF_FORMATMASK) | s->outfmt;
494}
495
496void SL_SampleSigned(SAMPLOAD* s)
497{
498 s->outfmt |= SF_SIGNED;
499 s->sample->flags = (s->sample->flags&~SF_FORMATMASK) | s->outfmt;
500}
501
502void SL_SampleUnsigned(SAMPLOAD* s)
503{
504 s->outfmt &= ~SF_SIGNED;
505 s->sample->flags = (s->sample->flags&~SF_FORMATMASK) | s->outfmt;
506}
507
508void 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
11char* 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
9char *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
86typedef 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
107static SWORD **Samples;
108static VINFO *vinf=NULL,*vnf;
109static long tickleft,samplesthatfit,vc_memory=0;
110static int vc_softchn;
111static SLONGLONG idxsize,idxlpos,idxlend;
112static SLONG *vc_tickbuf=NULL;
113static UWORD vc_mode;
114
115/* Reverb control variables */
116
117static int RVc1, RVc2, RVc3, RVc4, RVc5, RVc6, RVc7, RVc8;
118static ULONG RVRindex;
119
120/* For Mono or Left Channel */
121static 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) */
125static 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
135static 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
150static 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
260static 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
285static 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
310static 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
336static 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
371static 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
411static 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
463static 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
477static 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
493static 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
519static 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
554static 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
594static 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
642static 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
649static 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
680static 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
720static void (*MixLowPass)(SLONG* srce,NATIVE count);
721
722static int nLeftNR, nRightNR;
723
724static 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
743static 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
766static 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
795static 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
817static 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
844static 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
892static 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
927static 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
964static 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
1126void 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
1220int 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
1243int 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
1280void 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
1302int 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
34extern int VC1_Init(void);
35//extern int VC2_Init(void);
36static int (*VC_Init_ptr)(void)=VC1_Init;
37extern void VC1_Exit(void);
38//extern void VC2_Exit(void);
39static void (*VC_Exit_ptr)(void)=VC1_Exit;
40extern int VC1_SetNumVoices(void);
41//extern int VC2_SetNumVoices(void);
42static int (*VC_SetNumVoices_ptr)(void);
43extern ULONG VC1_SampleSpace(int);
44//extern ULONG VC2_SampleSpace(int);
45static ULONG (*VC_SampleSpace_ptr)(int);
46extern ULONG VC1_SampleLength(int,SAMPLE*);
47//extern ULONG VC2_SampleLength(int,SAMPLE*);
48static ULONG (*VC_SampleLength_ptr)(int,SAMPLE*);
49
50extern int VC1_PlayStart(void);
51//extern int VC2_PlayStart(void);
52static int (*VC_PlayStart_ptr)(void);
53extern void VC1_PlayStop(void);
54extern void VC2_PlayStop(void);
55static void (*VC_PlayStop_ptr)(void);
56
57extern SWORD VC1_SampleLoad(struct SAMPLOAD*,int);
58//extern SWORD VC2_SampleLoad(struct SAMPLOAD*,int);
59static SWORD (*VC_SampleLoad_ptr)(struct SAMPLOAD*,int);
60extern void VC1_SampleUnload(SWORD);
61//extern void VC2_SampleUnload(SWORD);
62static void (*VC_SampleUnload_ptr)(SWORD);
63
64extern ULONG VC1_WriteBytes(SBYTE*,ULONG);
65//extern ULONG VC2_WriteBytes(SBYTE*,ULONG);
66static ULONG (*VC_WriteBytes_ptr)(SBYTE*,ULONG);
67extern ULONG VC1_SilenceBytes(SBYTE*,ULONG);
68//extern ULONG VC2_SilenceBytes(SBYTE*,ULONG);
69static ULONG (*VC_SilenceBytes_ptr)(SBYTE*,ULONG);
70
71extern void VC1_VoiceSetVolume(UBYTE,UWORD);
72//extern void VC2_VoiceSetVolume(UBYTE,UWORD);
73static void (*VC_VoiceSetVolume_ptr)(UBYTE,UWORD);
74extern UWORD VC1_VoiceGetVolume(UBYTE);
75//extern UWORD VC2_VoiceGetVolume(UBYTE);
76static UWORD (*VC_VoiceGetVolume_ptr)(UBYTE);
77extern void VC1_VoiceSetFrequency(UBYTE,ULONG);
78//extern void VC2_VoiceSetFrequency(UBYTE,ULONG);
79static void (*VC_VoiceSetFrequency_ptr)(UBYTE,ULONG);
80extern ULONG VC1_VoiceGetFrequency(UBYTE);
81//extern ULONG VC2_VoiceGetFrequency(UBYTE);
82static ULONG (*VC_VoiceGetFrequency_ptr)(UBYTE);
83extern void VC1_VoiceSetPanning(UBYTE,ULONG);
84//extern void VC2_VoiceSetPanning(UBYTE,ULONG);
85static void (*VC_VoiceSetPanning_ptr)(UBYTE,ULONG);
86extern ULONG VC1_VoiceGetPanning(UBYTE);
87//extern ULONG VC2_VoiceGetPanning(UBYTE);
88static ULONG (*VC_VoiceGetPanning_ptr)(UBYTE);
89extern void VC1_VoicePlay(UBYTE,SWORD,ULONG,ULONG,ULONG,ULONG,UWORD);
90//extern void VC2_VoicePlay(UBYTE,SWORD,ULONG,ULONG,ULONG,ULONG,UWORD);
91static void (*VC_VoicePlay_ptr)(UBYTE,SWORD,ULONG,ULONG,ULONG,ULONG,UWORD);
92
93extern void VC1_VoiceStop(UBYTE);
94//extern void VC2_VoiceStop(UBYTE);
95static void (*VC_VoiceStop_ptr)(UBYTE);
96extern int VC1_VoiceStopped(UBYTE);
97//extern int VC2_VoiceStopped(UBYTE);
98static int (*VC_VoiceStopped_ptr)(UBYTE);
99extern SLONG VC1_VoiceGetPosition(UBYTE);
100//extern SLONG VC2_VoiceGetPosition(UBYTE);
101static SLONG (*VC_VoiceGetPosition_ptr)(UBYTE);
102extern ULONG VC1_VoiceRealVolume(UBYTE);
103//extern ULONG VC2_VoiceRealVolume(UBYTE);
104static ULONG (*VC_VoiceRealVolume_ptr)(UBYTE);
105
106#if defined __STDC__ || defined _MSC_VER || defined MPW_C
107#define VC_PROC0(suffix) \
108MIKMODAPI void VC_##suffix (void) { VC_##suffix##_ptr(); }
109
110#define VC_FUNC0(suffix,ret) \
111MIKMODAPI ret VC_##suffix (void) { return VC_##suffix##_ptr(); }
112
113#define VC_PROC1(suffix,typ1) \
114MIKMODAPI void VC_##suffix (typ1 a) { VC_##suffix##_ptr(a); }
115
116#define VC_FUNC1(suffix,ret,typ1) \
117MIKMODAPI ret VC_##suffix (typ1 a) { return VC_##suffix##_ptr(a); }
118
119#define VC_PROC2(suffix,typ1,typ2) \
120MIKMODAPI void VC_##suffix (typ1 a,typ2 b) { VC_##suffix##_ptr(a,b); }
121
122#define VC_FUNC2(suffix,ret,typ1,typ2) \
123MIKMODAPI ret VC_##suffix (typ1 a,typ2 b) { return VC_##suffix##_ptr(a,b); }
124#else
125#define VC_PROC0(suffix) \
126MIKMODAPI void VC_/**/suffix (void) { VC_/**/suffix/**/_ptr(); }
127
128#define VC_FUNC0(suffix,ret) \
129MIKMODAPI ret VC_/**/suffix (void) { return VC_/**/suffix/**/_ptr(); }
130
131#define VC_PROC1(suffix,typ1) \
132MIKMODAPI void VC_/**/suffix (typ1 a) { VC_/**/suffix/**/_ptr(a); }
133
134#define VC_FUNC1(suffix,ret,typ1) \
135MIKMODAPI ret VC_/**/suffix (typ1 a) { return VC_/**/suffix/**/_ptr(a); }
136
137#define VC_PROC2(suffix,typ1,typ2) \
138MIKMODAPI void VC_/**/suffix (typ1 a,typ2 b) { VC_/**/suffix/**/_ptr(a,b); }
139
140#define VC_FUNC2(suffix,ret,typ1,typ2) \
141MIKMODAPI ret VC_/**/suffix (typ1 a,typ2 b) { return VC_/**/suffix/**/_ptr(a,b); }
142#endif
143
144VC_FUNC0(Init,int)
145VC_PROC0(Exit)
146VC_FUNC0(SetNumVoices,int)
147VC_FUNC1(SampleSpace,ULONG,int)
148VC_FUNC2(SampleLength,ULONG,int,SAMPLE*)
149VC_FUNC0(PlayStart,int)
150VC_PROC0(PlayStop)
151VC_FUNC2(SampleLoad,SWORD,struct SAMPLOAD*,int)
152VC_PROC1(SampleUnload,SWORD)
153VC_FUNC2(WriteBytes,ULONG,SBYTE*,ULONG)
154VC_FUNC2(SilenceBytes,ULONG,SBYTE*,ULONG)
155VC_PROC2(VoiceSetVolume,UBYTE,UWORD)
156VC_FUNC1(VoiceGetVolume,UWORD,UBYTE)
157VC_PROC2(VoiceSetFrequency,UBYTE,ULONG)
158VC_FUNC1(VoiceGetFrequency,ULONG,UBYTE)
159VC_PROC2(VoiceSetPanning,UBYTE,ULONG)
160VC_FUNC1(VoiceGetPanning,ULONG,UBYTE)
161
162void 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
165VC_PROC1(VoiceStop,UBYTE)
166VC_FUNC1(VoiceStopped,int,UBYTE)
167VC_FUNC1(VoiceGetPosition,SLONG,UBYTE)
168VC_FUNC1(VoiceRealVolume,ULONG,UBYTE)
169
170void 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
228static 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
236static 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) */
246ULONG 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
261void 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). */
266ULONG 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
277void 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
290UWORD VC1_VoiceGetVolume(UBYTE voice)
291{
292 return vinf[voice].vol;
293}
294
295ULONG VC1_VoiceGetPanning(UBYTE voice)
296{
297 return vinf[voice].pan;
298}
299
300void VC1_VoiceSetFrequency(UBYTE voice,ULONG frq)
301{
302 vinf[voice].frq=frq;
303}
304
305ULONG VC1_VoiceGetFrequency(UBYTE voice)
306{
307 return vinf[voice].frq;
308}
309
310void 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
321void VC1_VoiceStop(UBYTE voice)
322{
323 vinf[voice].active = 0;
324}
325
326int VC1_VoiceStopped(UBYTE voice)
327{
328 return(vinf[voice].active==0);
329}
330
331SLONG VC1_VoiceGetPosition(UBYTE voice)
332{
333 return (SLONG)(vinf[voice].current>>FRACBITS);
334}
335
336void 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
344void 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
354void 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
363SWORD 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
417ULONG VC1_SampleSpace(int type)
418{
419 return vc_memory;
420}
421
422ULONG 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
429ULONG 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
460MikMod_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
33sgb,viewers/rockboy,6 33sgb,viewers/rockboy,6
34mid,viewers/midi,7 34mid,viewers/midi,7
35rmi,viewers/midi,7 35rmi,viewers/midi,7
36669,viewers/mikmod,7
37amf,viewers/mikmod,7
38asy,viewers/mikmod,7
39dsm,viewers/mikmod,7
40far,viewers/mikmod,7
41gdm,viewers/mikmod,7
42gt2,viewers/mikmod,7
43imf,viewers/mikmod,7
44it,viewers/mikmod,7
45m15,viewers/mikmod,7
46med,viewers/mikmod,7
47mod,viewers/mikmod,7
48mtm,viewers/mikmod,7
49okt,viewers/mikmod,7
50s3m,viewers/mikmod,7
51stm,viewers/mikmod,7
52stx,viewers/mikmod,7
53ult,viewers/mikmod,7
54uni,viewers/mikmod,7
55xm,viewers/mikmod,7
36pd,viewers/pdbox,2 56pd,viewers/pdbox,2
37rsp,viewers/searchengine,8 57rsp,viewers/searchengine,8
38sok,games/sokoban,1 58sok,games/sokoban,1
diff --git a/docs/CREDITS b/docs/CREDITS
index 77c0392868..d2eacb8e2a 100644
--- a/docs/CREDITS
+++ b/docs/CREDITS
@@ -568,6 +568,8 @@ Franz-Josef Haider
568Michael Hohmuth 568Michael Hohmuth
569Sergio Vera 569Sergio Vera
570Michael Leslie 570Michael Leslie
571Craig Mann
572William Peters
571 573
572The libmad team 574The libmad team
573The wavpack team 575The wavpack team
@@ -593,4 +595,4 @@ The libmtp team
593The asap team 595The asap team
594The libpng team 596The libpng team
595The Pure Data team (Miller Puckette and others) 597The Pure Data team (Miller Puckette and others)
596 598The MikMod team