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$
24 
25   Ultratracker (ULT) module loader
26 
27 ==============================================================================*/
28 
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32 
33 #include <string.h>
34 
35 #include "unimod_priv.h"
36 
37 /*========== Module structure */
38 
39 /* header */
40 typedef struct ULTHEADER
41   {
42     CHAR id[16];
43     CHAR songtitle[32];
44     UBYTE reserved;
45   }
46 ULTHEADER;
47 
48 /* sample information */
49 typedef struct ULTSAMPLE
50   {
51     CHAR samplename[32];
52     CHAR dosname[12];
53     SLONG loopstart;
54     SLONG loopend;
55     SLONG sizestart;
56     SLONG sizeend;
57     UBYTE volume;
58     UBYTE flags;
59     UWORD speed;
60     SWORD finetune;
61   }
62 ULTSAMPLE;
63 
64 typedef struct ULTEVENT
65   {
66     UBYTE note, sample, eff, dat1, dat2;
67   }
68 ULTEVENT;
69 
70 /*========== Loader variables */
71 
72 #define ULTS_16BITS     4
73 #define ULTS_LOOP       8
74 #define ULTS_REVERSE    16
75 
76 #define ULT_VERSION_LEN 18
77 static CHAR ULT_Version[ULT_VERSION_LEN] = "Ultra Tracker v1.x";
78 
79 static ULTEVENT ev;
80 
81 /*========== Loader code */
82 
83 static BOOL
ULT_Test(void)84 ULT_Test (void)
85 {
86   CHAR id[16];
87 
88   if (!_mm_read_string (id, 15, modreader))
89     return 0;
90   if (strncmp (id, "MAS_UTrack_V00", 14))
91     return 0;
92   if ((id[14] < '1') || (id[14] > '4'))
93     return 0;
94   return 1;
95 }
96 
97 static BOOL
ULT_Init(void)98 ULT_Init (void)
99 {
100   return 1;
101 }
102 
103 static void
ULT_Cleanup(void)104 ULT_Cleanup (void)
105 {
106 }
107 
108 static UBYTE
ReadUltEvent(ULTEVENT * event)109 ReadUltEvent (ULTEVENT * event)
110 {
111   UBYTE flag, rep = 1;
112 
113   flag = _mm_read_UBYTE (modreader);
114   if (flag == 0xfc)
115     {
116       rep = _mm_read_UBYTE (modreader);
117       event->note = _mm_read_UBYTE (modreader);
118     }
119   else
120     event->note = flag;
121 
122   event->sample = _mm_read_UBYTE (modreader);
123   event->eff = _mm_read_UBYTE (modreader);
124   event->dat1 = _mm_read_UBYTE (modreader);
125   event->dat2 = _mm_read_UBYTE (modreader);
126 
127   return rep;
128 }
129 
130 static BOOL
ULT_Load(BOOL curious)131 ULT_Load (BOOL curious)
132 {
133   int t, u, tracks = 0;
134   SAMPLE *q;
135   ULTSAMPLE s;
136   ULTHEADER mh;
137   UBYTE nos, noc, nop;
138 
139   /* try to read module header */
140   _mm_read_string (mh.id, 15, modreader);
141   _mm_read_string (mh.songtitle, 32, modreader);
142   mh.reserved = _mm_read_UBYTE (modreader);
143 
144   if (_mm_eof (modreader))
145     {
146       _mm_errno = MMERR_LOADING_HEADER;
147       return 0;
148     }
149 
150   ULT_Version[ULT_VERSION_LEN - 1] = '3' + (mh.id[14] - '1');
151   of.modtype = DupStr (ULT_Version, ULT_VERSION_LEN, 1);
152   of.initspeed = 6;
153   of.inittempo = 125;
154   of.reppos = 0;
155 
156   /* read songtext */
157   if ((mh.id[14] > '1') && (mh.reserved))
158     if (!ReadLinedComment (mh.reserved, 32))
159       return 0;
160 
161   nos = _mm_read_UBYTE (modreader);
162   if (_mm_eof (modreader))
163     {
164       _mm_errno = MMERR_LOADING_HEADER;
165       return 0;
166     }
167 
168   of.songname = DupStr (mh.songtitle, 32, 1);
169   of.numins = of.numsmp = nos;
170 
171   if (!AllocSamples ())
172     return 0;
173   q = of.samples;
174   for (t = 0; t < nos; t++)
175     {
176       /* try to read sample info */
177       _mm_read_string (s.samplename, 32, modreader);
178       _mm_read_string (s.dosname, 12, modreader);
179       s.loopstart = _mm_read_I_ULONG (modreader);
180       s.loopend = _mm_read_I_ULONG (modreader);
181       s.sizestart = _mm_read_I_ULONG (modreader);
182       s.sizeend = _mm_read_I_ULONG (modreader);
183       s.volume = _mm_read_UBYTE (modreader);
184       s.flags = _mm_read_UBYTE (modreader);
185       s.speed = (mh.id[14] >= '4') ? _mm_read_I_UWORD (modreader) : 8363;
186       s.finetune = _mm_read_I_SWORD (modreader);
187 
188       if (_mm_eof (modreader))
189 	{
190 	  _mm_errno = MMERR_LOADING_SAMPLEINFO;
191 	  return 0;
192 	}
193 
194       q->samplename = DupStr (s.samplename, 32, 1);
195       /* The correct formula for the coefficient would be
196          pow(2,(double)s.finetume/OCTAVE/32768), but to avoid floating point
197          here, we'll use a first order approximation here.
198          1/567290 == Ln(2)/OCTAVE/32768 */
199       q->speed = s.speed + s.speed * (((SLONG) s.speed * (SLONG) s.finetune) / 567290);
200       q->length = s.sizeend - s.sizestart;
201       q->volume = s.volume >> 2;
202       q->loopstart = s.loopstart;
203       q->loopend = s.loopend;
204       q->flags = SF_SIGNED;
205       if (s.flags & ULTS_LOOP)
206 	q->flags |= SF_LOOP;
207       if (s.flags & ULTS_16BITS)
208 	{
209 	  s.sizeend += (s.sizeend - s.sizestart);
210 	  s.sizestart <<= 1;
211 	  q->flags |= SF_16BITS;
212 	  q->loopstart >>= 1;
213 	  q->loopend >>= 1;
214 	}
215       q++;
216     }
217 
218   if (!AllocPositions (256))
219     return 0;
220   for (t = 0; t < 256; t++)
221     of.positions[t] = _mm_read_UBYTE (modreader);
222   for (t = 0; t < 256; t++)
223     if (of.positions[t] == 255)
224       break;
225   of.numpos = t;
226 
227   noc = _mm_read_UBYTE (modreader);
228   nop = _mm_read_UBYTE (modreader);
229 
230   of.numchn = ++noc;
231   of.numpat = ++nop;
232   of.numtrk = of.numchn * of.numpat;
233   if (!AllocTracks ())
234     return 0;
235   if (!AllocPatterns ())
236     return 0;
237   for (u = 0; u < of.numchn; u++)
238     for (t = 0; t < of.numpat; t++)
239       of.patterns[(t * of.numchn) + u] = tracks++;
240 
241   /* SA37775, CVE-2009-3996 */
242   if (of.numchn>=UF_MAXCHAN)
243     of.numchn=UF_MAXCHAN - 1;
244 
245   /* read pan position table for v1.5 and higher */
246   if (mh.id[14] >= '3')
247     for (t = 0; t < of.numchn; t++)
248       of.panning[t] = _mm_read_UBYTE (modreader) << 4;
249 
250   for (t = 0; t < of.numtrk; t++)
251     {
252       int rep, row = 0;
253 
254       UniReset ();
255       while (row < 64)
256 	{
257 	  rep = ReadUltEvent (&ev);
258 
259 	  if (_mm_eof (modreader))
260 	    {
261 	      _mm_errno = MMERR_LOADING_TRACK;
262 	      return 0;
263 	    }
264 
265 	  while (rep--)
266 	    {
267 	      UBYTE eff;
268 	      int offset;
269 
270 	      if (ev.sample)
271 		UniInstrument (ev.sample - 1);
272 	      if (ev.note)
273 		UniNote (ev.note + 2 * OCTAVE - 1);
274 
275 	      /* first effect - various fixes by Alexander Kerkhove and
276 	         Thomas Neumann */
277 	      eff = ev.eff >> 4;
278 	      switch (eff)
279 		{
280 		case 0x3:	/* tone portamento */
281 		  UniEffect (UNI_ITEFFECTG, ev.dat2);
282 		  break;
283 		case 0x5:
284 		  break;
285 		case 0x9:	/* sample offset */
286 		  offset = (ev.dat2 << 8) | ((ev.eff & 0xf) == 9 ? ev.dat1 : 0);
287 		  UniEffect (UNI_ULTEFFECT9, offset);
288 		  break;
289 		case 0xb:	/* panning */
290 		  UniPTEffect (8, ev.dat2 * 0xf);
291 		  break;
292 		case 0xc:	/* volume */
293 		  UniPTEffect (eff, ev.dat2 >> 2);
294 		  break;
295 		default:
296 		  UniPTEffect (eff, ev.dat2);
297 		  break;
298 		}
299 
300 	      /* second effect */
301 	      eff = ev.eff & 0xf;
302 	      switch (eff)
303 		{
304 		case 0x3:	/* tone portamento */
305 		  UniEffect (UNI_ITEFFECTG, ev.dat1);
306 		  break;
307 		case 0x5:
308 		  break;
309 		case 0x9:	/* sample offset */
310 		  if ((ev.eff >> 4) != 9)
311 		    UniEffect (UNI_ULTEFFECT9, ((UWORD) ev.dat1) << 8);
312 		  break;
313 		case 0xb:	/* panning */
314 		  UniPTEffect (8, ev.dat1 * 0xf);
315 		  break;
316 		case 0xc:	/* volume */
317 		  UniPTEffect (eff, ev.dat1 >> 2);
318 		  break;
319 		default:
320 		  UniPTEffect (eff, ev.dat1);
321 		  break;
322 		}
323 
324 	      UniNewline ();
325 	      row++;
326 	    }
327 	}
328       if (!(of.tracks[t] = UniDup ()))
329 	return 0;
330     }
331   return 1;
332 }
333 
334 static CHAR *
ULT_LoadTitle(void)335 ULT_LoadTitle (void)
336 {
337   CHAR s[32];
338 
339   _mm_fseek (modreader, 15, SEEK_SET);
340   if (!_mm_read_UBYTES (s, 32, modreader))
341     return NULL;
342 
343   return (DupStr (s, 32, 1));
344 }
345 
346 /*========== Loader information */
347 
348 MLOADER load_ult =
349 {
350   NULL,
351   "ULT",
352   "ULT (UltraTracker)",
353   ULT_Init,
354   ULT_Test,
355   ULT_Load,
356   ULT_Cleanup,
357   ULT_LoadTitle
358 };
359 
360 
361 /* ex:set ts=4: */
362