1 /* MikMod sound library
2 (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file
3 AUTHORS for complete list.
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.
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.
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
21 /*==============================================================================
23 $Id: load_ult.c,v 1.3 2010/01/12 03:30:32 realtech Exp $
25 Ultratracker (ULT) module loader
27 ==============================================================================*/
43 #include "mikmod_internals.h"
46 extern int fprintf(FILE *, const char *, ...);
49 /*========== Module structure */
52 typedef struct ULTHEADER
{
58 /* sample information */
59 typedef struct ULTSAMPLE
{
72 typedef struct ULTEVENT
{
73 UBYTE note
,sample
,eff
,dat1
,dat2
;
76 /*========== Loader variables */
80 #define ULTS_REVERSE 16
82 #define ULT_VERSION_LEN 18
83 static CHAR ULT_Version
[ULT_VERSION_LEN
]="Ultra Tracker v1.x";
87 /*========== Loader code */
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;
104 void ULT_Cleanup(void)
108 static UBYTE
ReadUltEvent(ULTEVENT
* event
)
112 flag
= _mm_read_UBYTE(modreader
);
114 rep
= _mm_read_UBYTE(modreader
);
115 event
->note
=_mm_read_UBYTE(modreader
);
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
);
127 int ULT_Load(int curious
)
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
);
140 if(_mm_eof(modreader
)) {
141 _mm_errno
= MMERR_LOADING_HEADER
;
145 ULT_Version
[ULT_VERSION_LEN
-1]='3'+(mh
.id
[14]-'1');
146 of
.modtype
= DupStr(ULT_Version
,ULT_VERSION_LEN
,1);
152 if ((mh
.id
[14]>'1')&&(mh
.reserved
))
153 if(!ReadLinedComment(mh
.reserved
* 32, 32)) return 0;
155 nos
=_mm_read_UBYTE(modreader
);
156 if(_mm_eof(modreader
)) {
157 _mm_errno
= MMERR_LOADING_HEADER
;
161 of
.songname
=DupStr(mh
.songtitle
,32,1);
162 of
.numins
=of
.numsmp
=nos
;
164 if(!AllocSamples()) return 0;
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
);
179 if(_mm_eof(modreader
)) {
180 _mm_errno
= MMERR_LOADING_SAMPLEINFO
;
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
);
206 if(!AllocPositions(256)) return 0;
208 of
.positions
[t
]=_mm_read_UBYTE(modreader
);
210 if(of
.positions
[t
]==255) {
211 of
.positions
[t
]=LAST_PATTERN
;
216 noc
=_mm_read_UBYTE(modreader
);
217 rbnop
=_mm_read_UBYTE(modreader
);
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
++;
229 if (of
.numchn
>=UF_MAXCHAN
)
230 of
.numchn
=UF_MAXCHAN
- 1;
232 /* read pan position table for v1.5 and higher */
234 for(t
=0;t
<of
.numchn
;t
++) of
.panning
[t
]=_mm_read_UBYTE(modreader
)<<4;
235 of
.flags
|= UF_PANNING
;
238 for(t
=0;t
<of
.numtrk
;t
++) {
243 rep
=ReadUltEvent(&ev
);
245 if(_mm_eof(modreader
)) {
246 _mm_errno
= MMERR_LOADING_TRACK
;
254 if(ev
.sample
) UniInstrument(ev
.sample
-1);
255 if(ev
.note
) UniNote(ev
.note
+2*OCTAVE
-1);
257 /* first effect - various fixes by Alexander Kerkhove and
261 case 0x3: /* tone portamento */
262 UniEffect(UNI_ITEFFECTG
,ev
.dat2
);
266 case 0x9: /* sample offset */
267 offset
=(ev
.dat2
<<8)|((ev
.eff
&0xf)==9?ev
.dat1
:0);
268 UniEffect(UNI_ULTEFFECT9
,offset
);
270 case 0xb: /* panning */
271 UniPTEffect(8,ev
.dat2
*0xf);
272 of
.flags
|= UF_PANNING
;
274 case 0xc: /* volume */
275 UniPTEffect(eff
,ev
.dat2
>>2);
278 UniPTEffect(eff
,ev
.dat2
);
285 case 0x3: /* tone portamento */
286 UniEffect(UNI_ITEFFECTG
,ev
.dat1
);
290 case 0x9: /* sample offset */
292 UniEffect(UNI_ULTEFFECT9
,((UWORD
)ev
.dat1
)<<8);
294 case 0xb: /* panning */
295 UniPTEffect(8,ev
.dat1
*0xf);
296 of
.flags
|= UF_PANNING
;
298 case 0xc: /* volume */
299 UniPTEffect(eff
,ev
.dat1
>>2);
302 UniPTEffect(eff
,ev
.dat1
);
310 if(!(of
.tracks
[t
]=UniDup())) return 0;
315 CHAR
*ULT_LoadTitle(void)
319 _mm_fseek(modreader
,15,SEEK_SET
);
320 if(!_mm_read_UBYTES(s
,32,modreader
)) return NULL
;
322 return(DupStr(s
,32,1));
325 /*========== Loader information */
327 MIKMODAPI MLOADER load_ult
={
330 "ULT (UltraTracker)",