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 */
89 static int ULT_Test(void)
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;
99 static int ULT_Init(void)
104 static 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 static int ULT_Load(int curious
)
136 /* try to read module header */
137 _mm_read_string(mh
.id
,15,modreader
);
138 _mm_read_string(mh
.songtitle
,32,modreader
);
139 mh
.reserved
=_mm_read_UBYTE(modreader
);
141 if(_mm_eof(modreader
)) {
142 _mm_errno
= MMERR_LOADING_HEADER
;
146 ULT_Version
[ULT_VERSION_LEN
-1]='3'+(mh
.id
[14]-'1');
147 of
.modtype
= DupStr(ULT_Version
,ULT_VERSION_LEN
,1);
153 if ((mh
.id
[14]>'1')&&(mh
.reserved
))
154 if(!ReadLinedComment(mh
.reserved
* 32, 32)) return 0;
156 nos
=_mm_read_UBYTE(modreader
);
157 if(_mm_eof(modreader
)) {
158 _mm_errno
= MMERR_LOADING_HEADER
;
162 of
.songname
=DupStr(mh
.songtitle
,32,1);
163 of
.numins
=of
.numsmp
=nos
;
165 if(!AllocSamples()) return 0;
168 /* try to read sample info */
169 _mm_read_string(s
.samplename
,32,modreader
);
170 _mm_read_string(s
.dosname
,12,modreader
);
171 s
.loopstart
=_mm_read_I_ULONG(modreader
);
172 s
.loopend
=_mm_read_I_ULONG(modreader
);
173 s
.sizestart
=_mm_read_I_ULONG(modreader
);
174 s
.sizeend
=_mm_read_I_ULONG(modreader
);
175 s
.volume
=_mm_read_UBYTE(modreader
);
176 s
.flags
=_mm_read_UBYTE(modreader
);
177 s
.speed
=(mh
.id
[14]>='4')?_mm_read_I_UWORD(modreader
):8363;
178 s
.finetune
=_mm_read_I_SWORD(modreader
);
180 if(_mm_eof(modreader
)) {
181 _mm_errno
= MMERR_LOADING_SAMPLEINFO
;
185 q
->samplename
=DupStr(s
.samplename
,32,1);
186 /* The correct formula for the coefficient would be
187 pow(2,(double)s.finetume/OCTAVE/32768), but to avoid floating point
188 here, we'll use a first order approximation here.
189 1/567290 == Ln(2)/OCTAVE/32768 */
190 q
->speed
=s
.speed
+s
.speed
*(((SLONG
)s
.speed
*(SLONG
)s
.finetune
)/567290);
191 q
->length
= s
.sizeend
-s
.sizestart
;
192 q
->volume
= s
.volume
>>2;
193 q
->loopstart
= s
.loopstart
;
194 q
->loopend
= s
.loopend
;
195 q
->flags
= SF_SIGNED
;
196 if(s
.flags
&ULTS_LOOP
) q
->flags
|=SF_LOOP
;
197 if(s
.flags
&ULTS_16BITS
) {
198 s
.sizeend
+=(s
.sizeend
-s
.sizestart
);
207 if(!AllocPositions(256)) return 0;
209 of
.positions
[t
]=_mm_read_UBYTE(modreader
);
211 if(of
.positions
[t
]==255) {
212 of
.positions
[t
]=LAST_PATTERN
;
217 noc
=_mm_read_UBYTE(modreader
);
218 rbnop
=_mm_read_UBYTE(modreader
);
222 of
.numtrk
=of
.numchn
*of
.numpat
;
223 if(!AllocTracks()) return 0;
224 if(!AllocPatterns()) return 0;
225 for(u
=0;u
<of
.numchn
;u
++)
226 for(t
=0;t
<of
.numpat
;t
++)
227 of
.patterns
[(t
*of
.numchn
)+u
]=tracks
++;
230 if (of
.numchn
>=UF_MAXCHAN
)
231 of
.numchn
=UF_MAXCHAN
- 1;
233 /* read pan position table for v1.5 and higher */
235 for(t
=0;t
<of
.numchn
;t
++) of
.panning
[t
]=_mm_read_UBYTE(modreader
)<<4;
236 of
.flags
|= UF_PANNING
;
239 for(t
=0;t
<of
.numtrk
;t
++) {
244 rep
=ReadUltEvent(&ev
);
246 if(_mm_eof(modreader
)) {
247 _mm_errno
= MMERR_LOADING_TRACK
;
255 if(ev
.sample
) UniInstrument(ev
.sample
-1);
256 if(ev
.note
) UniNote(ev
.note
+2*OCTAVE
-1);
258 /* first effect - various fixes by Alexander Kerkhove and
262 case 0x3: /* tone portamento */
263 UniEffect(UNI_ITEFFECTG
,ev
.dat2
);
267 case 0x9: /* sample offset */
268 offset
=(ev
.dat2
<<8)|((ev
.eff
&0xf)==9?ev
.dat1
:0);
269 UniEffect(UNI_ULTEFFECT9
,offset
);
271 case 0xb: /* panning */
272 UniPTEffect(8,ev
.dat2
*0xf);
273 of
.flags
|= UF_PANNING
;
275 case 0xc: /* volume */
276 UniPTEffect(eff
,ev
.dat2
>>2);
279 UniPTEffect(eff
,ev
.dat2
);
286 case 0x3: /* tone portamento */
287 UniEffect(UNI_ITEFFECTG
,ev
.dat1
);
291 case 0x9: /* sample offset */
293 UniEffect(UNI_ULTEFFECT9
,((UWORD
)ev
.dat1
)<<8);
295 case 0xb: /* panning */
296 UniPTEffect(8,ev
.dat1
*0xf);
297 of
.flags
|= UF_PANNING
;
299 case 0xc: /* volume */
300 UniPTEffect(eff
,ev
.dat1
>>2);
303 UniPTEffect(eff
,ev
.dat1
);
311 if(!(of
.tracks
[t
]=UniDup())) return 0;
316 static CHAR
*ULT_LoadTitle(void)
320 _mm_fseek(modreader
,15,SEEK_SET
);
321 if(!_mm_read_UBYTES(s
,32,modreader
)) return NULL
;
323 return(DupStr(s
,32,1));
326 /*========== Loader information */
328 MIKMODAPI MLOADER load_ult
={
331 "ULT (UltraTracker)",