Add "MikMod for Rockbox 0.1" from 2007-06-29
[mikmod-rockbox.git] / apps / plugins / mikmod / loaders / load_mtm.c
1 /*      MikMod sound library\r
2         (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file\r
3         AUTHORS for complete list.\r
4 \r
5         This library is free software; you can redistribute it and/or modify\r
6         it under the terms of the GNU Library General Public License as\r
7         published by the Free Software Foundation; either version 2 of\r
8         the License, or (at your option) any later version.\r
9  \r
10         This program is distributed in the hope that it will be useful,\r
11         but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13         GNU Library General Public License for more details.\r
14  \r
15         You should have received a copy of the GNU Library General Public\r
16         License along with this library; if not, write to the Free Software\r
17         Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA\r
18         02111-1307, USA.\r
19 */\r
20 \r
21 /*==============================================================================\r
22 \r
23   $Id: load_mtm.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $\r
24 \r
25   MTM module loader\r
26 \r
27 ==============================================================================*/\r
28 \r
29 #ifdef HAVE_CONFIG_H\r
30 #include "config.h"\r
31 #endif\r
32 \r
33 #ifdef HAVE_UNISTD_H\r
34 #include <unistd.h>\r
35 #endif\r
36 \r
37 #include <stdio.h>\r
38 #ifdef HAVE_MEMORY_H\r
39 #include <memory.h>\r
40 #endif\r
41 #include <string.h>\r
42 \r
43 #include "mikmod_internals.h"\r
44 \r
45 #ifdef SUNOS\r
46 extern int fprintf(FILE *, const char *, ...);\r
47 #endif\r
48 \r
49 /*========== Module structure */\r
50 \r
51 typedef struct MTMHEADER {\r
52         UBYTE id[3];                    /* MTM file marker */\r
53         UBYTE version;                  /* upper major, lower nibble minor version number */\r
54         CHAR  songname[20];             /* ASCIIZ songname */\r
55         UWORD numtracks;                /* number of tracks saved */\r
56         UBYTE lastpattern;              /* last pattern number saved */\r
57         UBYTE lastorder;                /* last order number to play (songlength-1) */\r
58         UWORD commentsize;              /* length of comment field */\r
59         UBYTE numsamples;               /* number of samples saved  */\r
60         UBYTE attribute;                /* attribute byte (unused) */\r
61         UBYTE beatspertrack;\r
62         UBYTE numchannels;              /* number of channels used  */\r
63         UBYTE panpos[32];               /* voice pan positions */\r
64 } MTMHEADER;\r
65 \r
66 typedef struct MTMSAMPLE {\r
67         CHAR  samplename[22];\r
68         ULONG length;\r
69         ULONG reppos;\r
70         ULONG repend;\r
71         UBYTE finetune;\r
72         UBYTE volume;\r
73         UBYTE attribute;\r
74 } MTMSAMPLE;\r
75 \r
76 typedef struct MTMNOTE {\r
77         UBYTE a,b,c;\r
78 } MTMNOTE;\r
79 \r
80 /*========== Loader variables */\r
81 \r
82 static MTMHEADER *mh = NULL;\r
83 static MTMNOTE *mtmtrk = NULL;\r
84 static UWORD pat[32];\r
85 \r
86 static CHAR MTM_Version[] = "MTM";\r
87 \r
88 /*========== Loader code */\r
89 \r
90 BOOL MTM_Test(void)\r
91 {\r
92         UBYTE id[3];\r
93 \r
94         if(!_mm_read_UBYTES(id,3,modreader)) return 0;\r
95         if(!memcmp(id,"MTM",3)) return 1;\r
96         return 0;\r
97 }\r
98 \r
99 BOOL MTM_Init(void)\r
100 {\r
101         if(!(mtmtrk=(MTMNOTE*)_mm_calloc(64,sizeof(MTMNOTE)))) return 0;\r
102         if(!(mh=(MTMHEADER*)_mm_malloc(sizeof(MTMHEADER)))) return 0;\r
103 \r
104         return 1;\r
105 }\r
106 \r
107 void MTM_Cleanup(void)\r
108 {\r
109         _mm_free(mtmtrk);\r
110         _mm_free(mh);\r
111 }\r
112 \r
113 static UBYTE* MTM_Convert(void)\r
114 {\r
115         int t;\r
116         UBYTE a,b,inst,note,eff,dat;\r
117 \r
118         UniReset();\r
119         for(t=0;t<64;t++) {\r
120                 a=mtmtrk[t].a;\r
121                 b=mtmtrk[t].b;\r
122                 inst=((a&0x3)<<4)|(b>>4);\r
123                 note=a>>2;\r
124                 eff=b&0xf;\r
125                 dat=mtmtrk[t].c;\r
126 \r
127                 if(inst) UniInstrument(inst-1);\r
128                 if(note) UniNote(note+2*OCTAVE);\r
129 \r
130                 /* MTM bug workaround : when the effect is volslide, slide-up *always*\r
131                    overrides slide-down. */\r
132                 if(eff==0xa && (dat&0xf0)) dat&=0xf0;\r
133 \r
134                 /* Convert pattern jump from Dec to Hex */\r
135                 if(eff==0xd)\r
136                         dat=(((dat&0xf0)>>4)*10)+(dat&0xf);\r
137                 UniPTEffect(eff,dat);\r
138                 UniNewline();\r
139         }\r
140         return UniDup();\r
141 }\r
142 \r
143 BOOL MTM_Load(BOOL curious)\r
144 {\r
145         int t,u;\r
146         MTMSAMPLE s;\r
147         SAMPLE *q;\r
148         (void)curious;\r
149 \r
150         /* try to read module header  */\r
151         _mm_read_UBYTES(mh->id,3,modreader);\r
152         mh->version     =_mm_read_UBYTE(modreader);\r
153         _mm_read_string(mh->songname,20,modreader);\r
154         mh->numtracks   =_mm_read_I_UWORD(modreader);\r
155         mh->lastpattern =_mm_read_UBYTE(modreader);\r
156         mh->lastorder   =_mm_read_UBYTE(modreader);\r
157         mh->commentsize =_mm_read_I_UWORD(modreader);\r
158         mh->numsamples  =_mm_read_UBYTE(modreader);\r
159         mh->attribute   =_mm_read_UBYTE(modreader);\r
160         mh->beatspertrack=_mm_read_UBYTE(modreader);\r
161         mh->numchannels =_mm_read_UBYTE(modreader);\r
162         _mm_read_UBYTES(mh->panpos,32,modreader);\r
163 \r
164         if(_mm_eof(modreader)) {\r
165                 _mm_errno = MMERR_LOADING_HEADER;\r
166                 return 0;\r
167         }\r
168 \r
169         /* set module variables */\r
170         of.initspeed = 6;\r
171         of.inittempo = 125;\r
172         of.modtype   = strdup(MTM_Version);\r
173         of.numchn    = mh->numchannels;\r
174         of.numtrk    = mh->numtracks+1;           /* get number of channels */\r
175         of.songname  = DupStr(mh->songname,20,1); /* make a cstr of songname */\r
176         of.numpos    = mh->lastorder+1;           /* copy the songlength */\r
177         of.numpat    = mh->lastpattern+1;\r
178         of.reppos    = 0;\r
179         of.flags    |= UF_PANNING;\r
180         for(t=0;t<32;t++) of.panning[t]=mh->panpos[t]<< 4;\r
181         of.numins=of.numsmp=mh->numsamples;\r
182 \r
183         if(!AllocSamples()) return 0;\r
184         q=of.samples;\r
185         for(t=0;t<of.numins;t++) {\r
186                 /* try to read sample info */\r
187                 _mm_read_string(s.samplename,22,modreader);\r
188                 s.length    =_mm_read_I_ULONG(modreader);\r
189                 s.reppos    =_mm_read_I_ULONG(modreader);\r
190                 s.repend    =_mm_read_I_ULONG(modreader);\r
191                 s.finetune  =_mm_read_UBYTE(modreader);\r
192                 s.volume    =_mm_read_UBYTE(modreader);\r
193                 s.attribute =_mm_read_UBYTE(modreader);\r
194 \r
195                 if(_mm_eof(modreader)) {\r
196                         _mm_errno = MMERR_LOADING_SAMPLEINFO; \r
197                         return 0;\r
198                 }\r
199 \r
200                 q->samplename = DupStr(s.samplename,22,1);\r
201                 q->seekpos   = 0;\r
202                 q->speed     = finetune[s.finetune];\r
203                 q->length    = s.length;\r
204                 q->loopstart = s.reppos;\r
205                 q->loopend   = s.repend;\r
206                 q->volume    = s.volume;\r
207                 if((s.repend-s.reppos)>2) q->flags |= SF_LOOP;\r
208 \r
209                 if(s.attribute&1) {\r
210                         /* If the sample is 16-bits, convert the length and replen\r
211                            byte-values into sample-values */\r
212                         q->flags|=SF_16BITS;\r
213                         q->length>>=1;\r
214                         q->loopstart>>=1;\r
215                         q->loopend>>=1;\r
216                 }\r
217                 q++;\r
218         }\r
219 \r
220         if(!AllocPositions(of.numpos)) return 0;\r
221         for(t=0;t<of.numpos;t++)\r
222                 of.positions[t]=_mm_read_UBYTE(modreader);\r
223         for(;t<128;t++) _mm_read_UBYTE(modreader);\r
224         if(_mm_eof(modreader)) {\r
225                 _mm_errno = MMERR_LOADING_HEADER;\r
226                 return 0;\r
227         }\r
228 \r
229         if(!AllocTracks()) return 0;\r
230         if(!AllocPatterns()) return 0;\r
231 \r
232         of.tracks[0]=MTM_Convert();             /* track 0 is empty */\r
233         for(t=1;t<of.numtrk;t++) {\r
234                 int s;\r
235 \r
236                 for(s=0;s<64;s++) {\r
237                         mtmtrk[s].a=_mm_read_UBYTE(modreader);\r
238                         mtmtrk[s].b=_mm_read_UBYTE(modreader);\r
239                         mtmtrk[s].c=_mm_read_UBYTE(modreader);\r
240                 }\r
241 \r
242                 if(_mm_eof(modreader)) {\r
243                         _mm_errno = MMERR_LOADING_TRACK;\r
244                         return 0;\r
245                 }\r
246 \r
247                 if(!(of.tracks[t]=MTM_Convert())) return 0;\r
248         }\r
249 \r
250         for(t=0;t<of.numpat;t++) {\r
251                 _mm_read_I_UWORDS(pat,32,modreader);\r
252                 for(u=0;u<of.numchn;u++)\r
253                         of.patterns[((long)t*of.numchn)+u]=pat[u];\r
254         }\r
255 \r
256         /* read comment field */\r
257         if(mh->commentsize)\r
258                 if(!ReadLinedComment(mh->commentsize, 40)) return 0;\r
259 \r
260         return 1;\r
261 }\r
262 \r
263 CHAR *MTM_LoadTitle(void)\r
264 {\r
265         CHAR s[20];\r
266 \r
267         _mm_fseek(modreader,4,SEEK_SET);\r
268         if(!_mm_read_UBYTES(s,20,modreader)) return NULL;\r
269 \r
270         return(DupStr(s,20,1));\r
271 }\r
272 \r
273 /*========== Loader information */\r
274 \r
275 MIKMODAPI MLOADER load_mtm={\r
276         NULL,\r
277         "MTM",\r
278         "MTM (MultiTracker Module editor)",\r
279         MTM_Init,\r
280         MTM_Test,\r
281         MTM_Load,\r
282         MTM_Cleanup,\r
283         MTM_LoadTitle\r
284 };\r
285 \r
286 /* ex:set ts=4: */\r