summaryrefslogtreecommitdiff
path: root/core/multimedia/opieplayer/modplug
authorllornkcor <llornkcor>2002-07-20 22:07:31 (UTC)
committer llornkcor <llornkcor>2002-07-20 22:07:31 (UTC)
commit2342d48be31847e7ead9d1cc682452e8f0122351 (patch) (unidiff)
tree8329bb94e9d429c905a0ef6b881cf1c0f775bf14 /core/multimedia/opieplayer/modplug
parent0f24c1fb86d3bb58d8696358b824c0e01752b10d (diff)
downloadopie-2342d48be31847e7ead9d1cc682452e8f0122351.zip
opie-2342d48be31847e7ead9d1cc682452e8f0122351.tar.gz
opie-2342d48be31847e7ead9d1cc682452e8f0122351.tar.bz2
initial commit of modplugin
Diffstat (limited to 'core/multimedia/opieplayer/modplug') (more/less context) (ignore whitespace changes)
-rw-r--r--core/multimedia/opieplayer/modplug/.cvsignore2
-rw-r--r--core/multimedia/opieplayer/modplug/fastmix.cpp2280
-rw-r--r--core/multimedia/opieplayer/modplug/it_defs.h136
-rw-r--r--core/multimedia/opieplayer/modplug/load_669.cpp189
-rw-r--r--core/multimedia/opieplayer/modplug/load_amf.cpp420
-rw-r--r--core/multimedia/opieplayer/modplug/load_ams.cpp631
-rw-r--r--core/multimedia/opieplayer/modplug/load_dbm.cpp371
-rw-r--r--core/multimedia/opieplayer/modplug/load_dmf.cpp609
-rw-r--r--core/multimedia/opieplayer/modplug/load_dsm.cpp239
-rw-r--r--core/multimedia/opieplayer/modplug/load_far.cpp263
-rw-r--r--core/multimedia/opieplayer/modplug/load_it.cpp1415
-rw-r--r--core/multimedia/opieplayer/modplug/load_j2b.cpp18
-rw-r--r--core/multimedia/opieplayer/modplug/load_mdl.cpp506
-rw-r--r--core/multimedia/opieplayer/modplug/load_med.cpp919
-rw-r--r--core/multimedia/opieplayer/modplug/load_mod.cpp501
-rw-r--r--core/multimedia/opieplayer/modplug/load_mt2.cpp635
-rw-r--r--core/multimedia/opieplayer/modplug/load_mtm.cpp167
-rw-r--r--core/multimedia/opieplayer/modplug/load_okt.cpp200
-rw-r--r--core/multimedia/opieplayer/modplug/load_psm.cpp842
-rw-r--r--core/multimedia/opieplayer/modplug/load_ptm.cpp210
-rw-r--r--core/multimedia/opieplayer/modplug/load_s3m.cpp653
-rw-r--r--core/multimedia/opieplayer/modplug/load_stm.cpp189
-rw-r--r--core/multimedia/opieplayer/modplug/load_ult.cpp225
-rw-r--r--core/multimedia/opieplayer/modplug/load_umx.cpp56
-rw-r--r--core/multimedia/opieplayer/modplug/load_wav.cpp223
-rw-r--r--core/multimedia/opieplayer/modplug/load_xm.cpp912
-rw-r--r--core/multimedia/opieplayer/modplug/memfile.cpp76
-rw-r--r--core/multimedia/opieplayer/modplug/memfile.h42
-rw-r--r--core/multimedia/opieplayer/modplug/mmcmp.cpp409
-rw-r--r--core/multimedia/opieplayer/modplug/modplug.pro19
-rw-r--r--core/multimedia/opieplayer/modplug/modplugin.cpp263
-rw-r--r--core/multimedia/opieplayer/modplug/modplugin.h95
-rw-r--r--core/multimedia/opieplayer/modplug/modpluginimpl.cpp60
-rw-r--r--core/multimedia/opieplayer/modplug/modpluginimpl.h46
-rw-r--r--core/multimedia/opieplayer/modplug/opie-modplugin.control9
-rwxr-xr-xcore/multimedia/opieplayer/modplug/opie-modplugin.postinst24
-rwxr-xr-xcore/multimedia/opieplayer/modplug/opie-modplugin.postrm26
-rw-r--r--core/multimedia/opieplayer/modplug/snd_dsp.cpp488
-rw-r--r--core/multimedia/opieplayer/modplug/snd_flt.cpp104
-rw-r--r--core/multimedia/opieplayer/modplug/snd_fx.cpp2394
-rw-r--r--core/multimedia/opieplayer/modplug/sndfile.cpp1875
-rw-r--r--core/multimedia/opieplayer/modplug/sndfile.h984
-rw-r--r--core/multimedia/opieplayer/modplug/sndmix.cpp1248
-rw-r--r--core/multimedia/opieplayer/modplug/stdafx.h107
-rw-r--r--core/multimedia/opieplayer/modplug/tables.cpp399
45 files changed, 21479 insertions, 0 deletions
diff --git a/core/multimedia/opieplayer/modplug/.cvsignore b/core/multimedia/opieplayer/modplug/.cvsignore
new file mode 100644
index 0000000..6fe2396
--- a/dev/null
+++ b/core/multimedia/opieplayer/modplug/.cvsignore
@@ -0,0 +1,2 @@
1moc_*
2Makefile
diff --git a/core/multimedia/opieplayer/modplug/fastmix.cpp b/core/multimedia/opieplayer/modplug/fastmix.cpp
new file mode 100644
index 0000000..7956ea4
--- a/dev/null
+++ b/core/multimedia/opieplayer/modplug/fastmix.cpp
@@ -0,0 +1,2280 @@
1/*
2 * This program is free software; you can redistribute it and modify it
3 * under the terms of the GNU General Public License as published by the
4 * Free Software Foundation; either version 2 of the license or (at your
5 * option) any later version.
6 *
7 * Authors: Olivier Lapicque <olivierl@jps.net>
8 * Markus Fick <webmaster@mark-f.de> spline + fir-resampler
9*/
10
11#include "stdafx.h"
12#include "sndfile.h"
13#include <math.h>
14
15#ifdef WIN32
16#pragma bss_seg(".modplug")
17#endif
18
19// Front Mix Buffer (Also room for interleaved rear mix)
20int MixSoundBuffer[MIXBUFFERSIZE*4];
21
22// Reverb Mix Buffer
23#ifndef NO_REVERB
24int MixReverbBuffer[MIXBUFFERSIZE*2];
25extern UINT gnReverbSend;
26#endif
27
28#ifndef FASTSOUNDLIB
29int MixRearBuffer[MIXBUFFERSIZE*2];
30float MixFloatBuffer[MIXBUFFERSIZE*2];
31#endif
32
33#ifdef WIN32
34#pragma bss_seg()
35#endif
36
37
38extern LONG gnDryROfsVol;
39extern LONG gnDryLOfsVol;
40extern LONG gnRvbROfsVol;
41extern LONG gnRvbLOfsVol;
42
43// 4x256 taps polyphase FIR resampling filter
44extern short int gFastSinc[];
45extern short int gKaiserSinc[]; // 8-taps polyphase
46/*
47 ------------------------------------------------------------------------------------------------
48 cubic spline interpolation doc,
49 (derived from "digital image warping", g. wolberg)
50
51 interpolation polynomial: f(x) = A3*(x-floor(x))**3 + A2*(x-floor(x))**2 + A1*(x-floor(x)) + A0
52
53 with Y = equispaced data points (dist=1), YD = first derivates of data points and IP = floor(x)
54 the A[0..3] can be found by solving
55 A0 = Y[IP]
56 A1 = YD[IP]
57 A2 = 3*(Y[IP+1]-Y[IP])-2.0*YD[IP]-YD[IP+1]
58 A3 = -2.0 * (Y[IP+1]-Y[IP]) + YD[IP] - YD[IP+1]
59
60 with the first derivates as
61 YD[IP] = 0.5 * (Y[IP+1] - Y[IP-1]);
62 YD[IP+1] = 0.5 * (Y[IP+2] - Y[IP])
63
64 the coefs becomes
65 A0 = Y[IP]
66 A1 = YD[IP]
67 = 0.5 * (Y[IP+1] - Y[IP-1]);
68 A2 = 3.0 * (Y[IP+1]-Y[IP])-2.0*YD[IP]-YD[IP+1]
69 = 3.0 * (Y[IP+1] - Y[IP]) - 0.5 * 2.0 * (Y[IP+1] - Y[IP-1]) - 0.5 * (Y[IP+2] - Y[IP])
70 = 3.0 * Y[IP+1] - 3.0 * Y[IP] - Y[IP+1] + Y[IP-1] - 0.5 * Y[IP+2] + 0.5 * Y[IP]
71 = -0.5 * Y[IP+2] + 2.0 * Y[IP+1] - 2.5 * Y[IP] + Y[IP-1]
72 = Y[IP-1] + 2 * Y[IP+1] - 0.5 * (5.0 * Y[IP] + Y[IP+2])
73 A3 = -2.0 * (Y[IP+1]-Y[IP]) + YD[IP] + YD[IP+1]
74 = -2.0 * Y[IP+1] + 2.0 * Y[IP] + 0.5 * (Y[IP+1] - Y[IP-1]) + 0.5 * (Y[IP+2] - Y[IP])
75 = -2.0 * Y[IP+1] + 2.0 * Y[IP] + 0.5 * Y[IP+1] - 0.5 * Y[IP-1] + 0.5 * Y[IP+2] - 0.5 * Y[IP]
76 = 0.5 * Y[IP+2] - 1.5 * Y[IP+1] + 1.5 * Y[IP] - 0.5 * Y[IP-1]
77 = 0.5 * (3.0 * (Y[IP] - Y[IP+1]) - Y[IP-1] + YP[IP+2])
78
79 then interpolated data value is (horner rule)
80 out = (((A3*x)+A2)*x+A1)*x+A0
81
82 this gives parts of data points Y[IP-1] to Y[IP+2] of
83 part x**3 x**2 x**1 x**0
84 Y[IP-1] -0.5 1 -0.5 0
85 Y[IP] 1.5 -2.5 0 1
86 Y[IP+1] -1.5 2 0.5 0
87 Y[IP+2] 0.5 -0.5 0 0
88 --------------------------------------------------------------------------------------------------
89*/
90// number of bits used to scale spline coefs
91 #define SPLINE_QUANTBITS14
92 #define SPLINE_QUANTSCALE(1L<<SPLINE_QUANTBITS)
93 #define SPLINE_8SHIFT (SPLINE_QUANTBITS-8)
94 #define SPLINE_16SHIFT (SPLINE_QUANTBITS)
95// forces coefsset to unity gain
96#define SPLINE_CLAMPFORUNITY
97// log2(number) of precalculated splines (range is [4..14])
98#define SPLINE_FRACBITS 10
99#define SPLINE_LUTLEN (1L<<SPLINE_FRACBITS)
100
101class CzCUBICSPLINE
102 {public:
103 CzCUBICSPLINE( );
104 ~CzCUBICSPLINE( );
105 static signed short lut[4*(1L<<SPLINE_FRACBITS)];
106};
107
108signed short CzCUBICSPLINE::lut[4*(1L<<SPLINE_FRACBITS)];
109
110CzCUBICSPLINE::CzCUBICSPLINE( )
111 {int _LIi;
112 int _LLen = (1L<<SPLINE_FRACBITS);
113 float _LFlen= 1.0f / (float)_LLen;
114 float _LScale= (float)SPLINE_QUANTSCALE;
115 for(_LIi=0;_LIi<_LLen;_LIi++)
116 {float _LCm1, _LC0, _LC1, _LC2;
117 float _LX = ((float)_LIi)*_LFlen;
118 int _LSum,_LIdx= _LIi<<2;
119 _LCm1 = (float)floor( 0.5 + _LScale * (-0.5*_LX*_LX*_LX + 1.0 * _LX*_LX - 0.5 * _LX ) );
120 _LC0 = (float)floor( 0.5 + _LScale * ( 1.5*_LX*_LX*_LX - 2.5 * _LX*_LX + 1.0 ) );
121 _LC1 = (float)floor( 0.5 + _LScale * (-1.5*_LX*_LX*_LX + 2.0 * _LX*_LX + 0.5 * _LX ) );
122 _LC2 = (float)floor( 0.5 + _LScale * ( 0.5*_LX*_LX*_LX - 0.5 * _LX*_LX ) );
123 lut[_LIdx+0]= (signed short)( (_LCm1 < -_LScale) ? -_LScale : ((_LCm1 > _LScale) ? _LScale : _LCm1) );
124 lut[_LIdx+1]= (signed short)( (_LC0 < -_LScale) ? -_LScale : ((_LC0 > _LScale) ? _LScale : _LC0 ) );
125 lut[_LIdx+2]= (signed short)( (_LC1 < -_LScale) ? -_LScale : ((_LC1 > _LScale) ? _LScale : _LC1 ) );
126 lut[_LIdx+3]= (signed short)( (_LC2 < -_LScale) ? -_LScale : ((_LC2 > _LScale) ? _LScale : _LC2 ) );
127#ifdef SPLINE_CLAMPFORUNITY
128 _LSum = lut[_LIdx+0]+lut[_LIdx+1]+lut[_LIdx+2]+lut[_LIdx+3];
129 if( _LSum != SPLINE_QUANTSCALE )
130 {int _LMax = _LIdx;
131 if( lut[_LIdx+1]>lut[_LMax] ) _LMax = _LIdx+1;
132 if( lut[_LIdx+2]>lut[_LMax] ) _LMax = _LIdx+2;
133 if( lut[_LIdx+3]>lut[_LMax] ) _LMax = _LIdx+3;
134 lut[_LMax] += (SPLINE_QUANTSCALE-_LSum);
135 }
136#endif
137 }
138}
139
140CzCUBICSPLINE::~CzCUBICSPLINE( )
141 {// nothing todo
142}
143
144CzCUBICSPLINE sspline;
145
146/*
147 ------------------------------------------------------------------------------------------------
148 fir interpolation doc,
149 (derived from "an engineer's guide to fir digital filters", n.j. loy)
150
151 calculate coefficients for ideal lowpass filter (with cutoff = fc in 0..1 (mapped to 0..nyquist))
152 c[-N..N] = (i==0) ? fc : sin(fc*pi*i)/(pi*i)
153
154 then apply selected window to coefficients
155 c[-N..N] *= w(0..N)
156 with n in 2*N and w(n) being a window function (see loy)
157
158 then calculate gain and scale filter coefs to have unity gain.
159 ------------------------------------------------------------------------------------------------
160*/
161// quantizer scale of window coefs
162 #define WFIR_QUANTBITS 15
163 #define WFIR_QUANTSCALE (1L<<WFIR_QUANTBITS)
164 #define WFIR_8SHIFT (WFIR_QUANTBITS-8)
165 #define WFIR_16BITSHIFT (WFIR_QUANTBITS)
166// log2(number)-1 of precalculated taps range is [4..12]
167 #define WFIR_FRACBITS 10
168 #define WFIR_LUTLEN ((1L<<(WFIR_FRACBITS+1))+1)
169// number of samples in window
170 #define WFIR_LOG2WIDTH 3
171 #define WFIR_WIDTH (1L<<WFIR_LOG2WIDTH)
172 #define WFIR_SMPSPERWING((WFIR_WIDTH-1)>>1)
173// cutoff (1.0 == pi/2)
174 #define WFIR_CUTOFF 0.90f
175// wfir type
176 #define WFIR_HANN 0
177 #define WFIR_HAMMING 1
178 #define WFIR_BLACKMANEXACT2
179 #define WFIR_BLACKMAN3T613
180 #define WFIR_BLACKMAN3T674
181 #define WFIR_BLACKMAN4T925
182 #define WFIR_BLACKMAN4T746
183 #define WFIR_KAISER4T 7
184 #define WFIR_TYPE WFIR_BLACKMANEXACT
185// wfir help
186#ifndef M_zPI
187 #define M_zPI 3.1415926535897932384626433832795
188#endif
189 #define M_zEPS 1e-8
190 #define M_zBESSELEPS1e-21
191
192class CzWINDOWEDFIR
193 {public:
194 CzWINDOWEDFIR( );
195 ~CzWINDOWEDFIR( );
196 float coef( int _PCnr, float _POfs, float _PCut, int _PWidth, int _PType ) //float _PPos, float _PFc, int _PLen )
197 { double _LWidthM1 = _PWidth-1;
198 double _LWidthM1Half= 0.5*_LWidthM1;
199 double _LPosU = ((double)_PCnr - _POfs);
200 double _LPos = _LPosU-_LWidthM1Half;
201 double _LPIdl = 2.0*M_zPI/_LWidthM1;
202 double_LWc,_LSi;
203 if( fabs(_LPos)<M_zEPS )
204 { _LWc= 1.0;
205 _LSi= _PCut;
206 }
207 else
208 {switch( _PType )
209 {case WFIR_HANN:
210 _LWc = 0.50 - 0.50 * cos(_LPIdl*_LPosU);
211 break;
212 case WFIR_HAMMING:
213 _LWc = 0.54 - 0.46 * cos(_LPIdl*_LPosU);
214 break;
215 case WFIR_BLACKMANEXACT:
216 _LWc = 0.42 - 0.50 * cos(_LPIdl*_LPosU) + 0.08 * cos(2.0*_LPIdl*_LPosU);
217 break;
218 case WFIR_BLACKMAN3T61:
219 _LWc = 0.44959 - 0.49364 * cos(_LPIdl*_LPosU) + 0.05677 * cos(2.0*_LPIdl*_LPosU);
220 break;
221 case WFIR_BLACKMAN3T67:
222 _LWc = 0.42323 - 0.49755 * cos(_LPIdl*_LPosU) + 0.07922 * cos(2.0*_LPIdl*_LPosU);
223 break;
224 case WFIR_BLACKMAN4T92:
225 _LWc = 0.35875 - 0.48829 * cos(_LPIdl*_LPosU) + 0.14128 * cos(2.0*_LPIdl*_LPosU) - 0.01168 * cos(3.0*_LPIdl*_LPosU);
226 break;
227 case WFIR_BLACKMAN4T74:
228 _LWc = 0.40217 - 0.49703 * cos(_LPIdl*_LPosU) + 0.09392 * cos(2.0*_LPIdl*_LPosU) - 0.00183 * cos(3.0*_LPIdl*_LPosU);
229 break;
230 case WFIR_KAISER4T:
231 _LWc = 0.40243 - 0.49804 * cos(_LPIdl*_LPosU) + 0.09831 * cos(2.0*_LPIdl*_LPosU) - 0.00122 * cos(3.0*_LPIdl*_LPosU);
232 break;
233 default:
234 _LWc = 1.0;
235 break;
236 }
237 _LPos *= M_zPI;
238 _LSi = sin(_PCut*_LPos)/_LPos;
239 }
240 return (float)(_LWc*_LSi);
241 }
242 static signed short lut[WFIR_LUTLEN*WFIR_WIDTH];
243};
244
245signed short CzWINDOWEDFIR::lut[WFIR_LUTLEN*WFIR_WIDTH];
246
247CzWINDOWEDFIR::CzWINDOWEDFIR()
248 {int _LPcl;
249 float _LPcllen = (float)(1L<<WFIR_FRACBITS);// number of precalculated lines for 0..1 (-1..0)
250 float _LNorm= 1.0f / (float)(2.0f * _LPcllen);
251 float _LCut = WFIR_CUTOFF;
252 float _LScale= (float)WFIR_QUANTSCALE;
253 for( _LPcl=0;_LPcl<WFIR_LUTLEN;_LPcl++ )
254 {float _LGain,_LCoefs[WFIR_WIDTH];
255 float _LOfs = ((float)_LPcl-_LPcllen)*_LNorm;
256 int _LCc,_LIdx= _LPcl<<WFIR_LOG2WIDTH;
257 for( _LCc=0,_LGain=0.0f;_LCc<WFIR_WIDTH;_LCc++ )
258 { _LGain+= (_LCoefs[_LCc] = coef( _LCc, _LOfs, _LCut, WFIR_WIDTH, WFIR_TYPE ));
259 }
260 _LGain = 1.0f/_LGain;
261 for( _LCc=0;_LCc<WFIR_WIDTH;_LCc++ )
262 {float _LCoef = (float)floor( 0.5 + _LScale*_LCoefs[_LCc]*_LGain );
263 lut[_LIdx+_LCc] = (signed short)( (_LCoef<-_LScale)?-_LScale:((_LCoef>_LScale)?_LScale:_LCoef) );
264 }
265 }
266}
267
268CzWINDOWEDFIR::~CzWINDOWEDFIR()
269 {// nothing todo
270}
271
272CzWINDOWEDFIR sfir;
273
274// ------------------------------------------------------------------------------------------------
275// MIXING MACROS
276// ------------------------------------------------------------------------------------------------
277/////////////////////////////////////////////////////
278// Mixing Macros
279
280#define SNDMIX_BEGINSAMPLELOOP8\
281 register MODCHANNEL * const pChn = pChannel;\
282 nPos = pChn->nPosLo;\
283 const signed char *p = (signed char *)(pChn->pCurrentSample+pChn->nPos);\
284 if (pChn->dwFlags & CHN_STEREO) p += pChn->nPos;\
285 int *pvol = pbuffer;\
286 do {
287
288#define SNDMIX_BEGINSAMPLELOOP16\
289 register MODCHANNEL * const pChn = pChannel;\
290 nPos = pChn->nPosLo;\
291 const signed short *p = (signed short *)(pChn->pCurrentSample+(pChn->nPos*2));\
292 if (pChn->dwFlags & CHN_STEREO) p += pChn->nPos;\
293 int *pvol = pbuffer;\
294 do {
295
296#define SNDMIX_ENDSAMPLELOOP\
297 nPos += pChn->nInc;\
298 } while (pvol < pbufmax);\
299 pChn->nPos += nPos >> 16;\
300 pChn->nPosLo = nPos & 0xFFFF;
301
302 #define SNDMIX_ENDSAMPLELOOP8SNDMIX_ENDSAMPLELOOP
303 #define SNDMIX_ENDSAMPLELOOP16SNDMIX_ENDSAMPLELOOP
304
305//////////////////////////////////////////////////////////////////////////////
306// Mono
307
308// No interpolation
309#define SNDMIX_GETMONOVOL8NOIDO\
310 int vol = p[nPos >> 16] << 8;
311
312#define SNDMIX_GETMONOVOL16NOIDO\
313 int vol = p[nPos >> 16];
314
315// Linear Interpolation
316#define SNDMIX_GETMONOVOL8LINEAR\
317 int poshi = nPos >> 16;\
318 int poslo = (nPos >> 8) & 0xFF;\
319 int srcvol = p[poshi];\
320 int destvol = p[poshi+1];\
321 int vol = (srcvol<<8) + ((int)(poslo * (destvol - srcvol)));
322
323#define SNDMIX_GETMONOVOL16LINEAR\
324 int poshi = nPos >> 16;\
325 int poslo = (nPos >> 8) & 0xFF;\
326 int srcvol = p[poshi];\
327 int destvol = p[poshi+1];\
328 int vol = srcvol + ((int)(poslo * (destvol - srcvol)) >> 8);
329
330// spline interpolation (2 guard bits should be enough???)
331#define SPLINE_FRACSHIFT ((16-SPLINE_FRACBITS)-2)
332#define SPLINE_FRACMASK (((1L<<(16-SPLINE_FRACSHIFT))-1)&~3)
333
334#define SNDMIX_GETMONOVOL8SPLINE \
335 int poshi= nPos >> 16; \
336 int poslo= (nPos >> SPLINE_FRACSHIFT) & SPLINE_FRACMASK; \
337 int vol = (CzCUBICSPLINE::lut[poslo ]*(int)p[poshi-1] + \
338 CzCUBICSPLINE::lut[poslo+1]*(int)p[poshi ] + \
339 CzCUBICSPLINE::lut[poslo+3]*(int)p[poshi+2] + \
340 CzCUBICSPLINE::lut[poslo+2]*(int)p[poshi+1]) >> SPLINE_8SHIFT;
341
342#define SNDMIX_GETMONOVOL16SPLINE \
343 int poshi= nPos >> 16; \
344 int poslo= (nPos >> SPLINE_FRACSHIFT) & SPLINE_FRACMASK; \
345 int vol = (CzCUBICSPLINE::lut[poslo ]*(int)p[poshi-1] + \
346 CzCUBICSPLINE::lut[poslo+1]*(int)p[poshi ] + \
347 CzCUBICSPLINE::lut[poslo+3]*(int)p[poshi+2] + \
348 CzCUBICSPLINE::lut[poslo+2]*(int)p[poshi+1]) >> SPLINE_16SHIFT;
349
350
351// fir interpolation
352 #define WFIR_FRACSHIFT(16-(WFIR_FRACBITS+1+WFIR_LOG2WIDTH))
353 #define WFIR_FRACMASK((((1L<<(17-WFIR_FRACSHIFT))-1)&~((1L<<WFIR_LOG2WIDTH)-1)))
354 #define WFIR_FRACHALVE(1L<<(16-(WFIR_FRACBITS+2)))
355
356#define SNDMIX_GETMONOVOL8FIRFILTER \
357 int poshi = nPos >> 16;\
358 int poslo = (nPos & 0xFFFF);\
359 int firidx = ((poslo+WFIR_FRACHALVE)>>WFIR_FRACSHIFT) & WFIR_FRACMASK; \
360 int vol = (CzWINDOWEDFIR::lut[firidx+0]*(int)p[poshi+1-4]);\
361 vol += (CzWINDOWEDFIR::lut[firidx+1]*(int)p[poshi+2-4]);\
362 vol += (CzWINDOWEDFIR::lut[firidx+2]*(int)p[poshi+3-4]);\
363 vol += (CzWINDOWEDFIR::lut[firidx+3]*(int)p[poshi+4-4]);\
364 vol += (CzWINDOWEDFIR::lut[firidx+4]*(int)p[poshi+5-4]);\
365 vol += (CzWINDOWEDFIR::lut[firidx+5]*(int)p[poshi+6-4]);\
366 vol += (CzWINDOWEDFIR::lut[firidx+6]*(int)p[poshi+7-4]);\
367 vol += (CzWINDOWEDFIR::lut[firidx+7]*(int)p[poshi+8-4]);\
368 vol >>= WFIR_8SHIFT;
369
370#define SNDMIX_GETMONOVOL16FIRFILTER \
371 int poshi = nPos >> 16;\
372 int poslo = (nPos & 0xFFFF);\
373 int firidx = ((poslo+WFIR_FRACHALVE)>>WFIR_FRACSHIFT) & WFIR_FRACMASK; \
374 int vol1 = (CzWINDOWEDFIR::lut[firidx+0]*(int)p[poshi+1-4]);\
375 vol1 += (CzWINDOWEDFIR::lut[firidx+1]*(int)p[poshi+2-4]);\
376 vol1 += (CzWINDOWEDFIR::lut[firidx+2]*(int)p[poshi+3-4]);\
377 vol1 += (CzWINDOWEDFIR::lut[firidx+3]*(int)p[poshi+4-4]);\
378 int vol2 = (CzWINDOWEDFIR::lut[firidx+4]*(int)p[poshi+5-4]);\
379 vol2 += (CzWINDOWEDFIR::lut[firidx+5]*(int)p[poshi+6-4]);\
380 vol2 += (CzWINDOWEDFIR::lut[firidx+6]*(int)p[poshi+7-4]);\
381 vol2 += (CzWINDOWEDFIR::lut[firidx+7]*(int)p[poshi+8-4]);\
382 int vol = ((vol1>>1)+(vol2>>1)) >> (WFIR_16BITSHIFT-1);
383
384/////////////////////////////////////////////////////////////////////////////
385// Stereo
386
387// No interpolation
388#define SNDMIX_GETSTEREOVOL8NOIDO\
389 int vol_l = p[(nPos>>16)*2] << 8;\
390 int vol_r = p[(nPos>>16)*2+1] << 8;
391
392#define SNDMIX_GETSTEREOVOL16NOIDO\
393 int vol_l = p[(nPos>>16)*2];\
394 int vol_r = p[(nPos>>16)*2+1];
395
396// Linear Interpolation
397#define SNDMIX_GETSTEREOVOL8LINEAR\
398 int poshi = nPos >> 16;\
399 int poslo = (nPos >> 8) & 0xFF;\
400 int srcvol_l = p[poshi*2];\
401 int vol_l = (srcvol_l<<8) + ((int)(poslo * (p[poshi*2+2] - srcvol_l)));\
402 int srcvol_r = p[poshi*2+1];\
403 int vol_r = (srcvol_r<<8) + ((int)(poslo * (p[poshi*2+3] - srcvol_r)));
404
405#define SNDMIX_GETSTEREOVOL16LINEAR\
406 int poshi = nPos >> 16;\
407 int poslo = (nPos >> 8) & 0xFF;\
408 int srcvol_l = p[poshi*2];\
409 int vol_l = srcvol_l + ((int)(poslo * (p[poshi*2+2] - srcvol_l)) >> 8);\
410 int srcvol_r = p[poshi*2+1];\
411 int vol_r = srcvol_r + ((int)(poslo * (p[poshi*2+3] - srcvol_r)) >> 8);\
412
413// Spline Interpolation
414#define SNDMIX_GETSTEREOVOL8SPLINE \
415 int poshi= nPos >> 16; \
416 int poslo= (nPos >> SPLINE_FRACSHIFT) & SPLINE_FRACMASK; \
417 int vol_l= (CzCUBICSPLINE::lut[poslo ]*(int)p[(poshi-1)*2 ] + \
418 CzCUBICSPLINE::lut[poslo+1]*(int)p[(poshi )*2 ] + \
419 CzCUBICSPLINE::lut[poslo+2]*(int)p[(poshi+1)*2 ] + \
420 CzCUBICSPLINE::lut[poslo+3]*(int)p[(poshi+2)*2 ]) >> SPLINE_8SHIFT; \
421 int vol_r= (CzCUBICSPLINE::lut[poslo ]*(int)p[(poshi-1)*2+1] + \
422 CzCUBICSPLINE::lut[poslo+1]*(int)p[(poshi )*2+1] + \
423 CzCUBICSPLINE::lut[poslo+2]*(int)p[(poshi+1)*2+1] + \
424 CzCUBICSPLINE::lut[poslo+3]*(int)p[(poshi+2)*2+1]) >> SPLINE_8SHIFT;
425
426#define SNDMIX_GETSTEREOVOL16SPLINE \
427 int poshi= nPos >> 16; \
428 int poslo= (nPos >> SPLINE_FRACSHIFT) & SPLINE_FRACMASK; \
429 int vol_l= (CzCUBICSPLINE::lut[poslo ]*(int)p[(poshi-1)*2 ] + \
430 CzCUBICSPLINE::lut[poslo+1]*(int)p[(poshi )*2 ] + \
431 CzCUBICSPLINE::lut[poslo+2]*(int)p[(poshi+1)*2 ] + \
432 CzCUBICSPLINE::lut[poslo+3]*(int)p[(poshi+2)*2 ]) >> SPLINE_16SHIFT; \
433 int vol_r= (CzCUBICSPLINE::lut[poslo ]*(int)p[(poshi-1)*2+1] + \
434 CzCUBICSPLINE::lut[poslo+1]*(int)p[(poshi )*2+1] + \
435 CzCUBICSPLINE::lut[poslo+2]*(int)p[(poshi+1)*2+1] + \
436 CzCUBICSPLINE::lut[poslo+3]*(int)p[(poshi+2)*2+1]) >> SPLINE_16SHIFT;
437
438// fir interpolation
439#define SNDMIX_GETSTEREOVOL8FIRFILTER \
440 int poshi = nPos >> 16;\
441 int poslo = (nPos & 0xFFFF);\
442 int firidx = ((poslo+WFIR_FRACHALVE)>>WFIR_FRACSHIFT) & WFIR_FRACMASK; \
443 int vol_l = (CzWINDOWEDFIR::lut[firidx+0]*(int)p[(poshi+1-4)*2 ]);\
444 vol_l += (CzWINDOWEDFIR::lut[firidx+1]*(int)p[(poshi+2-4)*2 ]);\
445 vol_l += (CzWINDOWEDFIR::lut[firidx+2]*(int)p[(poshi+3-4)*2 ]);\
446 vol_l += (CzWINDOWEDFIR::lut[firidx+3]*(int)p[(poshi+4-4)*2 ]);\
447 vol_l += (CzWINDOWEDFIR::lut[firidx+4]*(int)p[(poshi+5-4)*2 ]);\
448 vol_l += (CzWINDOWEDFIR::lut[firidx+5]*(int)p[(poshi+6-4)*2 ]);\
449 vol_l += (CzWINDOWEDFIR::lut[firidx+6]*(int)p[(poshi+7-4)*2 ]);\
450 vol_l += (CzWINDOWEDFIR::lut[firidx+7]*(int)p[(poshi+8-4)*2 ]);\
451 vol_l >>= WFIR_8SHIFT; \
452 int vol_r = (CzWINDOWEDFIR::lut[firidx+0]*(int)p[(poshi+1-4)*2+1]);\
453 vol_r += (CzWINDOWEDFIR::lut[firidx+1]*(int)p[(poshi+2-4)*2+1]);\
454 vol_r += (CzWINDOWEDFIR::lut[firidx+2]*(int)p[(poshi+3-4)*2+1]);\
455 vol_r += (CzWINDOWEDFIR::lut[firidx+3]*(int)p[(poshi+4-4)*2+1]);\
456 vol_r += (CzWINDOWEDFIR::lut[firidx+4]*(int)p[(poshi+5-4)*2+1]);\
457 vol_r += (CzWINDOWEDFIR::lut[firidx+5]*(int)p[(poshi+6-4)*2+1]);\
458 vol_r += (CzWINDOWEDFIR::lut[firidx+6]*(int)p[(poshi+7-4)*2+1]);\
459 vol_r += (CzWINDOWEDFIR::lut[firidx+7]*(int)p[(poshi+8-4)*2+1]);\
460 vol_r >>= WFIR_8SHIFT;
461
462#define SNDMIX_GETSTEREOVOL16FIRFILTER \
463 int poshi = nPos >> 16;\
464 int poslo = (nPos & 0xFFFF);\
465 int firidx = ((poslo+WFIR_FRACHALVE)>>WFIR_FRACSHIFT) & WFIR_FRACMASK; \
466 int vol1_l = (CzWINDOWEDFIR::lut[firidx+0]*(int)p[(poshi+1-4)*2 ]);\
467 vol1_l += (CzWINDOWEDFIR::lut[firidx+1]*(int)p[(poshi+2-4)*2 ]);\
468 vol1_l += (CzWINDOWEDFIR::lut[firidx+2]*(int)p[(poshi+3-4)*2 ]);\
469 vol1_l += (CzWINDOWEDFIR::lut[firidx+3]*(int)p[(poshi+4-4)*2 ]);\
470 int vol2_l = (CzWINDOWEDFIR::lut[firidx+4]*(int)p[(poshi+5-4)*2 ]);\
471 vol2_l += (CzWINDOWEDFIR::lut[firidx+5]*(int)p[(poshi+6-4)*2 ]);\
472 vol2_l += (CzWINDOWEDFIR::lut[firidx+6]*(int)p[(poshi+7-4)*2 ]);\
473 vol2_l += (CzWINDOWEDFIR::lut[firidx+7]*(int)p[(poshi+8-4)*2 ]);\
474 int vol_l = ((vol1_l>>1)+(vol2_l>>1)) >> (WFIR_16BITSHIFT-1); \
475 int vol1_r = (CzWINDOWEDFIR::lut[firidx+0]*(int)p[(poshi+1-4)*2+1]);\
476 vol1_r += (CzWINDOWEDFIR::lut[firidx+1]*(int)p[(poshi+2-4)*2+1]);\
477 vol1_r += (CzWINDOWEDFIR::lut[firidx+2]*(int)p[(poshi+3-4)*2+1]);\
478 vol1_r += (CzWINDOWEDFIR::lut[firidx+3]*(int)p[(poshi+4-4)*2+1]);\
479 int vol2_r = (CzWINDOWEDFIR::lut[firidx+4]*(int)p[(poshi+5-4)*2+1]);\
480 vol2_r += (CzWINDOWEDFIR::lut[firidx+5]*(int)p[(poshi+6-4)*2+1]);\
481 vol2_r += (CzWINDOWEDFIR::lut[firidx+6]*(int)p[(poshi+7-4)*2+1]);\
482 vol2_r += (CzWINDOWEDFIR::lut[firidx+7]*(int)p[(poshi+8-4)*2+1]);\
483 int vol_r = ((vol1_r>>1)+(vol2_r>>1)) >> (WFIR_16BITSHIFT-1);
484
485
486/////////////////////////////////////////////////////////////////////////////
487
488#define SNDMIX_STOREMONOVOL\
489 pvol[0] += vol * pChn->nRightVol;\
490 pvol[1] += vol * pChn->nLeftVol;\
491 pvol += 2;
492
493#define SNDMIX_STORESTEREOVOL\
494 pvol[0] += vol_l * pChn->nRightVol;\
495 pvol[1] += vol_r * pChn->nLeftVol;\
496 pvol += 2;
497
498#define SNDMIX_STOREFASTMONOVOL\
499 int v = vol * pChn->nRightVol;\
500 pvol[0] += v;\
501 pvol[1] += v;\
502 pvol += 2;
503
504#define SNDMIX_RAMPMONOVOL\
505 nRampLeftVol += pChn->nLeftRamp;\
506 nRampRightVol += pChn->nRightRamp;\
507 pvol[0] += vol * (nRampRightVol >> VOLUMERAMPPRECISION);\
508 pvol[1] += vol * (nRampLeftVol >> VOLUMERAMPPRECISION);\
509 pvol += 2;
510
511#define SNDMIX_RAMPFASTMONOVOL\
512 nRampRightVol += pChn->nRightRamp;\
513 int fastvol = vol * (nRampRightVol >> VOLUMERAMPPRECISION);\
514 pvol[0] += fastvol;\
515 pvol[1] += fastvol;\
516 pvol += 2;
517
518#define SNDMIX_RAMPSTEREOVOL\
519 nRampLeftVol += pChn->nLeftRamp;\
520 nRampRightVol += pChn->nRightRamp;\
521 pvol[0] += vol_l * (nRampRightVol >> VOLUMERAMPPRECISION);\
522 pvol[1] += vol_r * (nRampLeftVol >> VOLUMERAMPPRECISION);\
523 pvol += 2;
524
525
526///////////////////////////////////////////////////
527// Resonant Filters
528
529// Mono
530#define MIX_BEGIN_FILTER\
531 int fy1 = pChannel->nFilter_Y1;\
532 int fy2 = pChannel->nFilter_Y2;\
533
534#define MIX_END_FILTER\
535 pChannel->nFilter_Y1 = fy1;\
536 pChannel->nFilter_Y2 = fy2;
537
538#define SNDMIX_PROCESSFILTER\
539 vol = (vol * pChn->nFilter_A0 + fy1 * pChn->nFilter_B0 + fy2 * pChn->nFilter_B1 + 4096) >> 13;\
540 fy2 = fy1;\
541 fy1 = vol;\
542
543// Stereo
544#define MIX_BEGIN_STEREO_FILTER\
545 int fy1 = pChannel->nFilter_Y1;\
546 int fy2 = pChannel->nFilter_Y2;\
547 int fy3 = pChannel->nFilter_Y3;\
548 int fy4 = pChannel->nFilter_Y4;\
549
550#define MIX_END_STEREO_FILTER\
551 pChannel->nFilter_Y1 = fy1;\
552 pChannel->nFilter_Y2 = fy2;\
553 pChannel->nFilter_Y3 = fy3;\
554 pChannel->nFilter_Y4 = fy4;\
555
556#define SNDMIX_PROCESSSTEREOFILTER\
557 vol_l = (vol_l * pChn->nFilter_A0 + fy1 * pChn->nFilter_B0 + fy2 * pChn->nFilter_B1 + 4096) >> 13;\
558 vol_r = (vol_r * pChn->nFilter_A0 + fy3 * pChn->nFilter_B0 + fy4 * pChn->nFilter_B1 + 4096) >> 13;\
559 fy2 = fy1; fy1 = vol_l;\
560 fy4 = fy3; fy3 = vol_r;\
561
562//////////////////////////////////////////////////////////
563// Interfaces
564
565typedef VOID (MPPASMCALL * LPMIXINTERFACE)(MODCHANNEL *, int *, int *);
566
567#define BEGIN_MIX_INTERFACE(func)\
568 VOID MPPASMCALL func(MODCHANNEL *pChannel, int *pbuffer, int *pbufmax)\
569 {\
570 LONG nPos;
571
572#define END_MIX_INTERFACE()\
573 SNDMIX_ENDSAMPLELOOP\
574 }
575
576// Volume Ramps
577#define BEGIN_RAMPMIX_INTERFACE(func)\
578 BEGIN_MIX_INTERFACE(func)\
579 LONG nRampRightVol = pChannel->nRampRightVol;\
580 LONG nRampLeftVol = pChannel->nRampLeftVol;
581
582#define END_RAMPMIX_INTERFACE()\
583 SNDMIX_ENDSAMPLELOOP\
584 pChannel->nRampRightVol = nRampRightVol;\
585 pChannel->nRightVol = nRampRightVol >> VOLUMERAMPPRECISION;\
586 pChannel->nRampLeftVol = nRampLeftVol;\
587 pChannel->nLeftVol = nRampLeftVol >> VOLUMERAMPPRECISION;\
588 }
589
590#define BEGIN_FASTRAMPMIX_INTERFACE(func)\
591 BEGIN_MIX_INTERFACE(func)\
592 LONG nRampRightVol = pChannel->nRampRightVol;
593
594#define END_FASTRAMPMIX_INTERFACE()\
595 SNDMIX_ENDSAMPLELOOP\
596 pChannel->nRampRightVol = nRampRightVol;\
597 pChannel->nRampLeftVol = nRampRightVol;\
598 pChannel->nRightVol = nRampRightVol >> VOLUMERAMPPRECISION;\
599 pChannel->nLeftVol = pChannel->nRightVol;\
600 }
601
602
603// Mono Resonant Filters
604#define BEGIN_MIX_FLT_INTERFACE(func)\
605 BEGIN_MIX_INTERFACE(func)\
606 MIX_BEGIN_FILTER
607
608
609#define END_MIX_FLT_INTERFACE()\
610 SNDMIX_ENDSAMPLELOOP\
611 MIX_END_FILTER\
612 }
613
614#define BEGIN_RAMPMIX_FLT_INTERFACE(func)\
615 BEGIN_MIX_INTERFACE(func)\
616 LONG nRampRightVol = pChannel->nRampRightVol;\
617 LONG nRampLeftVol = pChannel->nRampLeftVol;\
618 MIX_BEGIN_FILTER
619
620#define END_RAMPMIX_FLT_INTERFACE()\
621 SNDMIX_ENDSAMPLELOOP\
622 MIX_END_FILTER\
623 pChannel->nRampRightVol = nRampRightVol;\
624 pChannel->nRightVol = nRampRightVol >> VOLUMERAMPPRECISION;\
625 pChannel->nRampLeftVol = nRampLeftVol;\
626 pChannel->nLeftVol = nRampLeftVol >> VOLUMERAMPPRECISION;\
627 }
628
629// Stereo Resonant Filters
630#define BEGIN_MIX_STFLT_INTERFACE(func)\
631 BEGIN_MIX_INTERFACE(func)\
632 MIX_BEGIN_STEREO_FILTER
633
634
635#define END_MIX_STFLT_INTERFACE()\
636 SNDMIX_ENDSAMPLELOOP\
637 MIX_END_STEREO_FILTER\
638 }
639
640#define BEGIN_RAMPMIX_STFLT_INTERFACE(func)\
641 BEGIN_MIX_INTERFACE(func)\
642 LONG nRampRightVol = pChannel->nRampRightVol;\
643 LONG nRampLeftVol = pChannel->nRampLeftVol;\
644 MIX_BEGIN_STEREO_FILTER
645
646#define END_RAMPMIX_STFLT_INTERFACE()\
647 SNDMIX_ENDSAMPLELOOP\
648 MIX_END_STEREO_FILTER\
649 pChannel->nRampRightVol = nRampRightVol;\
650 pChannel->nRightVol = nRampRightVol >> VOLUMERAMPPRECISION;\
651 pChannel->nRampLeftVol = nRampLeftVol;\
652 pChannel->nLeftVol = nRampLeftVol >> VOLUMERAMPPRECISION;\
653 }
654
655
656/////////////////////////////////////////////////////
657//
658
659void MPPASMCALL X86_InitMixBuffer(int *pBuffer, UINT nSamples);
660void MPPASMCALL X86_EndChannelOfs(MODCHANNEL *pChannel, int *pBuffer, UINT nSamples);
661void MPPASMCALL X86_StereoFill(int *pBuffer, UINT nSamples, LPLONG lpROfs, LPLONG lpLOfs);
662void X86_StereoMixToFloat(const int *, float *, float *, UINT nCount);
663void X86_FloatToStereoMix(const float *pIn1, const float *pIn2, int *pOut, UINT nCount);
664
665/////////////////////////////////////////////////////
666// Mono samples functions
667
668BEGIN_MIX_INTERFACE(Mono8BitMix)
669 SNDMIX_BEGINSAMPLELOOP8
670 SNDMIX_GETMONOVOL8NOIDO
671 SNDMIX_STOREMONOVOL
672END_MIX_INTERFACE()
673
674BEGIN_MIX_INTERFACE(Mono16BitMix)
675 SNDMIX_BEGINSAMPLELOOP16
676 SNDMIX_GETMONOVOL16NOIDO
677 SNDMIX_STOREMONOVOL
678END_MIX_INTERFACE()
679
680BEGIN_MIX_INTERFACE(Mono8BitLinearMix)
681 SNDMIX_BEGINSAMPLELOOP8
682 SNDMIX_GETMONOVOL8LINEAR
683 SNDMIX_STOREMONOVOL
684END_MIX_INTERFACE()
685
686BEGIN_MIX_INTERFACE(Mono16BitLinearMix)
687 SNDMIX_BEGINSAMPLELOOP16
688 SNDMIX_GETMONOVOL16LINEAR
689 SNDMIX_STOREMONOVOL
690END_MIX_INTERFACE()
691
692BEGIN_MIX_INTERFACE(Mono8BitSplineMix)
693 SNDMIX_BEGINSAMPLELOOP8
694 SNDMIX_GETMONOVOL8SPLINE
695 SNDMIX_STOREMONOVOL
696END_MIX_INTERFACE()
697
698BEGIN_MIX_INTERFACE(Mono16BitSplineMix)
699 SNDMIX_BEGINSAMPLELOOP16
700 SNDMIX_GETMONOVOL16SPLINE
701 SNDMIX_STOREMONOVOL
702END_MIX_INTERFACE()
703
704BEGIN_MIX_INTERFACE(Mono8BitFirFilterMix)
705 SNDMIX_BEGINSAMPLELOOP8
706 SNDMIX_GETMONOVOL8FIRFILTER
707 SNDMIX_STOREMONOVOL
708END_MIX_INTERFACE()
709
710BEGIN_MIX_INTERFACE(Mono16BitFirFilterMix)
711 SNDMIX_BEGINSAMPLELOOP16
712 SNDMIX_GETMONOVOL16FIRFILTER
713 SNDMIX_STOREMONOVOL
714END_MIX_INTERFACE()
715
716
717// Volume Ramps
718BEGIN_RAMPMIX_INTERFACE(Mono8BitRampMix)
719 SNDMIX_BEGINSAMPLELOOP8
720 SNDMIX_GETMONOVOL8NOIDO
721 SNDMIX_RAMPMONOVOL
722END_RAMPMIX_INTERFACE()
723
724BEGIN_RAMPMIX_INTERFACE(Mono16BitRampMix)
725 SNDMIX_BEGINSAMPLELOOP16
726 SNDMIX_GETMONOVOL16NOIDO
727 SNDMIX_RAMPMONOVOL
728END_RAMPMIX_INTERFACE()
729
730BEGIN_RAMPMIX_INTERFACE(Mono8BitLinearRampMix)
731 SNDMIX_BEGINSAMPLELOOP8
732 SNDMIX_GETMONOVOL8LINEAR
733 SNDMIX_RAMPMONOVOL
734END_RAMPMIX_INTERFACE()
735
736BEGIN_RAMPMIX_INTERFACE(Mono16BitLinearRampMix)
737 SNDMIX_BEGINSAMPLELOOP16
738 SNDMIX_GETMONOVOL16LINEAR
739 SNDMIX_RAMPMONOVOL
740END_RAMPMIX_INTERFACE()
741
742BEGIN_RAMPMIX_INTERFACE(Mono8BitSplineRampMix)
743 SNDMIX_BEGINSAMPLELOOP8
744 SNDMIX_GETMONOVOL8SPLINE
745 SNDMIX_RAMPMONOVOL
746END_RAMPMIX_INTERFACE()
747
748BEGIN_RAMPMIX_INTERFACE(Mono16BitSplineRampMix)
749 SNDMIX_BEGINSAMPLELOOP16
750 SNDMIX_GETMONOVOL16SPLINE
751 SNDMIX_RAMPMONOVOL
752END_RAMPMIX_INTERFACE()
753
754BEGIN_RAMPMIX_INTERFACE(Mono8BitFirFilterRampMix)
755 SNDMIX_BEGINSAMPLELOOP8
756 SNDMIX_GETMONOVOL8FIRFILTER
757 SNDMIX_RAMPMONOVOL
758END_RAMPMIX_INTERFACE()
759
760BEGIN_RAMPMIX_INTERFACE(Mono16BitFirFilterRampMix)
761 SNDMIX_BEGINSAMPLELOOP16
762 SNDMIX_GETMONOVOL16FIRFILTER
763 SNDMIX_RAMPMONOVOL
764END_RAMPMIX_INTERFACE()
765
766
767//////////////////////////////////////////////////////
768// Fast mono mix for leftvol=rightvol (1 less imul)
769
770BEGIN_MIX_INTERFACE(FastMono8BitMix)
771 SNDMIX_BEGINSAMPLELOOP8
772 SNDMIX_GETMONOVOL8NOIDO
773 SNDMIX_STOREFASTMONOVOL
774END_MIX_INTERFACE()
775
776BEGIN_MIX_INTERFACE(FastMono16BitMix)
777 SNDMIX_BEGINSAMPLELOOP16
778 SNDMIX_GETMONOVOL16NOIDO
779 SNDMIX_STOREFASTMONOVOL
780END_MIX_INTERFACE()
781
782BEGIN_MIX_INTERFACE(FastMono8BitLinearMix)
783 SNDMIX_BEGINSAMPLELOOP8
784 SNDMIX_GETMONOVOL8LINEAR
785 SNDMIX_STOREFASTMONOVOL
786END_MIX_INTERFACE()
787
788BEGIN_MIX_INTERFACE(FastMono16BitLinearMix)
789 SNDMIX_BEGINSAMPLELOOP16
790 SNDMIX_GETMONOVOL16LINEAR
791 SNDMIX_STOREFASTMONOVOL
792END_MIX_INTERFACE()
793
794BEGIN_MIX_INTERFACE(FastMono8BitSplineMix)
795 SNDMIX_BEGINSAMPLELOOP8
796 SNDMIX_GETMONOVOL8SPLINE
797 SNDMIX_STOREFASTMONOVOL
798END_MIX_INTERFACE()
799
800BEGIN_MIX_INTERFACE(FastMono16BitSplineMix)
801 SNDMIX_BEGINSAMPLELOOP16
802 SNDMIX_GETMONOVOL16SPLINE
803 SNDMIX_STOREFASTMONOVOL
804END_MIX_INTERFACE()
805
806BEGIN_MIX_INTERFACE(FastMono8BitFirFilterMix)
807 SNDMIX_BEGINSAMPLELOOP8
808 SNDMIX_GETMONOVOL8FIRFILTER
809 SNDMIX_STOREFASTMONOVOL
810END_MIX_INTERFACE()
811
812BEGIN_MIX_INTERFACE(FastMono16BitFirFilterMix)
813 SNDMIX_BEGINSAMPLELOOP16
814 SNDMIX_GETMONOVOL16FIRFILTER
815 SNDMIX_STOREFASTMONOVOL
816END_MIX_INTERFACE()
817
818
819// Fast Ramps
820BEGIN_FASTRAMPMIX_INTERFACE(FastMono8BitRampMix)
821 SNDMIX_BEGINSAMPLELOOP8
822 SNDMIX_GETMONOVOL8NOIDO
823 SNDMIX_RAMPFASTMONOVOL
824END_FASTRAMPMIX_INTERFACE()
825
826BEGIN_FASTRAMPMIX_INTERFACE(FastMono16BitRampMix)
827 SNDMIX_BEGINSAMPLELOOP16
828 SNDMIX_GETMONOVOL16NOIDO
829 SNDMIX_RAMPFASTMONOVOL
830END_FASTRAMPMIX_INTERFACE()
831
832BEGIN_FASTRAMPMIX_INTERFACE(FastMono8BitLinearRampMix)
833 SNDMIX_BEGINSAMPLELOOP8
834 SNDMIX_GETMONOVOL8LINEAR
835 SNDMIX_RAMPFASTMONOVOL
836END_FASTRAMPMIX_INTERFACE()
837
838BEGIN_FASTRAMPMIX_INTERFACE(FastMono16BitLinearRampMix)
839 SNDMIX_BEGINSAMPLELOOP16
840 SNDMIX_GETMONOVOL16LINEAR
841 SNDMIX_RAMPFASTMONOVOL
842END_FASTRAMPMIX_INTERFACE()
843
844BEGIN_FASTRAMPMIX_INTERFACE(FastMono8BitSplineRampMix)
845 SNDMIX_BEGINSAMPLELOOP8
846 SNDMIX_GETMONOVOL8SPLINE
847 SNDMIX_RAMPFASTMONOVOL
848END_FASTRAMPMIX_INTERFACE()
849
850BEGIN_FASTRAMPMIX_INTERFACE(FastMono16BitSplineRampMix)
851 SNDMIX_BEGINSAMPLELOOP16
852 SNDMIX_GETMONOVOL16SPLINE
853 SNDMIX_RAMPFASTMONOVOL
854END_FASTRAMPMIX_INTERFACE()
855
856BEGIN_FASTRAMPMIX_INTERFACE(FastMono8BitFirFilterRampMix)
857 SNDMIX_BEGINSAMPLELOOP8
858 SNDMIX_GETMONOVOL8FIRFILTER
859 SNDMIX_RAMPFASTMONOVOL
860END_FASTRAMPMIX_INTERFACE()
861
862BEGIN_FASTRAMPMIX_INTERFACE(FastMono16BitFirFilterRampMix)
863 SNDMIX_BEGINSAMPLELOOP16
864 SNDMIX_GETMONOVOL16FIRFILTER
865 SNDMIX_RAMPFASTMONOVOL
866END_FASTRAMPMIX_INTERFACE()
867
868
869//////////////////////////////////////////////////////
870// Stereo samples
871
872BEGIN_MIX_INTERFACE(Stereo8BitMix)
873 SNDMIX_BEGINSAMPLELOOP8
874 SNDMIX_GETSTEREOVOL8NOIDO
875 SNDMIX_STORESTEREOVOL
876END_MIX_INTERFACE()
877
878BEGIN_MIX_INTERFACE(Stereo16BitMix)
879 SNDMIX_BEGINSAMPLELOOP16
880 SNDMIX_GETSTEREOVOL16NOIDO
881 SNDMIX_STORESTEREOVOL
882END_MIX_INTERFACE()
883
884BEGIN_MIX_INTERFACE(Stereo8BitLinearMix)
885 SNDMIX_BEGINSAMPLELOOP8
886 SNDMIX_GETSTEREOVOL8LINEAR
887 SNDMIX_STORESTEREOVOL
888END_MIX_INTERFACE()
889
890BEGIN_MIX_INTERFACE(Stereo16BitLinearMix)
891 SNDMIX_BEGINSAMPLELOOP16
892 SNDMIX_GETSTEREOVOL16LINEAR
893 SNDMIX_STORESTEREOVOL
894END_MIX_INTERFACE()
895
896BEGIN_MIX_INTERFACE(Stereo8BitSplineMix)
897 SNDMIX_BEGINSAMPLELOOP8
898 SNDMIX_GETSTEREOVOL8SPLINE
899 SNDMIX_STORESTEREOVOL
900END_MIX_INTERFACE()
901
902BEGIN_MIX_INTERFACE(Stereo16BitSplineMix)
903 SNDMIX_BEGINSAMPLELOOP16
904 SNDMIX_GETSTEREOVOL16SPLINE
905 SNDMIX_STORESTEREOVOL
906END_MIX_INTERFACE()
907
908BEGIN_MIX_INTERFACE(Stereo8BitFirFilterMix)
909 SNDMIX_BEGINSAMPLELOOP8
910 SNDMIX_GETSTEREOVOL8FIRFILTER
911 SNDMIX_STORESTEREOVOL
912END_MIX_INTERFACE()
913
914BEGIN_MIX_INTERFACE(Stereo16BitFirFilterMix)
915 SNDMIX_BEGINSAMPLELOOP16
916 SNDMIX_GETSTEREOVOL16FIRFILTER
917 SNDMIX_STORESTEREOVOL
918END_MIX_INTERFACE()
919
920
921// Volume Ramps
922BEGIN_RAMPMIX_INTERFACE(Stereo8BitRampMix)
923 SNDMIX_BEGINSAMPLELOOP8
924 SNDMIX_GETSTEREOVOL8NOIDO
925 SNDMIX_RAMPSTEREOVOL
926END_RAMPMIX_INTERFACE()
927
928BEGIN_RAMPMIX_INTERFACE(Stereo16BitRampMix)
929 SNDMIX_BEGINSAMPLELOOP16
930 SNDMIX_GETSTEREOVOL16NOIDO
931 SNDMIX_RAMPSTEREOVOL
932END_RAMPMIX_INTERFACE()
933
934BEGIN_RAMPMIX_INTERFACE(Stereo8BitLinearRampMix)
935 SNDMIX_BEGINSAMPLELOOP8
936 SNDMIX_GETSTEREOVOL8LINEAR
937 SNDMIX_RAMPSTEREOVOL
938END_RAMPMIX_INTERFACE()
939
940BEGIN_RAMPMIX_INTERFACE(Stereo16BitLinearRampMix)
941 SNDMIX_BEGINSAMPLELOOP16
942 SNDMIX_GETSTEREOVOL16LINEAR
943 SNDMIX_RAMPSTEREOVOL
944END_RAMPMIX_INTERFACE()
945
946BEGIN_RAMPMIX_INTERFACE(Stereo8BitSplineRampMix)
947 SNDMIX_BEGINSAMPLELOOP8
948 SNDMIX_GETSTEREOVOL8SPLINE
949 SNDMIX_RAMPSTEREOVOL
950END_RAMPMIX_INTERFACE()
951
952BEGIN_RAMPMIX_INTERFACE(Stereo16BitSplineRampMix)
953 SNDMIX_BEGINSAMPLELOOP16
954 SNDMIX_GETSTEREOVOL16SPLINE
955 SNDMIX_RAMPSTEREOVOL
956END_RAMPMIX_INTERFACE()
957
958BEGIN_RAMPMIX_INTERFACE(Stereo8BitFirFilterRampMix)
959 SNDMIX_BEGINSAMPLELOOP8
960 SNDMIX_GETSTEREOVOL8FIRFILTER
961 SNDMIX_RAMPSTEREOVOL
962END_RAMPMIX_INTERFACE()
963
964BEGIN_RAMPMIX_INTERFACE(Stereo16BitFirFilterRampMix)
965 SNDMIX_BEGINSAMPLELOOP16
966 SNDMIX_GETSTEREOVOL16FIRFILTER
967 SNDMIX_RAMPSTEREOVOL
968END_RAMPMIX_INTERFACE()
969
970
971
972//////////////////////////////////////////////////////
973// Resonant Filter Mix
974
975#ifndef NO_FILTER
976
977// Mono Filter Mix
978BEGIN_MIX_FLT_INTERFACE(FilterMono8BitMix)
979 SNDMIX_BEGINSAMPLELOOP8
980 SNDMIX_GETMONOVOL8NOIDO
981 SNDMIX_PROCESSFILTER
982 SNDMIX_STOREMONOVOL
983END_MIX_FLT_INTERFACE()
984
985BEGIN_MIX_FLT_INTERFACE(FilterMono16BitMix)
986 SNDMIX_BEGINSAMPLELOOP16
987 SNDMIX_GETMONOVOL16NOIDO
988 SNDMIX_PROCESSFILTER
989 SNDMIX_STOREMONOVOL
990END_MIX_FLT_INTERFACE()
991
992BEGIN_MIX_FLT_INTERFACE(FilterMono8BitLinearMix)
993 SNDMIX_BEGINSAMPLELOOP8
994 SNDMIX_GETMONOVOL8LINEAR
995 SNDMIX_PROCESSFILTER
996 SNDMIX_STOREMONOVOL
997END_MIX_FLT_INTERFACE()
998
999BEGIN_MIX_FLT_INTERFACE(FilterMono16BitLinearMix)
1000 SNDMIX_BEGINSAMPLELOOP16
1001 SNDMIX_GETMONOVOL16LINEAR
1002 SNDMIX_PROCESSFILTER
1003 SNDMIX_STOREMONOVOL
1004END_MIX_FLT_INTERFACE()
1005
1006BEGIN_MIX_FLT_INTERFACE(FilterMono8BitSplineMix)
1007 SNDMIX_BEGINSAMPLELOOP8
1008 SNDMIX_GETMONOVOL8SPLINE
1009 SNDMIX_PROCESSFILTER
1010 SNDMIX_STOREMONOVOL
1011END_MIX_FLT_INTERFACE()
1012
1013BEGIN_MIX_FLT_INTERFACE(FilterMono16BitSplineMix)
1014 SNDMIX_BEGINSAMPLELOOP16
1015 SNDMIX_GETMONOVOL16SPLINE
1016 SNDMIX_PROCESSFILTER
1017 SNDMIX_STOREMONOVOL
1018END_MIX_FLT_INTERFACE()
1019
1020BEGIN_MIX_FLT_INTERFACE(FilterMono8BitFirFilterMix)
1021 SNDMIX_BEGINSAMPLELOOP8
1022 SNDMIX_GETMONOVOL8FIRFILTER
1023 SNDMIX_PROCESSFILTER
1024 SNDMIX_STOREMONOVOL
1025END_MIX_FLT_INTERFACE()
1026
1027BEGIN_MIX_FLT_INTERFACE(FilterMono16BitFirFilterMix)
1028 SNDMIX_BEGINSAMPLELOOP16
1029 SNDMIX_GETMONOVOL16FIRFILTER
1030 SNDMIX_PROCESSFILTER
1031 SNDMIX_STOREMONOVOL
1032END_MIX_FLT_INTERFACE()
1033
1034// Filter + Ramp
1035BEGIN_RAMPMIX_FLT_INTERFACE(FilterMono8BitRampMix)
1036 SNDMIX_BEGINSAMPLELOOP8
1037 SNDMIX_GETMONOVOL8NOIDO
1038 SNDMIX_PROCESSFILTER
1039 SNDMIX_RAMPMONOVOL
1040END_RAMPMIX_FLT_INTERFACE()
1041
1042BEGIN_RAMPMIX_FLT_INTERFACE(FilterMono16BitRampMix)
1043 SNDMIX_BEGINSAMPLELOOP16
1044 SNDMIX_GETMONOVOL16NOIDO
1045 SNDMIX_PROCESSFILTER
1046 SNDMIX_RAMPMONOVOL
1047END_RAMPMIX_FLT_INTERFACE()
1048
1049BEGIN_RAMPMIX_FLT_INTERFACE(FilterMono8BitLinearRampMix)
1050 SNDMIX_BEGINSAMPLELOOP8
1051 SNDMIX_GETMONOVOL8LINEAR
1052 SNDMIX_PROCESSFILTER
1053 SNDMIX_RAMPMONOVOL
1054END_RAMPMIX_FLT_INTERFACE()
1055
1056BEGIN_RAMPMIX_FLT_INTERFACE(FilterMono16BitLinearRampMix)
1057 SNDMIX_BEGINSAMPLELOOP16
1058 SNDMIX_GETMONOVOL16LINEAR
1059 SNDMIX_PROCESSFILTER
1060 SNDMIX_RAMPMONOVOL
1061END_RAMPMIX_FLT_INTERFACE()
1062
1063BEGIN_RAMPMIX_FLT_INTERFACE(FilterMono8BitSplineRampMix)
1064 SNDMIX_BEGINSAMPLELOOP8
1065 SNDMIX_GETMONOVOL8SPLINE
1066 SNDMIX_PROCESSFILTER
1067 SNDMIX_RAMPMONOVOL
1068END_RAMPMIX_FLT_INTERFACE()
1069
1070BEGIN_RAMPMIX_FLT_INTERFACE(FilterMono16BitSplineRampMix)
1071 SNDMIX_BEGINSAMPLELOOP16
1072 SNDMIX_GETMONOVOL16SPLINE
1073 SNDMIX_PROCESSFILTER
1074 SNDMIX_RAMPMONOVOL
1075END_RAMPMIX_FLT_INTERFACE()
1076
1077BEGIN_RAMPMIX_FLT_INTERFACE(FilterMono8BitFirFilterRampMix)
1078 SNDMIX_BEGINSAMPLELOOP8
1079 SNDMIX_GETMONOVOL8FIRFILTER
1080 SNDMIX_PROCESSFILTER
1081 SNDMIX_RAMPMONOVOL
1082END_RAMPMIX_FLT_INTERFACE()
1083
1084BEGIN_RAMPMIX_FLT_INTERFACE(FilterMono16BitFirFilterRampMix)
1085 SNDMIX_BEGINSAMPLELOOP16
1086 SNDMIX_GETMONOVOL16FIRFILTER
1087 SNDMIX_PROCESSFILTER
1088 SNDMIX_RAMPMONOVOL
1089END_RAMPMIX_FLT_INTERFACE()
1090
1091
1092// Stereo Filter Mix
1093BEGIN_MIX_STFLT_INTERFACE(FilterStereo8BitMix)
1094 SNDMIX_BEGINSAMPLELOOP8
1095 SNDMIX_GETSTEREOVOL8NOIDO
1096 SNDMIX_PROCESSSTEREOFILTER
1097 SNDMIX_STORESTEREOVOL
1098END_MIX_STFLT_INTERFACE()
1099
1100BEGIN_MIX_STFLT_INTERFACE(FilterStereo16BitMix)
1101 SNDMIX_BEGINSAMPLELOOP16
1102 SNDMIX_GETSTEREOVOL16NOIDO
1103 SNDMIX_PROCESSSTEREOFILTER
1104 SNDMIX_STORESTEREOVOL
1105END_MIX_STFLT_INTERFACE()
1106
1107BEGIN_MIX_STFLT_INTERFACE(FilterStereo8BitLinearMix)
1108 SNDMIX_BEGINSAMPLELOOP8
1109 SNDMIX_GETSTEREOVOL8LINEAR
1110 SNDMIX_PROCESSSTEREOFILTER
1111 SNDMIX_STORESTEREOVOL
1112END_MIX_STFLT_INTERFACE()
1113
1114BEGIN_MIX_STFLT_INTERFACE(FilterStereo16BitLinearMix)
1115 SNDMIX_BEGINSAMPLELOOP16
1116 SNDMIX_GETSTEREOVOL16LINEAR
1117 SNDMIX_PROCESSSTEREOFILTER
1118 SNDMIX_STORESTEREOVOL
1119END_MIX_STFLT_INTERFACE()
1120
1121BEGIN_MIX_STFLT_INTERFACE(FilterStereo8BitSplineMix)
1122 SNDMIX_BEGINSAMPLELOOP8
1123 SNDMIX_GETSTEREOVOL8SPLINE
1124 SNDMIX_PROCESSSTEREOFILTER
1125 SNDMIX_STORESTEREOVOL
1126END_MIX_STFLT_INTERFACE()
1127
1128BEGIN_MIX_STFLT_INTERFACE(FilterStereo16BitSplineMix)
1129 SNDMIX_BEGINSAMPLELOOP16
1130 SNDMIX_GETSTEREOVOL16SPLINE
1131 SNDMIX_PROCESSSTEREOFILTER
1132 SNDMIX_STORESTEREOVOL
1133END_MIX_STFLT_INTERFACE()
1134
1135BEGIN_MIX_STFLT_INTERFACE(FilterStereo8BitFirFilterMix)
1136 SNDMIX_BEGINSAMPLELOOP8
1137 SNDMIX_GETSTEREOVOL8FIRFILTER
1138 SNDMIX_PROCESSSTEREOFILTER
1139 SNDMIX_STORESTEREOVOL
1140END_MIX_STFLT_INTERFACE()
1141
1142BEGIN_MIX_STFLT_INTERFACE(FilterStereo16BitFirFilterMix)
1143 SNDMIX_BEGINSAMPLELOOP16
1144 SNDMIX_GETSTEREOVOL16FIRFILTER
1145 SNDMIX_PROCESSSTEREOFILTER
1146 SNDMIX_STORESTEREOVOL
1147END_MIX_STFLT_INTERFACE()
1148
1149// Stereo Filter + Ramp
1150BEGIN_RAMPMIX_STFLT_INTERFACE(FilterStereo8BitRampMix)
1151 SNDMIX_BEGINSAMPLELOOP8
1152 SNDMIX_GETSTEREOVOL8NOIDO
1153 SNDMIX_PROCESSSTEREOFILTER
1154 SNDMIX_RAMPSTEREOVOL
1155END_RAMPMIX_STFLT_INTERFACE()
1156
1157BEGIN_RAMPMIX_STFLT_INTERFACE(FilterStereo16BitRampMix)
1158 SNDMIX_BEGINSAMPLELOOP16
1159 SNDMIX_GETSTEREOVOL16NOIDO
1160 SNDMIX_PROCESSSTEREOFILTER
1161 SNDMIX_RAMPSTEREOVOL
1162END_RAMPMIX_STFLT_INTERFACE()
1163
1164BEGIN_RAMPMIX_STFLT_INTERFACE(FilterStereo8BitLinearRampMix)
1165 SNDMIX_BEGINSAMPLELOOP8
1166 SNDMIX_GETSTEREOVOL8LINEAR
1167 SNDMIX_PROCESSSTEREOFILTER
1168 SNDMIX_RAMPSTEREOVOL
1169END_RAMPMIX_STFLT_INTERFACE()
1170
1171BEGIN_RAMPMIX_STFLT_INTERFACE(FilterStereo16BitLinearRampMix)
1172 SNDMIX_BEGINSAMPLELOOP16
1173 SNDMIX_GETSTEREOVOL16LINEAR
1174 SNDMIX_PROCESSSTEREOFILTER
1175 SNDMIX_RAMPSTEREOVOL
1176END_RAMPMIX_STFLT_INTERFACE()
1177
1178BEGIN_RAMPMIX_STFLT_INTERFACE(FilterStereo8BitSplineRampMix)
1179 SNDMIX_BEGINSAMPLELOOP8
1180 SNDMIX_GETSTEREOVOL8SPLINE
1181 SNDMIX_PROCESSSTEREOFILTER
1182 SNDMIX_RAMPSTEREOVOL
1183END_RAMPMIX_STFLT_INTERFACE()
1184
1185BEGIN_RAMPMIX_STFLT_INTERFACE(FilterStereo16BitSplineRampMix)
1186 SNDMIX_BEGINSAMPLELOOP16
1187 SNDMIX_GETSTEREOVOL16SPLINE
1188 SNDMIX_PROCESSSTEREOFILTER
1189 SNDMIX_RAMPSTEREOVOL
1190END_RAMPMIX_STFLT_INTERFACE()
1191
1192BEGIN_RAMPMIX_STFLT_INTERFACE(FilterStereo8BitFirFilterRampMix)
1193 SNDMIX_BEGINSAMPLELOOP8
1194 SNDMIX_GETSTEREOVOL8FIRFILTER
1195 SNDMIX_PROCESSSTEREOFILTER
1196 SNDMIX_RAMPSTEREOVOL
1197END_RAMPMIX_STFLT_INTERFACE()
1198
1199BEGIN_RAMPMIX_STFLT_INTERFACE(FilterStereo16BitFirFilterRampMix)
1200 SNDMIX_BEGINSAMPLELOOP16
1201 SNDMIX_GETSTEREOVOL16FIRFILTER
1202 SNDMIX_PROCESSSTEREOFILTER
1203 SNDMIX_RAMPSTEREOVOL
1204END_RAMPMIX_STFLT_INTERFACE()
1205
1206
1207#else
1208// Mono
1209 #define FilterMono8BitMix Mono8BitMix
1210 #define FilterMono16BitMix Mono16BitMix
1211 #define FilterMono8BitLinearMix Mono8BitLinearMix
1212 #define FilterMono16BitLinearMix Mono16BitLinearMix
1213 #define FilterMono8BitSplineMix Mono8BitSplineMix
1214 #define FilterMono16BitSplineMix Mono16BitSplineMix
1215 #define FilterMono8BitFirFilterMix Mono8BitFirFilterMix
1216 #define FilterMono16BitFirFilterMix Mono16BitFirFilterMix
1217 #define FilterMono8BitRampMix Mono8BitRampMix
1218 #define FilterMono16BitRampMix Mono16BitRampMix
1219 #define FilterMono8BitLinearRampMix Mono8BitLinearRampMix
1220 #define FilterMono16BitLinearRampMix Mono16BitLinearRampMix
1221 #define FilterMono8BitSplineRampMix Mono8BitSplineRampMix
1222 #define FilterMono16BitSplineRampMix Mono16BitSplineRampMix
1223 #define FilterMono8BitFirFilterRampMix Mono8BitFirFilterRampMix
1224 #define FilterMono16BitFirFilterRampMix Mono16BitFirFilterRampMix
1225// Stereo
1226 #define FilterStereo8BitMix Stereo8BitMix
1227 #define FilterStereo16BitMix Stereo16BitMix
1228 #define FilterStereo8BitLinearMix Stereo8BitLinearMix
1229 #define FilterStereo16BitLinearMix Stereo16BitLinearMix
1230 #define FilterStereo8BitSplineMix Stereo8BitSplineMix
1231 #define FilterStereo16BitSplineMix Stereo16BitSplineMix
1232 #define FilterStereo8BitFirFilterMix Stereo8BitFirFilterMix
1233 #define FilterStereo16BitFirFilterMix Stereo16BitFirFilterMix
1234 #define FilterStereo8BitRampMix Stereo8BitRampMix
1235 #define FilterStereo16BitRampMix Stereo16BitRampMix
1236 #define FilterStereo8BitLinearRampMix Stereo8BitLinearRampMix
1237 #define FilterStereo16BitLinearRampMix Stereo16BitLinearRampMix
1238 #define FilterStereo8BitSplineRampMix Stereo8BitSplineRampMix
1239 #define FilterStereo16BitSplineRampMix Stereo16BitSplineRampMix
1240 #define FilterStereo8BitFirFilterRampMixStereo8BitFirFilterRampMix
1241 #define FilterStereo16BitFirFilterRampMixStereo16BitFirFilterRampMix
1242
1243#endif
1244
1245/////////////////////////////////////////////////////////////////////////////////////
1246//
1247// Mix function tables
1248//
1249//
1250// Index is as follow:
1251 // [b1-b0]format (8-bit-mono, 16-bit-mono, 8-bit-stereo, 16-bit-stereo)
1252 // [b2]ramp
1253 // [b3]filter
1254 // [b5-b4]src type
1255//
1256
1257 #define MIXNDX_16BIT 0x01
1258 #define MIXNDX_STEREO 0x02
1259 #define MIXNDX_RAMP 0x04
1260 #define MIXNDX_FILTER 0x08
1261 #define MIXNDX_LINEARSRC0x10
1262#define MIXNDX_SPLINESRC 0x20
1263 #define MIXNDX_FIRSRC 0x30
1264
1265const LPMIXINTERFACE gpMixFunctionTable[2*2*16] =
1266{
1267 // No SRC
1268 Mono8BitMix, Mono16BitMix, Stereo8BitMix, Stereo16BitMix,
1269 Mono8BitRampMix, Mono16BitRampMix, Stereo8BitRampMix, Stereo16BitRampMix,
1270 // No SRC, Filter
1271 FilterMono8BitMix, FilterMono16BitMix, FilterStereo8BitMix,FilterStereo16BitMix,
1272 FilterMono8BitRampMix, FilterMono16BitRampMix, FilterStereo8BitRampMix,FilterStereo16BitRampMix,
1273 // Linear SRC
1274 Mono8BitLinearMix, Mono16BitLinearMix, Stereo8BitLinearMix,Stereo16BitLinearMix,
1275 Mono8BitLinearRampMix, Mono16BitLinearRampMix, Stereo8BitLinearRampMix,Stereo16BitLinearRampMix,
1276 // Linear SRC, Filter
1277 FilterMono8BitLinearMix, FilterMono16BitLinearMix, FilterStereo8BitLinearMix,FilterStereo16BitLinearMix,
1278 FilterMono8BitLinearRampMix,FilterMono16BitLinearRampMix,FilterStereo8BitLinearRampMix,FilterStereo16BitLinearRampMix,
1279
1280 // FirFilter SRC
1281 Mono8BitSplineMix, Mono16BitSplineMix, Stereo8BitSplineMix,Stereo16BitSplineMix,
1282 Mono8BitSplineRampMix, Mono16BitSplineRampMix, Stereo8BitSplineRampMix,Stereo16BitSplineRampMix,
1283 // Spline SRC, Filter
1284 FilterMono8BitSplineMix, FilterMono16BitSplineMix, FilterStereo8BitSplineMix,FilterStereo16BitSplineMix,
1285 FilterMono8BitSplineRampMix,FilterMono16BitSplineRampMix,FilterStereo8BitSplineRampMix,FilterStereo16BitSplineRampMix,
1286
1287 // FirFilter SRC
1288 Mono8BitFirFilterMix, Mono16BitFirFilterMix, Stereo8BitFirFilterMix,Stereo16BitFirFilterMix,
1289 Mono8BitFirFilterRampMix, Mono16BitFirFilterRampMix, Stereo8BitFirFilterRampMix,Stereo16BitFirFilterRampMix,
1290 // FirFilter SRC, Filter
1291 FilterMono8BitFirFilterMix, FilterMono16BitFirFilterMix, FilterStereo8BitFirFilterMix,FilterStereo16BitFirFilterMix,
1292 FilterMono8BitFirFilterRampMix,FilterMono16BitFirFilterRampMix,FilterStereo8BitFirFilterRampMix,FilterStereo16BitFirFilterRampMix
1293};
1294
1295const LPMIXINTERFACE gpFastMixFunctionTable[2*2*16] =
1296{
1297 // No SRC
1298 FastMono8BitMix, FastMono16BitMix, Stereo8BitMix, Stereo16BitMix,
1299 FastMono8BitRampMix, FastMono16BitRampMix, Stereo8BitRampMix, Stereo16BitRampMix,
1300 // No SRC, Filter
1301 FilterMono8BitMix, FilterMono16BitMix, FilterStereo8BitMix,FilterStereo16BitMix,
1302 FilterMono8BitRampMix, FilterMono16BitRampMix, FilterStereo8BitRampMix,FilterStereo16BitRampMix,
1303 // Linear SRC
1304 FastMono8BitLinearMix, FastMono16BitLinearMix, Stereo8BitLinearMix,Stereo16BitLinearMix,
1305 FastMono8BitLinearRampMix, FastMono16BitLinearRampMix,Stereo8BitLinearRampMix,Stereo16BitLinearRampMix,
1306 // Linear SRC, Filter
1307 FilterMono8BitLinearMix, FilterMono16BitLinearMix, FilterStereo8BitLinearMix,FilterStereo16BitLinearMix,
1308 FilterMono8BitLinearRampMix,FilterMono16BitLinearRampMix,FilterStereo8BitLinearRampMix,FilterStereo16BitLinearRampMix,
1309
1310 // Spline SRC
1311 Mono8BitSplineMix, Mono16BitSplineMix, Stereo8BitSplineMix,Stereo16BitSplineMix,
1312 Mono8BitSplineRampMix, Mono16BitSplineRampMix,Stereo8BitSplineRampMix,Stereo16BitSplineRampMix,
1313 // Spline SRC, Filter
1314 FilterMono8BitSplineMix, FilterMono16BitSplineMix, FilterStereo8BitSplineMix,FilterStereo16BitSplineMix,
1315 FilterMono8BitSplineRampMix,FilterMono16BitSplineRampMix,FilterStereo8BitSplineRampMix,FilterStereo16BitSplineRampMix,
1316
1317 // FirFilter SRC
1318 Mono8BitFirFilterMix, Mono16BitFirFilterMix, Stereo8BitFirFilterMix,Stereo16BitFirFilterMix,
1319 Mono8BitFirFilterRampMix, Mono16BitFirFilterRampMix,Stereo8BitFirFilterRampMix,Stereo16BitFirFilterRampMix,
1320 // FirFilter SRC, Filter
1321 FilterMono8BitFirFilterMix, FilterMono16BitFirFilterMix, FilterStereo8BitFirFilterMix,FilterStereo16BitFirFilterMix,
1322 FilterMono8BitFirFilterRampMix,FilterMono16BitFirFilterRampMix,FilterStereo8BitFirFilterRampMix,FilterStereo16BitFirFilterRampMix,
1323};
1324
1325
1326/////////////////////////////////////////////////////////////////////////
1327
1328static LONG MPPFASTCALL GetSampleCount(MODCHANNEL *pChn, LONG nSamples)
1329//---------------------------------------------------------------------
1330{
1331 LONG nLoopStart = (pChn->dwFlags & CHN_LOOP) ? pChn->nLoopStart : 0;
1332 LONG nInc = pChn->nInc;
1333
1334 if ((nSamples <= 0) || (!nInc) || (!pChn->nLength)) return 0;
1335 // Under zero ?
1336 if ((LONG)pChn->nPos < nLoopStart)
1337 {
1338 if (nInc < 0)
1339 {
1340 // Invert loop for bidi loops
1341 LONG nDelta = ((nLoopStart - pChn->nPos) << 16) - (pChn->nPosLo & 0xffff);
1342 pChn->nPos = nLoopStart | (nDelta>>16);
1343 pChn->nPosLo = nDelta & 0xffff;
1344 if (((LONG)pChn->nPos < nLoopStart) || (pChn->nPos >= (nLoopStart+pChn->nLength)/2))
1345 {
1346 pChn->nPos = nLoopStart; pChn->nPosLo = 0;
1347 }
1348 nInc = -nInc;
1349 pChn->nInc = nInc;
1350 pChn->dwFlags &= ~(CHN_PINGPONGFLAG); // go forward
1351 if ((!(pChn->dwFlags & CHN_LOOP)) || (pChn->nPos >= pChn->nLength))
1352 {
1353 pChn->nPos = pChn->nLength;
1354 pChn->nPosLo = 0;
1355 return 0;
1356 }
1357 } else
1358 {
1359 // We probably didn't hit the loop end yet (first loop), so we do nothing
1360 if ((LONG)pChn->nPos < 0) pChn->nPos = 0;
1361 }
1362 } else
1363 // Past the end
1364 if (pChn->nPos >= pChn->nLength)
1365 {
1366 if (!(pChn->dwFlags & CHN_LOOP)) return 0; // not looping -> stop this channel
1367 if (pChn->dwFlags & CHN_PINGPONGLOOP)
1368 {
1369 // Invert loop
1370 if (nInc > 0)
1371 {
1372 nInc = -nInc;
1373 pChn->nInc = nInc;
1374 }
1375 pChn->dwFlags |= CHN_PINGPONGFLAG;
1376 // adjust loop position
1377 LONG nDeltaHi = (pChn->nPos - pChn->nLength);
1378 LONG nDeltaLo = 0x10000 - (pChn->nPosLo & 0xffff);
1379 pChn->nPos = pChn->nLength - nDeltaHi - (nDeltaLo>>16);
1380 pChn->nPosLo = nDeltaLo & 0xffff;
1381 if ((pChn->nPos <= pChn->nLoopStart) || (pChn->nPos >= pChn->nLength)) pChn->nPos = pChn->nLength-1;
1382 } else
1383 {
1384 if (nInc < 0) // This is a bug
1385 {
1386 nInc = -nInc;
1387 pChn->nInc = nInc;
1388 }
1389 // Restart at loop start
1390 pChn->nPos += nLoopStart - pChn->nLength;
1391 if ((LONG)pChn->nPos < nLoopStart) pChn->nPos = pChn->nLoopStart;
1392 }
1393 }
1394 LONG nPos = pChn->nPos;
1395 // too big increment, and/or too small loop length
1396 if (nPos < nLoopStart)
1397 {
1398 if ((nPos < 0) || (nInc < 0)) return 0;
1399 }
1400 if ((nPos < 0) || (nPos >= (LONG)pChn->nLength)) return 0;
1401 LONG nPosLo = (USHORT)pChn->nPosLo, nSmpCount = nSamples;
1402 if (nInc < 0)
1403 {
1404 LONG nInv = -nInc;
1405 LONG maxsamples = 16384 / ((nInv>>16)+1);
1406 if (maxsamples < 2) maxsamples = 2;
1407 if (nSamples > maxsamples) nSamples = maxsamples;
1408 LONG nDeltaHi = (nInv>>16) * (nSamples - 1);
1409 LONG nDeltaLo = (nInv&0xffff) * (nSamples - 1);
1410 LONG nPosDest = nPos - nDeltaHi + ((nPosLo - nDeltaLo) >> 16);
1411 if (nPosDest < nLoopStart)
1412 {
1413 nSmpCount = (ULONG)(((((LONGLONG)nPos - nLoopStart) << 16) + nPosLo - 1) / nInv) + 1;
1414 }
1415 } else
1416 {
1417 LONG maxsamples = 16384 / ((nInc>>16)+1);
1418 if (maxsamples < 2) maxsamples = 2;
1419 if (nSamples > maxsamples) nSamples = maxsamples;
1420 LONG nDeltaHi = (nInc>>16) * (nSamples - 1);
1421 LONG nDeltaLo = (nInc&0xffff) * (nSamples - 1);
1422 LONG nPosDest = nPos + nDeltaHi + ((nPosLo + nDeltaLo)>>16);
1423 if (nPosDest >= (LONG)pChn->nLength)
1424 {
1425 nSmpCount = (ULONG)(((((LONGLONG)pChn->nLength - nPos) << 16) - nPosLo - 1) / nInc) + 1;
1426 }
1427 }
1428 if (nSmpCount <= 1) return 1;
1429 if (nSmpCount > nSamples) return nSamples;
1430 return nSmpCount;
1431}
1432
1433
1434UINT CSoundFile::CreateStereoMix(int count)
1435//-----------------------------------------
1436{
1437 LPLONG pOfsL, pOfsR;
1438 DWORD nchused, nchmixed;
1439
1440 if (!count) return 0;
1441#ifndef FASTSOUNDLIB
1442 if (gnChannels > 2) X86_InitMixBuffer(MixRearBuffer, count*2);
1443#endif
1444 nchused = nchmixed = 0;
1445 for (UINT nChn=0; nChn<m_nMixChannels; nChn++)
1446 {
1447 const LPMIXINTERFACE *pMixFuncTable;
1448 MODCHANNEL * const pChannel = &Chn[ChnMix[nChn]];
1449 UINT nFlags, nMasterCh;
1450 LONG nSmpCount;
1451 int nsamples;
1452 int *pbuffer;
1453
1454 if (!pChannel->pCurrentSample) continue;
1455 nMasterCh = (ChnMix[nChn] < m_nChannels) ? ChnMix[nChn]+1 : pChannel->nMasterChn;
1456 pOfsR = &gnDryROfsVol;
1457 pOfsL = &gnDryLOfsVol;
1458 nFlags = 0;
1459 if (pChannel->dwFlags & CHN_16BIT) nFlags |= MIXNDX_16BIT;
1460 if (pChannel->dwFlags & CHN_STEREO) nFlags |= MIXNDX_STEREO;
1461 #ifndef NO_FILTER
1462 if (pChannel->dwFlags & CHN_FILTER) nFlags |= MIXNDX_FILTER;
1463 #endif
1464 if (!(pChannel->dwFlags & CHN_NOIDO))
1465 {
1466 // use hq-fir mixer?
1467 if( (gdwSoundSetup & (SNDMIX_HQRESAMPLER|SNDMIX_ULTRAHQSRCMODE)) == (SNDMIX_HQRESAMPLER|SNDMIX_ULTRAHQSRCMODE) )
1468 nFlags += MIXNDX_FIRSRC;
1469 else if( (gdwSoundSetup & (SNDMIX_HQRESAMPLER)) == SNDMIX_HQRESAMPLER )
1470 nFlags += MIXNDX_SPLINESRC;
1471 else
1472 nFlags += MIXNDX_LINEARSRC; // use
1473 }
1474 if ((nFlags < 0x40) && (pChannel->nLeftVol == pChannel->nRightVol)
1475 && ((!pChannel->nRampLength) || (pChannel->nLeftRamp == pChannel->nRightRamp)))
1476 {
1477 pMixFuncTable = gpFastMixFunctionTable;
1478 } else
1479 {
1480 pMixFuncTable = gpMixFunctionTable;
1481 }
1482 nsamples = count;
1483#ifndef NO_REVERB
1484 pbuffer = (gdwSoundSetup & SNDMIX_REVERB) ? MixReverbBuffer : MixSoundBuffer;
1485 if (pChannel->dwFlags & CHN_NOREVERB) pbuffer = MixSoundBuffer;
1486 if (pChannel->dwFlags & CHN_REVERB) pbuffer = MixReverbBuffer;
1487 if (pbuffer == MixReverbBuffer)
1488 {
1489 if (!gnReverbSend) memset(MixReverbBuffer, 0, count * 8);
1490 gnReverbSend += count;
1491 }
1492#else
1493 pbuffer = MixSoundBuffer;
1494#endif
1495 nchused++;
1496 ////////////////////////////////////////////////////
1497 SampleLooping:
1498 UINT nrampsamples = nsamples;
1499 if (pChannel->nRampLength > 0)
1500 {
1501 if ((LONG)nrampsamples > pChannel->nRampLength) nrampsamples = pChannel->nRampLength;
1502 }
1503 if ((nSmpCount = GetSampleCount(pChannel, nrampsamples)) <= 0)
1504 {
1505 // Stopping the channel
1506 pChannel->pCurrentSample = NULL;
1507 pChannel->nLength = 0;
1508 pChannel->nPos = 0;
1509 pChannel->nPosLo = 0;
1510 pChannel->nRampLength = 0;
1511 X86_EndChannelOfs(pChannel, pbuffer, nsamples);
1512 *pOfsR += pChannel->nROfs;
1513 *pOfsL += pChannel->nLOfs;
1514 pChannel->nROfs = pChannel->nLOfs = 0;
1515 pChannel->dwFlags &= ~CHN_PINGPONGFLAG;
1516 continue;
1517 }
1518 // Should we mix this channel ?
1519 UINT naddmix;
1520 if (((nchmixed >= m_nMaxMixChannels) && (!(gdwSoundSetup & SNDMIX_DIRECTTODISK)))
1521 || ((!pChannel->nRampLength) && (!(pChannel->nLeftVol|pChannel->nRightVol))))
1522 {
1523 LONG delta = (pChannel->nInc * (LONG)nSmpCount) + (LONG)pChannel->nPosLo;
1524 pChannel->nPosLo = delta & 0xFFFF;
1525 pChannel->nPos += (delta >> 16);
1526 pChannel->nROfs = pChannel->nLOfs = 0;
1527 pbuffer += nSmpCount*2;
1528 naddmix = 0;
1529 } else
1530 // Do mixing
1531 {
1532 // Choose function for mixing
1533 LPMIXINTERFACE pMixFunc;
1534 pMixFunc = (pChannel->nRampLength) ? pMixFuncTable[nFlags|MIXNDX_RAMP] : pMixFuncTable[nFlags];
1535 int *pbufmax = pbuffer + (nSmpCount*2);
1536 pChannel->nROfs = - *(pbufmax-2);
1537 pChannel->nLOfs = - *(pbufmax-1);
1538 pMixFunc(pChannel, pbuffer, pbufmax);
1539 pChannel->nROfs += *(pbufmax-2);
1540 pChannel->nLOfs += *(pbufmax-1);
1541 pbuffer = pbufmax;
1542 naddmix = 1;
1543
1544 }
1545 nsamples -= nSmpCount;
1546 if (pChannel->nRampLength)
1547 {
1548 pChannel->nRampLength -= nSmpCount;
1549 if (pChannel->nRampLength <= 0)
1550 {
1551 pChannel->nRampLength = 0;
1552 pChannel->nRightVol = pChannel->nNewRightVol;
1553 pChannel->nLeftVol = pChannel->nNewLeftVol;
1554 pChannel->nRightRamp = pChannel->nLeftRamp = 0;
1555 if ((pChannel->dwFlags & CHN_NOTEFADE) && (!(pChannel->nFadeOutVol)))
1556 {
1557 pChannel->nLength = 0;
1558 pChannel->pCurrentSample = NULL;
1559 }
1560 }
1561 }
1562 if (nsamples > 0) goto SampleLooping;
1563 nchmixed += naddmix;
1564 }
1565 return nchused;
1566}
1567
1568
1569#ifdef WIN32
1570#pragma warning (disable:4100)
1571#endif
1572
1573// Clip and convert to 8 bit
1574#ifdef WIN32
1575__declspec(naked) DWORD MPPASMCALL X86_Convert32To8(LPVOID lp16, int *pBuffer, DWORD lSampleCount, LPLONG lpMin, LPLONG lpMax)
1576//----------------------------------------------------------------------------------------------------------------------------
1577{
1578 _asm {
1579 push ebx
1580 push esi
1581 push edi
1582 mov ebx, 16[esp] // ebx = 8-bit buffer
1583 mov esi, 20[esp] // esi = pBuffer
1584 mov edi, 24[esp] // edi = lSampleCount
1585 mov eax, 28[esp]
1586 mov ecx, dword ptr [eax]// ecx = clipmin
1587 mov eax, 32[esp]
1588 mov edx, dword ptr [eax]// edx = clipmax
1589cliploop:
1590 mov eax, dword ptr [esi]
1591 inc ebx
1592 cdq
1593 and edx, (1 << (24-MIXING_ATTENUATION)) - 1
1594 add eax, edx
1595 cmp eax, MIXING_CLIPMIN
1596 jl cliplow
1597 cmp eax, MIXING_CLIPMAX
1598 jg cliphigh
1599 cmp eax, ecx
1600 jl updatemin
1601 cmp eax, edx
1602 jg updatemax
1603cliprecover:
1604 add esi, 4
1605 sar eax, 24-MIXING_ATTENUATION
1606 xor eax, 0x80
1607 dec edi
1608 mov byte ptr [ebx-1], al
1609 jnz cliploop
1610 mov eax, 28[esp]
1611 mov dword ptr [eax], ecx
1612 mov eax, 32[esp]
1613 mov dword ptr [eax], edx
1614 mov eax, 24[esp]
1615 pop edi
1616 pop esi
1617 pop ebx
1618 ret
1619updatemin:
1620 mov ecx, eax
1621 jmp cliprecover
1622updatemax:
1623 mov edx, eax
1624 jmp cliprecover
1625cliplow:
1626 mov ecx, MIXING_CLIPMIN
1627 mov edx, MIXING_CLIPMAX
1628 mov eax, MIXING_CLIPMIN
1629 jmp cliprecover
1630cliphigh:
1631 mov ecx, MIXING_CLIPMIN
1632 mov edx, MIXING_CLIPMAX
1633 mov eax, MIXING_CLIPMAX
1634 jmp cliprecover
1635 }
1636}
1637#else //WIN32
1638//---GCCFIX: Asm replaced with C function
1639// The C version was written by Rani Assaf <rani@magic.metawire.com>, I believe
1640__declspec(naked) DWORD MPPASMCALL X86_Convert32To8(LPVOID lp8, int *pBuffer, DWORD lSampleCount, LPLONG lpMin, LPLONG lpMax)
1641{
1642 int vumin = *lpMin, vumax = *lpMax;
1643 unsigned char *p = (unsigned char *)lp8;
1644 for (UINT i=0; i<lSampleCount; i++)
1645 {
1646 int n = pBuffer[i];
1647 if (n < MIXING_CLIPMIN)
1648 n = MIXING_CLIPMIN;
1649 else if (n > MIXING_CLIPMAX)
1650 n = MIXING_CLIPMAX;
1651 if (n < vumin)
1652 vumin = n;
1653 else if (n > vumax)
1654 vumax = n;
1655 p[i] = (n >> (24-MIXING_ATTENUATION)) ^ 0x80;// 8-bit unsigned
1656 }
1657 *lpMin = vumin;
1658 *lpMax = vumax;
1659 return lSampleCount;
1660}
1661#endif //WIN32, else
1662
1663
1664#ifdef WIN32
1665// Clip and convert to 16 bit
1666__declspec(naked) DWORD MPPASMCALL X86_Convert32To16(LPVOID lp16, int *pBuffer, DWORD lSampleCount, LPLONG lpMin, LPLONG lpMax)
1667//-----------------------------------------------------------------------------------------------------------------------------
1668{
1669 _asm {
1670 push ebx
1671 push esi
1672 push edi
1673 mov ebx, 16[esp] // ebx = 16-bit buffer
1674 mov eax, 28[esp]
1675 mov esi, 20[esp] // esi = pBuffer
1676 mov ecx, dword ptr [eax]// ecx = clipmin
1677 mov edi, 24[esp] // edi = lSampleCount
1678 mov eax, 32[esp]
1679 push ebp
1680 mov ebp, dword ptr [eax]// edx = clipmax
1681cliploop:
1682 mov eax, dword ptr [esi]
1683 add ebx, 2
1684 cdq
1685 and edx, (1 << (16-MIXING_ATTENUATION)) - 1
1686 add esi, 4
1687 add eax, edx
1688 cmp eax, MIXING_CLIPMIN
1689 jl cliplow
1690 cmp eax, MIXING_CLIPMAX
1691 jg cliphigh
1692 cmp eax, ecx
1693 jl updatemin
1694 cmp eax, ebp
1695 jg updatemax
1696cliprecover:
1697 sar eax, 16-MIXING_ATTENUATION
1698 dec edi
1699 mov word ptr [ebx-2], ax
1700 jnz cliploop
1701 mov edx, ebp
1702 pop ebp
1703 mov eax, 28[esp]
1704 mov dword ptr [eax], ecx
1705 mov eax, 32[esp]
1706 mov dword ptr [eax], edx
1707 mov eax, 24[esp]
1708 pop edi
1709 shl eax, 1
1710 pop esi
1711 pop ebx
1712 ret
1713updatemin:
1714 mov ecx, eax
1715 jmp cliprecover
1716updatemax:
1717 mov ebp, eax
1718 jmp cliprecover
1719cliplow:
1720 mov ecx, MIXING_CLIPMIN
1721 mov ebp, MIXING_CLIPMAX
1722 mov eax, MIXING_CLIPMIN
1723 jmp cliprecover
1724cliphigh:
1725 mov ecx, MIXING_CLIPMIN
1726 mov ebp, MIXING_CLIPMAX
1727 mov eax, MIXING_CLIPMAX
1728 jmp cliprecover
1729 }
1730}
1731#else //WIN32
1732//---GCCFIX: Asm replaced with C function
1733// The C version was written by Rani Assaf <rani@magic.metawire.com>, I believe
1734__declspec(naked) DWORD MPPASMCALL X86_Convert32To16(LPVOID lp16, int *pBuffer, DWORD lSampleCount, LPLONG lpMin, LPLONG lpMax)
1735{
1736 int vumin = *lpMin, vumax = *lpMax;
1737 signed short *p = (signed short *)lp16;
1738 for (UINT i=0; i<lSampleCount; i++)
1739 {
1740 int n = pBuffer[i];
1741 if (n < MIXING_CLIPMIN)
1742 n = MIXING_CLIPMIN;
1743 else if (n > MIXING_CLIPMAX)
1744 n = MIXING_CLIPMAX;
1745 if (n < vumin)
1746 vumin = n;
1747 else if (n > vumax)
1748 vumax = n;
1749 p[i] = n >> (16-MIXING_ATTENUATION);// 16-bit signed
1750 }
1751 *lpMin = vumin;
1752 *lpMax = vumax;
1753 return lSampleCount * 2;
1754}
1755#endif //WIN32, else
1756
1757#ifdef WIN32
1758// Clip and convert to 24 bit
1759__declspec(naked) DWORD MPPASMCALL X86_Convert32To24(LPVOID lp16, int *pBuffer, DWORD lSampleCount, LPLONG lpMin, LPLONG lpMax)
1760//-----------------------------------------------------------------------------------------------------------------------------
1761{
1762 _asm {
1763 push ebx
1764 push esi
1765 push edi
1766 mov ebx, 16[esp] // ebx = 8-bit buffer
1767 mov esi, 20[esp] // esi = pBuffer
1768 mov edi, 24[esp] // edi = lSampleCount
1769 mov eax, 28[esp]
1770 mov ecx, dword ptr [eax]// ecx = clipmin
1771 mov eax, 32[esp]
1772 push ebp
1773 mov edx, dword ptr [eax]// edx = clipmax
1774cliploop:
1775 mov eax, dword ptr [esi]
1776 mov ebp, eax
1777 sar ebp, 31
1778 and ebp, (1 << (8-MIXING_ATTENUATION)) - 1
1779 add eax, ebp
1780 cmp eax, MIXING_CLIPMIN
1781 jl cliplow
1782 cmp eax, MIXING_CLIPMAX
1783 jg cliphigh
1784 cmp eax, ecx
1785 jl updatemin
1786 cmp eax, edx
1787 jg updatemax
1788cliprecover:
1789 add ebx, 3
1790 sar eax, 8-MIXING_ATTENUATION
1791 add esi, 4
1792 mov word ptr [ebx-3], ax
1793 shr eax, 16
1794 dec edi
1795 mov byte ptr [ebx-1], al
1796 jnz cliploop
1797 pop ebp
1798 mov eax, 28[esp]
1799 mov dword ptr [eax], ecx
1800 mov eax, 32[esp]
1801 mov dword ptr [eax], edx
1802 mov edx, 24[esp]
1803 mov eax, edx
1804 pop edi
1805 shl eax, 1
1806 pop esi
1807 add eax, edx
1808 pop ebx
1809 ret
1810updatemin:
1811 mov ecx, eax
1812 jmp cliprecover
1813updatemax:
1814 mov edx, eax
1815 jmp cliprecover
1816cliplow:
1817 mov ecx, MIXING_CLIPMIN
1818 mov edx, MIXING_CLIPMAX
1819 mov eax, MIXING_CLIPMIN
1820 jmp cliprecover
1821cliphigh:
1822 mov ecx, MIXING_CLIPMIN
1823 mov edx, MIXING_CLIPMAX
1824 mov eax, MIXING_CLIPMAX
1825 jmp cliprecover
1826 }
1827}
1828#else //WIN32
1829//---GCCFIX: Asm replaced with C function
1830// 24-bit audio not supported.
1831__declspec(naked) DWORD MPPASMCALL X86_Convert32To24(LPVOID lp16, int *pBuffer, DWORD lSampleCount, LPLONG lpMin, LPLONG lpMax)
1832{
1833 return 0;
1834}
1835#endif
1836
1837#ifdef WIN32
1838// Clip and convert to 32 bit
1839__declspec(naked) DWORD MPPASMCALL X86_Convert32To32(LPVOID lp16, int *pBuffer, DWORD lSampleCount, LPLONG lpMin, LPLONG lpMax)
1840//-----------------------------------------------------------------------------------------------------------------------------
1841{
1842 _asm {
1843 push ebx
1844 push esi
1845 push edi
1846 mov ebx, 16[esp] // ebx = 32-bit buffer
1847 mov esi, 20[esp] // esi = pBuffer
1848 mov edi, 24[esp] // edi = lSampleCount
1849 mov eax, 28[esp]
1850 mov ecx, dword ptr [eax]// ecx = clipmin
1851 mov eax, 32[esp]
1852 mov edx, dword ptr [eax]// edx = clipmax
1853cliploop:
1854 mov eax, dword ptr [esi]
1855 add ebx, 4
1856 add esi, 4
1857 cmp eax, MIXING_CLIPMIN
1858 jl cliplow
1859 cmp eax, MIXING_CLIPMAX
1860 jg cliphigh
1861 cmp eax, ecx
1862 jl updatemin
1863 cmp eax, edx
1864 jg updatemax
1865cliprecover:
1866 shl eax, MIXING_ATTENUATION
1867 dec edi
1868 mov dword ptr [ebx-4], eax
1869 jnz cliploop
1870 mov eax, 28[esp]
1871 mov dword ptr [eax], ecx
1872 mov eax, 32[esp]
1873 mov dword ptr [eax], edx
1874 mov edx, 24[esp]
1875 pop edi
1876 mov eax, edx
1877 pop esi
1878 shl eax, 2
1879 pop ebx
1880 ret
1881updatemin:
1882 mov ecx, eax
1883 jmp cliprecover
1884updatemax:
1885 mov edx, eax
1886 jmp cliprecover
1887cliplow:
1888 mov ecx, MIXING_CLIPMIN
1889 mov edx, MIXING_CLIPMAX
1890 mov eax, MIXING_CLIPMIN
1891 jmp cliprecover
1892cliphigh:
1893 mov ecx, MIXING_CLIPMIN
1894 mov edx, MIXING_CLIPMAX
1895 mov eax, MIXING_CLIPMAX
1896 jmp cliprecover
1897 }
1898}
1899#else
1900//---GCCFIX: Asm replaced with C function
1901// 32-bit audio not supported
1902__declspec(naked) DWORD MPPASMCALL X86_Convert32To32(LPVOID lp16, int *pBuffer, DWORD lSampleCount, LPLONG lpMin, LPLONG lpMax)
1903{
1904 return 0;
1905}
1906#endif
1907
1908
1909#ifdef WIN32
1910void MPPASMCALL X86_InitMixBuffer(int *pBuffer, UINT nSamples)
1911//------------------------------------------------------------
1912{
1913 _asm {
1914 mov ecx, nSamples
1915 mov esi, pBuffer
1916 xor eax, eax
1917 mov edx, ecx
1918 shr ecx, 2
1919 and edx, 3
1920 jz unroll4x
1921loop1x:
1922 add esi, 4
1923 dec edx
1924 mov dword ptr [esi-4], eax
1925 jnz loop1x
1926unroll4x:
1927 or ecx, ecx
1928 jnz loop4x
1929 jmp done
1930loop4x:
1931 add esi, 16
1932 dec ecx
1933 mov dword ptr [esi-16], eax
1934 mov dword ptr [esi-12], eax
1935 mov dword ptr [esi-8], eax
1936 mov dword ptr [esi-4], eax
1937 jnz loop4x
1938done:;
1939 }
1940}
1941#else
1942//---GCCFIX: Asm replaced with C function
1943// Will fill in later.
1944void MPPASMCALL X86_InitMixBuffer(int *pBuffer, UINT nSamples)
1945{
1946 memset(pBuffer, 0, nSamples * sizeof(int));
1947}
1948#endif
1949
1950
1951#ifdef WIN32
1952__declspec(naked) void MPPASMCALL X86_InterleaveFrontRear(int *pFrontBuf, int *pRearBuf, DWORD nSamples)
1953//------------------------------------------------------------------------------------------------------
1954{
1955 _asm {
1956 push ebx
1957 push ebp
1958 push esi
1959 push edi
1960 mov ecx, 28[esp] // ecx = samplecount
1961 mov esi, 20[esp] // esi = front buffer
1962 mov edi, 24[esp] // edi = rear buffer
1963 lea esi, [esi+ecx*4]// esi = &front[N]
1964 lea edi, [edi+ecx*4]// edi = &rear[N]
1965 lea ebx, [esi+ecx*4]// ebx = &front[N*2]
1966interleaveloop:
1967 mov eax, dword ptr [esi-8]
1968 mov edx, dword ptr [esi-4]
1969 sub ebx, 16
1970 mov ebp, dword ptr [edi-8]
1971 mov dword ptr [ebx], eax
1972 mov dword ptr [ebx+4], edx
1973 mov eax, dword ptr [edi-4]
1974 sub esi, 8
1975 sub edi, 8
1976 dec ecx
1977 mov dword ptr [ebx+8], ebp
1978 mov dword ptr [ebx+12], eax
1979 jnz interleaveloop
1980 pop edi
1981 pop esi
1982 pop ebp
1983 pop ebx
1984 ret
1985 }
1986}
1987#else
1988//---GCCFIX: Asm replaced with C function
1989// Multichannel not supported.
1990__declspec(naked) void MPPASMCALL X86_InterleaveFrontRear(int *pFrontBuf, int *pRearBuf, DWORD nSamples)
1991{
1992}
1993#endif
1994
1995
1996#ifdef WIN32
1997VOID MPPASMCALL X86_MonoFromStereo(int *pMixBuf, UINT nSamples)
1998//-------------------------------------------------------------
1999{
2000 _asm {
2001 mov ecx, nSamples
2002 mov esi, pMixBuf
2003 mov edi, esi
2004stloop:
2005 mov eax, dword ptr [esi]
2006 mov edx, dword ptr [esi+4]
2007 add edi, 4
2008 add esi, 8
2009 add eax, edx
2010 sar eax, 1
2011 dec ecx
2012 mov dword ptr [edi-4], eax
2013 jnz stloop
2014 }
2015}
2016#else
2017//---GCCFIX: Asm replaced with C function
2018VOID MPPASMCALL X86_MonoFromStereo(int *pMixBuf, UINT nSamples)
2019{
2020 UINT j;
2021 for(UINT i = 0; i < nSamples; i++)
2022 {
2023 j = i << 1;
2024 pMixBuf[i] = (pMixBuf[j] + pMixBuf[j + 1]) >> 1;
2025 }
2026}
2027#endif
2028
2029 #define OFSDECAYSHIFT8
2030 #define OFSDECAYMASK0xFF
2031
2032
2033#ifdef WIN32
2034void MPPASMCALL X86_StereoFill(int *pBuffer, UINT nSamples, LPLONG lpROfs, LPLONG lpLOfs)
2035//---------------------------------------------------------------------------------------
2036{
2037 _asm {
2038 mov edi, pBuffer
2039 mov ecx, nSamples
2040 mov eax, lpROfs
2041 mov edx, lpLOfs
2042 mov eax, [eax]
2043 mov edx, [edx]
2044 or ecx, ecx
2045 jz fill_loop
2046 mov ebx, eax
2047 or ebx, edx
2048 jz fill_loop
2049ofsloop:
2050 mov ebx, eax
2051 mov esi, edx
2052 neg ebx
2053 neg esi
2054 sar ebx, 31
2055 sar esi, 31
2056 and ebx, OFSDECAYMASK
2057 and esi, OFSDECAYMASK
2058 add ebx, eax
2059 add esi, edx
2060 sar ebx, OFSDECAYSHIFT
2061 sar esi, OFSDECAYSHIFT
2062 sub eax, ebx
2063 sub edx, esi
2064 mov ebx, eax
2065 or ebx, edx
2066 jz fill_loop
2067 add edi, 8
2068 dec ecx
2069 mov [edi-8], eax
2070 mov [edi-4], edx
2071 jnz ofsloop
2072fill_loop:
2073 mov ebx, ecx
2074 and ebx, 3
2075 jz fill4x
2076fill1x:
2077 mov [edi], eax
2078 mov [edi+4], edx
2079 add edi, 8
2080 dec ebx
2081 jnz fill1x
2082fill4x:
2083 shr ecx, 2
2084 or ecx, ecx
2085 jz done
2086fill4xloop:
2087 mov [edi], eax
2088 mov [edi+4], edx
2089 mov [edi+8], eax
2090 mov [edi+12], edx
2091 add edi, 8*4
2092 dec ecx
2093 mov [edi-16], eax
2094 mov [edi-12], edx
2095 mov [edi-8], eax
2096 mov [edi-4], edx
2097 jnz fill4xloop
2098done:
2099 mov esi, lpROfs
2100 mov edi, lpLOfs
2101 mov [esi], eax
2102 mov [edi], edx
2103 }
2104}
2105#else
2106//---GCCFIX: Asm replaced with C function
2107#define OFSDECAYSHIFT 8
2108#define OFSDECAYMASK 0xFF
2109__declspec(naked) void MPPASMCALL X86_StereoFill(int *pBuffer, UINT nSamples, LPLONG lpROfs, LPLONG lpLOfs)
2110//---------------------------------------------------------------------------------------------------------
2111{
2112 int rofs = *lpROfs;
2113 int lofs = *lpLOfs;
2114
2115 if ((!rofs) && (!lofs))
2116 {
2117 X86_InitMixBuffer(pBuffer, nSamples*2);
2118 return;
2119 }
2120 for (UINT i=0; i<nSamples; i++)
2121 {
2122 int x_r = (rofs + (((-rofs)>>31) & OFSDECAYMASK)) >> OFSDECAYSHIFT;
2123 int x_l = (lofs + (((-lofs)>>31) & OFSDECAYMASK)) >> OFSDECAYSHIFT;
2124 rofs -= x_r;
2125 lofs -= x_l;
2126 pBuffer[i*2] = x_r;
2127 pBuffer[i*2+1] = x_l;
2128 }
2129 *lpROfs = rofs;
2130 *lpLOfs = lofs;
2131}
2132#endif
2133
2134#ifdef WIN32
2135void MPPASMCALL X86_EndChannelOfs(MODCHANNEL *pChannel, int *pBuffer, UINT nSamples)
2136//----------------------------------------------------------------------------------
2137{
2138 _asm {
2139 mov esi, pChannel
2140 mov edi, pBuffer
2141 mov ecx, nSamples
2142 mov eax, dword ptr [esi+MODCHANNEL.nROfs]
2143 mov edx, dword ptr [esi+MODCHANNEL.nLOfs]
2144 or ecx, ecx
2145 jz brkloop
2146ofsloop:
2147 mov ebx, eax
2148 mov esi, edx
2149 neg ebx
2150 neg esi
2151 sar ebx, 31
2152 sar esi, 31
2153 and ebx, OFSDECAYMASK
2154 and esi, OFSDECAYMASK
2155 add ebx, eax
2156 add esi, edx
2157 sar ebx, OFSDECAYSHIFT
2158 sar esi, OFSDECAYSHIFT
2159 sub eax, ebx
2160 sub edx, esi
2161 mov ebx, eax
2162 add dword ptr [edi], eax
2163 add dword ptr [edi+4], edx
2164 or ebx, edx
2165 jz brkloop
2166 add edi, 8
2167 dec ecx
2168 jnz ofsloop
2169brkloop:
2170 mov esi, pChannel
2171 mov dword ptr [esi+MODCHANNEL.nROfs], eax
2172 mov dword ptr [esi+MODCHANNEL.nLOfs], edx
2173 }
2174}
2175#else
2176//---GCCFIX: Asm replaced with C function
2177// Will fill in later.
2178void MPPASMCALL X86_EndChannelOfs(MODCHANNEL *pChannel, int *pBuffer, UINT nSamples)
2179{
2180 int rofs = pChannel->nROfs;
2181 int lofs = pChannel->nLOfs;
2182
2183 if ((!rofs) && (!lofs)) return;
2184 for (UINT i=0; i<nSamples; i++)
2185 {
2186 int x_r = (rofs + (((-rofs)>>31) & OFSDECAYMASK)) >> OFSDECAYSHIFT;
2187 int x_l = (lofs + (((-lofs)>>31) & OFSDECAYMASK)) >> OFSDECAYSHIFT;
2188 rofs -= x_r;
2189 lofs -= x_l;
2190 pBuffer[i*2] += x_r;
2191 pBuffer[i*2+1] += x_l;
2192 }
2193 pChannel->nROfs = rofs;
2194 pChannel->nLOfs = lofs;
2195}
2196#endif
2197
2198
2199//////////////////////////////////////////////////////////////////////////////////
2200// Automatic Gain Control
2201
2202#ifndef NO_AGC
2203
2204// Limiter
2205 #define MIXING_LIMITMAX (0x08100000)
2206 #define MIXING_LIMITMIN (-MIXING_LIMITMAX)
2207
2208__declspec(naked) UINT MPPASMCALL X86_AGC(int *pBuffer, UINT nSamples, UINT nAGC)
2209//-------------------------------------------------------------------------------
2210{
2211 __asm {
2212 push ebx
2213 push ebp
2214 push esi
2215 push edi
2216 mov esi, 20[esp]// esi = pBuffer+i
2217 mov ecx, 24[esp]// ecx = i
2218 mov edi, 28[esp]// edi = AGC (0..256)
2219agcloop:
2220 mov eax, dword ptr [esi]
2221 imul edi
2222 shrd eax, edx, AGC_PRECISION
2223 add esi, 4
2224 cmp eax, MIXING_LIMITMIN
2225 jl agcupdate
2226 cmp eax, MIXING_LIMITMAX
2227 jg agcupdate
2228agcrecover:
2229 dec ecx
2230 mov dword ptr [esi-4], eax
2231 jnz agcloop
2232 mov eax, edi
2233 pop edi
2234 pop esi
2235 pop ebp
2236 pop ebx
2237 ret
2238agcupdate:
2239 dec edi
2240 jmp agcrecover
2241 }
2242}
2243
2244#pragma warning (default:4100)
2245
2246void CSoundFile::ProcessAGC(int count)
2247//------------------------------------
2248{
2249 static DWORD gAGCRecoverCount = 0;
2250 UINT agc = X86_AGC(MixSoundBuffer, count, gnAGC);
2251 // Some kind custom law, so that the AGC stays quite stable, but slowly
2252 // goes back up if the sound level stays below a level inversely proportional
2253 // to the AGC level. (J'me comprends)
2254 if ((agc >= gnAGC) && (gnAGC < AGC_UNITY) && (gnVUMeter < (0xFF - (gnAGC >> (AGC_PRECISION-7))) ))
2255 {
2256 gAGCRecoverCount += count;
2257 UINT agctimeout = gdwMixingFreq + gnAGC;
2258 if (gnChannels >= 2) agctimeout <<= 1;
2259 if (gAGCRecoverCount >= agctimeout)
2260 {
2261 gAGCRecoverCount = 0;
2262 gnAGC++;
2263 }
2264 } else
2265 {
2266 gnAGC = agc;
2267 gAGCRecoverCount = 0;
2268 }
2269}
2270
2271
2272
2273void CSoundFile::ResetAGC()
2274//-------------------------
2275{
2276 gnAGC = AGC_UNITY;
2277}
2278
2279#endif // NO_AGC
2280
diff --git a/core/multimedia/opieplayer/modplug/it_defs.h b/core/multimedia/opieplayer/modplug/it_defs.h
new file mode 100644
index 0000000..1eaf086
--- a/dev/null
+++ b/core/multimedia/opieplayer/modplug/it_defs.h
@@ -0,0 +1,136 @@
1#ifndef _ITDEFS_H_
2#define _ITDEFS_H_
3
4#include "stdafx.h"
5
6#pragma pack(1)
7
8typedef struct tagITFILEHEADER
9{
10 DWORD id; // 0x4D504D49
11 CHAR songname[26];
12 WORD reserved1; // 0x1004
13 WORD ordnum;
14 WORD insnum;
15 WORD smpnum;
16 WORD patnum;
17 WORD cwtv;
18 WORD cmwt;
19 WORD flags;
20 WORD special;
21 BYTE globalvol;
22 BYTE mv;
23 BYTE speed;
24 BYTE tempo;
25 BYTE sep;
26 BYTE zero;
27 WORD msglength;
28 DWORD msgoffset;
29 DWORD reserved2;
30 BYTE chnpan[64];
31 BYTE chnvol[64];
32} Q_PACKED ITFILEHEADER;
33
34
35typedef struct tagITENVELOPE
36{
37 BYTE flags;
38 BYTE num;
39 BYTE lpb;
40 BYTE lpe;
41 BYTE slb;
42 BYTE sle;
43 BYTE data[25*3];
44 BYTE reserved;
45} Q_PACKED ITENVELOPE;
46
47// Old Impulse Instrument Format (cmwt < 0x200)
48typedef struct tagITOLDINSTRUMENT
49{
50 DWORD id; // IMPI = 0x49504D49
51 CHAR filename[12];// DOS file name
52 BYTE zero;
53 BYTE flags;
54 BYTE vls;
55 BYTE vle;
56 BYTE sls;
57 BYTE sle;
58 WORD reserved1;
59 WORD fadeout;
60 BYTE nna;
61 BYTE dnc;
62 WORD trkvers;
63 BYTE nos;
64 BYTE reserved2;
65 CHAR name[26];
66 WORD reserved3[3];
67 BYTE keyboard[240];
68 BYTE volenv[200];
69 BYTE nodes[50];
70} Q_PACKED ITOLDINSTRUMENT;
71
72
73// Impulse Instrument Format
74typedef struct tagITINSTRUMENT
75{
76 DWORD id;
77 CHAR filename[12];
78 BYTE zero;
79 BYTE nna;
80 BYTE dct;
81 BYTE dca;
82 WORD fadeout;
83 signed char pps;
84 BYTE ppc;
85 BYTE gbv;
86 BYTE dfp;
87 BYTE rv;
88 BYTE rp;
89 WORD trkvers;
90 BYTE nos;
91 BYTE reserved1;
92 CHAR name[26];
93 BYTE ifc;
94 BYTE ifr;
95 BYTE mch;
96 BYTE mpr;
97 WORD mbank;
98 BYTE keyboard[240];
99 ITENVELOPE volenv;
100 ITENVELOPE panenv;
101 ITENVELOPE pitchenv;
102 BYTE dummy[4]; // was 7, but IT v2.17 saves 554 bytes
103} Q_PACKED ITINSTRUMENT;
104
105
106// IT Sample Format
107typedef struct ITSAMPLESTRUCT
108{
109 DWORD id; // 0x53504D49
110 CHAR filename[12];
111 BYTE zero;
112 BYTE gvl;
113 BYTE flags;
114 BYTE vol;
115 CHAR name[26];
116 BYTE cvt;
117 BYTE dfp;
118 DWORD length;
119 DWORD loopbegin;
120 DWORD loopend;
121 DWORD C5Speed;
122 DWORD susloopbegin;
123 DWORD susloopend;
124 DWORD samplepointer;
125 BYTE vis;
126 BYTE vid;
127 BYTE vir;
128 BYTE vit;
129} Q_PACKED ITSAMPLESTRUCT;
130
131#pragma pack()
132
133extern const BYTE autovibit2xm[8];
134extern const BYTE autovibxm2it[8];
135
136#endif
diff --git a/core/multimedia/opieplayer/modplug/load_669.cpp b/core/multimedia/opieplayer/modplug/load_669.cpp
new file mode 100644
index 0000000..905ca93
--- a/dev/null
+++ b/core/multimedia/opieplayer/modplug/load_669.cpp
@@ -0,0 +1,189 @@
1/*
2 * This program is free software; you can redistribute it and modify it
3 * under the terms of the GNU General Public License as published by the
4 * Free Software Foundation; either version 2 of the license or (at your
5 * option) any later version.
6 *
7 * Authors: Olivier Lapicque <olivierl@jps.net>,
8 * Adam Goode <adam@evdebs.org> (endian and char fixes for PPC)
9*/
10
11////////////////////////////////////////////////////////////
12// 669 Composer / UNIS 669 module loader
13////////////////////////////////////////////////////////////
14
15#include "stdafx.h"
16#include "sndfile.h"
17
18//#pragma warning(disable:4244)
19
20typedef struct tagFILEHEADER669
21{
22 WORD sig; // 'if' or 'JN'
23 signed char songmessage[108];// Song Message
24 BYTE samples; // number of samples (1-64)
25 BYTE patterns; // number of patterns (1-128)
26 BYTE restartpos;
27 BYTE orders[128];
28 BYTE tempolist[128];
29 BYTE breaks[128];
30} Q_PACKED FILEHEADER669;
31
32
33typedef struct tagSAMPLE669
34{
35 BYTE filename[13];
36 BYTE length[4];// when will somebody think about DWORD align ???
37 BYTE loopstart[4];
38 BYTE loopend[4];
39} Q_PACKED SAMPLE669;
40
41
42BOOL CSoundFile::Read669(const BYTE *lpStream, DWORD dwMemLength)
43//---------------------------------------------------------------
44{
45 BOOL b669Ext;
46 const FILEHEADER669 *pfh = (const FILEHEADER669 *)lpStream;
47 const SAMPLE669 *psmp = (const SAMPLE669 *)(lpStream + 0x1F1);
48 DWORD dwMemPos = 0;
49
50 if ((!lpStream) || (dwMemLength < sizeof(FILEHEADER669))) return FALSE;
51 if ((bswapLE16(pfh->sig) != 0x6669) && (bswapLE16(pfh->sig) != 0x4E4A)) return FALSE;
52 b669Ext = (bswapLE16(pfh->sig) == 0x4E4A) ? TRUE : FALSE;
53 if ((!pfh->samples) || (pfh->samples > 64) || (pfh->restartpos >= 128)
54 || (!pfh->patterns) || (pfh->patterns > 128)) return FALSE;
55 DWORD dontfuckwithme = 0x1F1 + pfh->samples * sizeof(SAMPLE669) + pfh->patterns * 0x600;
56 if (dontfuckwithme > dwMemLength) return FALSE;
57 for (UINT ichk=0; ichk<pfh->samples; ichk++)
58 {
59 DWORD len = bswapLE32(*((DWORD *)(&psmp[ichk].length)));
60 dontfuckwithme += len;
61 }
62 if (dontfuckwithme > dwMemLength) return FALSE;
63 // That should be enough checking: this must be a 669 module.
64 m_nType = MOD_TYPE_669;
65 m_dwSongFlags |= SONG_LINEARSLIDES;
66 m_nMinPeriod = 28 << 2;
67 m_nMaxPeriod = 1712 << 3;
68 m_nDefaultTempo = 125;
69 m_nDefaultSpeed = 6;
70 m_nChannels = 8;
71 memcpy(m_szNames[0], pfh->songmessage, 16);
72 m_nSamples = pfh->samples;
73 for (UINT nins=1; nins<=m_nSamples; nins++, psmp++)
74 {
75 DWORD len = bswapLE32(*((DWORD *)(&psmp->length)));
76 DWORD loopstart = bswapLE32(*((DWORD *)(&psmp->loopstart)));
77 DWORD loopend = bswapLE32(*((DWORD *)(&psmp->loopend)));
78 if (len > MAX_SAMPLE_LENGTH) len = MAX_SAMPLE_LENGTH;
79 if ((loopend > len) && (!loopstart)) loopend = 0;
80 if (loopend > len) loopend = len;
81 if (loopstart + 4 >= loopend) loopstart = loopend = 0;
82 Ins[nins].nLength = len;
83 Ins[nins].nLoopStart = loopstart;
84 Ins[nins].nLoopEnd = loopend;
85 if (loopend) Ins[nins].uFlags |= CHN_LOOP;
86 memcpy(m_szNames[nins], psmp->filename, 13);
87 Ins[nins].nVolume = 256;
88 Ins[nins].nGlobalVol = 64;
89 Ins[nins].nPan = 128;
90 }
91 // Song Message
92 m_lpszSongComments = new char[109];
93 memcpy(m_lpszSongComments, pfh->songmessage, 108);
94 m_lpszSongComments[108] = 0;
95 // Reading Orders
96 memcpy(Order, pfh->orders, 128);
97 m_nRestartPos = pfh->restartpos;
98 if (Order[m_nRestartPos] >= pfh->patterns) m_nRestartPos = 0;
99 // Reading Pattern Break Locations
100 for (UINT npan=0; npan<8; npan++)
101 {
102 ChnSettings[npan].nPan = (npan & 1) ? 0x30 : 0xD0;
103 ChnSettings[npan].nVolume = 64;
104 }
105 // Reading Patterns
106 dwMemPos = 0x1F1 + pfh->samples * 25;
107 for (UINT npat=0; npat<pfh->patterns; npat++)
108 {
109 Patterns[npat] = AllocatePattern(64, m_nChannels);
110 if (!Patterns[npat]) break;
111 PatternSize[npat] = 64;
112 MODCOMMAND *m = Patterns[npat];
113 const BYTE *p = lpStream + dwMemPos;
114 for (UINT row=0; row<64; row++)
115 {
116 MODCOMMAND *mspeed = m;
117 if ((row == pfh->breaks[npat]) && (row != 63))
118 {
119 for (UINT i=0; i<8; i++)
120 {
121 m[i].command = CMD_PATTERNBREAK;
122 m[i].param = 0;
123 }
124 }
125 for (UINT n=0; n<8; n++, m++, p+=3)
126 {
127 UINT note = p[0] >> 2;
128 UINT instr = ((p[0] & 0x03) << 4) | (p[1] >> 4);
129 UINT vol = p[1] & 0x0F;
130 if (p[0] < 0xFE)
131 {
132 m->note = note + 37;
133 m->instr = instr + 1;
134 }
135 if (p[0] <= 0xFE)
136 {
137 m->volcmd = VOLCMD_VOLUME;
138 m->vol = (vol << 2) + 2;
139 }
140 if (p[2] != 0xFF)
141 {
142 UINT command = p[2] >> 4;
143 UINT param = p[2] & 0x0F;
144 switch(command)
145 {
146 case 0x00:command = CMD_PORTAMENTOUP; break;
147 case 0x01:command = CMD_PORTAMENTODOWN; break;
148 case 0x02:command = CMD_TONEPORTAMENTO; break;
149 case 0x03:command = CMD_MODCMDEX; param |= 0x50; break;
150 case 0x04:command = CMD_VIBRATO; param |= 0x40; break;
151 case 0x05:if (param) command = CMD_SPEED; else command = 0; param += 2; break;
152 case 0x06:if (param == 0) { command = CMD_PANNINGSLIDE; param = 0xFE; } else
153 if (param == 1) { command = CMD_PANNINGSLIDE; param = 0xEF; } else
154 command = 0;
155 break;
156 default:command = 0;
157 }
158 if (command)
159 {
160 if (command == CMD_SPEED) mspeed = NULL;
161 m->command = command;
162 m->param = param;
163 }
164 }
165 }
166 if ((!row) && (mspeed))
167 {
168 for (UINT i=0; i<8; i++) if (!mspeed[i].command)
169 {
170 mspeed[i].command = CMD_SPEED;
171 mspeed[i].param = pfh->tempolist[npat] + 2;
172 break;
173 }
174 }
175 }
176 dwMemPos += 0x600;
177 }
178 // Reading Samples
179 for (UINT n=1; n<=m_nSamples; n++)
180 {
181 UINT len = Ins[n].nLength;
182 if (dwMemPos >= dwMemLength) break;
183 if (len > 4) ReadSample(&Ins[n], RS_PCM8U, (LPSTR)(lpStream+dwMemPos), dwMemLength - dwMemPos);
184 dwMemPos += len;
185 }
186 return TRUE;
187}
188
189
diff --git a/core/multimedia/opieplayer/modplug/load_amf.cpp b/core/multimedia/opieplayer/modplug/load_amf.cpp
new file mode 100644
index 0000000..188b5f5
--- a/dev/null
+++ b/core/multimedia/opieplayer/modplug/load_amf.cpp
@@ -0,0 +1,420 @@
1/*
2 * This program is free software; you can redistribute it and modify it
3 * under the terms of the GNU General Public License as published by the
4 * Free Software Foundation; either version 2 of the license or (at your
5 * option) any later version.
6 *
7 * Authors: Olivier Lapicque <olivierl@jps.net>
8*/
9
10///////////////////////////////////////////////////
11//
12// AMF module loader
13//
14// There is 2 types of AMF files:
15// - ASYLUM Music Format
16// - Advanced Music Format(DSM)
17//
18///////////////////////////////////////////////////
19#include "stdafx.h"
20#include "sndfile.h"
21
22//#define AMFLOG
23
24//#pragma warning(disable:4244)
25
26#pragma pack(1)
27
28typedef struct _AMFFILEHEADER
29{
30 UCHAR szAMF[3];
31 UCHAR version;
32 CHAR title[32];
33 UCHAR numsamples;
34 UCHAR numorders;
35 USHORT numtracks;
36 UCHAR numchannels;
37} Q_PACKED AMFFILEHEADER;
38
39typedef struct _AMFSAMPLE
40{
41 UCHAR type;
42 CHAR samplename[32];
43 CHAR filename[13];
44 ULONG offset;
45 ULONG length;
46 USHORT c2spd;
47 UCHAR volume;
48} Q_PACKED AMFSAMPLE;
49
50
51#pragma pack()
52
53
54#ifdef AMFLOG
55extern void Log(LPCSTR, ...);
56#endif
57
58VOID AMF_Unpack(MODCOMMAND *pPat, const BYTE *pTrack, UINT nRows, UINT nChannels)
59//-------------------------------------------------------------------------------
60{
61 UINT lastinstr = 0;
62 UINT nTrkSize = *(USHORT *)pTrack;
63 nTrkSize += (UINT)pTrack[2] << 16;
64 pTrack += 3;
65 while (nTrkSize--)
66 {
67 UINT row = pTrack[0];
68 UINT cmd = pTrack[1];
69 UINT arg = pTrack[2];
70 if (row >= nRows) break;
71 MODCOMMAND *m = pPat + row * nChannels;
72 if (cmd < 0x7F) // note+vol
73 {
74 m->note = cmd+1;
75 if (!m->instr) m->instr = lastinstr;
76 m->volcmd = VOLCMD_VOLUME;
77 m->vol = arg;
78 } else
79 if (cmd == 0x7F) // duplicate row
80 {
81 signed char rdelta = (signed char)arg;
82 int rowsrc = (int)row + (int)rdelta;
83 if ((rowsrc >= 0) && (rowsrc < (int)nRows)) *m = pPat[rowsrc*nChannels];
84 } else
85 if (cmd == 0x80) // instrument
86 {
87 m->instr = arg+1;
88 lastinstr = m->instr;
89 } else
90 if (cmd == 0x83) // volume
91 {
92 m->volcmd = VOLCMD_VOLUME;
93 m->vol = arg;
94 } else
95 // effect
96 {
97 UINT command = cmd & 0x7F;
98 UINT param = arg;
99 switch(command)
100 {
101 // 0x01: Set Speed
102 case 0x01:command = CMD_SPEED; break;
103 // 0x02: Volume Slide
104 // 0x0A: Tone Porta + Vol Slide
105 // 0x0B: Vibrato + Vol Slide
106 case 0x02:command = CMD_VOLUMESLIDE;
107 case 0x0A:if (command == 0x0A) command = CMD_TONEPORTAVOL;
108 case 0x0B:if (command == 0x0B) command = CMD_VIBRATOVOL;
109 if (param & 0x80) param = (-(signed char)param)&0x0F;
110 else param = (param&0x0F)<<4;
111 break;
112 // 0x04: Porta Up/Down
113 case 0x04:if (param & 0x80) { command = CMD_PORTAMENTOUP; param = -(signed char)param; }
114 else { command = CMD_PORTAMENTODOWN; } break;
115 // 0x06: Tone Portamento
116 case 0x06:command = CMD_TONEPORTAMENTO; break;
117 // 0x07: Tremor
118 case 0x07:command = CMD_TREMOR; break;
119 // 0x08: Arpeggio
120 case 0x08:command = CMD_ARPEGGIO; break;
121 // 0x09: Vibrato
122 case 0x09:command = CMD_VIBRATO; break;
123 // 0x0C: Pattern Break
124 case 0x0C:command = CMD_PATTERNBREAK; break;
125 // 0x0D: Position Jump
126 case 0x0D:command = CMD_POSITIONJUMP; break;
127 // 0x0F: Retrig
128 case 0x0F:command = CMD_RETRIG; break;
129 // 0x10: Offset
130 case 0x10:command = CMD_OFFSET; break;
131 // 0x11: Fine Volume Slide
132 case 0x11:if (param) { command = CMD_VOLUMESLIDE;
133 if (param & 0x80) param = 0xF0|((-(signed char)param)&0x0F);
134 else param = 0x0F|((param&0x0F)<<4);
135 } else command = 0; break;
136 // 0x12: Fine Portamento
137 // 0x16: Extra Fine Portamento
138 case 0x12:
139 case 0x16:if (param) { int mask = (command == 0x16) ? 0xE0 : 0xF0;
140 command = (param & 0x80) ? CMD_PORTAMENTOUP : CMD_PORTAMENTODOWN;
141 if (param & 0x80) param = mask|((-(signed char)param)&0x0F);
142 else param |= mask;
143 } else command = 0; break;
144 // 0x13: Note Delay
145 case 0x13:command = CMD_S3MCMDEX; param = 0xD0|(param & 0x0F); break;
146 // 0x14: Note Cut
147 case 0x14:command = CMD_S3MCMDEX; param = 0xC0|(param & 0x0F); break;
148 // 0x15: Set Tempo
149 case 0x15:command = CMD_TEMPO; break;
150 // 0x17: Panning
151 case 0x17:param = (param+64)&0x7F;
152 if (m->command) { if (!m->volcmd) { m->volcmd = VOLCMD_PANNING; m->vol = param/2; } command = 0; }
153 else { command = CMD_PANNING8; }
154 // Unknown effects
155 default:command = param = 0;
156 }
157 if (command)
158 {
159 m->command = command;
160 m->param = param;
161 }
162 }
163 pTrack += 3;
164 }
165}
166
167
168
169BOOL CSoundFile::ReadAMF(LPCBYTE lpStream, DWORD dwMemLength)
170//-----------------------------------------------------------
171{
172 AMFFILEHEADER *pfh = (AMFFILEHEADER *)lpStream;
173 DWORD dwMemPos;
174
175 if ((!lpStream) || (dwMemLength < 2048)) return FALSE;
176 if ((!strncmp((LPCTSTR)lpStream, "ASYLUM Music Format V1.0", 25)) && (dwMemLength > 4096))
177 {
178 UINT numorders, numpats, numsamples;
179
180 dwMemPos = 32;
181 numpats = lpStream[dwMemPos+3];
182 numorders = lpStream[dwMemPos+4];
183 numsamples = 64;
184 dwMemPos += 6;
185 if ((!numpats) || (numpats > MAX_PATTERNS) || (!numorders)
186 || (numpats*64*32 + 294 + 37*64 >= dwMemLength)) return FALSE;
187 m_nType = MOD_TYPE_AMF0;
188 m_nChannels = 8;
189 m_nInstruments = 0;
190 m_nSamples = 31;
191 m_nDefaultTempo = 125;
192 m_nDefaultSpeed = 6;
193 for (UINT iOrd=0; iOrd<MAX_ORDERS; iOrd++)
194 {
195 Order[iOrd] = (iOrd < numorders) ? lpStream[dwMemPos+iOrd] : 0xFF;
196 }
197 dwMemPos = 294; // ???
198 for (UINT iSmp=0; iSmp<numsamples; iSmp++)
199 {
200 MODINSTRUMENT *psmp = &Ins[iSmp+1];
201 memcpy(m_szNames[iSmp+1], lpStream+dwMemPos, 22);
202 psmp->nFineTune = MOD2XMFineTune(lpStream[dwMemPos+22]);
203 psmp->nVolume = lpStream[dwMemPos+23];
204 psmp->nGlobalVol = 64;
205 if (psmp->nVolume > 0x40) psmp->nVolume = 0x40;
206 psmp->nVolume <<= 2;
207 psmp->nLength = *((LPDWORD)(lpStream+dwMemPos+25));
208 psmp->nLoopStart = *((LPDWORD)(lpStream+dwMemPos+29));
209 psmp->nLoopEnd = psmp->nLoopStart + *((LPDWORD)(lpStream+dwMemPos+33));
210 if ((psmp->nLoopEnd > psmp->nLoopStart) && (psmp->nLoopEnd <= psmp->nLength))
211 {
212 psmp->uFlags = CHN_LOOP;
213 } else
214 {
215 psmp->nLoopStart = psmp->nLoopEnd = 0;
216 }
217 if ((psmp->nLength) && (iSmp>31)) m_nSamples = iSmp+1;
218 dwMemPos += 37;
219 }
220 for (UINT iPat=0; iPat<numpats; iPat++)
221 {
222 MODCOMMAND *p = AllocatePattern(64, m_nChannels);
223 if (!p) break;
224 Patterns[iPat] = p;
225 PatternSize[iPat] = 64;
226 const UCHAR *pin = lpStream + dwMemPos;
227 for (UINT i=0; i<8*64; i++)
228 {
229 p->note = 0;
230
231 if (pin[0])
232 {
233 p->note = pin[0] + 13;
234 }
235 p->instr = pin[1];
236 p->command = pin[2];
237 p->param = pin[3];
238 if (p->command > 0x0F)
239 {
240 #ifdef AMFLOG
241 Log("0x%02X.0x%02X ?", p->command, p->param);
242 #endif
243 p->command = 0;
244 }
245 ConvertModCommand(p);
246 pin += 4;
247 p++;
248 }
249 dwMemPos += 64*32;
250 }
251 // Read samples
252 for (UINT iData=0; iData<m_nSamples; iData++)
253 {
254 MODINSTRUMENT *psmp = &Ins[iData+1];
255 if (psmp->nLength)
256 {
257 dwMemPos += ReadSample(psmp, RS_PCM8S, (LPCSTR)(lpStream+dwMemPos), dwMemLength);
258 }
259 }
260 return TRUE;
261 }
262 ////////////////////////////
263 // DSM/AMF
264 USHORT *ptracks[MAX_PATTERNS];
265 DWORD sampleseekpos[MAX_SAMPLES];
266
267 if ((pfh->szAMF[0] != 'A') || (pfh->szAMF[1] != 'M') || (pfh->szAMF[2] != 'F')
268 || (pfh->version < 10) || (pfh->version > 14) || (!pfh->numtracks)
269 || (!pfh->numorders) || (pfh->numorders > MAX_PATTERNS)
270 || (!pfh->numsamples) || (pfh->numsamples > MAX_SAMPLES)
271 || (pfh->numchannels < 4) || (pfh->numchannels > 32))
272 return FALSE;
273 memcpy(m_szNames[0], pfh->title, 32);
274 dwMemPos = sizeof(AMFFILEHEADER);
275 m_nType = MOD_TYPE_AMF;
276 m_nChannels = pfh->numchannels;
277 m_nSamples = pfh->numsamples;
278 m_nInstruments = 0;
279 // Setup Channel Pan Positions
280 if (pfh->version >= 11)
281 {
282 signed char *panpos = (signed char *)(lpStream + dwMemPos);
283 UINT nchannels = (pfh->version >= 13) ? 32 : 16;
284 for (UINT i=0; i<nchannels; i++)
285 {
286 int pan = (panpos[i] + 64) * 2;
287 if (pan < 0) pan = 0;
288 if (pan > 256) { pan = 128; ChnSettings[i].dwFlags |= CHN_SURROUND; }
289 ChnSettings[i].nPan = pan;
290 }
291 dwMemPos += nchannels;
292 } else
293 {
294 for (UINT i=0; i<16; i++)
295 {
296 ChnSettings[i].nPan = (lpStream[dwMemPos+i] & 1) ? 0x30 : 0xD0;
297 }
298 dwMemPos += 16;
299 }
300 // Get Tempo/Speed
301 m_nDefaultTempo = 125;
302 m_nDefaultSpeed = 6;
303 if (pfh->version >= 13)
304 {
305 if (lpStream[dwMemPos] >= 32) m_nDefaultTempo = lpStream[dwMemPos];
306 if (lpStream[dwMemPos+1] <= 32) m_nDefaultSpeed = lpStream[dwMemPos+1];
307 dwMemPos += 2;
308 }
309 // Setup sequence list
310 for (UINT iOrd=0; iOrd<MAX_ORDERS; iOrd++)
311 {
312 Order[iOrd] = 0xFF;
313 if (iOrd < pfh->numorders)
314 {
315 Order[iOrd] = iOrd;
316 PatternSize[iOrd] = 64;
317 if (pfh->version >= 14)
318 {
319 PatternSize[iOrd] = *(USHORT *)(lpStream+dwMemPos);
320 dwMemPos += 2;
321 }
322 ptracks[iOrd] = (USHORT *)(lpStream+dwMemPos);
323 dwMemPos += m_nChannels * sizeof(USHORT);
324 }
325 }
326 if (dwMemPos + m_nSamples * (sizeof(AMFSAMPLE)+8) > dwMemLength) return TRUE;
327 // Read Samples
328 UINT maxsampleseekpos = 0;
329 for (UINT iIns=0; iIns<m_nSamples; iIns++)
330 {
331 MODINSTRUMENT *pins = &Ins[iIns+1];
332 AMFSAMPLE *psh = (AMFSAMPLE *)(lpStream + dwMemPos);
333
334 dwMemPos += sizeof(AMFSAMPLE);
335 memcpy(m_szNames[iIns+1], psh->samplename, 32);
336 memcpy(pins->name, psh->filename, 13);
337 pins->nLength = psh->length;
338 pins->nC4Speed = psh->c2spd;
339 pins->nGlobalVol = 64;
340 pins->nVolume = psh->volume * 4;
341 if (pfh->version >= 11)
342 {
343 pins->nLoopStart = *(DWORD *)(lpStream+dwMemPos);
344 pins->nLoopEnd = *(DWORD *)(lpStream+dwMemPos+4);
345 dwMemPos += 8;
346 } else
347 {
348 pins->nLoopStart = *(WORD *)(lpStream+dwMemPos);
349 pins->nLoopEnd = pins->nLength;
350 dwMemPos += 2;
351 }
352 sampleseekpos[iIns] = 0;
353 if ((psh->type) && (psh->offset < dwMemLength-1))
354 {
355 sampleseekpos[iIns] = psh->offset;
356 if (psh->offset > maxsampleseekpos) maxsampleseekpos = psh->offset;
357 if ((pins->nLoopEnd > pins->nLoopStart + 2)
358 && (pins->nLoopEnd <= pins->nLength)) pins->uFlags |= CHN_LOOP;
359 }
360 }
361 // Read Track Mapping Table
362 USHORT *pTrackMap = (USHORT *)(lpStream+dwMemPos);
363 UINT realtrackcnt = 0;
364 dwMemPos += pfh->numtracks * sizeof(USHORT);
365 for (UINT iTrkMap=0; iTrkMap<pfh->numtracks; iTrkMap++)
366 {
367 if (realtrackcnt < pTrackMap[iTrkMap]) realtrackcnt = pTrackMap[iTrkMap];
368 }
369 // Store tracks positions
370 BYTE **pTrackData = new BYTE *[realtrackcnt];
371 memset(pTrackData, 0, sizeof(pTrackData));
372 for (UINT iTrack=0; iTrack<realtrackcnt; iTrack++) if (dwMemPos + 3 <= dwMemLength)
373 {
374 UINT nTrkSize = *(USHORT *)(lpStream+dwMemPos);
375 nTrkSize += (UINT)lpStream[dwMemPos+2] << 16;
376 if (dwMemPos + nTrkSize * 3 + 3 <= dwMemLength)
377 {
378 pTrackData[iTrack] = (BYTE *)(lpStream + dwMemPos);
379 }
380 dwMemPos += nTrkSize * 3 + 3;
381 }
382 // Create the patterns from the list of tracks
383 for (UINT iPat=0; iPat<pfh->numorders; iPat++)
384 {
385 MODCOMMAND *p = AllocatePattern(PatternSize[iPat], m_nChannels);
386 if (!p) break;
387 Patterns[iPat] = p;
388 for (UINT iChn=0; iChn<m_nChannels; iChn++)
389 {
390 UINT nTrack = ptracks[iPat][iChn];
391 if ((nTrack) && (nTrack <= pfh->numtracks))
392 {
393 UINT realtrk = pTrackMap[nTrack-1];
394 if (realtrk)
395 {
396 realtrk--;
397 if ((realtrk < realtrackcnt) && (pTrackData[realtrk]))
398 {
399 AMF_Unpack(p+iChn, pTrackData[realtrk], PatternSize[iPat], m_nChannels);
400 }
401 }
402 }
403 }
404 }
405 delete pTrackData;
406 // Read Sample Data
407 for (UINT iSeek=1; iSeek<=maxsampleseekpos; iSeek++)
408 {
409 if (dwMemPos >= dwMemLength) break;
410 for (UINT iSmp=0; iSmp<m_nSamples; iSmp++) if (iSeek == sampleseekpos[iSmp])
411 {
412 MODINSTRUMENT *pins = &Ins[iSmp+1];
413 dwMemPos += ReadSample(pins, RS_PCM8U, (LPCSTR)(lpStream+dwMemPos), dwMemLength-dwMemPos);
414 break;
415 }
416 }
417 return TRUE;
418}
419
420
diff --git a/core/multimedia/opieplayer/modplug/load_ams.cpp b/core/multimedia/opieplayer/modplug/load_ams.cpp
new file mode 100644
index 0000000..3dd1c2b
--- a/dev/null
+++ b/core/multimedia/opieplayer/modplug/load_ams.cpp
@@ -0,0 +1,631 @@
1/*
2 * This program is free software; you can redistribute it and modify it
3 * under the terms of the GNU General Public License as published by the
4 * Free Software Foundation; either version 2 of the license or (at your
5 * option) any later version.
6 *
7 * Authors: Olivier Lapicque <olivierl@jps.net>
8*/
9
10//////////////////////////////////////////////
11// AMS module loader //
12//////////////////////////////////////////////
13#include "stdafx.h"
14#include "sndfile.h"
15
16//#pragma warning(disable:4244)
17
18#pragma pack(1)
19
20typedef struct AMSFILEHEADER
21{
22 char szHeader[7];// "Extreme" // changed from CHAR
23 BYTE verlo, verhi;// 0x??,0x01
24 BYTE chncfg;
25 BYTE samples;
26 WORD patterns;
27 WORD orders;
28 BYTE vmidi;
29 WORD extra;
30} Q_PACKED AMSFILEHEADER;
31
32typedef struct AMSSAMPLEHEADER
33{
34 DWORD length;
35 DWORD loopstart;
36 DWORD loopend;
37 BYTE finetune_and_pan;
38 WORD samplerate;// C-2 = 8363
39 BYTE volume; // 0-127
40 BYTE infobyte;
41} Q_PACKED AMSSAMPLEHEADER;
42
43
44#pragma pack()
45
46
47
48BOOL CSoundFile::ReadAMS(LPCBYTE lpStream, DWORD dwMemLength)
49//-----------------------------------------------------------
50{
51 BYTE pkinf[MAX_SAMPLES];
52 AMSFILEHEADER *pfh = (AMSFILEHEADER *)lpStream;
53 DWORD dwMemPos;
54 UINT tmp, tmp2;
55
56 if ((!lpStream) || (dwMemLength < 1024)) return FALSE;
57 if ((pfh->verhi != 0x01) || (strncmp(pfh->szHeader, "Extreme", 7))
58 || (!pfh->patterns) || (!pfh->orders) || (!pfh->samples) || (pfh->samples > MAX_SAMPLES)
59 || (pfh->patterns > MAX_PATTERNS) || (pfh->orders > MAX_ORDERS))
60 {
61 return ReadAMS2(lpStream, dwMemLength);
62 }
63 dwMemPos = sizeof(AMSFILEHEADER) + pfh->extra;
64 if (dwMemPos + pfh->samples * sizeof(AMSSAMPLEHEADER) + 256 >= dwMemLength) return FALSE;
65 m_nType = MOD_TYPE_AMS;
66 m_nInstruments = 0;
67 m_nChannels = (pfh->chncfg & 0x1F) + 1;
68 m_nSamples = pfh->samples;
69 for (UINT nSmp=1; nSmp<=m_nSamples; nSmp++, dwMemPos += sizeof(AMSSAMPLEHEADER))
70 {
71 AMSSAMPLEHEADER *psh = (AMSSAMPLEHEADER *)(lpStream + dwMemPos);
72 MODINSTRUMENT *pins = &Ins[nSmp];
73 pins->nLength = psh->length;
74 pins->nLoopStart = psh->loopstart;
75 pins->nLoopEnd = psh->loopend;
76 pins->nGlobalVol = 64;
77 pins->nVolume = psh->volume << 1;
78 pins->nC4Speed = psh->samplerate;
79 pins->nPan = (psh->finetune_and_pan & 0xF0);
80 if (pins->nPan < 0x80) pins->nPan += 0x10;
81 pins->nFineTune = MOD2XMFineTune(psh->finetune_and_pan & 0x0F);
82 pins->uFlags = (psh->infobyte & 0x80) ? CHN_16BIT : 0;
83 if ((pins->nLoopEnd <= pins->nLength) && (pins->nLoopStart+4 <= pins->nLoopEnd)) pins->uFlags |= CHN_LOOP;
84 pkinf[nSmp] = psh->infobyte;
85 }
86 // Read Song Name
87 tmp = lpStream[dwMemPos++];
88 if (dwMemPos + tmp + 1 >= dwMemLength) return TRUE;
89 tmp2 = (tmp < 32) ? tmp : 31;
90 if (tmp2) memcpy(m_szNames[0], lpStream+dwMemPos, tmp2);
91 m_szNames[0][tmp2] = 0;
92 dwMemPos += tmp;
93 // Read sample names
94 for (UINT sNam=1; sNam<=m_nSamples; sNam++)
95 {
96 if (dwMemPos + 32 >= dwMemLength) return TRUE;
97 tmp = lpStream[dwMemPos++];
98 tmp2 = (tmp < 32) ? tmp : 31;
99 if (tmp2) memcpy(m_szNames[sNam], lpStream+dwMemPos, tmp2);
100 dwMemPos += tmp;
101 }
102 // Skip Channel names
103 for (UINT cNam=0; cNam<m_nChannels; cNam++)
104 {
105 if (dwMemPos + 32 >= dwMemLength) return TRUE;
106 tmp = lpStream[dwMemPos++];
107 dwMemPos += tmp;
108 }
109 // Read Pattern Names
110 m_lpszPatternNames = new char[pfh->patterns * 32]; // changed from CHAR
111 if (!m_lpszPatternNames) return TRUE;
112 m_nPatternNames = pfh->patterns;
113 memset(m_lpszPatternNames, 0, m_nPatternNames * 32);
114 for (UINT pNam=0; pNam < m_nPatternNames; pNam++)
115 {
116 if (dwMemPos + 32 >= dwMemLength) return TRUE;
117 tmp = lpStream[dwMemPos++];
118 tmp2 = (tmp < 32) ? tmp : 31;
119 if (tmp2) memcpy(m_lpszPatternNames+pNam*32, lpStream+dwMemPos, tmp2);
120 dwMemPos += tmp;
121 }
122 // Read Song Comments
123 tmp = *((WORD *)(lpStream+dwMemPos));
124 dwMemPos += 2;
125 if (dwMemPos + tmp >= dwMemLength) return TRUE;
126 if (tmp)
127 {
128 m_lpszSongComments = new char[tmp+1]; // changed from CHAR
129 if (!m_lpszSongComments) return TRUE;
130 memset(m_lpszSongComments, 0, tmp+1);
131 memcpy(m_lpszSongComments, lpStream + dwMemPos, tmp);
132 dwMemPos += tmp;
133 }
134 // Read Order List
135 for (UINT iOrd=0; iOrd<pfh->orders; iOrd++, dwMemPos += 2)
136 {
137 UINT n = *((WORD *)(lpStream+dwMemPos));
138 Order[iOrd] = (BYTE)n;
139 }
140 // Read Patterns
141 for (UINT iPat=0; iPat<pfh->patterns; iPat++)
142 {
143 if (dwMemPos + 4 >= dwMemLength) return TRUE;
144 UINT len = *((DWORD *)(lpStream + dwMemPos));
145 dwMemPos += 4;
146 if ((len >= dwMemLength) || (dwMemPos + len > dwMemLength)) return TRUE;
147 PatternSize[iPat] = 64;
148 MODCOMMAND *m = AllocatePattern(PatternSize[iPat], m_nChannels);
149 if (!m) return TRUE;
150 Patterns[iPat] = m;
151 const BYTE *p = lpStream + dwMemPos;
152 UINT row = 0, i = 0;
153 while ((row < PatternSize[iPat]) && (i+2 < len))
154 {
155 BYTE b0 = p[i++];
156 BYTE b1 = p[i++];
157 BYTE b2 = 0;
158 UINT ch = b0 & 0x3F;
159 // Note+Instr
160 if (!(b0 & 0x40))
161 {
162 b2 = p[i++];
163 if (ch < m_nChannels)
164 {
165 if (b1 & 0x7F) m[ch].note = (b1 & 0x7F) + 25;
166 m[ch].instr = b2;
167 }
168 if (b1 & 0x80)
169 {
170 b0 |= 0x40;
171 b1 = p[i++];
172 }
173 }
174 // Effect
175 if (b0 & 0x40)
176 {
177 anothercommand:
178 if (b1 & 0x40)
179 {
180 if (ch < m_nChannels)
181 {
182 m[ch].volcmd = VOLCMD_VOLUME;
183 m[ch].vol = b1 & 0x3F;
184 }
185 } else
186 {
187 b2 = p[i++];
188 if (ch < m_nChannels)
189 {
190 UINT cmd = b1 & 0x3F;
191 if (cmd == 0x0C)
192 {
193 m[ch].volcmd = VOLCMD_VOLUME;
194 m[ch].vol = b2 >> 1;
195 } else
196 if (cmd == 0x0E)
197 {
198 if (!m[ch].command)
199 {
200 UINT command = CMD_S3MCMDEX;
201 UINT param = b2;
202 switch(param & 0xF0)
203 {
204 case 0x00:if (param & 0x08) { param &= 0x07; param |= 0x90; } else {command=param=0;} break;
205 case 0x10:command = CMD_PORTAMENTOUP; param |= 0xF0; break;
206 case 0x20:command = CMD_PORTAMENTODOWN; param |= 0xF0; break;
207 case 0x30:param = (param & 0x0F) | 0x10; break;
208 case 0x40:param = (param & 0x0F) | 0x30; break;
209 case 0x50:param = (param & 0x0F) | 0x20; break;
210 case 0x60:param = (param & 0x0F) | 0xB0; break;
211 case 0x70:param = (param & 0x0F) | 0x40; break;
212 case 0x90:command = CMD_RETRIG; param &= 0x0F; break;
213 case 0xA0:if (param & 0x0F) { command = CMD_VOLUMESLIDE; param = (param << 4) | 0x0F; } else command=param=0; break;
214 case 0xB0:if (param & 0x0F) { command = CMD_VOLUMESLIDE; param |= 0xF0; } else command=param=0; break;
215 }
216 m[ch].command = command;
217 m[ch].param = param;
218 }
219 } else
220 {
221 m[ch].command = cmd;
222 m[ch].param = b2;
223 ConvertModCommand(&m[ch]);
224 }
225 }
226 }
227 if (b1 & 0x80)
228 {
229 b1 = p[i++];
230 if (i <= len) goto anothercommand;
231 }
232 }
233 if (b0 & 0x80)
234 {
235 row++;
236 m += m_nChannels;
237 }
238 }
239 dwMemPos += len;
240 }
241 // Read Samples
242 for (UINT iSmp=1; iSmp<=m_nSamples; iSmp++) if (Ins[iSmp].nLength)
243 {
244 if (dwMemPos >= dwMemLength - 9) return TRUE;
245 UINT flags = (Ins[iSmp].uFlags & CHN_16BIT) ? RS_AMS16 : RS_AMS8;
246 dwMemPos += ReadSample(&Ins[iSmp], flags, (LPSTR)(lpStream+dwMemPos), dwMemLength-dwMemPos);
247 }
248 return TRUE;
249}
250
251
252/////////////////////////////////////////////////////////////////////
253// AMS 2.2 loader
254
255#pragma pack(1)
256
257typedef struct AMS2FILEHEADER
258{
259 DWORD dwHdr1; // AMShdr
260 WORD wHdr2;
261 BYTE b1A; // 0x1A
262 BYTE titlelen; // 30-bytes max
263 CHAR szTitle[30];// [titlelen]
264} Q_PACKED AMS2FILEHEADER;
265
266typedef struct AMS2SONGHEADER
267{
268 WORD version;
269 BYTE instruments;
270 WORD patterns;
271 WORD orders;
272 WORD bpm;
273 BYTE speed;
274 BYTE channels;
275 BYTE commands;
276 BYTE rows;
277 WORD flags;
278} Q_PACKED AMS2SONGHEADER;
279
280typedef struct AMS2INSTRUMENT
281{
282 BYTE samples;
283 BYTE notemap[120];
284} Q_PACKED AMS2INSTRUMENT;
285
286typedef struct AMS2ENVELOPE
287{
288 BYTE speed;
289 BYTE sustain;
290 BYTE loopbegin;
291 BYTE loopend;
292 BYTE points;
293 BYTE info[3];
294} Q_PACKED AMS2ENVELOPE;
295
296typedef struct AMS2SAMPLE
297{
298 DWORD length;
299 DWORD loopstart;
300 DWORD loopend;
301 WORD frequency;
302 BYTE finetune;
303 WORD c4speed;
304 CHAR transpose;
305 BYTE volume;
306 BYTE flags;
307} Q_PACKED AMS2SAMPLE;
308
309
310#pragma pack()
311
312
313BOOL CSoundFile::ReadAMS2(LPCBYTE lpStream, DWORD dwMemLength)
314//------------------------------------------------------------
315{
316 AMS2FILEHEADER *pfh = (AMS2FILEHEADER *)lpStream;
317 AMS2SONGHEADER *psh;
318 DWORD dwMemPos;
319 BYTE smpmap[16];
320 BYTE packedsamples[MAX_SAMPLES];
321
322 if ((pfh->dwHdr1 != 0x68534D41) || (pfh->wHdr2 != 0x7264)
323 || (pfh->b1A != 0x1A) || (pfh->titlelen > 30)) return FALSE;
324 dwMemPos = pfh->titlelen + 8;
325 psh = (AMS2SONGHEADER *)(lpStream + dwMemPos);
326 if (((psh->version & 0xFF00) != 0x0200) || (!psh->instruments)
327 || (psh->instruments > MAX_INSTRUMENTS) || (!psh->patterns) || (!psh->orders)) return FALSE;
328 dwMemPos += sizeof(AMS2SONGHEADER);
329 if (pfh->titlelen)
330 {
331 memcpy(m_szNames, pfh->szTitle, pfh->titlelen);
332 m_szNames[0][pfh->titlelen] = 0;
333 }
334 m_nType = MOD_TYPE_AMS;
335 m_nChannels = 32;
336 m_nDefaultTempo = psh->bpm >> 8;
337 m_nDefaultSpeed = psh->speed;
338 m_nInstruments = psh->instruments;
339 m_nSamples = 0;
340 if (psh->flags & 0x40) m_dwSongFlags |= SONG_LINEARSLIDES;
341 for (UINT nIns=1; nIns<=m_nInstruments; nIns++)
342 {
343 UINT insnamelen = lpStream[dwMemPos];
344 CHAR *pinsname = (CHAR *)(lpStream+dwMemPos+1);
345 dwMemPos += insnamelen + 1;
346 AMS2INSTRUMENT *pins = (AMS2INSTRUMENT *)(lpStream + dwMemPos);
347 dwMemPos += sizeof(AMS2INSTRUMENT);
348 if (dwMemPos + 1024 >= dwMemLength) return TRUE;
349 AMS2ENVELOPE *volenv, *panenv, *pitchenv;
350 volenv = (AMS2ENVELOPE *)(lpStream+dwMemPos);
351 dwMemPos += 5 + volenv->points*3;
352 panenv = (AMS2ENVELOPE *)(lpStream+dwMemPos);
353 dwMemPos += 5 + panenv->points*3;
354 pitchenv = (AMS2ENVELOPE *)(lpStream+dwMemPos);
355 dwMemPos += 5 + pitchenv->points*3;
356 INSTRUMENTHEADER *penv = new INSTRUMENTHEADER;
357 if (!penv) return TRUE;
358 memset(smpmap, 0, sizeof(smpmap));
359 memset(penv, 0, sizeof(INSTRUMENTHEADER));
360 for (UINT ismpmap=0; ismpmap<pins->samples; ismpmap++)
361 {
362 if ((ismpmap >= 16) || (m_nSamples+1 >= MAX_SAMPLES)) break;
363 m_nSamples++;
364 smpmap[ismpmap] = m_nSamples;
365 }
366 penv->nGlobalVol = 64;
367 penv->nPan = 128;
368 penv->nPPC = 60;
369 Headers[nIns] = penv;
370 if (insnamelen)
371 {
372 if (insnamelen > 31) insnamelen = 31;
373 memcpy(penv->name, pinsname, insnamelen);
374 penv->name[insnamelen] = 0;
375 }
376 for (UINT inotemap=0; inotemap<120; inotemap++)
377 {
378 penv->NoteMap[inotemap] = inotemap+1;
379 penv->Keyboard[inotemap] = smpmap[pins->notemap[inotemap] & 0x0F];
380 }
381 // Volume Envelope
382 {
383 UINT pos = 0;
384 penv->nVolEnv = (volenv->points > 16) ? 16 : volenv->points;
385 penv->nVolSustainBegin = penv->nVolSustainEnd = volenv->sustain;
386 penv->nVolLoopStart = volenv->loopbegin;
387 penv->nVolLoopEnd = volenv->loopend;
388 for (UINT i=0; i<penv->nVolEnv; i++)
389 {
390 penv->VolEnv[i] = (BYTE)((volenv->info[i*3+2] & 0x7F) >> 1);
391 pos += volenv->info[i*3] + ((volenv->info[i*3+1] & 1) << 8);
392 penv->VolPoints[i] = (WORD)pos;
393 }
394 }
395 penv->nFadeOut = (((lpStream[dwMemPos+2] & 0x0F) << 8) | (lpStream[dwMemPos+1])) << 3;
396 UINT envflags = lpStream[dwMemPos+3];
397 if (envflags & 0x01) penv->dwFlags |= ENV_VOLLOOP;
398 if (envflags & 0x02) penv->dwFlags |= ENV_VOLSUSTAIN;
399 if (envflags & 0x04) penv->dwFlags |= ENV_VOLUME;
400 dwMemPos += 5;
401 // Read Samples
402 for (UINT ismp=0; ismp<pins->samples; ismp++)
403 {
404 MODINSTRUMENT *psmp = ((ismp < 16) && (smpmap[ismp])) ? &Ins[smpmap[ismp]] : NULL;
405 UINT smpnamelen = lpStream[dwMemPos];
406 if ((psmp) && (smpnamelen) && (smpnamelen <= 22))
407 {
408 memcpy(m_szNames[smpmap[ismp]], lpStream+dwMemPos+1, smpnamelen);
409 }
410 dwMemPos += smpnamelen + 1;
411 if (psmp)
412 {
413 AMS2SAMPLE *pams = (AMS2SAMPLE *)(lpStream+dwMemPos);
414 psmp->nGlobalVol = 64;
415 psmp->nPan = 128;
416 psmp->nLength = pams->length;
417 psmp->nLoopStart = pams->loopstart;
418 psmp->nLoopEnd = pams->loopend;
419 psmp->nC4Speed = pams->c4speed;
420 psmp->RelativeTone = pams->transpose;
421 psmp->nVolume = pams->volume / 2;
422 packedsamples[smpmap[ismp]] = pams->flags;
423 if (pams->flags & 0x04) psmp->uFlags |= CHN_16BIT;
424 if (pams->flags & 0x08) psmp->uFlags |= CHN_LOOP;
425 if (pams->flags & 0x10) psmp->uFlags |= CHN_PINGPONGLOOP;
426 }
427 dwMemPos += sizeof(AMS2SAMPLE);
428 }
429 }
430 if (dwMemPos + 256 >= dwMemLength) return TRUE;
431 // Comments
432 {
433 UINT composernamelen = lpStream[dwMemPos];
434 if (composernamelen)
435 {
436 m_lpszSongComments = new char[composernamelen+1]; // changed from CHAR
437 if (m_lpszSongComments)
438 {
439 memcpy(m_lpszSongComments, lpStream+dwMemPos+1, composernamelen);
440 m_lpszSongComments[composernamelen] = 0;
441 }
442 }
443 dwMemPos += composernamelen + 1;
444 // channel names
445 for (UINT i=0; i<32; i++)
446 {
447 UINT chnnamlen = lpStream[dwMemPos];
448 if ((chnnamlen) && (chnnamlen < MAX_CHANNELNAME))
449 {
450 memcpy(ChnSettings[i].szName, lpStream+dwMemPos+1, chnnamlen);
451 }
452 dwMemPos += chnnamlen + 1;
453 if (dwMemPos + chnnamlen + 256 >= dwMemLength) return TRUE;
454 }
455 // packed comments (ignored)
456 UINT songtextlen = *((LPDWORD)(lpStream+dwMemPos));
457 dwMemPos += songtextlen;
458 if (dwMemPos + 256 >= dwMemLength) return TRUE;
459 }
460 // Order List
461 {
462 for (UINT i=0; i<MAX_ORDERS; i++)
463 {
464 Order[i] = 0xFF;
465 if (dwMemPos + 2 >= dwMemLength) return TRUE;
466 if (i < psh->orders)
467 {
468 Order[i] = lpStream[dwMemPos];
469 dwMemPos += 2;
470 }
471 }
472 }
473 // Pattern Data
474 for (UINT ipat=0; ipat<psh->patterns; ipat++)
475 {
476 if (dwMemPos+8 >= dwMemLength) return TRUE;
477 UINT packedlen = *((LPDWORD)(lpStream+dwMemPos));
478 UINT numrows = 1 + (UINT)(lpStream[dwMemPos+4]);
479 //UINT patchn = 1 + (UINT)(lpStream[dwMemPos+5] & 0x1F);
480 //UINT patcmds = 1 + (UINT)(lpStream[dwMemPos+5] >> 5);
481 UINT patnamlen = lpStream[dwMemPos+6];
482 dwMemPos += 4;
483 if ((ipat < MAX_PATTERNS) && (packedlen < dwMemLength-dwMemPos) && (numrows >= 8))
484 {
485 if ((patnamlen) && (patnamlen < MAX_PATTERNNAME))
486 {
487 char s[MAX_PATTERNNAME]; // changed from CHAR
488 memcpy(s, lpStream+dwMemPos+3, patnamlen);
489 s[patnamlen] = 0;
490 SetPatternName(ipat, s);
491 }
492 PatternSize[ipat] = numrows;
493 Patterns[ipat] = AllocatePattern(numrows, m_nChannels);
494 if (!Patterns[ipat]) return TRUE;
495 // Unpack Pattern Data
496 LPCBYTE psrc = lpStream + dwMemPos;
497 UINT pos = 3 + patnamlen;
498 UINT row = 0;
499 while ((pos < packedlen) && (row < numrows))
500 {
501 MODCOMMAND *m = Patterns[ipat] + row * m_nChannels;
502 UINT byte1 = psrc[pos++];
503 UINT ch = byte1 & 0x1F;
504 // Read Note + Instr
505 if (!(byte1 & 0x40))
506 {
507 UINT byte2 = psrc[pos++];
508 UINT note = byte2 & 0x7F;
509 if (note) m[ch].note = (note > 1) ? (note-1) : 0xFF;
510 m[ch].instr = psrc[pos++];
511 // Read Effect
512 while (byte2 & 0x80)
513 {
514 byte2 = psrc[pos++];
515 if (byte2 & 0x40)
516 {
517 m[ch].volcmd = VOLCMD_VOLUME;
518 m[ch].vol = byte2 & 0x3F;
519 } else
520 {
521 UINT command = byte2 & 0x3F;
522 UINT param = psrc[pos++];
523 if (command == 0x0C)
524 {
525 m[ch].volcmd = VOLCMD_VOLUME;
526 m[ch].vol = param / 2;
527 } else
528 if (command < 0x10)
529 {
530 m[ch].command = command;
531 m[ch].param = param;
532 ConvertModCommand(&m[ch]);
533 } else
534 {
535 // TODO: AMS effects
536 }
537 }
538 }
539 }
540 if (byte1 & 0x80) row++;
541 }
542 }
543 dwMemPos += packedlen;
544 }
545 // Read Samples
546 for (UINT iSmp=1; iSmp<=m_nSamples; iSmp++) if (Ins[iSmp].nLength)
547 {
548 if (dwMemPos >= dwMemLength - 9) return TRUE;
549 UINT flags;
550 if (packedsamples[iSmp] & 0x03)
551 {
552 flags = (Ins[iSmp].uFlags & CHN_16BIT) ? RS_AMS16 : RS_AMS8;
553 } else
554 {
555 flags = (Ins[iSmp].uFlags & CHN_16BIT) ? RS_PCM16S : RS_PCM8S;
556 }
557 dwMemPos += ReadSample(&Ins[iSmp], flags, (LPSTR)(lpStream+dwMemPos), dwMemLength-dwMemPos);
558 }
559 return TRUE;
560}
561
562
563/////////////////////////////////////////////////////////////////////
564// AMS Sample unpacking
565
566void AMSUnpack(const char *psrc, UINT inputlen, char *pdest, UINT dmax, char packcharacter)
567{
568 UINT tmplen = dmax;
569 signed char *amstmp = new signed char[tmplen];
570
571 if (!amstmp) return;
572 // Unpack Loop
573 {
574 signed char *p = amstmp;
575 UINT i=0, j=0;
576 while ((i < inputlen) && (j < tmplen))
577 {
578 signed char ch = psrc[i++];
579 if (ch == packcharacter)
580 {
581 BYTE ch2 = psrc[i++];
582 if (ch2)
583 {
584 ch = psrc[i++];
585 while (ch2--)
586 {
587 p[j++] = ch;
588 if (j >= tmplen) break;
589 }
590 } else p[j++] = packcharacter;
591 } else p[j++] = ch;
592 }
593 }
594 // Bit Unpack Loop
595 {
596 signed char *p = amstmp;
597 UINT bitcount = 0x80, dh;
598 UINT k=0;
599 for (UINT i=0; i<dmax; i++)
600 {
601 BYTE al = *p++;
602 dh = 0;
603 for (UINT count=0; count<8; count++)
604 {
605 UINT bl = al & bitcount;
606 bl = ((bl|(bl<<8)) >> ((dh+8-count) & 7)) & 0xFF;
607 bitcount = ((bitcount|(bitcount<<8)) >> 1) & 0xFF;
608 pdest[k++] |= bl;
609 if (k >= dmax)
610 {
611 k = 0;
612 dh++;
613 }
614 }
615 bitcount = ((bitcount|(bitcount<<8)) >> dh) & 0xFF;
616 }
617 }
618 // Delta Unpack
619 {
620 signed char old = 0;
621 for (UINT i=0; i<dmax; i++)
622 {
623 int pos = ((LPBYTE)pdest)[i];
624 if ((pos != 128) && (pos & 0x80)) pos = -(pos & 0x7F);
625 old -= (signed char)pos;
626 pdest[i] = old;
627 }
628 }
629 delete amstmp;
630}
631
diff --git a/core/multimedia/opieplayer/modplug/load_dbm.cpp b/core/multimedia/opieplayer/modplug/load_dbm.cpp
new file mode 100644
index 0000000..258fd88
--- a/dev/null
+++ b/core/multimedia/opieplayer/modplug/load_dbm.cpp
@@ -0,0 +1,371 @@
1/*
2 * This program is free software; you can redistribute it and modify it
3 * under the terms of the GNU General Public License as published by the
4 * Free Software Foundation; either version 2 of the license or (at your
5 * option) any later version.
6 *
7 * Authors: Olivier Lapicque <olivierl@jps.net>,
8 * Adam Goode <adam@evdebs.org> (endian and char fixes for PPC)
9*/
10
11///////////////////////////////////////////////////////////////
12//
13// DigiBooster Pro Module Loader (*.dbm)
14//
15// Note: this loader doesn't handle multiple songs
16//
17///////////////////////////////////////////////////////////////
18
19#include "stdafx.h"
20#include "sndfile.h"
21
22//#pragma warning(disable:4244)
23
24 #define DBM_FILE_MAGIC0x304d4244
25 #define DBM_ID_NAME 0x454d414e
26 #define DBM_NAMELEN 0x2c000000
27 #define DBM_ID_INFO 0x4f464e49
28 #define DBM_INFOLEN 0x0a000000
29 #define DBM_ID_SONG 0x474e4f53
30 #define DBM_ID_INST 0x54534e49
31 #define DBM_ID_VENV 0x564e4556
32 #define DBM_ID_PATT 0x54544150
33 #define DBM_ID_SMPL 0x4c504d53
34
35#pragma pack(1)
36
37typedef struct DBMFILEHEADER
38{
39 DWORD dbm_id; // "DBM0" = 0x304d4244
40 WORD trkver; // Tracker version: 02.15
41 WORD reserved;
42 DWORD name_id; // "NAME" = 0x454d414e
43 DWORD name_len; // name length: always 44
44 CHAR songname[44];
45 DWORD info_id; // "INFO" = 0x4f464e49
46 DWORD info_len; // 0x0a000000
47 WORD instruments;
48 WORD samples;
49 WORD songs;
50 WORD patterns;
51 WORD channels;
52 DWORD song_id; // "SONG" = 0x474e4f53
53 DWORD song_len;
54 CHAR songname2[44];
55 WORD orders;
56 // WORD orderlist[0];// orderlist[orders] in words
57} Q_PACKED DBMFILEHEADER;
58
59typedef struct DBMINSTRUMENT
60{
61 CHAR name[30];
62 WORD sampleno;
63 WORD volume;
64 DWORD finetune;
65 DWORD loopstart;
66 DWORD looplen;
67 WORD panning;
68 WORD flags;
69} Q_PACKED DBMINSTRUMENT;
70
71typedef struct DBMENVELOPE
72{
73 WORD instrument;
74 BYTE flags;
75 BYTE numpoints;
76 BYTE sustain1;
77 BYTE loopbegin;
78 BYTE loopend;
79 BYTE sustain2;
80 WORD volenv[2*32];
81} Q_PACKED DBMENVELOPE;
82
83typedef struct DBMPATTERN
84{
85 WORD rows;
86 DWORD packedsize;
87 BYTE patterndata[2];// [packedsize]
88} Q_PACKED DBMPATTERN;
89
90typedef struct DBMSAMPLE
91{
92 DWORD flags;
93 DWORD samplesize;
94 BYTE sampledata[2]; // [samplesize]
95} Q_PACKED DBMSAMPLE;
96
97#pragma pack()
98
99
100BOOL CSoundFile::ReadDBM(const BYTE *lpStream, DWORD dwMemLength)
101//---------------------------------------------------------------
102{
103 DBMFILEHEADER *pfh = (DBMFILEHEADER *)lpStream;
104 DWORD dwMemPos;
105 UINT nOrders, nSamples, nInstruments, nPatterns;
106
107 if ((!lpStream) || (dwMemLength <= sizeof(DBMFILEHEADER)) || (!pfh->channels)
108 || (pfh->dbm_id != DBM_FILE_MAGIC) || (!pfh->songs) || (pfh->song_id != DBM_ID_SONG)
109 || (pfh->name_id != DBM_ID_NAME) || (pfh->name_len != DBM_NAMELEN)
110 || (pfh->info_id != DBM_ID_INFO) || (pfh->info_len != DBM_INFOLEN)) return FALSE;
111 dwMemPos = sizeof(DBMFILEHEADER);
112 nOrders = bswapBE16(pfh->orders);
113 if (dwMemPos + 2 * nOrders + 8*3 >= dwMemLength) return FALSE;
114 nInstruments = bswapBE16(pfh->instruments);
115 nSamples = bswapBE16(pfh->samples);
116 nPatterns = bswapBE16(pfh->patterns);
117 m_nType = MOD_TYPE_DBM;
118 m_nChannels = bswapBE16(pfh->channels);
119 if (m_nChannels < 4) m_nChannels = 4;
120 if (m_nChannels > 64) m_nChannels = 64;
121 memcpy(m_szNames[0], (pfh->songname[0]) ? pfh->songname : pfh->songname2, 32);
122 m_szNames[0][31] = 0;
123 for (UINT iOrd=0; iOrd < nOrders; iOrd++)
124 {
125 Order[iOrd] = lpStream[dwMemPos+iOrd*2+1];
126 if (iOrd >= MAX_ORDERS-2) break;
127 }
128 dwMemPos += 2*nOrders;
129 while (dwMemPos + 10 < dwMemLength)
130 {
131 DWORD chunk_id = ((LPDWORD)(lpStream+dwMemPos))[0];
132 DWORD chunk_size = bswapBE32(((LPDWORD)(lpStream+dwMemPos))[1]);
133 DWORD chunk_pos;
134
135 dwMemPos += 8;
136 chunk_pos = dwMemPos;
137 if ((dwMemPos + chunk_size > dwMemLength) || (chunk_size > dwMemLength)) break;
138 dwMemPos += chunk_size;
139 // Instruments
140 if (chunk_id == DBM_ID_INST)
141 {
142 if (nInstruments >= MAX_INSTRUMENTS) nInstruments = MAX_INSTRUMENTS-1;
143 for (UINT iIns=0; iIns<nInstruments; iIns++)
144 {
145 MODINSTRUMENT *psmp;
146 INSTRUMENTHEADER *penv;
147 DBMINSTRUMENT *pih;
148 UINT nsmp;
149
150 if (chunk_pos + sizeof(DBMINSTRUMENT) > dwMemPos) break;
151 if ((penv = new INSTRUMENTHEADER) == NULL) break;
152 pih = (DBMINSTRUMENT *)(lpStream+chunk_pos);
153 nsmp = bswapBE16(pih->sampleno);
154 psmp = ((nsmp) && (nsmp < MAX_SAMPLES)) ? &Ins[nsmp] : NULL;
155 memset(penv, 0, sizeof(INSTRUMENTHEADER));
156 memcpy(penv->name, pih->name, 30);
157 if (psmp)
158 {
159 memcpy(m_szNames[nsmp], pih->name, 30);
160 m_szNames[nsmp][30] = 0;
161 }
162 Headers[iIns+1] = penv;
163 penv->nFadeOut = 1024;// ???
164 penv->nGlobalVol = 64;
165 penv->nPan = bswapBE16(pih->panning);
166 if ((penv->nPan) && (penv->nPan < 256))
167 penv->dwFlags = ENV_SETPANNING;
168 else
169 penv->nPan = 128;
170 penv->nPPC = 5*12;
171 for (UINT i=0; i<120; i++)
172 {
173 penv->Keyboard[i] = nsmp;
174 penv->NoteMap[i] = i+1;
175 }
176 // Sample Info
177 if (psmp)
178 {
179 DWORD sflags = bswapBE16(pih->flags);
180 psmp->nVolume = bswapBE16(pih->volume) * 4;
181 if ((!psmp->nVolume) || (psmp->nVolume > 256)) psmp->nVolume = 256;
182 psmp->nGlobalVol = 64;
183 psmp->nC4Speed = bswapBE32(pih->finetune);
184 int f2t = FrequencyToTranspose(psmp->nC4Speed);
185 psmp->RelativeTone = f2t >> 7;
186 psmp->nFineTune = f2t & 0x7F;
187 if ((pih->looplen) && (sflags & 3))
188 {
189 psmp->nLoopStart = bswapBE32(pih->loopstart);
190 psmp->nLoopEnd = psmp->nLoopStart + bswapBE32(pih->looplen);
191 psmp->uFlags |= CHN_LOOP;
192 psmp->uFlags &= ~CHN_PINGPONGLOOP;
193 if (sflags & 2) psmp->uFlags |= CHN_PINGPONGLOOP;
194 }
195 }
196 chunk_pos += sizeof(DBMINSTRUMENT);
197 m_nInstruments = iIns+1;
198 }
199 } else
200 // Volume Envelopes
201 if (chunk_id == DBM_ID_VENV)
202 {
203 UINT nEnvelopes = lpStream[chunk_pos+1];
204
205 chunk_pos += 2;
206 for (UINT iEnv=0; iEnv<nEnvelopes; iEnv++)
207 {
208 DBMENVELOPE *peh;
209 UINT nins;
210
211 if (chunk_pos + sizeof(DBMENVELOPE) > dwMemPos) break;
212 peh = (DBMENVELOPE *)(lpStream+chunk_pos);
213 nins = bswapBE16(peh->instrument);
214 if ((nins) && (nins < MAX_INSTRUMENTS) && (Headers[nins]) && (peh->numpoints))
215 {
216 INSTRUMENTHEADER *penv = Headers[nins];
217
218 if (peh->flags & 1) penv->dwFlags |= ENV_VOLUME;
219 if (peh->flags & 2) penv->dwFlags |= ENV_VOLSUSTAIN;
220 if (peh->flags & 4) penv->dwFlags |= ENV_VOLLOOP;
221 penv->nVolEnv = peh->numpoints + 1;
222 if (penv->nVolEnv > MAX_ENVPOINTS) penv->nVolEnv = MAX_ENVPOINTS;
223 penv->nVolLoopStart = peh->loopbegin;
224 penv->nVolLoopEnd = peh->loopend;
225 penv->nVolSustainBegin = penv->nVolSustainEnd = peh->sustain1;
226 for (UINT i=0; i<penv->nVolEnv; i++)
227 {
228 penv->VolPoints[i] = bswapBE16(peh->volenv[i*2]);
229 penv->VolEnv[i] = (BYTE)bswapBE16(peh->volenv[i*2+1]);
230 }
231 }
232 chunk_pos += sizeof(DBMENVELOPE);
233 }
234 } else
235 // Packed Pattern Data
236 if (chunk_id == DBM_ID_PATT)
237 {
238 if (nPatterns > MAX_PATTERNS) nPatterns = MAX_PATTERNS;
239 for (UINT iPat=0; iPat<nPatterns; iPat++)
240 {
241 DBMPATTERN *pph;
242 DWORD pksize;
243 UINT nRows;
244
245 if (chunk_pos + sizeof(DBMPATTERN) > dwMemPos) break;
246 pph = (DBMPATTERN *)(lpStream+chunk_pos);
247 pksize = bswapBE32(pph->packedsize);
248 if ((chunk_pos + pksize + 6 > dwMemPos) || (pksize > dwMemPos)) break;
249 nRows = bswapBE16(pph->rows);
250 if ((nRows >= 4) && (nRows <= 256))
251 {
252 MODCOMMAND *m = AllocatePattern(nRows, m_nChannels);
253 if (m)
254 {
255 LPBYTE pkdata = (LPBYTE)&pph->patterndata;
256 UINT row = 0;
257 UINT i = 0;
258
259 PatternSize[iPat] = nRows;
260 Patterns[iPat] = m;
261 while ((i+3<pksize) && (row < nRows))
262 {
263 UINT ch = pkdata[i++];
264
265 if (ch)
266 {
267 BYTE b = pkdata[i++];
268 ch--;
269 if (ch < m_nChannels)
270 {
271 if (b & 0x01)
272 {
273 UINT note = pkdata[i++];
274
275 if (note == 0x1F) note = 0xFF; else
276 if ((note) && (note < 0xFE))
277 {
278 note = ((note >> 4)*12) + (note & 0x0F) + 13;
279 }
280 m[ch].note = note;
281 }
282 if (b & 0x02) m[ch].instr = pkdata[i++];
283 if (b & 0x3C)
284 {
285 UINT cmd1 = 0xFF, param1 = 0, cmd2 = 0xFF, param2 = 0;
286 if (b & 0x04) cmd1 = (UINT)pkdata[i++];
287 if (b & 0x08) param1 = pkdata[i++];
288 if (b & 0x10) cmd2 = (UINT)pkdata[i++];
289 if (b & 0x20) param2 = pkdata[i++];
290 if (cmd1 == 0x0C)
291 {
292 m[ch].volcmd = VOLCMD_VOLUME;
293 m[ch].vol = param1;
294 cmd1 = 0xFF;
295 } else
296 if (cmd2 == 0x0C)
297 {
298 m[ch].volcmd = VOLCMD_VOLUME;
299 m[ch].vol = param2;
300 cmd2 = 0xFF;
301 }
302 if ((cmd1 > 0x13) || ((cmd1 >= 0x10) && (cmd2 < 0x10)))
303 {
304 cmd1 = cmd2;
305 param1 = param2;
306 cmd2 = 0xFF;
307 }
308 if (cmd1 <= 0x13)
309 {
310 m[ch].command = cmd1;
311 m[ch].param = param1;
312 ConvertModCommand(&m[ch]);
313 }
314 }
315 } else
316 {
317 if (b & 0x01) i++;
318 if (b & 0x02) i++;
319 if (b & 0x04) i++;
320 if (b & 0x08) i++;
321 if (b & 0x10) i++;
322 if (b & 0x20) i++;
323 }
324 } else
325 {
326 row++;
327 m += m_nChannels;
328 }
329 }
330 }
331 }
332 chunk_pos += 6 + pksize;
333 }
334 } else
335 // Reading Sample Data
336 if (chunk_id == DBM_ID_SMPL)
337 {
338 if (nSamples >= MAX_SAMPLES) nSamples = MAX_SAMPLES-1;
339 m_nSamples = nSamples;
340 for (UINT iSmp=1; iSmp<=nSamples; iSmp++)
341 {
342 MODINSTRUMENT *pins;
343 DBMSAMPLE *psh;
344 DWORD samplesize;
345 DWORD sampleflags;
346
347 if (chunk_pos + sizeof(DBMSAMPLE) >= dwMemPos) break;
348 psh = (DBMSAMPLE *)(lpStream+chunk_pos);
349 chunk_pos += 8;
350 samplesize = bswapBE32(psh->samplesize);
351 sampleflags = bswapBE32(psh->flags);
352 pins = &Ins[iSmp];
353 pins->nLength = samplesize;
354 if (sampleflags & 2)
355 {
356 pins->uFlags |= CHN_16BIT;
357 samplesize <<= 1;
358 }
359 if ((chunk_pos+samplesize > dwMemPos) || (samplesize > dwMemLength)) break;
360 if (sampleflags & 3)
361 {
362 ReadSample(pins, (pins->uFlags & CHN_16BIT) ? RS_PCM16M : RS_PCM8S,
363 (LPSTR)(psh->sampledata), samplesize);
364 }
365 chunk_pos += samplesize;
366 }
367 }
368 }
369 return TRUE;
370}
371
diff --git a/core/multimedia/opieplayer/modplug/load_dmf.cpp b/core/multimedia/opieplayer/modplug/load_dmf.cpp
new file mode 100644
index 0000000..71ec9de
--- a/dev/null
+++ b/core/multimedia/opieplayer/modplug/load_dmf.cpp
@@ -0,0 +1,609 @@
1/*
2 * This program is free software; you can redistribute it and modify it
3 * under the terms of the GNU General Public License as published by the
4 * Free Software Foundation; either version 2 of the license or (at your
5 * option) any later version.
6 *
7 * Authors: Olivier Lapicque <olivierl@jps.net>
8*/
9
10///////////////////////////////////////////////////////
11// DMF DELUSION DIGITAL MUSIC FILEFORMAT (X-Tracker) //
12///////////////////////////////////////////////////////
13#include "stdafx.h"
14#include "sndfile.h"
15
16//#define DMFLOG
17
18//#pragma warning(disable:4244)
19
20#pragma pack(1)
21
22typedef struct DMFHEADER
23{
24 DWORD id; // "DDMF" = 0x464d4444
25 BYTE version; // 4
26 CHAR trackername[8];// "XTRACKER"
27 CHAR songname[30];
28 CHAR composer[20];
29 BYTE date[3];
30} Q_PACKED DMFHEADER;
31
32typedef struct DMFINFO
33{
34 DWORD id; // "INFO"
35 DWORD infosize;
36} Q_PACKED DMFINFO;
37
38typedef struct DMFSEQU
39{
40 DWORD id; // "SEQU"
41 DWORD seqsize;
42 WORD loopstart;
43 WORD loopend;
44 WORD sequ[2];
45} Q_PACKED DMFSEQU;
46
47typedef struct DMFPATT
48{
49 DWORD id; // "PATT"
50 DWORD patsize;
51 WORD numpat; // 1-1024
52 BYTE tracks;
53 BYTE firstpatinfo;
54} Q_PACKED DMFPATT;
55
56typedef struct DMFTRACK
57{
58 BYTE tracks;
59 BYTE beat; // [hi|lo] -> hi=ticks per beat, lo=beats per measure
60 WORD ticks; // max 512
61 DWORD jmpsize;
62} Q_PACKED DMFTRACK;
63
64typedef struct DMFSMPI
65{
66 DWORD id;
67 DWORD size;
68 BYTE samples;
69} Q_PACKED DMFSMPI;
70
71typedef struct DMFSAMPLE
72{
73 DWORD len;
74 DWORD loopstart;
75 DWORD loopend;
76 WORD c3speed;
77 BYTE volume;
78 BYTE flags;
79} Q_PACKED DMFSAMPLE;
80
81#pragma pack()
82
83
84#ifdef DMFLOG
85extern void Log(LPCSTR s, ...);
86#endif
87
88
89BOOL CSoundFile::ReadDMF(const BYTE *lpStream, DWORD dwMemLength)
90//---------------------------------------------------------------
91{
92 DMFHEADER *pfh = (DMFHEADER *)lpStream;
93 DMFINFO *psi;
94 DMFSEQU *sequ;
95 DWORD dwMemPos;
96 BYTE infobyte[32];
97 BYTE smplflags[MAX_SAMPLES];
98
99 if ((!lpStream) || (dwMemLength < 1024)) return FALSE;
100 if ((pfh->id != 0x464d4444) || (!pfh->version) || (pfh->version & 0xF0)) return FALSE;
101 dwMemPos = 66;
102 memcpy(m_szNames[0], pfh->songname, 30);
103 m_szNames[0][30] = 0;
104 m_nType = MOD_TYPE_DMF;
105 m_nChannels = 0;
106#ifdef DMFLOG
107 Log("DMF version %d: \"%s\": %d bytes (0x%04X)\n", pfh->version, m_szNames[0], dwMemLength, dwMemLength);
108#endif
109 while (dwMemPos + 7 < dwMemLength)
110 {
111 DWORD id = *((LPDWORD)(lpStream+dwMemPos));
112
113 switch(id)
114 {
115 // "INFO"
116 case 0x4f464e49:
117 // "CMSG"
118 case 0x47534d43:
119 psi = (DMFINFO *)(lpStream+dwMemPos);
120 if (id == 0x47534d43) dwMemPos++;
121 if ((psi->infosize > dwMemLength) || (psi->infosize + dwMemPos + 8 > dwMemLength)) goto dmfexit;
122 if ((psi->infosize >= 8) && (!m_lpszSongComments))
123 {
124 m_lpszSongComments = new char[psi->infosize]; // changed from CHAR
125 if (m_lpszSongComments)
126 {
127 for (UINT i=0; i<psi->infosize-1; i++)
128 {
129 CHAR c = lpStream[dwMemPos+8+i];
130 if ((i % 40) == 39)
131 m_lpszSongComments[i] = 0x0d;
132 else
133 m_lpszSongComments[i] = (c < ' ') ? ' ' : c;
134 }
135 m_lpszSongComments[psi->infosize-1] = 0;
136 }
137 }
138 dwMemPos += psi->infosize + 8 - 1;
139 break;
140
141 // "SEQU"
142 case 0x55514553:
143 sequ = (DMFSEQU *)(lpStream+dwMemPos);
144 if ((sequ->seqsize >= dwMemLength) || (dwMemPos + sequ->seqsize + 12 > dwMemLength)) goto dmfexit;
145 {
146 UINT nseq = sequ->seqsize >> 1;
147 if (nseq >= MAX_ORDERS-1) nseq = MAX_ORDERS-1;
148 if (sequ->loopstart < nseq) m_nRestartPos = sequ->loopstart;
149 for (UINT i=0; i<nseq; i++) Order[i] = (BYTE)sequ->sequ[i];
150 }
151 dwMemPos += sequ->seqsize + 8;
152 break;
153
154 // "PATT"
155 case 0x54544150:
156 if (!m_nChannels)
157 {
158 DMFPATT *patt = (DMFPATT *)(lpStream+dwMemPos);
159 UINT numpat;
160 DWORD dwPos = dwMemPos + 11;
161 if ((patt->patsize >= dwMemLength) || (dwMemPos + patt->patsize + 8 > dwMemLength)) goto dmfexit;
162 numpat = patt->numpat;
163 if (numpat > MAX_PATTERNS) numpat = MAX_PATTERNS;
164 m_nChannels = patt->tracks;
165 if (m_nChannels < patt->firstpatinfo) m_nChannels = patt->firstpatinfo;
166 if (m_nChannels > 32) m_nChannels = 32;
167 if (m_nChannels < 4) m_nChannels = 4;
168 for (UINT npat=0; npat<numpat; npat++)
169 {
170 DMFTRACK *pt = (DMFTRACK *)(lpStream+dwPos);
171 #ifdef DMFLOG
172 Log("Pattern #%d: %d tracks, %d rows\n", npat, pt->tracks, pt->ticks);
173 #endif
174 UINT tracks = pt->tracks;
175 if (tracks > 32) tracks = 32;
176 UINT ticks = pt->ticks;
177 if (ticks > 256) ticks = 256;
178 if (ticks < 16) ticks = 16;
179 dwPos += 8;
180 if ((pt->jmpsize >= dwMemLength) || (dwPos + pt->jmpsize + 4 >= dwMemLength)) break;
181 PatternSize[npat] = (WORD)ticks;
182 MODCOMMAND *m = AllocatePattern(PatternSize[npat], m_nChannels);
183 if (!m) goto dmfexit;
184 Patterns[npat] = m;
185 DWORD d = dwPos;
186 dwPos += pt->jmpsize;
187 UINT ttype = 1;
188 UINT tempo = 125;
189 UINT glbinfobyte = 0;
190 UINT pbeat = (pt->beat & 0xf0) ? pt->beat>>4 : 8;
191 BOOL tempochange = (pt->beat & 0xf0) ? TRUE : FALSE;
192 memset(infobyte, 0, sizeof(infobyte));
193 for (UINT row=0; row<ticks; row++)
194 {
195 MODCOMMAND *p = &m[row*m_nChannels];
196 // Parse track global effects
197 if (!glbinfobyte)
198 {
199 BYTE info = lpStream[d++];
200 BYTE infoval = 0;
201 if ((info & 0x80) && (d < dwPos)) glbinfobyte = lpStream[d++];
202 info &= 0x7f;
203 if ((info) && (d < dwPos)) infoval = lpStream[d++];
204 switch(info)
205 {
206 case 1:ttype = 0; tempo = infoval; tempochange = TRUE; break;
207 case 2: ttype = 1; tempo = infoval; tempochange = TRUE; break;
208 case 3: pbeat = infoval>>4; tempochange = ttype; break;
209 #ifdef DMFLOG
210 default: if (info) Log("GLB: %02X.%02X\n", info, infoval);
211 #endif
212 }
213 } else
214 {
215 glbinfobyte--;
216 }
217 // Parse channels
218 for (UINT i=0; i<tracks; i++) if (!infobyte[i])
219 {
220 MODCOMMAND cmd = {0,0,0,0,0,0};
221 BYTE info = lpStream[d++];
222 if (info & 0x80) infobyte[i] = lpStream[d++];
223 // Instrument
224 if (info & 0x40)
225 {
226 cmd.instr = lpStream[d++];
227 }
228 // Note
229 if (info & 0x20)
230 {
231 cmd.note = lpStream[d++];
232 if ((cmd.note) && (cmd.note < 0xfe)) cmd.note &= 0x7f;
233 if ((cmd.note) && (cmd.note < 128)) cmd.note += 24;
234 }
235 // Volume
236 if (info & 0x10)
237 {
238 cmd.volcmd = VOLCMD_VOLUME;
239 cmd.vol = (lpStream[d++]+3)>>2;
240 }
241 // Effect 1
242 if (info & 0x08)
243 {
244 BYTE efx = lpStream[d++];
245 BYTE eval = lpStream[d++];
246 switch(efx)
247 {
248 // 1: Key Off
249 case 1: if (!cmd.note) cmd.note = 0xFE; break;
250 // 2: Set Loop
251 // 4: Sample Delay
252 case 4: if (eval&0xe0) { cmd.command = CMD_S3MCMDEX; cmd.param = (eval>>5)|0xD0; } break;
253 // 5: Retrig
254 case 5: if (eval&0xe0) { cmd.command = CMD_RETRIG; cmd.param = (eval>>5); } break;
255 // 6: Offset
256 case 6: cmd.command = CMD_OFFSET; cmd.param = eval; break;
257 #ifdef DMFLOG
258 default: Log("FX1: %02X.%02X\n", efx, eval);
259 #endif
260 }
261 }
262 // Effect 2
263 if (info & 0x04)
264 {
265 BYTE efx = lpStream[d++];
266 BYTE eval = lpStream[d++];
267 switch(efx)
268 {
269 // 1: Finetune
270 case 1: if (eval&0xf0) { cmd.command = CMD_S3MCMDEX; cmd.param = (eval>>4)|0x20; } break;
271 // 2: Note Delay
272 case 2: if (eval&0xe0) { cmd.command = CMD_S3MCMDEX; cmd.param = (eval>>5)|0xD0; } break;
273 // 3: Arpeggio
274 case 3: if (eval) { cmd.command = CMD_ARPEGGIO; cmd.param = eval; } break;
275 // 4: Portamento Up
276 case 4: cmd.command = CMD_PORTAMENTOUP; cmd.param = (eval >= 0xe0) ? 0xdf : eval; break;
277 // 5: Portamento Down
278 case 5: cmd.command = CMD_PORTAMENTODOWN; cmd.param = (eval >= 0xe0) ? 0xdf : eval; break;
279 // 6: Tone Portamento
280 case 6: cmd.command = CMD_TONEPORTAMENTO; cmd.param = eval; break;
281 // 8: Vibrato
282 case 8: cmd.command = CMD_VIBRATO; cmd.param = eval; break;
283 // 12: Note cut
284 case 12: if (eval & 0xe0) { cmd.command = CMD_S3MCMDEX; cmd.param = (eval>>5)|0xc0; }
285 else if (!cmd.note) { cmd.note = 0xfe; } break;
286 #ifdef DMFLOG
287 default: Log("FX2: %02X.%02X\n", efx, eval);
288 #endif
289 }
290 }
291 // Effect 3
292 if (info & 0x02)
293 {
294 BYTE efx = lpStream[d++];
295 BYTE eval = lpStream[d++];
296 switch(efx)
297 {
298 // 1: Vol Slide Up
299 case 1: if (eval == 0xff) break;
300 eval = (eval+3)>>2; if (eval > 0x0f) eval = 0x0f;
301 cmd.command = CMD_VOLUMESLIDE; cmd.param = eval<<4; break;
302 // 2: Vol Slide Down
303 case 2:if (eval == 0xff) break;
304 eval = (eval+3)>>2; if (eval > 0x0f) eval = 0x0f;
305 cmd.command = CMD_VOLUMESLIDE; cmd.param = eval; break;
306 // 7: Set Pan
307 case 7: if (!cmd.volcmd) { cmd.volcmd = VOLCMD_PANNING; cmd.vol = (eval+3)>>2; }
308 else { cmd.command = CMD_PANNING8; cmd.param = eval; } break;
309 // 8: Pan Slide Left
310 case 8: eval = (eval+3)>>2; if (eval > 0x0f) eval = 0x0f;
311 cmd.command = CMD_PANNINGSLIDE; cmd.param = eval<<4; break;
312 // 9: Pan Slide Right
313 case 9: eval = (eval+3)>>2; if (eval > 0x0f) eval = 0x0f;
314 cmd.command = CMD_PANNINGSLIDE; cmd.param = eval; break;
315 #ifdef DMFLOG
316 default: Log("FX3: %02X.%02X\n", efx, eval);
317 #endif
318
319 }
320 }
321 // Store effect
322 if (i < m_nChannels) p[i] = cmd;
323 if (d > dwPos)
324 {
325 #ifdef DMFLOG
326 Log("Unexpected EOP: row=%d\n", row);
327 #endif
328 break;
329 }
330 } else
331 {
332 infobyte[i]--;
333 }
334
335 // Find free channel for tempo change
336 if (tempochange)
337 {
338 tempochange = FALSE;
339 UINT speed=6, modtempo=tempo;
340 UINT rpm = ((ttype) && (pbeat)) ? tempo*pbeat : (tempo+1)*15;
341 for (speed=30; speed>1; speed--)
342 {
343 modtempo = rpm*speed/24;
344 if (modtempo <= 200) break;
345 if ((speed < 6) && (modtempo < 256)) break;
346 }
347 #ifdef DMFLOG
348 Log("Tempo change: ttype=%d pbeat=%d tempo=%3d -> speed=%d tempo=%d\n",
349 ttype, pbeat, tempo, speed, modtempo);
350 #endif
351 for (UINT ich=0; ich<m_nChannels; ich++) if (!p[ich].command)
352 {
353 if (speed)
354 {
355 p[ich].command = CMD_SPEED;
356 p[ich].param = (BYTE)speed;
357 speed = 0;
358 } else
359 if ((modtempo >= 32) && (modtempo < 256))
360 {
361 p[ich].command = CMD_TEMPO;
362 p[ich].param = (BYTE)modtempo;
363 modtempo = 0;
364 } else
365 {
366 break;
367 }
368 }
369 }
370 if (d >= dwPos) break;
371 }
372 #ifdef DMFLOG
373 Log(" %d/%d bytes remaining\n", dwPos-d, pt->jmpsize);
374 #endif
375 if (dwPos + 8 >= dwMemLength) break;
376 }
377 dwMemPos += patt->patsize + 8;
378 }
379 break;
380
381 // "SMPI": Sample Info
382 case 0x49504d53:
383 {
384 DMFSMPI *pds = (DMFSMPI *)(lpStream+dwMemPos);
385 if (pds->size <= dwMemLength - dwMemPos)
386 {
387 DWORD dwPos = dwMemPos + 9;
388 m_nSamples = pds->samples;
389 if (m_nSamples >= MAX_SAMPLES) m_nSamples = MAX_SAMPLES-1;
390 for (UINT iSmp=1; iSmp<=m_nSamples; iSmp++)
391 {
392 UINT namelen = lpStream[dwPos];
393 smplflags[iSmp] = 0;
394 if (dwPos+namelen+1+sizeof(DMFSAMPLE) > dwMemPos+pds->size+8) break;
395 if (namelen)
396 {
397 UINT rlen = (namelen < 32) ? namelen : 31;
398 memcpy(m_szNames[iSmp], lpStream+dwPos+1, rlen);
399 m_szNames[iSmp][rlen] = 0;
400 }
401 dwPos += namelen + 1;
402 DMFSAMPLE *psh = (DMFSAMPLE *)(lpStream+dwPos);
403 MODINSTRUMENT *psmp = &Ins[iSmp];
404 psmp->nLength = psh->len;
405 psmp->nLoopStart = psh->loopstart;
406 psmp->nLoopEnd = psh->loopend;
407 psmp->nC4Speed = psh->c3speed;
408 psmp->nGlobalVol = 64;
409 psmp->nVolume = (psh->volume) ? ((WORD)psh->volume)+1 : (WORD)256;
410 psmp->uFlags = (psh->flags & 2) ? CHN_16BIT : 0;
411 if (psmp->uFlags & CHN_16BIT) psmp->nLength >>= 1;
412 if (psh->flags & 1) psmp->uFlags |= CHN_LOOP;
413 smplflags[iSmp] = psh->flags;
414 dwPos += (pfh->version < 8) ? 22 : 30;
415 #ifdef DMFLOG
416 Log("SMPI %d/%d: len=%d flags=0x%02X\n", iSmp, m_nSamples, psmp->nLength, psh->flags);
417 #endif
418 }
419 }
420 dwMemPos += pds->size + 8;
421 }
422 break;
423
424 // "SMPD": Sample Data
425 case 0x44504d53:
426 {
427 DWORD dwPos = dwMemPos + 8;
428 UINT ismpd = 0;
429 for (UINT iSmp=1; iSmp<=m_nSamples; iSmp++)
430 {
431 ismpd++;
432 DWORD pksize;
433 if (dwPos + 4 >= dwMemLength)
434 {
435 #ifdef DMFLOG
436 Log("Unexpected EOF at sample %d/%d! (pos=%d)\n", iSmp, m_nSamples, dwPos);
437 #endif
438 break;
439 }
440 pksize = *((LPDWORD)(lpStream+dwPos));
441 #ifdef DMFLOG
442 Log("sample %d: pos=0x%X pksize=%d ", iSmp, dwPos, pksize);
443 Log("len=%d flags=0x%X [%08X]\n", Ins[iSmp].nLength, smplflags[ismpd], *((LPDWORD)(lpStream+dwPos+4)));
444 #endif
445 dwPos += 4;
446 if (pksize > dwMemLength - dwPos)
447 {
448 #ifdef DMFLOG
449 Log("WARNING: pksize=%d, but only %d bytes left\n", pksize, dwMemLength-dwPos);
450 #endif
451 pksize = dwMemLength - dwPos;
452 }
453 if ((pksize) && (iSmp <= m_nSamples))
454 {
455 UINT flags = (Ins[iSmp].uFlags & CHN_16BIT) ? RS_PCM16S : RS_PCM8S;
456 if (smplflags[ismpd] & 4) flags = (Ins[iSmp].uFlags & CHN_16BIT) ? RS_DMF16 : RS_DMF8;
457 ReadSample(&Ins[iSmp], flags, (LPSTR)(lpStream+dwPos), pksize);
458 }
459 dwPos += pksize;
460 }
461 dwMemPos = dwPos;
462 }
463 break;
464
465 // "ENDE": end of file
466 case 0x45444e45:
467 goto dmfexit;
468
469 // Unrecognized id, or "ENDE" field
470 default:
471 dwMemPos += 4;
472 break;
473 }
474 }
475dmfexit:
476 if (!m_nChannels)
477 {
478 if (!m_nSamples)
479 {
480 m_nType = MOD_TYPE_NONE;
481 return FALSE;
482 }
483 m_nChannels = 4;
484 }
485 return TRUE;
486}
487
488
489///////////////////////////////////////////////////////////////////////
490// DMF Compression
491
492#pragma pack(1)
493
494typedef struct DMF_HNODE
495{
496 short int left, right;
497 BYTE value;
498} Q_PACKED DMF_HNODE;
499
500typedef struct DMF_HTREE
501{
502 LPBYTE ibuf, ibufmax;
503 DWORD bitbuf;
504 UINT bitnum;
505 UINT lastnode, nodecount;
506 DMF_HNODE nodes[256];
507} Q_PACKED DMF_HTREE;
508
509#pragma pack()
510
511
512// DMF Huffman ReadBits
513BYTE DMFReadBits(DMF_HTREE *tree, UINT nbits)
514//-------------------------------------------
515{
516 BYTE x = 0, bitv = 1;
517 while (nbits--)
518 {
519 if (tree->bitnum)
520 {
521 tree->bitnum--;
522 } else
523 {
524 tree->bitbuf = (tree->ibuf < tree->ibufmax) ? *(tree->ibuf++) : 0;
525 tree->bitnum = 7;
526 }
527 if (tree->bitbuf & 1) x |= bitv;
528 bitv <<= 1;
529 tree->bitbuf >>= 1;
530 }
531 return x;
532}
533
534//
535// tree: [8-bit value][12-bit index][12-bit index] = 32-bit
536//
537
538void DMFNewNode(DMF_HTREE *tree)
539//------------------------------
540{
541 BYTE isleft, isright;
542 UINT actnode;
543
544 actnode = tree->nodecount;
545 if (actnode > 255) return;
546 tree->nodes[actnode].value = DMFReadBits(tree, 7);
547 isleft = DMFReadBits(tree, 1);
548 isright = DMFReadBits(tree, 1);
549 actnode = tree->lastnode;
550 if (actnode > 255) return;
551 tree->nodecount++;
552 tree->lastnode = tree->nodecount;
553 if (isleft)
554 {
555 tree->nodes[actnode].left = tree->lastnode;
556 DMFNewNode(tree);
557 } else
558 {
559 tree->nodes[actnode].left = -1;
560 }
561 tree->lastnode = tree->nodecount;
562 if (isright)
563 {
564 tree->nodes[actnode].right = tree->lastnode;
565 DMFNewNode(tree);
566 } else
567 {
568 tree->nodes[actnode].right = -1;
569 }
570}
571
572
573int DMFUnpack(LPBYTE psample, LPBYTE ibuf, LPBYTE ibufmax, UINT maxlen)
574//----------------------------------------------------------------------
575{
576 DMF_HTREE tree;
577 UINT actnode;
578 BYTE value, sign, delta = 0;
579
580 memset(&tree, 0, sizeof(tree));
581 tree.ibuf = ibuf;
582 tree.ibufmax = ibufmax;
583 DMFNewNode(&tree);
584 value = 0;
585 for (UINT i=0; i<maxlen; i++)
586 {
587 actnode = 0;
588 sign = DMFReadBits(&tree, 1);
589 do
590 {
591 if (DMFReadBits(&tree, 1))
592 actnode = tree.nodes[actnode].right;
593 else
594 actnode = tree.nodes[actnode].left;
595 if (actnode > 255) break;
596 delta = tree.nodes[actnode].value;
597 if ((tree.ibuf >= tree.ibufmax) && (!tree.bitnum)) break;
598 } while ((tree.nodes[actnode].left >= 0) && (tree.nodes[actnode].right >= 0));
599 if (sign) delta ^= 0xFF;
600 value += delta;
601 psample[i] = (i) ? value : 0;
602 }
603#ifdef DMFLOG
604 //Log("DMFUnpack: %d remaining bytes\n", tree.ibufmax-tree.ibuf);
605#endif
606 return tree.ibuf - ibuf;
607}
608
609
diff --git a/core/multimedia/opieplayer/modplug/load_dsm.cpp b/core/multimedia/opieplayer/modplug/load_dsm.cpp
new file mode 100644
index 0000000..4751f5f
--- a/dev/null
+++ b/core/multimedia/opieplayer/modplug/load_dsm.cpp
@@ -0,0 +1,239 @@
1/*
2 * This program is free software; you can redistribute it and modify it
3 * under the terms of the GNU General Public License as published by the
4 * Free Software Foundation; either version 2 of the license or (at your
5 * option) any later version.
6 *
7 * Authors: Olivier Lapicque <olivierl@jps.net>
8*/
9
10//////////////////////////////////////////////
11// DSIK Internal Format (DSM) module loader //
12//////////////////////////////////////////////
13#include "stdafx.h"
14#include "sndfile.h"
15
16#pragma pack(1)
17
18 #define DSMID_RIFF 0x46464952// "RIFF"
19 #define DSMID_DSMF 0x464d5344// "DSMF"
20 #define DSMID_SONG 0x474e4f53// "SONG"
21 #define DSMID_INST 0x54534e49// "INST"
22 #define DSMID_PATT 0x54544150// "PATT"
23
24
25typedef struct DSMNOTE
26{
27 BYTE note,ins,vol,cmd,inf;
28} Q_PACKED DSMNOTE;
29
30
31typedef struct DSMINST
32{
33 DWORD id_INST;
34 DWORD inst_len;
35 CHAR filename[13];
36 BYTE flags;
37 BYTE flags2;
38 BYTE volume;
39 DWORD length;
40 DWORD loopstart;
41 DWORD loopend;
42 DWORD reserved1;
43 WORD c2spd;
44 WORD reserved2;
45 CHAR samplename[28];
46} Q_PACKED DSMINST;
47
48
49typedef struct DSMFILEHEADER
50{
51 DWORD id_RIFF;// "RIFF"
52 DWORD riff_len;
53 DWORD id_DSMF;// "DSMF"
54 DWORD id_SONG;// "SONG"
55 DWORD song_len;
56} Q_PACKED DSMFILEHEADER;
57
58
59typedef struct DSMSONG
60{
61 CHAR songname[28];
62 WORD reserved1;
63 WORD flags;
64 DWORD reserved2;
65 WORD numord;
66 WORD numsmp;
67 WORD numpat;
68 WORD numtrk;
69 BYTE globalvol;
70 BYTE mastervol;
71 BYTE speed;
72 BYTE bpm;
73 BYTE panpos[16];
74 BYTE orders[128];
75} Q_PACKED DSMSONG;
76
77typedef struct DSMPATT
78{
79 DWORD id_PATT;
80 DWORD patt_len;
81 BYTE dummy1;
82 BYTE dummy2;
83} Q_PACKED DSMPATT;
84
85#pragma pack()
86
87
88BOOL CSoundFile::ReadDSM(LPCBYTE lpStream, DWORD dwMemLength)
89//-----------------------------------------------------------
90{
91 DSMFILEHEADER *pfh = (DSMFILEHEADER *)lpStream;
92 DSMSONG *psong;
93 DWORD dwMemPos;
94 UINT nPat, nSmp;
95
96 if ((!lpStream) || (dwMemLength < 1024) || (pfh->id_RIFF != DSMID_RIFF)
97 || (pfh->riff_len + 8 > dwMemLength) || (pfh->riff_len < 1024)
98 || (pfh->id_DSMF != DSMID_DSMF) || (pfh->id_SONG != DSMID_SONG)
99 || (pfh->song_len > dwMemLength)) return FALSE;
100 psong = (DSMSONG *)(lpStream + sizeof(DSMFILEHEADER));
101 dwMemPos = sizeof(DSMFILEHEADER) + pfh->song_len;
102 m_nType = MOD_TYPE_DSM;
103 m_nChannels = psong->numtrk;
104 if (m_nChannels < 4) m_nChannels = 4;
105 if (m_nChannels > 16) m_nChannels = 16;
106 m_nSamples = psong->numsmp;
107 if (m_nSamples > MAX_SAMPLES) m_nSamples = MAX_SAMPLES;
108 m_nDefaultSpeed = psong->speed;
109 m_nDefaultTempo = psong->bpm;
110 m_nDefaultGlobalVolume = psong->globalvol << 2;
111 if ((!m_nDefaultGlobalVolume) || (m_nDefaultGlobalVolume > 256)) m_nDefaultGlobalVolume = 256;
112 m_nSongPreAmp = psong->mastervol & 0x7F;
113 for (UINT iOrd=0; iOrd<MAX_ORDERS; iOrd++)
114 {
115 Order[iOrd] = (BYTE)((iOrd < psong->numord) ? psong->orders[iOrd] : 0xFF);
116 }
117 for (UINT iPan=0; iPan<16; iPan++)
118 {
119 ChnSettings[iPan].nPan = 0x80;
120 if (psong->panpos[iPan] <= 0x80)
121 {
122 ChnSettings[iPan].nPan = psong->panpos[iPan] << 1;
123 }
124 }
125 memcpy(m_szNames[0], psong->songname, 28);
126 nPat = 0;
127 nSmp = 1;
128 while (dwMemPos < dwMemLength - 8)
129 {
130 DSMPATT *ppatt = (DSMPATT *)(lpStream + dwMemPos);
131 DSMINST *pins = (DSMINST *)(lpStream+dwMemPos);
132 // Reading Patterns
133 if (ppatt->id_PATT == DSMID_PATT)
134 {
135 dwMemPos += 8;
136 if (dwMemPos + ppatt->patt_len >= dwMemLength) break;
137 DWORD dwPos = dwMemPos;
138 dwMemPos += ppatt->patt_len;
139 MODCOMMAND *m = AllocatePattern(64, m_nChannels);
140 if (!m) break;
141 PatternSize[nPat] = 64;
142 Patterns[nPat] = m;
143 UINT row = 0;
144 while ((row < 64) && (dwPos + 2 <= dwMemPos))
145 {
146 UINT flag = lpStream[dwPos++];
147 if (flag)
148 {
149 UINT ch = (flag & 0x0F) % m_nChannels;
150 if (flag & 0x80)
151 {
152 UINT note = lpStream[dwPos++];
153 if (note)
154 {
155 if (note <= 12*9) note += 12;
156 m[ch].note = (BYTE)note;
157 }
158 }
159 if (flag & 0x40)
160 {
161 m[ch].instr = lpStream[dwPos++];
162 }
163 if (flag & 0x20)
164 {
165 m[ch].volcmd = VOLCMD_VOLUME;
166 m[ch].vol = lpStream[dwPos++];
167 }
168 if (flag & 0x10)
169 {
170 UINT command = lpStream[dwPos++];
171 UINT param = lpStream[dwPos++];
172 switch(command)
173 {
174 // 4-bit Panning
175 case 0x08:
176 switch(param & 0xF0)
177 {
178 case 0x00: param <<= 4; break;
179 case 0x10: command = 0x0A; param = (param & 0x0F) << 4; break;
180 case 0x20: command = 0x0E; param = (param & 0x0F) | 0xA0; break;
181 case 0x30: command = 0x0E; param = (param & 0x0F) | 0x10; break;
182 case 0x40: command = 0x0E; param = (param & 0x0F) | 0x20; break;
183 default: command = 0;
184 }
185 break;
186 // Portamentos
187 case 0x11:
188 case 0x12:
189 command &= 0x0F;
190 break;
191 // 3D Sound (?)
192 case 0x13:
193 command = 'X' - 55;
194 param = 0x91;
195 break;
196 default:
197 // Volume + Offset (?)
198 command = ((command & 0xF0) == 0x20) ? 0x09 : 0;
199 }
200 m[ch].command = (BYTE)command;
201 m[ch].param = (BYTE)param;
202 if (command) ConvertModCommand(&m[ch]);
203 }
204 } else
205 {
206 m += m_nChannels;
207 row++;
208 }
209 }
210 nPat++;
211 } else
212 // Reading Samples
213 if ((nSmp <= m_nSamples) && (pins->id_INST == DSMID_INST))
214 {
215 if (dwMemPos + pins->inst_len >= dwMemLength - 8) break;
216 DWORD dwPos = dwMemPos + sizeof(DSMINST);
217 dwMemPos += 8 + pins->inst_len;
218 memcpy(m_szNames[nSmp], pins->samplename, 28);
219 MODINSTRUMENT *psmp = &Ins[nSmp];
220 memcpy(psmp->name, pins->filename, 13);
221 psmp->nGlobalVol = 64;
222 psmp->nC4Speed = pins->c2spd;
223 psmp->uFlags = (WORD)((pins->flags & 1) ? CHN_LOOP : 0);
224 psmp->nLength = pins->length;
225 psmp->nLoopStart = pins->loopstart;
226 psmp->nLoopEnd = pins->loopend;
227 psmp->nVolume = (WORD)(pins->volume << 2);
228 if (psmp->nVolume > 256) psmp->nVolume = 256;
229 UINT smptype = (pins->flags & 2) ? RS_PCM8S : RS_PCM8U;
230 ReadSample(psmp, smptype, (LPCSTR)(lpStream+dwPos), dwMemLength - dwPos);
231 nSmp++;
232 } else
233 {
234 break;
235 }
236 }
237 return TRUE;
238}
239
diff --git a/core/multimedia/opieplayer/modplug/load_far.cpp b/core/multimedia/opieplayer/modplug/load_far.cpp
new file mode 100644
index 0000000..32bc431
--- a/dev/null
+++ b/core/multimedia/opieplayer/modplug/load_far.cpp
@@ -0,0 +1,263 @@
1/*
2 * This program is free software; you can redistribute it and modify it
3 * under the terms of the GNU General Public License as published by the
4 * Free Software Foundation; either version 2 of the license or (at your
5 * option) any later version.
6 *
7 * Authors: Olivier Lapicque <olivierl@jps.net>
8*/
9
10////////////////////////////////////////
11 // Farandole (FAR) module loader //
12////////////////////////////////////////
13#include "stdafx.h"
14#include "sndfile.h"
15
16//#pragma warning(disable:4244)
17
18 #define FARFILEMAGIC 0xFE524146// "FAR"
19
20#pragma pack(1)
21
22typedef struct FARHEADER1
23{
24 DWORD id; // file magic FAR=
25 CHAR songname[40]; // songname
26 CHAR magic2[3]; // 13,10,26
27 WORD headerlen; // remaining length of header in bytes
28 BYTE version; // 0xD1
29 BYTE onoff[16];
30 BYTE edit1[9];
31 BYTE speed;
32 BYTE panning[16];
33 BYTE edit2[4];
34 WORD stlen;
35} Q_PACKED FARHEADER1;
36
37typedef struct FARHEADER2
38{
39 BYTE orders[256];
40 BYTE numpat;
41 BYTE snglen;
42 BYTE loopto;
43 WORD patsiz[256];
44} Q_PACKED FARHEADER2;
45
46typedef struct FARSAMPLE
47{
48 CHAR samplename[32];
49 DWORD length;
50 BYTE finetune;
51 BYTE volume;
52 DWORD reppos;
53 DWORD repend;
54 BYTE type;
55 BYTE loop;
56} Q_PACKED FARSAMPLE;
57
58#pragma pack()
59
60
61BOOL CSoundFile::ReadFAR(const BYTE *lpStream, DWORD dwMemLength)
62//---------------------------------------------------------------
63{
64 FARHEADER1 *pmh1 = (FARHEADER1 *)lpStream;
65 FARHEADER2 *pmh2;
66 DWORD dwMemPos = sizeof(FARHEADER1);
67 UINT headerlen;
68 BYTE samplemap[8];
69
70 if ((!lpStream) || (dwMemLength < 1024) || (pmh1->id != FARFILEMAGIC)
71 || (pmh1->magic2[0] != 13) || (pmh1->magic2[1] != 10) || (pmh1->magic2[2] != 26)) return FALSE;
72 headerlen = pmh1->headerlen;
73 if ((headerlen >= dwMemLength) || (dwMemPos + pmh1->stlen + sizeof(FARHEADER2) >= dwMemLength)) return FALSE;
74 // Globals
75 m_nType = MOD_TYPE_FAR;
76 m_nChannels = 16;
77 m_nInstruments = 0;
78 m_nSamples = 0;
79 m_nSongPreAmp = 0x20;
80 m_nDefaultSpeed = pmh1->speed;
81 m_nDefaultTempo = 80;
82 m_nDefaultGlobalVolume = 256;
83
84 memcpy(m_szNames[0], pmh1->songname, 32);
85 // Channel Setting
86 for (UINT nchpan=0; nchpan<16; nchpan++)
87 {
88 ChnSettings[nchpan].dwFlags = 0;
89 ChnSettings[nchpan].nPan = ((pmh1->panning[nchpan] & 0x0F) << 4) + 8;
90 ChnSettings[nchpan].nVolume = 64;
91 }
92 // Reading comment
93 if (pmh1->stlen)
94 {
95 UINT szLen = pmh1->stlen;
96 if (szLen > dwMemLength - dwMemPos) szLen = dwMemLength - dwMemPos;
97 if ((m_lpszSongComments = new char[szLen + 1]) != NULL)
98 {
99 memcpy(m_lpszSongComments, lpStream+dwMemPos, szLen);
100 m_lpszSongComments[szLen] = 0;
101 }
102 dwMemPos += pmh1->stlen;
103 }
104 // Reading orders
105 pmh2 = (FARHEADER2 *)(lpStream + dwMemPos);
106 dwMemPos += sizeof(FARHEADER2);
107 if (dwMemPos >= dwMemLength) return TRUE;
108 for (UINT iorder=0; iorder<MAX_ORDERS; iorder++)
109 {
110 Order[iorder] = (iorder <= pmh2->snglen) ? pmh2->orders[iorder] : 0xFF;
111 }
112 m_nRestartPos = pmh2->loopto;
113 // Reading Patterns
114 dwMemPos += headerlen - (869 + pmh1->stlen);
115 if (dwMemPos >= dwMemLength) return TRUE;
116
117 WORD *patsiz = (WORD *)pmh2->patsiz;
118 for (UINT ipat=0; ipat<256; ipat++) if (patsiz[ipat])
119 {
120 UINT patlen = patsiz[ipat];
121 if ((ipat >= MAX_PATTERNS) || (patsiz[ipat] < 2))
122 {
123 dwMemPos += patlen;
124 continue;
125 }
126 if (dwMemPos + patlen >= dwMemLength) return TRUE;
127 UINT rows = (patlen - 2) >> 6;
128 if (!rows)
129 {
130 dwMemPos += patlen;
131 continue;
132 }
133 if (rows > 256) rows = 256;
134 if (rows < 16) rows = 16;
135 PatternSize[ipat] = rows;
136 if ((Patterns[ipat] = AllocatePattern(rows, m_nChannels)) == NULL) return TRUE;
137 MODCOMMAND *m = Patterns[ipat];
138 UINT patbrk = lpStream[dwMemPos];
139 const BYTE *p = lpStream + dwMemPos + 2;
140 UINT max = rows*16*4;
141 if (max > patlen-2) max = patlen-2;
142 for (UINT len=0; len<max; len += 4, m++)
143 {
144 BYTE note = p[len];
145 BYTE ins = p[len+1];
146 BYTE vol = p[len+2];
147 BYTE eff = p[len+3];
148 if (note)
149 {
150 m->instr = ins + 1;
151 m->note = note + 36;
152 }
153 if (vol & 0x0F)
154 {
155 m->volcmd = VOLCMD_VOLUME;
156 m->vol = (vol & 0x0F) << 2;
157 if (m->vol <= 4) m->vol = 0;
158 }
159 switch(eff & 0xF0)
160 {
161 // 1.x: Portamento Up
162 case 0x10:
163 m->command = CMD_PORTAMENTOUP;
164 m->param = eff & 0x0F;
165 break;
166 // 2.x: Portamento Down
167 case 0x20:
168 m->command = CMD_PORTAMENTODOWN;
169 m->param = eff & 0x0F;
170 break;
171 // 3.x: Tone-Portamento
172 case 0x30:
173 m->command = CMD_TONEPORTAMENTO;
174 m->param = (eff & 0x0F) << 2;
175 break;
176 // 4.x: Retrigger
177 case 0x40:
178 m->command = CMD_RETRIG;
179 m->param = 6 / (1+(eff&0x0F)) + 1;
180 break;
181 // 5.x: Set Vibrato Depth
182 case 0x50:
183 m->command = CMD_VIBRATO;
184 m->param = (eff & 0x0F);
185 break;
186 // 6.x: Set Vibrato Speed
187 case 0x60:
188 m->command = CMD_VIBRATO;
189 m->param = (eff & 0x0F) << 4;
190 break;
191 // 7.x: Vol Slide Up
192 case 0x70:
193 m->command = CMD_VOLUMESLIDE;
194 m->param = (eff & 0x0F) << 4;
195 break;
196 // 8.x: Vol Slide Down
197 case 0x80:
198 m->command = CMD_VOLUMESLIDE;
199 m->param = (eff & 0x0F);
200 break;
201 // A.x: Port to vol
202 case 0xA0:
203 m->volcmd = VOLCMD_VOLUME;
204 m->vol = ((eff & 0x0F) << 2) + 4;
205 break;
206 // B.x: Set Balance
207 case 0xB0:
208 m->command = CMD_PANNING8;
209 m->param = (eff & 0x0F) << 4;
210 break;
211 // F.x: Set Speed
212 case 0xF0:
213 m->command = CMD_SPEED;
214 m->param = eff & 0x0F;
215 break;
216 default:
217 if ((patbrk) &&(patbrk+1 == (len >> 6)) && (patbrk+1 != rows-1))
218 {
219 m->command = CMD_PATTERNBREAK;
220 patbrk = 0;
221 }
222 }
223 }
224 dwMemPos += patlen;
225 }
226 // Reading samples
227 if (dwMemPos + 8 >= dwMemLength) return TRUE;
228 memcpy(samplemap, lpStream+dwMemPos, 8);
229 dwMemPos += 8;
230 MODINSTRUMENT *pins = &Ins[1];
231 for (UINT ismp=0; ismp<64; ismp++, pins++) if (samplemap[ismp >> 3] & (1 << (ismp & 7)))
232 {
233 if (dwMemPos + sizeof(FARSAMPLE) > dwMemLength) return TRUE;
234 FARSAMPLE *pfs = (FARSAMPLE *)(lpStream + dwMemPos);
235 dwMemPos += sizeof(FARSAMPLE);
236 m_nSamples = ismp + 1;
237 memcpy(m_szNames[ismp+1], pfs->samplename, 32);
238 pins->nLength = pfs->length;
239 pins->nLoopStart = pfs->reppos;
240 pins->nLoopEnd = pfs->repend;
241 pins->nFineTune = 0;
242 pins->nC4Speed = 8363*2;
243 pins->nGlobalVol = 64;
244 pins->nVolume = pfs->volume << 4;
245 pins->uFlags = 0;
246 if ((pins->nLength > 3) && (dwMemPos + 4 < dwMemLength))
247 {
248 if (pfs->type & 1)
249 {
250 pins->uFlags |= CHN_16BIT;
251 pins->nLength >>= 1;
252 pins->nLoopStart >>= 1;
253 pins->nLoopEnd >>= 1;
254 }
255 if ((pfs->loop & 8) && (pins->nLoopEnd > 4)) pins->uFlags |= CHN_LOOP;
256 ReadSample(pins, (pins->uFlags & CHN_16BIT) ? RS_PCM16S : RS_PCM8S,
257 (LPSTR)(lpStream+dwMemPos), dwMemLength - dwMemPos);
258 }
259 dwMemPos += pfs->length;
260 }
261 return TRUE;
262}
263
diff --git a/core/multimedia/opieplayer/modplug/load_it.cpp b/core/multimedia/opieplayer/modplug/load_it.cpp
new file mode 100644
index 0000000..006b746
--- a/dev/null
+++ b/core/multimedia/opieplayer/modplug/load_it.cpp
@@ -0,0 +1,1415 @@
1/*
2 * This program is free software; you can redistribute it and modify it
3 * under the terms of the GNU General Public License as published by the
4 * Free Software Foundation; either version 2 of the license or (at your
5 * option) any later version.
6 *
7 * Authors: Olivier Lapicque <olivierl@jps.net>,
8 * Adam Goode <adam@evdebs.org> (endian and char fixes for PPC)
9*/
10
11#include "stdafx.h"
12#include "sndfile.h"
13#include "it_defs.h"
14
15#ifdef WIN32
16#pragma warning(disable:4244)
17#endif
18
19const BYTE autovibit2xm[8] =
20{ 0, 3, 1, 4, 2, 0, 0, 0 };
21
22const BYTE autovibxm2it[8] =
23{ 0, 2, 4, 1, 3, 0, 0, 0 };
24
25//////////////////////////////////////////////////////////
26// Impulse Tracker IT file support (import only)
27
28
29static inline UINT ConvertVolParam(UINT value)
30//--------------------------------------------
31{
32 return (value > 9) ? 9 : value;
33}
34
35
36BOOL CSoundFile::ITInstrToMPT(const void *p, INSTRUMENTHEADER *penv, UINT trkvers)
37//--------------------------------------------------------------------------------
38{
39 if (trkvers < 0x0200)
40 {
41 const ITOLDINSTRUMENT *pis = (const ITOLDINSTRUMENT *)p;
42 memcpy(penv->name, pis->name, 26);
43 memcpy(penv->filename, pis->filename, 12);
44 penv->nFadeOut = bswapLE16(pis->fadeout) << 6;
45 penv->nGlobalVol = 64;
46 for (UINT j=0; j<120; j++)
47 {
48 UINT note = pis->keyboard[j*2];
49 UINT ins = pis->keyboard[j*2+1];
50 if (ins < MAX_SAMPLES) penv->Keyboard[j] = ins;
51 if (note < 128) penv->NoteMap[j] = note+1;
52 else if (note >= 0xFE) penv->NoteMap[j] = note;
53 }
54 if (pis->flags & 0x01) penv->dwFlags |= ENV_VOLUME;
55 if (pis->flags & 0x02) penv->dwFlags |= ENV_VOLLOOP;
56 if (pis->flags & 0x04) penv->dwFlags |= ENV_VOLSUSTAIN;
57 penv->nVolLoopStart = pis->vls;
58 penv->nVolLoopEnd = pis->vle;
59 penv->nVolSustainBegin = pis->sls;
60 penv->nVolSustainEnd = pis->sle;
61 penv->nVolEnv = 25;
62 for (UINT ev=0; ev<25; ev++)
63 {
64 if ((penv->VolPoints[ev] = pis->nodes[ev*2]) == 0xFF)
65 {
66 penv->nVolEnv = ev;
67 break;
68 }
69 penv->VolEnv[ev] = pis->nodes[ev*2+1];
70 }
71 penv->nNNA = pis->nna;
72 penv->nDCT = pis->dnc;
73 penv->nPan = 0x80;
74 } else
75 {
76 const ITINSTRUMENT *pis = (const ITINSTRUMENT *)p;
77 memcpy(penv->name, pis->name, 26);
78 memcpy(penv->filename, pis->filename, 12);
79 penv->nMidiProgram = pis->mpr;
80 penv->nMidiChannel = pis->mch;
81 penv->wMidiBank = bswapLE16(pis->mbank);
82 penv->nFadeOut = bswapLE16(pis->fadeout) << 5;
83 penv->nGlobalVol = pis->gbv >> 1;
84 if (penv->nGlobalVol > 64) penv->nGlobalVol = 64;
85 for (UINT j=0; j<120; j++)
86 {
87 UINT note = pis->keyboard[j*2];
88 UINT ins = pis->keyboard[j*2+1];
89 if (ins < MAX_SAMPLES) penv->Keyboard[j] = ins;
90 if (note < 128) penv->NoteMap[j] = note+1;
91 else if (note >= 0xFE) penv->NoteMap[j] = note;
92 }
93 // Volume Envelope
94 if (pis->volenv.flags & 1) penv->dwFlags |= ENV_VOLUME;
95 if (pis->volenv.flags & 2) penv->dwFlags |= ENV_VOLLOOP;
96 if (pis->volenv.flags & 4) penv->dwFlags |= ENV_VOLSUSTAIN;
97 if (pis->volenv.flags & 8) penv->dwFlags |= ENV_VOLCARRY;
98 penv->nVolEnv = pis->volenv.num;
99 if (penv->nVolEnv > 25) penv->nVolEnv = 25;
100
101 penv->nVolLoopStart = pis->volenv.lpb;
102 penv->nVolLoopEnd = pis->volenv.lpe;
103 penv->nVolSustainBegin = pis->volenv.slb;
104 penv->nVolSustainEnd = pis->volenv.sle;
105 // Panning Envelope
106 if (pis->panenv.flags & 1) penv->dwFlags |= ENV_PANNING;
107 if (pis->panenv.flags & 2) penv->dwFlags |= ENV_PANLOOP;
108 if (pis->panenv.flags & 4) penv->dwFlags |= ENV_PANSUSTAIN;
109 if (pis->panenv.flags & 8) penv->dwFlags |= ENV_PANCARRY;
110 penv->nPanEnv = pis->panenv.num;
111 if (penv->nPanEnv > 25) penv->nPanEnv = 25;
112 penv->nPanLoopStart = pis->panenv.lpb;
113 penv->nPanLoopEnd = pis->panenv.lpe;
114 penv->nPanSustainBegin = pis->panenv.slb;
115 penv->nPanSustainEnd = pis->panenv.sle;
116 // Pitch Envelope
117 if (pis->pitchenv.flags & 1) penv->dwFlags |= ENV_PITCH;
118 if (pis->pitchenv.flags & 2) penv->dwFlags |= ENV_PITCHLOOP;
119 if (pis->pitchenv.flags & 4) penv->dwFlags |= ENV_PITCHSUSTAIN;
120 if (pis->pitchenv.flags & 8) penv->dwFlags |= ENV_PITCHCARRY;
121 if (pis->pitchenv.flags & 0x80) penv->dwFlags |= ENV_FILTER;
122 penv->nPitchEnv = pis->pitchenv.num;
123 if (penv->nPitchEnv > 25) penv->nPitchEnv = 25;
124 penv->nPitchLoopStart = pis->pitchenv.lpb;
125 penv->nPitchLoopEnd = pis->pitchenv.lpe;
126 penv->nPitchSustainBegin = pis->pitchenv.slb;
127 penv->nPitchSustainEnd = pis->pitchenv.sle;
128 // Envelopes Data
129 for (UINT ev=0; ev<25; ev++)
130 {
131 penv->VolEnv[ev] = pis->volenv.data[ev*3];
132 penv->VolPoints[ev] = (pis->volenv.data[ev*3+2] << 8) | (pis->volenv.data[ev*3+1]);
133 penv->PanEnv[ev] = pis->panenv.data[ev*3] + 32;
134 penv->PanPoints[ev] = (pis->panenv.data[ev*3+2] << 8) | (pis->panenv.data[ev*3+1]);
135 penv->PitchEnv[ev] = pis->pitchenv.data[ev*3] + 32;
136 penv->PitchPoints[ev] = (pis->pitchenv.data[ev*3+2] << 8) | (pis->pitchenv.data[ev*3+1]);
137 }
138 penv->nNNA = pis->nna;
139 penv->nDCT = pis->dct;
140 penv->nDNA = pis->dca;
141 penv->nPPS = pis->pps;
142 penv->nPPC = pis->ppc;
143 penv->nIFC = pis->ifc;
144 penv->nIFR = pis->ifr;
145 penv->nVolSwing = pis->rv;
146 penv->nPanSwing = pis->rp;
147 penv->nPan = (pis->dfp & 0x7F) << 2;
148 if (penv->nPan > 256) penv->nPan = 128;
149 if (pis->dfp < 0x80) penv->dwFlags |= ENV_SETPANNING;
150 }
151 if ((penv->nVolLoopStart >= 25) || (penv->nVolLoopEnd >= 25)) penv->dwFlags &= ~ENV_VOLLOOP;
152 if ((penv->nVolSustainBegin >= 25) || (penv->nVolSustainEnd >= 25)) penv->dwFlags &= ~ENV_VOLSUSTAIN;
153 return TRUE;
154}
155
156
157BOOL CSoundFile::ReadIT(const BYTE *lpStream, DWORD dwMemLength)
158//--------------------------------------------------------------
159{
160 ITFILEHEADER pifh = *(ITFILEHEADER *)lpStream;
161 DWORD dwMemPos = sizeof(ITFILEHEADER);
162 DWORD inspos[MAX_INSTRUMENTS];
163 DWORD smppos[MAX_SAMPLES];
164 DWORD patpos[MAX_PATTERNS];
165 BYTE chnmask[64], channels_used[64];
166 MODCOMMAND lastvalue[64];
167
168 pifh.id = bswapLE32(pifh.id);
169 pifh.reserved1 = bswapLE16(pifh.reserved1);
170 pifh.ordnum = bswapLE16(pifh.ordnum);
171 pifh.insnum = bswapLE16(pifh.insnum);
172 pifh.smpnum = bswapLE16(pifh.smpnum);
173 pifh.patnum = bswapLE16(pifh.patnum);
174 pifh.cwtv = bswapLE16(pifh.cwtv);
175 pifh.cmwt = bswapLE16(pifh.cmwt);
176 pifh.flags = bswapLE16(pifh.flags);
177 pifh.special = bswapLE16(pifh.special);
178 pifh.msglength = bswapLE16(pifh.msglength);
179 pifh.msgoffset = bswapLE32(pifh.msgoffset);
180 pifh.reserved2 = bswapLE32(pifh.reserved2);
181
182 if ((!lpStream) || (dwMemLength < 0x100)) return FALSE;
183 if ((pifh.id != 0x4D504D49) || (pifh.insnum >= MAX_INSTRUMENTS)
184 || (!pifh.smpnum) || (pifh.smpnum >= MAX_INSTRUMENTS) || (!pifh.ordnum)) return FALSE;
185 if (dwMemPos + pifh.ordnum + pifh.insnum*4
186 + pifh.smpnum*4 + pifh.patnum*4 > dwMemLength) return FALSE;
187 m_nType = MOD_TYPE_IT;
188 if (pifh.flags & 0x08) m_dwSongFlags |= SONG_LINEARSLIDES;
189 if (pifh.flags & 0x10) m_dwSongFlags |= SONG_ITOLDEFFECTS;
190 if (pifh.flags & 0x20) m_dwSongFlags |= SONG_ITCOMPATMODE;
191 if (pifh.flags & 0x80) m_dwSongFlags |= SONG_EMBEDMIDICFG;
192 if (pifh.flags & 0x1000) m_dwSongFlags |= SONG_EXFILTERRANGE;
193 memcpy(m_szNames[0], pifh.songname, 26);
194 m_szNames[0][26] = 0;
195 // Global Volume
196 if (pifh.globalvol)
197 {
198 m_nDefaultGlobalVolume = pifh.globalvol << 1;
199 if (!m_nDefaultGlobalVolume) m_nDefaultGlobalVolume = 256;
200 if (m_nDefaultGlobalVolume > 256) m_nDefaultGlobalVolume = 256;
201 }
202 if (pifh.speed) m_nDefaultSpeed = pifh.speed;
203 if (pifh.tempo) m_nDefaultTempo = pifh.tempo;
204 m_nSongPreAmp = pifh.mv & 0x7F;
205 // Reading Channels Pan Positions
206 for (int ipan=0; ipan<64; ipan++) if (pifh.chnpan[ipan] != 0xFF)
207 {
208 ChnSettings[ipan].nVolume = pifh.chnvol[ipan];
209 ChnSettings[ipan].nPan = 128;
210 if (pifh.chnpan[ipan] & 0x80) ChnSettings[ipan].dwFlags |= CHN_MUTE;
211 UINT n = pifh.chnpan[ipan] & 0x7F;
212 if (n <= 64) ChnSettings[ipan].nPan = n << 2;
213 if (n == 100) ChnSettings[ipan].dwFlags |= CHN_SURROUND;
214 }
215 if (m_nChannels < 4) m_nChannels = 4;
216 // Reading Song Message
217 if ((pifh.special & 0x01) && (pifh.msglength) && (pifh.msgoffset + pifh.msglength < dwMemLength))
218 {
219 m_lpszSongComments = new char[pifh.msglength+1];
220 if (m_lpszSongComments)
221 {
222 memcpy(m_lpszSongComments, lpStream+pifh.msgoffset, pifh.msglength);
223 m_lpszSongComments[pifh.msglength] = 0;
224 }
225 }
226 // Reading orders
227 UINT nordsize = pifh.ordnum;
228 if (nordsize > MAX_ORDERS) nordsize = MAX_ORDERS;
229 memcpy(Order, lpStream+dwMemPos, nordsize);
230 dwMemPos += pifh.ordnum;
231 // Reading Instrument Offsets
232 memset(inspos, 0, sizeof(inspos));
233 UINT inspossize = pifh.insnum;
234 if (inspossize > MAX_INSTRUMENTS) inspossize = MAX_INSTRUMENTS;
235 inspossize <<= 2;
236 memcpy(inspos, lpStream+dwMemPos, inspossize);
237 for (UINT j=0; j < (inspossize>>2); j++)
238 {
239 inspos[j] = bswapLE32(inspos[j]);
240 }
241 dwMemPos += pifh.insnum * 4;
242 // Reading Samples Offsets
243 memset(smppos, 0, sizeof(smppos));
244 UINT smppossize = pifh.smpnum;
245 if (smppossize > MAX_SAMPLES) smppossize = MAX_SAMPLES;
246 smppossize <<= 2;
247 memcpy(smppos, lpStream+dwMemPos, smppossize);
248 for (UINT j=0; j < (smppossize>>2); j++)
249 {
250 smppos[j] = bswapLE32(smppos[j]);
251 }
252 dwMemPos += pifh.smpnum * 4;
253 // Reading Patterns Offsets
254 memset(patpos, 0, sizeof(patpos));
255 UINT patpossize = pifh.patnum;
256 if (patpossize > MAX_PATTERNS) patpossize = MAX_PATTERNS;
257 patpossize <<= 2;
258 memcpy(patpos, lpStream+dwMemPos, patpossize);
259 for (UINT j=0; j < (patpossize>>2); j++)
260 {
261 patpos[j] = bswapLE32(patpos[j]);
262 }
263 dwMemPos += pifh.patnum * 4;
264 // Reading IT Extra Info
265 if (dwMemPos + 2 < dwMemLength)
266 {
267 UINT nflt = bswapLE16(*((WORD *)(lpStream + dwMemPos)));
268 dwMemPos += 2;
269 if (dwMemPos + nflt * 8 < dwMemLength) dwMemPos += nflt * 8;
270 }
271 // Reading Midi Output & Macros
272 if (m_dwSongFlags & SONG_EMBEDMIDICFG)
273 {
274 if (dwMemPos + sizeof(MODMIDICFG) < dwMemLength)
275 {
276 memcpy(&m_MidiCfg, lpStream+dwMemPos, sizeof(MODMIDICFG));
277 dwMemPos += sizeof(MODMIDICFG);
278 }
279 }
280 // Read pattern names: "PNAM"
281 if ((dwMemPos + 8 < dwMemLength) && (bswapLE32(*((DWORD *)(lpStream+dwMemPos))) == 0x4d414e50))
282 {
283 UINT len = bswapLE32(*((DWORD *)(lpStream+dwMemPos+4)));
284 dwMemPos += 8;
285 if ((dwMemPos + len <= dwMemLength) && (len <= MAX_PATTERNS*MAX_PATTERNNAME) && (len >= MAX_PATTERNNAME))
286 {
287 m_lpszPatternNames = new char[len];
288 if (m_lpszPatternNames)
289 {
290 m_nPatternNames = len / MAX_PATTERNNAME;
291 memcpy(m_lpszPatternNames, lpStream+dwMemPos, len);
292 }
293 dwMemPos += len;
294 }
295 }
296 // 4-channels minimum
297 m_nChannels = 4;
298 // Read channel names: "CNAM"
299 if ((dwMemPos + 8 < dwMemLength) && (bswapLE32(*((DWORD *)(lpStream+dwMemPos))) == 0x4d414e43))
300 {
301 UINT len = bswapLE32(*((DWORD *)(lpStream+dwMemPos+4)));
302 dwMemPos += 8;
303 if ((dwMemPos + len <= dwMemLength) && (len <= 64*MAX_CHANNELNAME))
304 {
305 UINT n = len / MAX_CHANNELNAME;
306 if (n > m_nChannels) m_nChannels = n;
307 for (UINT i=0; i<n; i++)
308 {
309 memcpy(ChnSettings[i].szName, (lpStream+dwMemPos+i*MAX_CHANNELNAME), MAX_CHANNELNAME);
310 ChnSettings[i].szName[MAX_CHANNELNAME-1] = 0;
311 }
312 dwMemPos += len;
313 }
314 }
315 // Read mix plugins information
316 if (dwMemPos + 8 < dwMemLength)
317 {
318 dwMemPos += LoadMixPlugins(lpStream+dwMemPos, dwMemLength-dwMemPos);
319 }
320 // Checking for unused channels
321 UINT npatterns = pifh.patnum;
322 if (npatterns > MAX_PATTERNS) npatterns = MAX_PATTERNS;
323 for (UINT patchk=0; patchk<npatterns; patchk++)
324 {
325 memset(chnmask, 0, sizeof(chnmask));
326 if ((!patpos[patchk]) || ((DWORD)patpos[patchk] + 4 >= dwMemLength)) continue;
327 UINT len = bswapLE16(*((WORD *)(lpStream+patpos[patchk])));
328 UINT rows = bswapLE16(*((WORD *)(lpStream+patpos[patchk]+2)));
329 if ((rows < 4) || (rows > 256)) continue;
330 if (patpos[patchk]+8+len > dwMemLength) continue;
331 UINT i = 0;
332 const BYTE *p = lpStream+patpos[patchk]+8;
333 UINT nrow = 0;
334 while (nrow<rows)
335 {
336 if (i >= len) break;
337 BYTE b = p[i++];
338 if (!b)
339 {
340 nrow++;
341 continue;
342 }
343 UINT ch = b & 0x7F;
344 if (ch) ch = (ch - 1) & 0x3F;
345 if (b & 0x80)
346 {
347 if (i >= len) break;
348 chnmask[ch] = p[i++];
349 }
350 // Channel used
351 if (chnmask[ch] & 0x0F)
352 {
353 if ((ch >= m_nChannels) && (ch < 64)) m_nChannels = ch+1;
354 }
355 // Note
356 if (chnmask[ch] & 1) i++;
357 // Instrument
358 if (chnmask[ch] & 2) i++;
359 // Volume
360 if (chnmask[ch] & 4) i++;
361 // Effect
362 if (chnmask[ch] & 8) i += 2;
363 if (i >= len) break;
364 }
365 }
366 // Reading Instruments
367 m_nInstruments = 0;
368 if (pifh.flags & 0x04) m_nInstruments = pifh.insnum;
369 if (m_nInstruments >= MAX_INSTRUMENTS) m_nInstruments = MAX_INSTRUMENTS-1;
370 for (UINT nins=0; nins<m_nInstruments; nins++)
371 {
372 if ((inspos[nins] > 0) && (inspos[nins] < dwMemLength - sizeof(ITOLDINSTRUMENT)))
373 {
374 INSTRUMENTHEADER *penv = new INSTRUMENTHEADER;
375 if (!penv) continue;
376 Headers[nins+1] = penv;
377 memset(penv, 0, sizeof(INSTRUMENTHEADER));
378 ITInstrToMPT(lpStream + inspos[nins], penv, pifh.cmwt);
379 }
380 }
381 // Reading Samples
382 m_nSamples = pifh.smpnum;
383 if (m_nSamples >= MAX_SAMPLES) m_nSamples = MAX_SAMPLES-1;
384 for (UINT nsmp=0; nsmp<pifh.smpnum; nsmp++) if ((smppos[nsmp]) && (smppos[nsmp] + sizeof(ITSAMPLESTRUCT) <= dwMemLength))
385 {
386 ITSAMPLESTRUCT pis = *(ITSAMPLESTRUCT *)(lpStream+smppos[nsmp]);
387 pis.id = bswapLE32(pis.id);
388 pis.length = bswapLE32(pis.length);
389 pis.loopbegin = bswapLE32(pis.loopbegin);
390 pis.loopend = bswapLE32(pis.loopend);
391 pis.C5Speed = bswapLE32(pis.C5Speed);
392 pis.susloopbegin = bswapLE32(pis.susloopbegin);
393 pis.susloopend = bswapLE32(pis.susloopend);
394 pis.samplepointer = bswapLE32(pis.samplepointer);
395
396 if (pis.id == 0x53504D49)
397 {
398 MODINSTRUMENT *pins = &Ins[nsmp+1];
399 memcpy(pins->name, pis.filename, 12);
400 pins->uFlags = 0;
401 pins->nLength = 0;
402 pins->nLoopStart = pis.loopbegin;
403 pins->nLoopEnd = pis.loopend;
404 pins->nSustainStart = pis.susloopbegin;
405 pins->nSustainEnd = pis.susloopend;
406 pins->nC4Speed = pis.C5Speed;
407 if (!pins->nC4Speed) pins->nC4Speed = 8363;
408 if (pis.C5Speed < 256) pins->nC4Speed = 256;
409 pins->nVolume = pis.vol << 2;
410 if (pins->nVolume > 256) pins->nVolume = 256;
411 pins->nGlobalVol = pis.gvl;
412 if (pins->nGlobalVol > 64) pins->nGlobalVol = 64;
413 if (pis.flags & 0x10) pins->uFlags |= CHN_LOOP;
414 if (pis.flags & 0x20) pins->uFlags |= CHN_SUSTAINLOOP;
415 if (pis.flags & 0x40) pins->uFlags |= CHN_PINGPONGLOOP;
416 if (pis.flags & 0x80) pins->uFlags |= CHN_PINGPONGSUSTAIN;
417 pins->nPan = (pis.dfp & 0x7F) << 2;
418 if (pins->nPan > 256) pins->nPan = 256;
419 if (pis.dfp & 0x80) pins->uFlags |= CHN_PANNING;
420 pins->nVibType = autovibit2xm[pis.vit & 7];
421 pins->nVibRate = pis.vis;
422 pins->nVibDepth = pis.vid & 0x7F;
423 pins->nVibSweep = (pis.vir + 3) / 4;
424 if ((pis.samplepointer) && (pis.samplepointer < dwMemLength) && (pis.length))
425 {
426 pins->nLength = pis.length;
427 if (pins->nLength > MAX_SAMPLE_LENGTH) pins->nLength = MAX_SAMPLE_LENGTH;
428 UINT flags = (pis.cvt & 1) ? RS_PCM8S : RS_PCM8U;
429 if (pis.flags & 2)
430 {
431 flags += 5;
432 if (pis.flags & 4) flags |= RSF_STEREO;
433 pins->uFlags |= CHN_16BIT;
434 // IT 2.14 16-bit packed sample ?
435 if (pis.flags & 8) flags = ((pifh.cmwt >= 0x215) && (pis.cvt & 4)) ? RS_IT21516 : RS_IT21416;
436 } else
437 {
438 if (pis.flags & 4) flags |= RSF_STEREO;
439 if (pis.cvt == 0xFF) flags = RS_ADPCM4; else
440 // IT 2.14 8-bit packed sample ?
441 if (pis.flags & 8) flags =((pifh.cmwt >= 0x215) && (pis.cvt & 4)) ? RS_IT2158 : RS_IT2148;
442 }
443 ReadSample(&Ins[nsmp+1], flags, (LPSTR)(lpStream+pis.samplepointer), dwMemLength - pis.samplepointer);
444 }
445 }
446 memcpy(m_szNames[nsmp+1], pis.name, 26);
447 }
448 // Reading Patterns
449 for (UINT npat=0; npat<npatterns; npat++)
450 {
451 if ((!patpos[npat]) || ((DWORD)patpos[npat] + 4 >= dwMemLength))
452 {
453 PatternSize[npat] = 64;
454 Patterns[npat] = AllocatePattern(64, m_nChannels);
455 continue;
456 }
457
458 UINT len = bswapLE16(*((WORD *)(lpStream+patpos[npat])));
459 UINT rows = bswapLE16(*((WORD *)(lpStream+patpos[npat]+2)));
460 if ((rows < 4) || (rows > 256)) continue;
461 if (patpos[npat]+8+len > dwMemLength) continue;
462 PatternSize[npat] = rows;
463 if ((Patterns[npat] = AllocatePattern(rows, m_nChannels)) == NULL) continue;
464 memset(lastvalue, 0, sizeof(lastvalue));
465 memset(chnmask, 0, sizeof(chnmask));
466 MODCOMMAND *m = Patterns[npat];
467 UINT i = 0;
468 const BYTE *p = lpStream+patpos[npat]+8;
469 UINT nrow = 0;
470 while (nrow<rows)
471 {
472 if (i >= len) break;
473 BYTE b = p[i++];
474 if (!b)
475 {
476 nrow++;
477 m+=m_nChannels;
478 continue;
479 }
480 UINT ch = b & 0x7F;
481 if (ch) ch = (ch - 1) & 0x3F;
482 if (b & 0x80)
483 {
484 if (i >= len) break;
485 chnmask[ch] = p[i++];
486 }
487 if ((chnmask[ch] & 0x10) && (ch < m_nChannels))
488 {
489 m[ch].note = lastvalue[ch].note;
490 }
491 if ((chnmask[ch] & 0x20) && (ch < m_nChannels))
492 {
493 m[ch].instr = lastvalue[ch].instr;
494 }
495 if ((chnmask[ch] & 0x40) && (ch < m_nChannels))
496 {
497 m[ch].volcmd = lastvalue[ch].volcmd;
498 m[ch].vol = lastvalue[ch].vol;
499 }
500 if ((chnmask[ch] & 0x80) && (ch < m_nChannels))
501 {
502 m[ch].command = lastvalue[ch].command;
503 m[ch].param = lastvalue[ch].param;
504 }
505 if (chnmask[ch] & 1)// Note
506 {
507 if (i >= len) break;
508 UINT note = p[i++];
509 if (ch < m_nChannels)
510 {
511 if (note < 0x80) note++;
512 m[ch].note = note;
513 lastvalue[ch].note = note;
514 channels_used[ch] = TRUE;
515 }
516 }
517 if (chnmask[ch] & 2)
518 {
519 if (i >= len) break;
520 UINT instr = p[i++];
521 if (ch < m_nChannels)
522 {
523 m[ch].instr = instr;
524 lastvalue[ch].instr = instr;
525 }
526 }
527 if (chnmask[ch] & 4)
528 {
529 if (i >= len) break;
530 UINT vol = p[i++];
531 if (ch < m_nChannels)
532 {
533 // 0-64: Set Volume
534 if (vol <= 64) { m[ch].volcmd = VOLCMD_VOLUME; m[ch].vol = vol; } else
535 // 128-192: Set Panning
536 if ((vol >= 128) && (vol <= 192)) { m[ch].volcmd = VOLCMD_PANNING; m[ch].vol = vol - 128; } else
537 // 65-74: Fine Volume Up
538 if (vol < 75) { m[ch].volcmd = VOLCMD_FINEVOLUP; m[ch].vol = vol - 65; } else
539 // 75-84: Fine Volume Down
540 if (vol < 85) { m[ch].volcmd = VOLCMD_FINEVOLDOWN; m[ch].vol = vol - 75; } else
541 // 85-94: Volume Slide Up
542 if (vol < 95) { m[ch].volcmd = VOLCMD_VOLSLIDEUP; m[ch].vol = vol - 85; } else
543 // 95-104: Volume Slide Down
544 if (vol < 105) { m[ch].volcmd = VOLCMD_VOLSLIDEDOWN; m[ch].vol = vol - 95; } else
545 // 105-114: Pitch Slide Up
546 if (vol < 115) { m[ch].volcmd = VOLCMD_PORTADOWN; m[ch].vol = vol - 105; } else
547 // 115-124: Pitch Slide Down
548 if (vol < 125) { m[ch].volcmd = VOLCMD_PORTAUP; m[ch].vol = vol - 115; } else
549 // 193-202: Portamento To
550 if ((vol >= 193) && (vol <= 202)) { m[ch].volcmd = VOLCMD_TONEPORTAMENTO; m[ch].vol = vol - 193; } else
551 // 203-212: Vibrato
552 if ((vol >= 203) && (vol <= 212)) { m[ch].volcmd = VOLCMD_VIBRATOSPEED; m[ch].vol = vol - 203; }
553 lastvalue[ch].volcmd = m[ch].volcmd;
554 lastvalue[ch].vol = m[ch].vol;
555 }
556 }
557 // Reading command/param
558 if (chnmask[ch] & 8)
559 {
560 if (i > len - 2) break;
561 UINT cmd = p[i++];
562 UINT param = p[i++];
563 if (ch < m_nChannels)
564 {
565 if (cmd)
566 {
567 m[ch].command = cmd;
568 m[ch].param = param;
569 S3MConvert(&m[ch], TRUE);
570 lastvalue[ch].command = m[ch].command;
571 lastvalue[ch].param = m[ch].param;
572 }
573 }
574 }
575 }
576 }
577 for (UINT ncu=0; ncu<MAX_BASECHANNELS; ncu++)
578 {
579 if (ncu>=m_nChannels)
580 {
581 ChnSettings[ncu].nVolume = 64;
582 ChnSettings[ncu].dwFlags &= ~CHN_MUTE;
583 }
584 }
585 m_nMinPeriod = 8;
586 m_nMaxPeriod = 0xF000;
587 return TRUE;
588}
589
590
591#ifndef MODPLUG_NO_FILESAVE
592//#define SAVEITTIMESTAMP
593#pragma warning(disable:4100)
594
595BOOL CSoundFile::SaveIT(LPCSTR lpszFileName, UINT nPacking)
596//---------------------------------------------------------
597{
598 DWORD dwPatNamLen, dwChnNamLen;
599 ITFILEHEADER header;
600 ITINSTRUMENT iti;
601 ITSAMPLESTRUCT itss;
602 BYTE smpcount[MAX_SAMPLES];
603 DWORD inspos[MAX_INSTRUMENTS];
604 DWORD patpos[MAX_PATTERNS];
605 DWORD smppos[MAX_SAMPLES];
606 DWORD dwPos = 0, dwHdrPos = 0, dwExtra = 2;
607 WORD patinfo[4];
608 BYTE chnmask[64];
609 BYTE buf[512];
610 MODCOMMAND lastvalue[64];
611 FILE *f;
612
613
614 if ((!lpszFileName) || ((f = fopen(lpszFileName, "wb")) == NULL)) return FALSE;
615 memset(inspos, 0, sizeof(inspos));
616 memset(patpos, 0, sizeof(patpos));
617 memset(smppos, 0, sizeof(smppos));
618 // Writing Header
619 memset(&header, 0, sizeof(header));
620 dwPatNamLen = 0;
621 dwChnNamLen = 0;
622 header.id = 0x4D504D49;
623 lstrcpyn(header.songname, m_szNames[0], 27);
624 header.reserved1 = 0x1004;
625 header.ordnum = 0;
626 while ((header.ordnum < MAX_ORDERS) && (Order[header.ordnum] < 0xFF)) header.ordnum++;
627 if (header.ordnum < MAX_ORDERS) Order[header.ordnum++] = 0xFF;
628 header.insnum = m_nInstruments;
629 header.smpnum = m_nSamples;
630 header.patnum = MAX_PATTERNS;
631 while ((header.patnum > 0) && (!Patterns[header.patnum-1])) header.patnum--;
632 header.cwtv = 0x217;
633 header.cmwt = 0x200;
634 header.flags = 0x0001;
635 header.special = 0x0006;
636 if (m_nInstruments) header.flags |= 0x04;
637 if (m_dwSongFlags & SONG_LINEARSLIDES) header.flags |= 0x08;
638 if (m_dwSongFlags & SONG_ITOLDEFFECTS) header.flags |= 0x10;
639 if (m_dwSongFlags & SONG_ITCOMPATMODE) header.flags |= 0x20;
640 if (m_dwSongFlags & SONG_EXFILTERRANGE) header.flags |= 0x1000;
641 header.globalvol = m_nDefaultGlobalVolume >> 1;
642 header.mv = m_nSongPreAmp;
643 if (header.mv < 0x20) header.mv = 0x20;
644 if (header.mv > 0x7F) header.mv = 0x7F;
645 header.speed = m_nDefaultSpeed;
646 header.tempo = m_nDefaultTempo;
647 header.sep = 128;
648 dwHdrPos = sizeof(header) + header.ordnum;
649 // Channel Pan and Volume
650 memset(header.chnpan, 0xFF, 64);
651 memset(header.chnvol, 64, 64);
652 for (UINT ich=0; ich<m_nChannels; ich++)
653 {
654 header.chnpan[ich] = ChnSettings[ich].nPan >> 2;
655 if (ChnSettings[ich].dwFlags & CHN_SURROUND) header.chnpan[ich] = 100;
656 header.chnvol[ich] = ChnSettings[ich].nVolume;
657 if (ChnSettings[ich].dwFlags & CHN_MUTE) header.chnpan[ich] |= 0x80;
658 if (ChnSettings[ich].szName[0])
659 {
660 dwChnNamLen = (ich+1) * MAX_CHANNELNAME;
661 }
662 }
663 if (dwChnNamLen) dwExtra += dwChnNamLen + 8;
664#ifdef SAVEITTIMESTAMP
665 dwExtra += 8; // Time Stamp
666#endif
667 if (m_dwSongFlags & SONG_EMBEDMIDICFG)
668 {
669 header.flags |= 0x80;
670 header.special |= 0x08;
671 dwExtra += sizeof(MODMIDICFG);
672 }
673 // Pattern Names
674 if ((m_nPatternNames) && (m_lpszPatternNames))
675 {
676 dwPatNamLen = m_nPatternNames * MAX_PATTERNNAME;
677 while ((dwPatNamLen >= MAX_PATTERNNAME) && (!m_lpszPatternNames[dwPatNamLen-MAX_PATTERNNAME])) dwPatNamLen -= MAX_PATTERNNAME;
678 if (dwPatNamLen < MAX_PATTERNNAME) dwPatNamLen = 0;
679 if (dwPatNamLen) dwExtra += dwPatNamLen + 8;
680 }
681 // Mix Plugins
682 dwExtra += SaveMixPlugins(NULL, TRUE);
683 // Comments
684 if (m_lpszSongComments)
685 {
686 header.special |= 1;
687 header.msglength = strlen(m_lpszSongComments)+1;
688 header.msgoffset = dwHdrPos + dwExtra + header.insnum*4 + header.patnum*4 + header.smpnum*4;
689 }
690 // Write file header
691 fwrite(&header, 1, sizeof(header), f);
692 fwrite(Order, 1, header.ordnum, f);
693 if (header.insnum) fwrite(inspos, 4, header.insnum, f);
694 if (header.smpnum) fwrite(smppos, 4, header.smpnum, f);
695 if (header.patnum) fwrite(patpos, 4, header.patnum, f);
696 // Writing editor history information
697 {
698#ifdef SAVEITTIMESTAMP
699 SYSTEMTIME systime;
700 FILETIME filetime;
701 WORD timestamp[4];
702 WORD nInfoEx = 1;
703 memset(timestamp, 0, sizeof(timestamp));
704 fwrite(&nInfoEx, 1, 2, f);
705 GetSystemTime(&systime);
706 SystemTimeToFileTime(&systime, &filetime);
707 FileTimeToDosDateTime(&filetime, &timestamp[0], &timestamp[1]);
708 fwrite(timestamp, 1, 8, f);
709#else
710 WORD nInfoEx = 0;
711 fwrite(&nInfoEx, 1, 2, f);
712#endif
713 }
714 // Writing midi cfg
715 if (header.flags & 0x80)
716 {
717 fwrite(&m_MidiCfg, 1, sizeof(MODMIDICFG), f);
718 }
719 // Writing pattern names
720 if (dwPatNamLen)
721 {
722 DWORD d = 0x4d414e50;
723 fwrite(&d, 1, 4, f);
724 fwrite(&dwPatNamLen, 1, 4, f);
725 fwrite(m_lpszPatternNames, 1, dwPatNamLen, f);
726 }
727 // Writing channel Names
728 if (dwChnNamLen)
729 {
730 DWORD d = 0x4d414e43;
731 fwrite(&d, 1, 4, f);
732 fwrite(&dwChnNamLen, 1, 4, f);
733 UINT nChnNames = dwChnNamLen / MAX_CHANNELNAME;
734 for (UINT inam=0; inam<nChnNames; inam++)
735 {
736 fwrite(ChnSettings[inam].szName, 1, MAX_CHANNELNAME, f);
737 }
738 }
739 // Writing mix plugins info
740 SaveMixPlugins(f, FALSE);
741 // Writing song message
742 dwPos = dwHdrPos + dwExtra + (header.insnum + header.smpnum + header.patnum) * 4;
743 if (header.special & 1)
744 {
745 dwPos += strlen(m_lpszSongComments) + 1;
746 fwrite(m_lpszSongComments, 1, strlen(m_lpszSongComments)+1, f);
747 }
748 // Writing instruments
749 for (UINT nins=1; nins<=header.insnum; nins++)
750 {
751 memset(&iti, 0, sizeof(iti));
752 iti.id = 0x49504D49;// "IMPI"
753 iti.trkvers = 0x211;
754 if (Headers[nins])
755 {
756 INSTRUMENTHEADER *penv = Headers[nins];
757 memset(smpcount, 0, sizeof(smpcount));
758 memcpy(iti.filename, penv->filename, 12);
759 memcpy(iti.name, penv->name, 26);
760 iti.mbank = penv->wMidiBank;
761 iti.mpr = penv->nMidiProgram;
762 iti.mch = penv->nMidiChannel;
763 iti.nna = penv->nNNA;
764 iti.dct = penv->nDCT;
765 iti.dca = penv->nDNA;
766 iti.fadeout = penv->nFadeOut >> 5;
767 iti.pps = penv->nPPS;
768 iti.ppc = penv->nPPC;
769 iti.gbv = (BYTE)(penv->nGlobalVol << 1);
770 iti.dfp = (BYTE)penv->nPan >> 2;
771 if (!(penv->dwFlags & ENV_SETPANNING)) iti.dfp |= 0x80;
772 iti.rv = penv->nVolSwing;
773 iti.rp = penv->nPanSwing;
774 iti.ifc = penv->nIFC;
775 iti.ifr = penv->nIFR;
776 iti.nos = 0;
777 for (UINT i=0; i<120; i++) if (penv->Keyboard[i] < MAX_SAMPLES)
778 {
779 UINT smp = penv->Keyboard[i];
780 if ((smp) && (!smpcount[smp]))
781 {
782 smpcount[smp] = 1;
783 iti.nos++;
784 }
785 iti.keyboard[i*2] = penv->NoteMap[i] - 1;
786 iti.keyboard[i*2+1] = smp;
787 }
788 // Writing Volume envelope
789 if (penv->dwFlags & ENV_VOLUME) iti.volenv.flags |= 0x01;
790 if (penv->dwFlags & ENV_VOLLOOP) iti.volenv.flags |= 0x02;
791 if (penv->dwFlags & ENV_VOLSUSTAIN) iti.volenv.flags |= 0x04;
792 if (penv->dwFlags & ENV_VOLCARRY) iti.volenv.flags |= 0x08;
793 iti.volenv.num = (BYTE)penv->nVolEnv;
794 iti.volenv.lpb = (BYTE)penv->nVolLoopStart;
795 iti.volenv.lpe = (BYTE)penv->nVolLoopEnd;
796 iti.volenv.slb = penv->nVolSustainBegin;
797 iti.volenv.sle = penv->nVolSustainEnd;
798 // Writing Panning envelope
799 if (penv->dwFlags & ENV_PANNING) iti.panenv.flags |= 0x01;
800 if (penv->dwFlags & ENV_PANLOOP) iti.panenv.flags |= 0x02;
801 if (penv->dwFlags & ENV_PANSUSTAIN) iti.panenv.flags |= 0x04;
802 if (penv->dwFlags & ENV_PANCARRY) iti.panenv.flags |= 0x08;
803 iti.panenv.num = (BYTE)penv->nPanEnv;
804 iti.panenv.lpb = (BYTE)penv->nPanLoopStart;
805 iti.panenv.lpe = (BYTE)penv->nPanLoopEnd;
806 iti.panenv.slb = penv->nPanSustainBegin;
807 iti.panenv.sle = penv->nPanSustainEnd;
808 // Writing Pitch Envelope
809 if (penv->dwFlags & ENV_PITCH) iti.pitchenv.flags |= 0x01;
810 if (penv->dwFlags & ENV_PITCHLOOP) iti.pitchenv.flags |= 0x02;
811 if (penv->dwFlags & ENV_PITCHSUSTAIN) iti.pitchenv.flags |= 0x04;
812 if (penv->dwFlags & ENV_PITCHCARRY) iti.pitchenv.flags |= 0x08;
813 if (penv->dwFlags & ENV_FILTER) iti.pitchenv.flags |= 0x80;
814 iti.pitchenv.num = (BYTE)penv->nPitchEnv;
815 iti.pitchenv.lpb = (BYTE)penv->nPitchLoopStart;
816 iti.pitchenv.lpe = (BYTE)penv->nPitchLoopEnd;
817 iti.pitchenv.slb = (BYTE)penv->nPitchSustainBegin;
818 iti.pitchenv.sle = (BYTE)penv->nPitchSustainEnd;
819 // Writing Envelopes data
820 for (UINT ev=0; ev<25; ev++)
821 {
822 iti.volenv.data[ev*3] = penv->VolEnv[ev];
823 iti.volenv.data[ev*3+1] = penv->VolPoints[ev] & 0xFF;
824 iti.volenv.data[ev*3+2] = penv->VolPoints[ev] >> 8;
825 iti.panenv.data[ev*3] = penv->PanEnv[ev] - 32;
826 iti.panenv.data[ev*3+1] = penv->PanPoints[ev] & 0xFF;
827 iti.panenv.data[ev*3+2] = penv->PanPoints[ev] >> 8;
828 iti.pitchenv.data[ev*3] = penv->PitchEnv[ev] - 32;
829 iti.pitchenv.data[ev*3+1] = penv->PitchPoints[ev] & 0xFF;
830 iti.pitchenv.data[ev*3+2] = penv->PitchPoints[ev] >> 8;
831 }
832 } else
833 // Save Empty Instrument
834 {
835 for (UINT i=0; i<120; i++) iti.keyboard[i*2] = i;
836 iti.ppc = 5*12;
837 iti.gbv = 128;
838 iti.dfp = 0x20;
839 iti.ifc = 0xFF;
840 }
841 if (!iti.nos) iti.trkvers = 0;
842 // Writing instrument
843 inspos[nins-1] = dwPos;
844 dwPos += sizeof(ITINSTRUMENT);
845 fwrite(&iti, 1, sizeof(ITINSTRUMENT), f);
846 }
847 // Writing sample headers
848 memset(&itss, 0, sizeof(itss));
849 for (UINT hsmp=0; hsmp<header.smpnum; hsmp++)
850 {
851 smppos[hsmp] = dwPos;
852 dwPos += sizeof(ITSAMPLESTRUCT);
853 fwrite(&itss, 1, sizeof(ITSAMPLESTRUCT), f);
854 }
855 // Writing Patterns
856 for (UINT npat=0; npat<header.patnum; npat++)
857 {
858 DWORD dwPatPos = dwPos;
859 UINT len;
860 if (!Patterns[npat]) continue;
861 patpos[npat] = dwPos;
862 patinfo[0] = 0;
863 patinfo[1] = PatternSize[npat];
864 patinfo[2] = 0;
865 patinfo[3] = 0;
866 // Check for empty pattern
867 if (PatternSize[npat] == 64)
868 {
869 MODCOMMAND *pzc = Patterns[npat];
870 UINT nz = PatternSize[npat] * m_nChannels;
871 for (UINT iz=0; iz<nz; iz++)
872 {
873 if ((pzc[iz].note) || (pzc[iz].instr)
874 || (pzc[iz].volcmd) || (pzc[iz].command)) break;
875 }
876 if (iz == nz)
877 {
878 patpos[npat] = 0;
879 continue;
880 }
881 }
882 fwrite(patinfo, 8, 1, f);
883 dwPos += 8;
884 memset(chnmask, 0xFF, sizeof(chnmask));
885 memset(lastvalue, 0, sizeof(lastvalue));
886 MODCOMMAND *m = Patterns[npat];
887 for (UINT row=0; row<PatternSize[npat]; row++)
888 {
889 len = 0;
890 for (UINT ch=0; ch<m_nChannels; ch++, m++)
891 {
892 BYTE b = 0;
893 UINT command = m->command;
894 UINT param = m->param;
895 UINT vol = 0xFF;
896 UINT note = m->note;
897 if (note) b |= 1;
898 if ((note) && (note < 0xFE)) note--;
899 if (m->instr) b |= 2;
900 if (m->volcmd)
901 {
902 UINT volcmd = m->volcmd;
903 switch(volcmd)
904 {
905 case VOLCMD_VOLUME: vol = m->vol; if (vol > 64) vol = 64; break;
906 case VOLCMD_PANNING: vol = m->vol + 128; if (vol > 192) vol = 192; break;
907 case VOLCMD_VOLSLIDEUP: vol = 85 + ConvertVolParam(m->vol); break;
908 case VOLCMD_VOLSLIDEDOWN:vol = 95 + ConvertVolParam(m->vol); break;
909 case VOLCMD_FINEVOLUP: vol = 65 + ConvertVolParam(m->vol); break;
910 case VOLCMD_FINEVOLDOWN:vol = 75 + ConvertVolParam(m->vol); break;
911 case VOLCMD_VIBRATO: vol = 203; break;
912 case VOLCMD_VIBRATOSPEED:vol = 203 + ConvertVolParam(m->vol); break;
913 case VOLCMD_TONEPORTAMENTO:vol = 193 + ConvertVolParam(m->vol); break;
914 case VOLCMD_PORTADOWN: vol = 105 + ConvertVolParam(m->vol); break;
915 case VOLCMD_PORTAUP: vol = 115 + ConvertVolParam(m->vol); break;
916 default: vol = 0xFF;
917 }
918 }
919 if (vol != 0xFF) b |= 4;
920 if (command)
921 {
922 S3MSaveConvert(&command, &param, TRUE);
923 if (command) b |= 8;
924 }
925 // Packing information
926 if (b)
927 {
928 // Same note ?
929 if (b & 1)
930 {
931 if ((note == lastvalue[ch].note) && (lastvalue[ch].volcmd & 1))
932 {
933 b &= ~1;
934 b |= 0x10;
935 } else
936 {
937 lastvalue[ch].note = note;
938 lastvalue[ch].volcmd |= 1;
939 }
940 }
941 // Same instrument ?
942 if (b & 2)
943 {
944 if ((m->instr == lastvalue[ch].instr) && (lastvalue[ch].volcmd & 2))
945 {
946 b &= ~2;
947 b |= 0x20;
948 } else
949 {
950 lastvalue[ch].instr = m->instr;
951 lastvalue[ch].volcmd |= 2;
952 }
953 }
954 // Same volume column byte ?
955 if (b & 4)
956 {
957 if ((vol == lastvalue[ch].vol) && (lastvalue[ch].volcmd & 4))
958 {
959 b &= ~4;
960 b |= 0x40;
961 } else
962 {
963 lastvalue[ch].vol = vol;
964 lastvalue[ch].volcmd |= 4;
965 }
966 }
967 // Same command / param ?
968 if (b & 8)
969 {
970 if ((command == lastvalue[ch].command) && (param == lastvalue[ch].param) && (lastvalue[ch].volcmd & 8))
971 {
972 b &= ~8;
973 b |= 0x80;
974 } else
975 {
976 lastvalue[ch].command = command;
977 lastvalue[ch].param = param;
978 lastvalue[ch].volcmd |= 8;
979 }
980 }
981 if (b != chnmask[ch])
982 {
983 chnmask[ch] = b;
984 buf[len++] = (ch+1) | 0x80;
985 buf[len++] = b;
986 } else
987 {
988 buf[len++] = ch+1;
989 }
990 if (b & 1) buf[len++] = note;
991 if (b & 2) buf[len++] = m->instr;
992 if (b & 4) buf[len++] = vol;
993 if (b & 8)
994 {
995 buf[len++] = command;
996 buf[len++] = param;
997 }
998 }
999 }
1000 buf[len++] = 0;
1001 dwPos += len;
1002 patinfo[0] += len;
1003 fwrite(buf, 1, len, f);
1004 }
1005 fseek(f, dwPatPos, SEEK_SET);
1006 fwrite(patinfo, 8, 1, f);
1007 fseek(f, dwPos, SEEK_SET);
1008 }
1009 // Writing Sample Data
1010 for (UINT nsmp=1; nsmp<=header.smpnum; nsmp++)
1011 {
1012 MODINSTRUMENT *psmp = &Ins[nsmp];
1013 memset(&itss, 0, sizeof(itss));
1014 memcpy(itss.filename, psmp->name, 12);
1015 memcpy(itss.name, m_szNames[nsmp], 26);
1016 itss.id = 0x53504D49;
1017 itss.gvl = (BYTE)psmp->nGlobalVol;
1018 if (m_nInstruments)
1019 {
1020 for (UINT iu=1; iu<=m_nInstruments; iu++) if (Headers[iu])
1021 {
1022 INSTRUMENTHEADER *penv = Headers[iu];
1023 for (UINT ju=0; ju<128; ju++) if (penv->Keyboard[ju] == nsmp)
1024 {
1025 itss.flags = 0x01;
1026 break;
1027 }
1028 }
1029 } else
1030 {
1031 itss.flags = 0x01;
1032 }
1033 if (psmp->uFlags & CHN_LOOP) itss.flags |= 0x10;
1034 if (psmp->uFlags & CHN_SUSTAINLOOP) itss.flags |= 0x20;
1035 if (psmp->uFlags & CHN_PINGPONGLOOP) itss.flags |= 0x40;
1036 if (psmp->uFlags & CHN_PINGPONGSUSTAIN) itss.flags |= 0x80;
1037 itss.C5Speed = psmp->nC4Speed;
1038 if (!itss.C5Speed) itss.C5Speed = 8363;
1039 itss.length = psmp->nLength;
1040 itss.loopbegin = psmp->nLoopStart;
1041 itss.loopend = psmp->nLoopEnd;
1042 itss.susloopbegin = psmp->nSustainStart;
1043 itss.susloopend = psmp->nSustainEnd;
1044 itss.vol = psmp->nVolume >> 2;
1045 itss.dfp = psmp->nPan >> 2;
1046 itss.vit = autovibxm2it[psmp->nVibType & 7];
1047 itss.vis = psmp->nVibRate;
1048 itss.vid = psmp->nVibDepth;
1049 itss.vir = (psmp->nVibSweep < 64) ? psmp->nVibSweep * 4 : 255;
1050 if (psmp->uFlags & CHN_PANNING) itss.dfp |= 0x80;
1051 if ((psmp->pSample) && (psmp->nLength)) itss.cvt = 0x01;
1052 UINT flags = RS_PCM8S;
1053#ifndef NO_PACKING
1054 if (nPacking)
1055 {
1056 if ((!(psmp->uFlags & (CHN_16BIT|CHN_STEREO)))
1057 && (CanPackSample(psmp->pSample, psmp->nLength, nPacking)))
1058 {
1059 flags = RS_ADPCM4;
1060 itss.cvt = 0xFF;
1061 }
1062 } else
1063#endif // NO_PACKING
1064 {
1065 if (psmp->uFlags & CHN_STEREO)
1066 {
1067 flags = RS_STPCM8S;
1068 itss.flags |= 0x04;
1069 }
1070 if (psmp->uFlags & CHN_16BIT)
1071 {
1072 itss.flags |= 0x02;
1073 flags = (psmp->uFlags & CHN_STEREO) ? RS_STPCM16S : RS_PCM16S;
1074 }
1075 }
1076 itss.samplepointer = dwPos;
1077 fseek(f, smppos[nsmp-1], SEEK_SET);
1078 fwrite(&itss, 1, sizeof(ITSAMPLESTRUCT), f);
1079 fseek(f, dwPos, SEEK_SET);
1080 if ((psmp->pSample) && (psmp->nLength))
1081 {
1082 dwPos += WriteSample(f, psmp, flags);
1083 }
1084 }
1085 // Updating offsets
1086 fseek(f, dwHdrPos, SEEK_SET);
1087 if (header.insnum) fwrite(inspos, 4, header.insnum, f);
1088 if (header.smpnum) fwrite(smppos, 4, header.smpnum, f);
1089 if (header.patnum) fwrite(patpos, 4, header.patnum, f);
1090 fclose(f);
1091 return TRUE;
1092}
1093
1094#pragma warning(default:4100)
1095#endif // MODPLUG_NO_FILESAVE
1096
1097//////////////////////////////////////////////////////////////////////////////
1098// IT 2.14 compression
1099
1100DWORD ITReadBits(DWORD &bitbuf, UINT &bitnum, LPBYTE &ibuf, CHAR n)
1101//-----------------------------------------------------------------
1102{
1103 DWORD retval = 0;
1104 UINT i = n;
1105
1106 if (n > 0)
1107 {
1108 do
1109 {
1110 if (!bitnum)
1111 {
1112 bitbuf = *ibuf++;
1113 bitnum = 8;
1114 }
1115 retval >>= 1;
1116 retval |= bitbuf << 31;
1117 bitbuf >>= 1;
1118 bitnum--;
1119 i--;
1120 } while (i);
1121 i = n;
1122 }
1123 return (retval >> (32-i));
1124}
1125
1126#define IT215_SUPPORT
1127void ITUnpack8Bit(signed char *pSample, DWORD dwLen, LPBYTE lpMemFile, DWORD dwMemLength, BOOL b215)
1128//-------------------------------------------------------------------------------------------
1129{
1130 signed char *pDst = pSample;
1131 LPBYTE pSrc = lpMemFile;
1132 DWORD wHdr = 0;
1133 DWORD wCount = 0;
1134 DWORD bitbuf = 0;
1135 UINT bitnum = 0;
1136 BYTE bLeft = 0, bTemp = 0, bTemp2 = 0;
1137
1138 while (dwLen)
1139 {
1140 if (!wCount)
1141 {
1142 wCount = 0x8000;
1143 wHdr = bswapLE16(*((LPWORD)pSrc));
1144 pSrc += 2;
1145 bLeft = 9;
1146 bTemp = bTemp2 = 0;
1147 bitbuf = bitnum = 0;
1148 }
1149 DWORD d = wCount;
1150 if (d > dwLen) d = dwLen;
1151 // Unpacking
1152 DWORD dwPos = 0;
1153 do
1154 {
1155 WORD wBits = (WORD)ITReadBits(bitbuf, bitnum, pSrc, bLeft);
1156 if (bLeft < 7)
1157 {
1158 DWORD i = 1 << (bLeft-1);
1159 DWORD j = wBits & 0xFFFF;
1160 if (i != j) goto UnpackByte;
1161 wBits = (WORD)(ITReadBits(bitbuf, bitnum, pSrc, 3) + 1) & 0xFF;
1162 bLeft = ((BYTE)wBits < bLeft) ? (BYTE)wBits : (BYTE)((wBits+1) & 0xFF);
1163 goto Next;
1164 }
1165 if (bLeft < 9)
1166 {
1167 WORD i = (0xFF >> (9 - bLeft)) + 4;
1168 WORD j = i - 8;
1169 if ((wBits <= j) || (wBits > i)) goto UnpackByte;
1170 wBits -= j;
1171 bLeft = ((BYTE)(wBits & 0xFF) < bLeft) ? (BYTE)(wBits & 0xFF) : (BYTE)((wBits+1) & 0xFF);
1172 goto Next;
1173 }
1174 if (bLeft >= 10) goto SkipByte;
1175 if (wBits >= 256)
1176 {
1177 bLeft = (BYTE)(wBits + 1) & 0xFF;
1178 goto Next;
1179 }
1180 UnpackByte:
1181 if (bLeft < 8)
1182 {
1183 BYTE shift = 8 - bLeft;
1184 signed char c = (signed char)(wBits << shift);
1185 c >>= shift;
1186 wBits = (WORD)c;
1187 }
1188 wBits += bTemp;
1189 bTemp = (BYTE)wBits;
1190 bTemp2 += bTemp;
1191#ifdef IT215_SUPPORT
1192 pDst[dwPos] = (b215) ? bTemp2 : bTemp;
1193#else
1194 pDst[dwPos] = bTemp;
1195#endif
1196 SkipByte:
1197 dwPos++;
1198 Next:
1199 if (pSrc >= lpMemFile+dwMemLength+1) return;
1200 } while (dwPos < d);
1201 // Move On
1202 wCount -= d;
1203 dwLen -= d;
1204 pDst += d;
1205 }
1206}
1207
1208
1209void ITUnpack16Bit(signed char *pSample, DWORD dwLen, LPBYTE lpMemFile, DWORD dwMemLength, BOOL b215)
1210//--------------------------------------------------------------------------------------------
1211{
1212 signed short *pDst = (signed short *)pSample;
1213 LPBYTE pSrc = lpMemFile;
1214 DWORD wHdr = 0;
1215 DWORD wCount = 0;
1216 DWORD bitbuf = 0;
1217 UINT bitnum = 0;
1218 BYTE bLeft = 0;
1219 signed short wTemp = 0, wTemp2 = 0;
1220
1221 while (dwLen)
1222 {
1223 if (!wCount)
1224 {
1225 wCount = 0x4000;
1226 wHdr = bswapLE16(*((LPWORD)pSrc));
1227 pSrc += 2;
1228 bLeft = 17;
1229 wTemp = wTemp2 = 0;
1230 bitbuf = bitnum = 0;
1231 }
1232 DWORD d = wCount;
1233 if (d > dwLen) d = dwLen;
1234 // Unpacking
1235 DWORD dwPos = 0;
1236 do
1237 {
1238 DWORD dwBits = ITReadBits(bitbuf, bitnum, pSrc, bLeft);
1239 if (bLeft < 7)
1240 {
1241 DWORD i = 1 << (bLeft-1);
1242 DWORD j = dwBits;
1243 if (i != j) goto UnpackByte;
1244 dwBits = ITReadBits(bitbuf, bitnum, pSrc, 4) + 1;
1245 bLeft = ((BYTE)(dwBits & 0xFF) < bLeft) ? (BYTE)(dwBits & 0xFF) : (BYTE)((dwBits+1) & 0xFF);
1246 goto Next;
1247 }
1248 if (bLeft < 17)
1249 {
1250 DWORD i = (0xFFFF >> (17 - bLeft)) + 8;
1251 DWORD j = (i - 16) & 0xFFFF;
1252 if ((dwBits <= j) || (dwBits > (i & 0xFFFF))) goto UnpackByte;
1253 dwBits -= j;
1254 bLeft = ((BYTE)(dwBits & 0xFF) < bLeft) ? (BYTE)(dwBits & 0xFF) : (BYTE)((dwBits+1) & 0xFF);
1255 goto Next;
1256 }
1257 if (bLeft >= 18) goto SkipByte;
1258 if (dwBits >= 0x10000)
1259 {
1260 bLeft = (BYTE)(dwBits + 1) & 0xFF;
1261 goto Next;
1262 }
1263 UnpackByte:
1264 if (bLeft < 16)
1265 {
1266 BYTE shift = 16 - bLeft;
1267 signed short c = (signed short)(dwBits << shift);
1268 c >>= shift;
1269 dwBits = (DWORD)c;
1270 }
1271 dwBits += wTemp;
1272 wTemp = (signed short)dwBits;
1273 wTemp2 += wTemp;
1274#ifdef IT215_SUPPORT
1275 pDst[dwPos] = (b215) ? wTemp2 : wTemp;
1276#else
1277 pDst[dwPos] = wTemp;
1278#endif
1279 SkipByte:
1280 dwPos++;
1281 Next:
1282 if (pSrc >= lpMemFile+dwMemLength+1) return;
1283 } while (dwPos < d);
1284 // Move On
1285 wCount -= d;
1286 dwLen -= d;
1287 pDst += d;
1288 if (pSrc >= lpMemFile+dwMemLength) break;
1289 }
1290}
1291
1292
1293UINT CSoundFile::SaveMixPlugins(FILE *f, BOOL bUpdate)
1294//----------------------------------------------------
1295{
1296 DWORD chinfo[64];
1297 CHAR s[32];
1298 DWORD nPluginSize;
1299 UINT nTotalSize = 0;
1300 UINT nChInfo = 0;
1301
1302 for (UINT i=0; i<MAX_MIXPLUGINS; i++)
1303 {
1304 PSNDMIXPLUGIN p = &m_MixPlugins[i];
1305 if ((p->Info.dwPluginId1) || (p->Info.dwPluginId2))
1306 {
1307 nPluginSize = sizeof(SNDMIXPLUGININFO)+4; // plugininfo+4 (datalen)
1308 if ((p->pMixPlugin) && (bUpdate))
1309 {
1310 p->pMixPlugin->SaveAllParameters();
1311 }
1312 if (p->pPluginData)
1313 {
1314 nPluginSize += p->nPluginDataSize;
1315 }
1316 if (f)
1317 {
1318 s[0] = 'F';
1319 s[1] = 'X';
1320 s[2] = '0' + (i/10);
1321 s[3] = '0' + (i%10);
1322 fwrite(s, 1, 4, f);
1323 fwrite(&nPluginSize, 1, 4, f);
1324 fwrite(&p->Info, 1, sizeof(SNDMIXPLUGININFO), f);
1325 fwrite(&m_MixPlugins[i].nPluginDataSize, 1, 4, f);
1326 if (m_MixPlugins[i].pPluginData)
1327 {
1328 fwrite(m_MixPlugins[i].pPluginData, 1, m_MixPlugins[i].nPluginDataSize, f);
1329 }
1330 }
1331 nTotalSize += nPluginSize + 8;
1332 }
1333 }
1334 for (UINT j=0; j<m_nChannels; j++)
1335 {
1336 if (j < 64)
1337 {
1338 if ((chinfo[j] = ChnSettings[j].nMixPlugin) != 0)
1339 {
1340 nChInfo = j+1;
1341 }
1342 }
1343 }
1344 if (nChInfo)
1345 {
1346 if (f)
1347 {
1348 nPluginSize = 0x58464843;
1349 fwrite(&nPluginSize, 1, 4, f);
1350 nPluginSize = nChInfo*4;
1351 fwrite(&nPluginSize, 1, 4, f);
1352 fwrite(chinfo, 1, nPluginSize, f);
1353 }
1354 nTotalSize += nChInfo*4 + 8;
1355 }
1356 return nTotalSize;
1357}
1358
1359
1360UINT CSoundFile::LoadMixPlugins(const void *pData, UINT nLen)
1361//-----------------------------------------------------------
1362{
1363 const BYTE *p = (const BYTE *)pData;
1364 UINT nPos = 0;
1365
1366 while (nPos+8 < nLen)
1367 {
1368 DWORD nPluginSize;
1369 UINT nPlugin;
1370
1371 nPluginSize = bswapLE32(*(DWORD *)(p+nPos+4));
1372 if (nPluginSize > nLen-nPos-8) break;;
1373 if ((bswapLE32(*(DWORD *)(p+nPos))) == 0x58464843)
1374 {
1375 for (UINT ch=0; ch<64; ch++) if (ch*4 < nPluginSize)
1376 {
1377 ChnSettings[ch].nMixPlugin = bswapLE32(*(DWORD *)(p+nPos+8+ch*4));
1378 }
1379 } else
1380 {
1381 if ((p[nPos] != 'F') || (p[nPos+1] != 'X')
1382 || (p[nPos+2] < '0') || (p[nPos+3] < '0'))
1383 {
1384 break;
1385 }
1386 nPlugin = (p[nPos+2]-'0')*10 + (p[nPos+3]-'0');
1387 if ((nPlugin < MAX_MIXPLUGINS) && (nPluginSize >= sizeof(SNDMIXPLUGININFO)+4))
1388 {
1389 DWORD dwExtra = bswapLE32(*(DWORD *)(p+nPos+8+sizeof(SNDMIXPLUGININFO)));
1390 m_MixPlugins[nPlugin].Info = *(const SNDMIXPLUGININFO *)(p+nPos+8);
1391 m_MixPlugins[nPlugin].Info.dwPluginId1 = bswapLE32(m_MixPlugins[nPlugin].Info.dwPluginId1);
1392 m_MixPlugins[nPlugin].Info.dwPluginId2 = bswapLE32(m_MixPlugins[nPlugin].Info.dwPluginId2);
1393 m_MixPlugins[nPlugin].Info.dwInputRouting = bswapLE32(m_MixPlugins[nPlugin].Info.dwInputRouting);
1394 m_MixPlugins[nPlugin].Info.dwOutputRouting = bswapLE32(m_MixPlugins[nPlugin].Info.dwOutputRouting);
1395 for (UINT j=0; j<4; j++)
1396 {
1397 m_MixPlugins[nPlugin].Info.dwReserved[j] = bswapLE32(m_MixPlugins[nPlugin].Info.dwReserved[j]);
1398 }
1399 if ((dwExtra) && (dwExtra <= nPluginSize-sizeof(SNDMIXPLUGININFO)-4))
1400 {
1401 m_MixPlugins[nPlugin].nPluginDataSize = 0;
1402 m_MixPlugins[nPlugin].pPluginData = new signed char [dwExtra];
1403 if (m_MixPlugins[nPlugin].pPluginData)
1404 {
1405 m_MixPlugins[nPlugin].nPluginDataSize = dwExtra;
1406 memcpy(m_MixPlugins[nPlugin].pPluginData, p+nPos+8+sizeof(SNDMIXPLUGININFO)+4, dwExtra);
1407 }
1408 }
1409 }
1410 }
1411 nPos += nPluginSize + 8;
1412 }
1413 return nPos;
1414}
1415
diff --git a/core/multimedia/opieplayer/modplug/load_j2b.cpp b/core/multimedia/opieplayer/modplug/load_j2b.cpp
new file mode 100644
index 0000000..5f60bbb
--- a/dev/null
+++ b/core/multimedia/opieplayer/modplug/load_j2b.cpp
@@ -0,0 +1,18 @@
1/*
2 * This program is free software; you can redistribute it and modify it
3 * under the terms of the GNU General Public License as published by the
4 * Free Software Foundation; either version 2 of the license or (at your
5 * option) any later version.
6 *
7 * Authors: Olivier Lapicque <olivierl@jps.net>
8*/
9
10
11///////////////////////////////////////////////////
12//
13// J2B module loader
14//
15///////////////////////////////////////////////////
16#include "stdafx.h"
17#include "sndfile.h"
18
diff --git a/core/multimedia/opieplayer/modplug/load_mdl.cpp b/core/multimedia/opieplayer/modplug/load_mdl.cpp
new file mode 100644
index 0000000..806b68b
--- a/dev/null
+++ b/core/multimedia/opieplayer/modplug/load_mdl.cpp
@@ -0,0 +1,506 @@
1/*
2 * This program is free software; you can redistribute it and modify it
3 * under the terms of the GNU General Public License as published by the
4 * Free Software Foundation; either version 2 of the license or (at your
5 * option) any later version.
6 *
7 * Authors: Olivier Lapicque <olivierl@jps.net>
8*/
9
10//////////////////////////////////////////////
11// DigiTracker (MDL) module loader //
12//////////////////////////////////////////////
13#include "stdafx.h"
14#include "sndfile.h"
15
16//#pragma warning(disable:4244)
17
18typedef struct MDLSONGHEADER
19{
20 DWORD id;// "DMDL" = 0x4C444D44
21 BYTE version;
22} Q_PACKED MDLSONGHEADER;
23
24
25typedef struct MDLINFOBLOCK
26{
27 CHAR songname[32];
28 CHAR composer[20];
29 WORD norders;
30 WORD repeatpos;
31 BYTE globalvol;
32 BYTE speed;
33 BYTE tempo;
34 BYTE channelinfo[32];
35 BYTE seq[256];
36} Q_PACKED MDLINFOBLOCK;
37
38
39typedef struct MDLPATTERNDATA
40{
41 BYTE channels;
42 BYTE lastrow;// nrows = lastrow+1
43 CHAR name[16];
44 WORD data[1];
45} Q_PACKED MDLPATTERNDATA;
46
47
48void ConvertMDLCommand(MODCOMMAND *m, UINT eff, UINT data)
49//--------------------------------------------------------
50{
51 UINT command = 0, param = data;
52 switch(eff)
53 {
54 case 0x01:command = CMD_PORTAMENTOUP; break;
55 case 0x02:command = CMD_PORTAMENTODOWN; break;
56 case 0x03:command = CMD_TONEPORTAMENTO; break;
57 case 0x04:command = CMD_VIBRATO; break;
58 case 0x05:command = CMD_ARPEGGIO; break;
59 case 0x07:command = (param < 0x20) ? CMD_SPEED : CMD_TEMPO; break;
60 case 0x08:command = CMD_PANNING8; param <<= 1; break;
61 case 0x0B:command = CMD_POSITIONJUMP; break;
62 case 0x0C:command = CMD_GLOBALVOLUME; break;
63 case 0x0D:command = CMD_PATTERNBREAK; param = (data & 0x0F) + (data>>4)*10; break;
64 case 0x0E:
65 command = CMD_S3MCMDEX;
66 switch(data & 0xF0)
67 {
68 case 0x00:command = 0; break; // What is E0x in MDL (there is a bunch) ?
69 case 0x10:if (param & 0x0F) { param |= 0xF0; command = CMD_PANNINGSLIDE; } else command = 0; break;
70 case 0x20:if (param & 0x0F) { param = (param << 4) | 0x0F; command = CMD_PANNINGSLIDE; } else command = 0; break;
71 case 0x30:param = (data & 0x0F) | 0x10; break; // glissando
72 case 0x40:param = (data & 0x0F) | 0x30; break; // vibrato waveform
73 case 0x60:param = (data & 0x0F) | 0xB0; break;
74 case 0x70:param = (data & 0x0F) | 0x40; break; // tremolo waveform
75 case 0x90:command = CMD_RETRIG; param &= 0x0F; break;
76 case 0xA0:param = (data & 0x0F) << 4; command = CMD_GLOBALVOLSLIDE; break;
77 case 0xB0:param = data & 0x0F; command = CMD_GLOBALVOLSLIDE; break;
78 case 0xF0:param = ((data >> 8) & 0x0F) | 0xA0; break;
79 }
80 break;
81 case 0x0F:command = CMD_SPEED; break;
82 case 0x10:if ((param & 0xF0) != 0xE0) { command = CMD_VOLUMESLIDE; if ((param & 0xF0) == 0xF0) param = ((param << 4) | 0x0F); else param >>= 2; } break;
83 case 0x20:if ((param & 0xF0) != 0xE0) { command = CMD_VOLUMESLIDE; if ((param & 0xF0) != 0xF0) param >>= 2; } break;
84 case 0x30:command = CMD_RETRIG; break;
85 case 0x40:command = CMD_TREMOLO; break;
86 case 0x50:command = CMD_TREMOR; break;
87 case 0xEF:if (param > 0xFF) param = 0xFF; command = CMD_OFFSET; break;
88 }
89 if (command)
90 {
91 m->command = command;
92 m->param = param;
93 }
94}
95
96
97void UnpackMDLTrack(MODCOMMAND *pat, UINT nChannels, UINT nRows, UINT nTrack, const BYTE *lpTracks)
98//-------------------------------------------------------------------------------------------------
99{
100 MODCOMMAND cmd, *m = pat;
101 UINT len = *((WORD *)lpTracks);
102 UINT pos = 0, row = 0, i;
103 lpTracks += 2;
104 for (UINT ntrk=1; ntrk<nTrack; ntrk++)
105 {
106 lpTracks += len;
107 len = *((WORD *)lpTracks);
108 lpTracks += 2;
109 }
110 cmd.note = cmd.instr = 0;
111 cmd.volcmd = cmd.vol = 0;
112 cmd.command = cmd.param = 0;
113 while ((row < nRows) && (pos < len))
114 {
115 UINT xx;
116 BYTE b = lpTracks[pos++];
117 xx = b >> 2;
118 switch(b & 0x03)
119 {
120 case 0x01:
121 for (i=0; i<=xx; i++)
122 {
123 if (row) *m = *(m-nChannels);
124 m += nChannels;
125 row++;
126 if (row >= nRows) break;
127 }
128 break;
129
130 case 0x02:
131 if (xx < row) *m = pat[nChannels*xx];
132 m += nChannels;
133 row++;
134 break;
135
136 case 0x03:
137 {
138 cmd.note = (xx & 0x01) ? lpTracks[pos++] : 0;
139 cmd.instr = (xx & 0x02) ? lpTracks[pos++] : 0;
140 cmd.volcmd = cmd.vol = 0;
141 cmd.command = cmd.param = 0;
142 if ((cmd.note < 120-12) && (cmd.note)) cmd.note += 12;
143 UINT volume = (xx & 0x04) ? lpTracks[pos++] : 0;
144 UINT commands = (xx & 0x08) ? lpTracks[pos++] : 0;
145 UINT command1 = commands & 0x0F;
146 UINT command2 = commands & 0xF0;
147 UINT param1 = (xx & 0x10) ? lpTracks[pos++] : 0;
148 UINT param2 = (xx & 0x20) ? lpTracks[pos++] : 0;
149 if ((command1 == 0x0E) && ((param1 & 0xF0) == 0xF0) && (!command2))
150 {
151 param1 = ((param1 & 0x0F) << 8) | param2;
152 command1 = 0xEF;
153 command2 = param2 = 0;
154 }
155 if (volume)
156 {
157 cmd.volcmd = VOLCMD_VOLUME;
158 cmd.vol = (volume+1) >> 2;
159 }
160 ConvertMDLCommand(&cmd, command1, param1);
161 if ((cmd.command != CMD_SPEED)
162 && (cmd.command != CMD_TEMPO)
163 && (cmd.command != CMD_PATTERNBREAK))
164 ConvertMDLCommand(&cmd, command2, param2);
165 *m = cmd;
166 m += nChannels;
167 row++;
168 }
169 break;
170
171 // Empty Slots
172 default:
173 row += xx+1;
174 m += (xx+1)*nChannels;
175 if (row >= nRows) break;
176 }
177 }
178}
179
180
181
182BOOL CSoundFile::ReadMDL(const BYTE *lpStream, DWORD dwMemLength)
183//---------------------------------------------------------------
184{
185 DWORD dwMemPos, dwPos, blocklen, dwTrackPos;
186 const MDLSONGHEADER *pmsh = (const MDLSONGHEADER *)lpStream;
187 MDLINFOBLOCK *pmib;
188 MDLPATTERNDATA *pmpd;
189 UINT i,j, norders = 0, npatterns = 0, ntracks = 0;
190 UINT ninstruments = 0, nsamples = 0;
191 WORD block;
192 WORD patterntracks[MAX_PATTERNS*32];
193 BYTE smpinfo[MAX_SAMPLES];
194 BYTE insvolenv[MAX_INSTRUMENTS];
195 BYTE inspanenv[MAX_INSTRUMENTS];
196 LPCBYTE pvolenv, ppanenv, ppitchenv;
197 UINT nvolenv, npanenv, npitchenv;
198
199 if ((!lpStream) || (dwMemLength < 1024)) return FALSE;
200 if ((pmsh->id != 0x4C444D44) || ((pmsh->version & 0xF0) > 0x10)) return FALSE;
201 memset(patterntracks, 0, sizeof(patterntracks));
202 memset(smpinfo, 0, sizeof(smpinfo));
203 memset(insvolenv, 0, sizeof(insvolenv));
204 memset(inspanenv, 0, sizeof(inspanenv));
205 dwMemPos = 5;
206 dwTrackPos = 0;
207 pvolenv = ppanenv = ppitchenv = NULL;
208 nvolenv = npanenv = npitchenv = 0;
209 m_nSamples = m_nInstruments = 0;
210 while (dwMemPos+6 < dwMemLength)
211 {
212 block = *((WORD *)(lpStream+dwMemPos));
213 blocklen = *((DWORD *)(lpStream+dwMemPos+2));
214 dwMemPos += 6;
215 if (dwMemPos + blocklen > dwMemLength)
216 {
217 if (dwMemPos == 11) return FALSE;
218 break;
219 }
220 switch(block)
221 {
222 // IN: infoblock
223 case 0x4E49:
224 pmib = (MDLINFOBLOCK *)(lpStream+dwMemPos);
225 memcpy(m_szNames[0], pmib->songname, 32);
226 norders = pmib->norders;
227 if (norders > MAX_ORDERS) norders = MAX_ORDERS;
228 m_nRestartPos = pmib->repeatpos;
229 m_nDefaultGlobalVolume = pmib->globalvol;
230 m_nDefaultTempo = pmib->tempo;
231 m_nDefaultSpeed = pmib->speed;
232 m_nChannels = 4;
233 for (i=0; i<32; i++)
234 {
235 ChnSettings[i].nVolume = 64;
236 ChnSettings[i].nPan = (pmib->channelinfo[i] & 0x7F) << 1;
237 if (pmib->channelinfo[i] & 0x80)
238 ChnSettings[i].dwFlags |= CHN_MUTE;
239 else
240 m_nChannels = i+1;
241 }
242 for (j=0; j<norders; j++) Order[j] = pmib->seq[j];
243 break;
244 // ME: song message
245 case 0x454D:
246 if (blocklen)
247 {
248 if (m_lpszSongComments) delete m_lpszSongComments;
249 m_lpszSongComments = new char[blocklen];
250 if (m_lpszSongComments)
251 {
252 memcpy(m_lpszSongComments, lpStream+dwMemPos, blocklen);
253 m_lpszSongComments[blocklen-1] = 0;
254 }
255 }
256 break;
257 // PA: Pattern Data
258 case 0x4150:
259 npatterns = lpStream[dwMemPos];
260 if (npatterns > MAX_PATTERNS) npatterns = MAX_PATTERNS;
261 dwPos = dwMemPos + 1;
262 for (i=0; i<npatterns; i++)
263 {
264 if (dwPos+18 >= dwMemLength) break;
265 pmpd = (MDLPATTERNDATA *)(lpStream + dwPos);
266 if (pmpd->channels > 32) break;
267 PatternSize[i] = pmpd->lastrow+1;
268 if (m_nChannels < pmpd->channels) m_nChannels = pmpd->channels;
269 dwPos += 18 + 2*pmpd->channels;
270 for (j=0; j<pmpd->channels; j++)
271 {
272 patterntracks[i*32+j] = pmpd->data[j];
273 }
274 }
275 break;
276 // TR: Track Data
277 case 0x5254:
278 if (dwTrackPos) break;
279 ntracks = *((WORD *)(lpStream+dwMemPos));
280 dwTrackPos = dwMemPos+2;
281 break;
282 // II: Instruments
283 case 0x4949:
284 ninstruments = lpStream[dwMemPos];
285 dwPos = dwMemPos+1;
286 for (i=0; i<ninstruments; i++)
287 {
288 UINT nins = lpStream[dwPos];
289 if ((nins >= MAX_INSTRUMENTS) || (!nins)) break;
290 if (m_nInstruments < nins) m_nInstruments = nins;
291 if (!Headers[nins])
292 {
293 UINT note = 12;
294 if ((Headers[nins] = new INSTRUMENTHEADER) == NULL) break;
295 INSTRUMENTHEADER *penv = Headers[nins];
296 memset(penv, 0, sizeof(INSTRUMENTHEADER));
297 memcpy(penv->name, lpStream+dwPos+2, 32);
298 penv->nGlobalVol = 64;
299 penv->nPPC = 5*12;
300 for (j=0; j<lpStream[dwPos+1]; j++)
301 {
302 const BYTE *ps = lpStream+dwPos+34+14*j;
303 while ((note < (UINT)(ps[1]+12)) && (note < 120))
304 {
305 penv->NoteMap[note] = note+1;
306 if (ps[0] < MAX_SAMPLES)
307 {
308 int ismp = ps[0];
309 penv->Keyboard[note] = ps[0];
310 Ins[ismp].nVolume = ps[2];
311 Ins[ismp].nPan = ps[4] << 1;
312 Ins[ismp].nVibType = ps[11];
313 Ins[ismp].nVibSweep = ps[10];
314 Ins[ismp].nVibDepth = ps[9];
315 Ins[ismp].nVibRate = ps[8];
316 }
317 penv->nFadeOut = (ps[7] << 8) | ps[6];
318 if (penv->nFadeOut == 0xFFFF) penv->nFadeOut = 0;
319 note++;
320 }
321 // Use volume envelope ?
322 if (ps[3] & 0x80)
323 {
324 penv->dwFlags |= ENV_VOLUME;
325 insvolenv[nins] = (ps[3] & 0x3F) + 1;
326 }
327 // Use panning envelope ?
328 if (ps[5] & 0x80)
329 {
330 penv->dwFlags |= ENV_PANNING;
331 inspanenv[nins] = (ps[5] & 0x3F) + 1;
332 }
333 }
334 }
335 dwPos += 34 + 14*lpStream[dwPos+1];
336 }
337 for (j=1; j<=m_nInstruments; j++) if (!Headers[j])
338 {
339 Headers[j] = new INSTRUMENTHEADER;
340 if (Headers[j]) memset(Headers[j], 0, sizeof(INSTRUMENTHEADER));
341 }
342 break;
343 // VE: Volume Envelope
344 case 0x4556:
345 if ((nvolenv = lpStream[dwMemPos]) == 0) break;
346 if (dwMemPos + nvolenv*32 + 1 <= dwMemLength) pvolenv = lpStream + dwMemPos + 1;
347 break;
348 // PE: Panning Envelope
349 case 0x4550:
350 if ((npanenv = lpStream[dwMemPos]) == 0) break;
351 if (dwMemPos + npanenv*32 + 1 <= dwMemLength) ppanenv = lpStream + dwMemPos + 1;
352 break;
353 // FE: Pitch Envelope
354 case 0x4546:
355 if ((npitchenv = lpStream[dwMemPos]) == 0) break;
356 if (dwMemPos + npitchenv*32 + 1 <= dwMemLength) ppitchenv = lpStream + dwMemPos + 1;
357 break;
358 // IS: Sample Infoblock
359 case 0x5349:
360 nsamples = lpStream[dwMemPos];
361 dwPos = dwMemPos+1;
362 for (i=0; i<nsamples; i++, dwPos += 59)
363 {
364 UINT nins = lpStream[dwPos];
365 if ((nins >= MAX_SAMPLES) || (!nins)) continue;
366 if (m_nSamples < nins) m_nSamples = nins;
367 MODINSTRUMENT *pins = &Ins[nins];
368 memcpy(m_szNames[nins], lpStream+dwPos+1, 32);
369 memcpy(pins->name, lpStream+dwPos+33, 8);
370 pins->nC4Speed = *((DWORD *)(lpStream+dwPos+41));
371 pins->nLength = *((DWORD *)(lpStream+dwPos+45));
372 pins->nLoopStart = *((DWORD *)(lpStream+dwPos+49));
373 pins->nLoopEnd = pins->nLoopStart + *((DWORD *)(lpStream+dwPos+53));
374 if (pins->nLoopEnd > pins->nLoopStart) pins->uFlags |= CHN_LOOP;
375 pins->nGlobalVol = 64;
376 if (lpStream[dwPos+58] & 0x01)
377 {
378 pins->uFlags |= CHN_16BIT;
379 pins->nLength >>= 1;
380 pins->nLoopStart >>= 1;
381 pins->nLoopEnd >>= 1;
382 }
383 if (lpStream[dwPos+58] & 0x02) pins->uFlags |= CHN_PINGPONGLOOP;
384 smpinfo[nins] = (lpStream[dwPos+58] >> 2) & 3;
385 }
386 break;
387 // SA: Sample Data
388 case 0x4153:
389 dwPos = dwMemPos;
390 for (i=1; i<=m_nSamples; i++) if ((Ins[i].nLength) && (!Ins[i].pSample) && (smpinfo[i] != 3) && (dwPos < dwMemLength))
391 {
392 MODINSTRUMENT *pins = &Ins[i];
393 UINT flags = (pins->uFlags & CHN_16BIT) ? RS_PCM16S : RS_PCM8S;
394 if (!smpinfo[i])
395 {
396 dwPos += ReadSample(pins, flags, (LPSTR)(lpStream+dwPos), dwMemLength - dwPos);
397 } else
398 {
399 DWORD dwLen = *((DWORD *)(lpStream+dwPos));
400 dwPos += 4;
401 if ((dwPos+dwLen <= dwMemLength) && (dwLen > 4))
402 {
403 flags = (pins->uFlags & CHN_16BIT) ? RS_MDL16 : RS_MDL8;
404 ReadSample(pins, flags, (LPSTR)(lpStream+dwPos), dwLen);
405 }
406 dwPos += dwLen;
407 }
408 }
409 break;
410 }
411 dwMemPos += blocklen;
412 }
413 // Unpack Patterns
414 if ((dwTrackPos) && (npatterns) && (m_nChannels) && (ntracks))
415 {
416 for (UINT ipat=0; ipat<npatterns; ipat++)
417 {
418 if ((Patterns[ipat] = AllocatePattern(PatternSize[ipat], m_nChannels)) == NULL) break;
419 for (UINT chn=0; chn<m_nChannels; chn++) if ((patterntracks[ipat*32+chn]) && (patterntracks[ipat*32+chn] <= ntracks))
420 {
421 MODCOMMAND *m = Patterns[ipat] + chn;
422 UnpackMDLTrack(m, m_nChannels, PatternSize[ipat], patterntracks[ipat*32+chn], lpStream+dwTrackPos);
423 }
424 }
425 }
426 // Set up envelopes
427 for (UINT iIns=1; iIns<=m_nInstruments; iIns++) if (Headers[iIns])
428 {
429 INSTRUMENTHEADER *penv = Headers[iIns];
430 // Setup volume envelope
431 if ((nvolenv) && (pvolenv) && (insvolenv[iIns]))
432 {
433 LPCBYTE pve = pvolenv;
434 for (UINT nve=0; nve<nvolenv; nve++, pve+=33) if (pve[0]+1 == insvolenv[iIns])
435 {
436 WORD vtick = 1;
437 penv->nVolEnv = 15;
438 for (UINT iv=0; iv<15; iv++)
439 {
440 if (iv) vtick += pve[iv*2+1];
441 penv->VolPoints[iv] = vtick;
442 penv->VolEnv[iv] = pve[iv*2+2];
443 if (!pve[iv*2+1])
444 {
445 penv->nVolEnv = iv+1;
446 break;
447 }
448 }
449 penv->nVolSustainBegin = penv->nVolSustainEnd = pve[31] & 0x0F;
450 if (pve[31] & 0x10) penv->dwFlags |= ENV_VOLSUSTAIN;
451 if (pve[31] & 0x20) penv->dwFlags |= ENV_VOLLOOP;
452 penv->nVolLoopStart = pve[32] & 0x0F;
453 penv->nVolLoopEnd = pve[32] >> 4;
454 }
455 }
456 // Setup panning envelope
457 if ((npanenv) && (ppanenv) && (inspanenv[iIns]))
458 {
459 LPCBYTE ppe = ppanenv;
460 for (UINT npe=0; npe<npanenv; npe++, ppe+=33) if (ppe[0]+1 == inspanenv[iIns])
461 {
462 WORD vtick = 1;
463 penv->nPanEnv = 15;
464 for (UINT iv=0; iv<15; iv++)
465 {
466 if (iv) vtick += ppe[iv*2+1];
467 penv->PanPoints[iv] = vtick;
468 penv->PanEnv[iv] = ppe[iv*2+2];
469 if (!ppe[iv*2+1])
470 {
471 penv->nPanEnv = iv+1;
472 break;
473 }
474 }
475 if (ppe[31] & 0x10) penv->dwFlags |= ENV_PANSUSTAIN;
476 if (ppe[31] & 0x20) penv->dwFlags |= ENV_PANLOOP;
477 penv->nPanLoopStart = ppe[32] & 0x0F;
478 penv->nPanLoopEnd = ppe[32] >> 4;
479 }
480 }
481 }
482 m_dwSongFlags |= SONG_LINEARSLIDES;
483 m_nType = MOD_TYPE_MDL;
484 return TRUE;
485}
486
487
488/////////////////////////////////////////////////////////////////////////
489// MDL Sample Unpacking
490
491// MDL Huffman ReadBits compression
492WORD MDLReadBits(DWORD &bitbuf, UINT &bitnum, LPBYTE &ibuf, CHAR n)
493//-----------------------------------------------------------------
494{
495 WORD v = (WORD)(bitbuf & ((1 << n) - 1) );
496 bitbuf >>= n;
497 bitnum -= n;
498 if (bitnum <= 24)
499 {
500 bitbuf |= (((DWORD)(*ibuf++)) << bitnum);
501 bitnum += 8;
502 }
503 return v;
504}
505
506
diff --git a/core/multimedia/opieplayer/modplug/load_med.cpp b/core/multimedia/opieplayer/modplug/load_med.cpp
new file mode 100644
index 0000000..1a4b30c
--- a/dev/null
+++ b/core/multimedia/opieplayer/modplug/load_med.cpp
@@ -0,0 +1,919 @@
1/*
2 * This program is free software; you can redistribute it and modify it
3 * under the terms of the GNU General Public License as published by the
4 * Free Software Foundation; either version 2 of the license or (at your
5 * option) any later version.
6 *
7 * Authors: Olivier Lapicque <olivierl@jps.net>,
8 * Adam Goode <adam@evdebs.org> (endian and char fixes for PPC)
9*/
10
11#include "stdafx.h"
12#include "sndfile.h"
13
14//#define MED_LOG
15
16#ifdef MED_LOG
17extern void Log(LPCSTR s, ...);
18#endif
19
20//////////////////////////////////////////////////////////
21// OctaMed MED file support (import only)
22
23// flags
24 #define MMD_FLAG_FILTERON0x1
25 #define MMD_FLAG_JUMPINGON0x2
26 #define MMD_FLAG_JUMP8TH0x4
27 #define MMD_FLAG_INSTRSATT0x8 // instruments are attached (this is a module)
28 #define MMD_FLAG_VOLHEX 0x10
29 #define MMD_FLAG_STSLIDE0x20 // SoundTracker mode for slides
30 #define MMD_FLAG_8CHANNEL0x40 // OctaMED 8 channel song
31 #define MMD_FLAG_SLOWHQ 0x80 // HQ slows playing speed (V2-V4 compatibility)
32// flags2
33 #define MMD_FLAG2_BMASK 0x1F
34 #define MMD_FLAG2_BPM 0x20
35 #define MMD_FLAG2_MIX 0x80 // uses Mixing (V7+)
36// flags3:
37 #define MMD_FLAG3_STEREO 0x1// mixing in Stereo mode
38 #define MMD_FLAG3_FREEPAN 0x2// free panning
39 #define MMD_FLAG3_GM 0x4 // module designed for GM/XG compatibility
40
41
42// generic MMD tags
43 #define MMDTAG_END 0
44 #define MMDTAG_PTR 0x80000000// data needs relocation
45 #define MMDTAG_MUSTKNOW 0x40000000// loader must fail if this isn't recognized
46 #define MMDTAG_MUSTWARN 0x20000000// loader must warn if this isn't recognized
47
48// ExpData tags
49// # of effect groups, including the global group (will
50// override settings in MMDSong struct), default = 1
51 #define MMDTAG_EXP_NUMFXGROUPS1
52 #define MMDTAG_TRK_NAME (MMDTAG_PTR|1)// trackinfo tags
53 #define MMDTAG_TRK_NAMELEN 2 // namelen includes zero term.
54 #define MMDTAG_TRK_FXGROUP3
55// effectinfo tags
56 #define MMDTAG_FX_ECHOTYPE1
57 #define MMDTAG_FX_ECHOLEN2
58 #define MMDTAG_FX_ECHODEPTH3
59 #define MMDTAG_FX_STEREOSEP4
60 #define MMDTAG_FX_GROUPNAME (MMDTAG_PTR|5)// the Global Effects group shouldn't have name saved!
61 #define MMDTAG_FX_GRPNAMELEN 6// namelen includes zero term.
62
63#pragma pack(1)
64
65typedef struct tagMEDMODULEHEADER
66{
67 DWORD id; // MMD1-MMD3
68 DWORD modlen;// Size of file
69 DWORD song; // Position in file for this song
70 WORD psecnum;
71 WORD pseq;
72 DWORD blockarr;// Position in file for blocks
73 DWORD mmdflags;
74 DWORD smplarr;// Position in file for samples
75 DWORD reserved;
76 DWORD expdata;// Absolute offset in file for ExpData (0 if not present)
77 DWORD reserved2;
78 WORD pstate;
79 WORD pblock;
80 WORD pline;
81 WORD pseqnum;
82 WORD actplayline;
83 BYTE counter;
84 BYTE extra_songs;// # of songs - 1
85} Q_PACKED MEDMODULEHEADER;
86
87
88typedef struct tagMMD0SAMPLE
89{
90 WORD rep, replen;
91 BYTE midich;
92 BYTE midipreset;
93 BYTE svol;
94 signed char strans;
95} Q_PACKED MMD0SAMPLE;
96
97
98// Sample header is immediately followed by sample data...
99typedef struct tagMMDSAMPLEHEADER
100{
101 DWORD length; // length of *one* *unpacked* channel in *bytes*
102 WORD type;
103 // if non-negative
104 // bits 0-3 reserved for multi-octave instruments, not supported on the PC
105 // 0x10: 16 bit (otherwise 8 bit)
106 // 0x20: Stereo (otherwise mono)
107 // 0x40: Uses DeltaCode
108 // 0x80: Packed data
109 // -1: Synth
110 // -2: Hybrid
111 // if type indicates packed data, these fields follow, otherwise we go right to the data
112 WORD packtype;// Only 1 = ADPCM is supported
113 WORD subtype;// Packing subtype
114 // ADPCM subtype
115 // 1: g723_40
116 // 2: g721
117 // 3: g723_24
118 BYTE commonflags;// flags common to all packtypes (none defined so far)
119 BYTE packerflags;// flags for the specific packtype
120 ULONG leftchlen;// packed length of left channel in bytes
121 ULONG rightchlen;// packed length of right channel in bytes (ONLY PRESENT IN STEREO SAMPLES)
122 BYTE SampleData[1];// Sample Data
123} Q_PACKED MMDSAMPLEHEADER;
124
125
126// MMD0/MMD1 song header
127typedef struct tagMMD0SONGHEADER
128{
129 MMD0SAMPLE sample[63];
130 WORD numblocks; // # of blocks
131 WORD songlen; // # of entries used in playseq
132 BYTE playseq[256];// Play sequence
133 WORD deftempo; // BPM tempo
134 signed char playtransp;// Play transpose
135 BYTE flags; // 0x10: Hex Volumes | 0x20: ST/NT/PT Slides | 0x40: 8 Channels song
136 BYTE flags2; // [b4-b0]+1: Tempo LPB, 0x20: tempo mode, 0x80: mix_conv=on
137 BYTE tempo2; // tempo TPL
138 BYTE trkvol[16];// track volumes
139 BYTE mastervol; // master volume
140 BYTE numsamples;// # of samples (max=63)
141} Q_PACKED MMD0SONGHEADER;
142
143
144// MMD2/MMD3 song header
145typedef struct tagMMD2SONGHEADER
146{
147 MMD0SAMPLE sample[63];
148 WORD numblocks; // # of blocks
149 WORD numsections;// # of sections
150 DWORD playseqtable;// filepos of play sequence
151 DWORD sectiontable;// filepos of sections table (WORD array)
152 DWORD trackvols;// filepos of tracks volume (BYTE array)
153 WORD numtracks; // # of tracks (max 64)
154 WORD numpseqs; // # of play sequences
155 DWORD trackpans;// filepos of tracks pan values (BYTE array)
156 LONG flags3; // 0x1:stereo_mix, 0x2:free_panning, 0x4:GM/XG compatibility
157 WORD voladj; // vol_adjust (set to 100 if 0)
158 WORD channels; // # of channels (4 if =0)
159 BYTE mix_echotype;// 1:normal,2:xecho
160 BYTE mix_echodepth;// 1..6
161 WORD mix_echolen;// > 0
162 signed char mix_stereosep;// -4..4
163 BYTE pad0[223];
164 WORD deftempo; // BPM tempo
165 signed char playtransp;// play transpose
166 BYTE flags; // 0x1:filteron, 0x2:jumpingon, 0x4:jump8th, 0x8:instr_attached, 0x10:hex_vol, 0x20:PT_slides, 0x40:8ch_conv,0x80:hq slows playing speed
167 BYTE flags2; // 0x80:mix_conv=on, [b4-b0]+1:tempo LPB, 0x20:tempo_mode
168 BYTE tempo2; // tempo TPL
169 BYTE pad1[16];
170 BYTE mastervol; // master volume
171 BYTE numsamples;// # of samples (max 63)
172} Q_PACKED MMD2SONGHEADER;
173
174// For MMD0 the note information is held in 3 bytes, byte0, byte1, byte2. For reference we
175// number the bits in each byte 0..7, where 0 is the low bit.
176// The note is held as bits 5..0 of byte0
177// The instrument is encoded in 6 bits, bits 7 and 6 of byte0 and bits 7,6,5,4 of byte1
178// The command number is bits 3,2,1,0 of byte1, command data is in byte2:
179// For command 0, byte2 represents the second data byte, otherwise byte2
180// represents the first data byte.
181typedef struct tagMMD0BLOCK
182{
183 BYTE numtracks;
184 BYTE lines; // File value is 1 less than actual, so 0 -> 1 line
185 } Q_PACKED MMD0BLOCK; // BYTE data[lines+1][tracks][3];
186
187
188// For MMD1,MMD2,MMD3 the note information is carried in 4 bytes, byte0, byte1,
189// byte2 and byte3
190// The note is held as byte0 (values above 0x84 are ignored)
191// The instrument is held as byte1
192// The command number is held as byte2, command data is in byte3
193// For commands 0 and 0x19 byte3 represents the second data byte,
194// otherwise byte2 represents the first data byte.
195typedef struct tagMMD1BLOCK
196{
197 WORD numtracks;// Number of tracks, may be > 64, but then that data is skipped.
198 WORD lines; // Stored value is 1 less than actual, so 0 -> 1 line
199 DWORD info; // Offset of BlockInfo (if 0, no block_info is present)
200} Q_PACKED MMD1BLOCK;
201
202
203typedef struct tagMMD1BLOCKINFO
204{
205 DWORD hlmask; // Unimplemented - ignore
206 DWORD blockname;// file offset of block name
207 DWORD blocknamelen;// length of block name (including term. 0)
208 DWORD pagetable;// file offset of command page table
209 DWORD cmdexttable;// file offset of command extension table
210 DWORD reserved[4];// future expansion
211} Q_PACKED MMD1BLOCKINFO;
212
213
214// A set of play sequences is stored as an array of ULONG files offsets
215// Each offset points to the play sequence itself.
216typedef struct tagMMD2PLAYSEQ
217{
218 CHAR name[32];
219 DWORD command_offs;// filepos of command table
220 DWORD reserved;
221 WORD length;
222 WORD seq[512];// skip if > 0x8000
223} Q_PACKED MMD2PLAYSEQ;
224
225
226// A command table contains commands that effect a particular play sequence
227// entry. The only commands read in are STOP or POSJUMP, all others are ignored
228// POSJUMP is presumed to have extra bytes containing a WORD for the position
229typedef struct tagMMDCOMMAND
230{
231 WORD offset; // Offset within current sequence entry
232 BYTE cmdnumber; // STOP (537) or POSJUMP (538) (others skipped)
233 BYTE extra_count;
234 BYTE extra_bytes[4];// [extra_count];
235} Q_PACKED MMDCOMMAND; // Last entry has offset == 0xFFFF, cmd_number == 0 and 0 extrabytes
236
237
238typedef struct tagMMD0EXP
239{
240 DWORD nextmod; // File offset of next Hdr
241 DWORD exp_smp; // Pointer to extra instrument data
242 WORD s_ext_entries; // Number of extra instrument entries
243 WORD s_ext_entrsz; // Size of extra instrument data
244 DWORD annotxt;
245 DWORD annolen;
246 DWORD iinfo; // Instrument names
247 WORD i_ext_entries;
248 WORD i_ext_entrsz;
249 DWORD jumpmask;
250 DWORD rgbtable;
251 BYTE channelsplit[4];// Only used if 8ch_conv (extra channel for every nonzero entry)
252 DWORD n_info;
253 DWORD songname; // Song name
254 DWORD songnamelen;
255 DWORD dumps;
256 DWORD mmdinfo;
257 DWORD mmdrexx;
258 DWORD mmdcmd3x;
259 DWORD trackinfo_ofs;// ptr to song->numtracks ptrs to tag lists
260 DWORD effectinfo_ofs;// ptr to group ptrs
261 DWORD tag_end;
262} Q_PACKED MMD0EXP;
263
264#pragma pack()
265
266
267
268static void MedConvert(MODCOMMAND *p, const MMD0SONGHEADER *pmsh)
269//---------------------------------------------------------------
270{
271 const BYTE bpmvals[9] = { 179,164,152,141,131,123,116,110,104};
272
273 UINT command = p->command;
274 UINT param = p->param;
275 switch(command)
276 {
277 case 0x00:if (param) command = CMD_ARPEGGIO; else command = 0; break;
278 case 0x01:command = CMD_PORTAMENTOUP; break;
279 case 0x02:command = CMD_PORTAMENTODOWN; break;
280 case 0x03:command = CMD_TONEPORTAMENTO; break;
281 case 0x04:command = CMD_VIBRATO; break;
282 case 0x05:command = CMD_TONEPORTAVOL; break;
283 case 0x06:command = CMD_VIBRATOVOL; break;
284 case 0x07:command = CMD_TREMOLO; break;
285 case 0x0A:if (param & 0xF0) param &= 0xF0; command = CMD_VOLUMESLIDE; if (!param) command = 0; break;
286 case 0x0B:command = CMD_POSITIONJUMP; break;
287 case 0x0C:command = CMD_VOLUME;
288 if (pmsh->flags & MMD_FLAG_VOLHEX)
289 {
290 if (param < 0x80)
291 {
292 param = (param+1) / 2;
293 } else command = 0;
294 } else
295 {
296 if (param <= 0x99)
297 {
298 param = (param >> 4)*10+((param & 0x0F) % 10);
299 if (param > 64) param = 64;
300 } else command = 0;
301 }
302 break;
303 case 0x09:command = (param < 0x20) ? CMD_SPEED : CMD_TEMPO; break;
304 case 0x0D:if (param & 0xF0) param &= 0xF0; command = CMD_VOLUMESLIDE; if (!param) command = 0; break;
305 case 0x0F:// Set Tempo / Special
306 // F.00 = Pattern Break
307 if (!param) command = CMD_PATTERNBREAK;else
308 // F.01 - F.F0: Set tempo/speed
309 if (param <= 0xF0)
310 {
311 if (pmsh->flags & MMD_FLAG_8CHANNEL)
312 {
313 param = (param > 10) ? 99 : bpmvals[param-1];
314 } else
315 // F.01 - F.0A: Set Speed
316 if (param <= 0x0A)
317 {
318 command = CMD_SPEED;
319 } else
320 // Old tempo
321 if (!(pmsh->flags2 & MMD_FLAG2_BPM))
322 {
323 param = _muldiv(param, 5*715909, 2*474326);
324 }
325 // F.0B - F.F0: Set Tempo (assumes LPB=4)
326 if (param > 0x0A)
327 {
328 command = CMD_TEMPO;
329 if (param < 0x21) param = 0x21;
330 if (param > 240) param = 240;
331 }
332 } else
333 switch(param)
334 {
335 // F.F1: Retrig 2x
336 case 0xF1:
337 command = CMD_MODCMDEX;
338 param = 0x93;
339 break;
340 // F.F2: Note Delay 2x
341 case 0xF2:
342 command = CMD_MODCMDEX;
343 param = 0xD3;
344 break;
345 // F.F3: Retrig 3x
346 case 0xF3:
347 command = CMD_MODCMDEX;
348 param = 0x92;
349 break;
350 // F.F4: Note Delay 1/3
351 case 0xF4:
352 command = CMD_MODCMDEX;
353 param = 0xD2;
354 break;
355 // F.F5: Note Delay 2/3
356 case 0xF5:
357 command = CMD_MODCMDEX;
358 param = 0xD4;
359 break;
360 // F.F8: Filter Off
361 case 0xF8:
362 command = CMD_MODCMDEX;
363 param = 0x00;
364 break;
365 // F.F9: Filter On
366 case 0xF9:
367 command = CMD_MODCMDEX;
368 param = 0x01;
369 break;
370 // F.FD: Very fast tone-portamento
371 case 0xFD:
372 command = CMD_TONEPORTAMENTO;
373 param = 0xFF;
374 break;
375 // F.FE: End Song
376 case 0xFE:
377 command = CMD_SPEED;
378 param = 0;
379 break;
380 // F.FF: Note Cut
381 case 0xFF:
382 command = CMD_MODCMDEX;
383 param = 0xC0;
384 break;
385 default:
386#ifdef MED_LOG
387 Log("Unknown Fxx command: cmd=0x%02X param=0x%02X\n", command, param);
388#endif
389 param = command = 0;
390 }
391 break;
392 // 11.0x: Fine Slide Up
393 case 0x11:
394 command = CMD_MODCMDEX;
395 if (param > 0x0F) param = 0x0F;
396 param |= 0x10;
397 break;
398 // 12.0x: Fine Slide Down
399 case 0x12:
400 command = CMD_MODCMDEX;
401 if (param > 0x0F) param = 0x0F;
402 param |= 0x20;
403 break;
404 // 14.xx: Vibrato
405 case 0x14:
406 command = CMD_VIBRATO;
407 break;
408 // 15.xx: FineTune
409 case 0x15:
410 command = CMD_MODCMDEX;
411 param &= 0x0F;
412 param |= 0x50;
413 break;
414 // 16.xx: Pattern Loop
415 case 0x16:
416 command = CMD_MODCMDEX;
417 if (param > 0x0F) param = 0x0F;
418 param |= 0x60;
419 break;
420 // 18.xx: Note Cut
421 case 0x18:
422 command = CMD_MODCMDEX;
423 if (param > 0x0F) param = 0x0F;
424 param |= 0xC0;
425 break;
426 // 19.xx: Sample Offset
427 case 0x19:
428 command = CMD_OFFSET;
429 break;
430 // 1A.0x: Fine Volume Up
431 case 0x1A:
432 command = CMD_MODCMDEX;
433 if (param > 0x0F) param = 0x0F;
434 param |= 0xA0;
435 break;
436 // 1B.0x: Fine Volume Down
437 case 0x1B:
438 command = CMD_MODCMDEX;
439 if (param > 0x0F) param = 0x0F;
440 param |= 0xB0;
441 break;
442 // 1D.xx: Pattern Break
443 case 0x1D:
444 command = CMD_PATTERNBREAK;
445 break;
446 // 1E.0x: Pattern Delay
447 case 0x1E:
448 command = CMD_MODCMDEX;
449 if (param > 0x0F) param = 0x0F;
450 param |= 0xE0;
451 break;
452 // 1F.xy: Retrig
453 case 0x1F:
454 command = CMD_RETRIG;
455 param &= 0x0F;
456 break;
457 // 2E.xx: set panning
458 case 0x2E:
459 command = CMD_MODCMDEX;
460 param = ((param + 0x10) & 0xFF) >> 1;
461 if (param > 0x0F) param = 0x0F;
462 param |= 0x80;
463 break;
464 default:
465#ifdef MED_LOG
466 // 0x2E ?
467 Log("Unknown command: cmd=0x%02X param=0x%02X\n", command, param);
468#endif
469 command = param = 0;
470 }
471 p->command = command;
472 p->param = param;
473}
474
475
476BOOL CSoundFile::ReadMed(const BYTE *lpStream, DWORD dwMemLength)
477//---------------------------------------------------------------
478{
479 const MEDMODULEHEADER *pmmh;
480 const MMD0SONGHEADER *pmsh;
481 const MMD2SONGHEADER *pmsh2;
482 const MMD0EXP *pmex;
483 DWORD dwBlockArr, dwSmplArr, dwExpData, wNumBlocks;
484 LPDWORD pdwTable;
485 CHAR version;
486 UINT deftempo;
487 int playtransp = 0;
488
489 if ((!lpStream) || (dwMemLength < 0x200)) return FALSE;
490 pmmh = (MEDMODULEHEADER *)lpStream;
491 if (((pmmh->id & 0x00FFFFFF) != 0x444D4D) || (!pmmh->song)) return FALSE;
492 // Check for 'MMDx'
493 DWORD dwSong = bswapBE32(pmmh->song);
494 if ((dwSong >= dwMemLength) || (dwSong + sizeof(MMD0SONGHEADER) >= dwMemLength)) return FALSE;
495 version = (signed char)((pmmh->id >> 24) & 0xFF);
496 if ((version < '0') || (version > '3')) return FALSE;
497#ifdef MED_LOG
498 Log("\nLoading MMD%c module (flags=0x%02X)...\n", version, bswapBE32(pmmh->mmdflags));
499 Log(" modlen = %d\n", bswapBE32(pmmh->modlen));
500 Log(" song = 0x%08X\n", bswapBE32(pmmh->song));
501 Log(" psecnum = %d\n", bswapBE16(pmmh->psecnum));
502 Log(" pseq = %d\n", bswapBE16(pmmh->pseq));
503 Log(" blockarr = 0x%08X\n", bswapBE32(pmmh->blockarr));
504 Log(" mmdflags = 0x%08X\n", bswapBE32(pmmh->mmdflags));
505 Log(" smplarr = 0x%08X\n", bswapBE32(pmmh->smplarr));
506 Log(" reserved = 0x%08X\n", bswapBE32(pmmh->reserved));
507 Log(" expdata = 0x%08X\n", bswapBE32(pmmh->expdata));
508 Log(" reserved2= 0x%08X\n", bswapBE32(pmmh->reserved2));
509 Log(" pstate = %d\n", bswapBE16(pmmh->pstate));
510 Log(" pblock = %d\n", bswapBE16(pmmh->pblock));
511 Log(" pline = %d\n", bswapBE16(pmmh->pline));
512 Log(" pseqnum = %d\n", bswapBE16(pmmh->pseqnum));
513 Log(" actplayline=%d\n", bswapBE16(pmmh->actplayline));
514 Log(" counter = %d\n", pmmh->counter);
515 Log(" extra_songs = %d\n", pmmh->extra_songs);
516 Log("\n");
517#endif
518 m_nType = MOD_TYPE_MED;
519 m_nSongPreAmp = 0x20;
520 dwBlockArr = bswapBE32(pmmh->blockarr);
521 dwSmplArr = bswapBE32(pmmh->smplarr);
522 dwExpData = bswapBE32(pmmh->expdata);
523 if ((dwExpData) && (dwExpData+sizeof(MMD0EXP) < dwMemLength))
524 pmex = (MMD0EXP *)(lpStream+dwExpData);
525 else
526 pmex = NULL;
527 pmsh = (MMD0SONGHEADER *)(lpStream + dwSong);
528 pmsh2 = (MMD2SONGHEADER *)pmsh;
529#ifdef MED_LOG
530 if (version < '2')
531 {
532 Log("MMD0 Header:\n");
533 Log(" numblocks = %d\n", bswapBE16(pmsh->numblocks));
534 Log(" songlen = %d\n", bswapBE16(pmsh->songlen));
535 Log(" playseq = ");
536 for (UINT idbg1=0; idbg1<16; idbg1++) Log("%2d, ", pmsh->playseq[idbg1]);
537 Log("...\n");
538 Log(" deftempo = 0x%04X\n", bswapBE16(pmsh->deftempo));
539 Log(" playtransp = %d\n", (signed char)pmsh->playtransp);
540 Log(" flags(1,2) = 0x%02X, 0x%02X\n", pmsh->flags, pmsh->flags2);
541 Log(" tempo2 = %d\n", pmsh->tempo2);
542 Log(" trkvol = ");
543 for (UINT idbg2=0; idbg2<16; idbg2++) Log("0x%02X, ", pmsh->trkvol[idbg2]);
544 Log("...\n");
545 Log(" mastervol = 0x%02X\n", pmsh->mastervol);
546 Log(" numsamples = %d\n", pmsh->numsamples);
547 } else
548 {
549 Log("MMD2 Header:\n");
550 Log(" numblocks = %d\n", bswapBE16(pmsh2->numblocks));
551 Log(" numsections= %d\n", bswapBE16(pmsh2->numsections));
552 Log(" playseqptr = 0x%04X\n", bswapBE32(pmsh2->playseqtable));
553 Log(" sectionptr = 0x%04X\n", bswapBE32(pmsh2->sectiontable));
554 Log(" trackvols = 0x%04X\n", bswapBE32(pmsh2->trackvols));
555 Log(" numtracks = %d\n", bswapBE16(pmsh2->numtracks));
556 Log(" numpseqs = %d\n", bswapBE16(pmsh2->numpseqs));
557 Log(" trackpans = 0x%04X\n", bswapBE32(pmsh2->trackpans));
558 Log(" flags3 = 0x%08X\n", bswapBE32(pmsh2->flags3));
559 Log(" voladj = %d\n", bswapBE16(pmsh2->voladj));
560 Log(" channels = %d\n", bswapBE16(pmsh2->channels));
561 Log(" echotype = %d\n", pmsh2->mix_echotype);
562 Log(" echodepth = %d\n", pmsh2->mix_echodepth);
563 Log(" echolen = %d\n", bswapBE16(pmsh2->mix_echolen));
564 Log(" stereosep = %d\n", (signed char)pmsh2->mix_stereosep);
565 Log(" deftempo = 0x%04X\n", bswapBE16(pmsh2->deftempo));
566 Log(" playtransp = %d\n", (signed char)pmsh2->playtransp);
567 Log(" flags(1,2) = 0x%02X, 0x%02X\n", pmsh2->flags, pmsh2->flags2);
568 Log(" tempo2 = %d\n", pmsh2->tempo2);
569 Log(" mastervol = 0x%02X\n", pmsh2->mastervol);
570 Log(" numsamples = %d\n", pmsh->numsamples);
571 }
572 Log("\n");
573#endif
574 wNumBlocks = bswapBE16(pmsh->numblocks);
575 m_nChannels = 4;
576 m_nSamples = pmsh->numsamples;
577 if (m_nSamples > 63) m_nSamples = 63;
578 // Tempo
579 m_nDefaultTempo = 125;
580 deftempo = bswapBE16(pmsh->deftempo);
581 if (!deftempo) deftempo = 125;
582 if (pmsh->flags2 & MMD_FLAG2_BPM)
583 {
584 UINT tempo_tpl = (pmsh->flags2 & MMD_FLAG2_BMASK) + 1;
585 if (!tempo_tpl) tempo_tpl = 4;
586 deftempo *= tempo_tpl;
587 deftempo /= 4;
588 #ifdef MED_LOG
589 Log("newtempo: %3d bpm (bpm=%3d lpb=%2d)\n", deftempo, bswapBE16(pmsh->deftempo), (pmsh->flags2 & MMD_FLAG2_BMASK)+1);
590 #endif
591 } else
592 {
593 deftempo = _muldiv(deftempo, 5*715909, 2*474326);
594 #ifdef MED_LOG
595 Log("oldtempo: %3d bpm (bpm=%3d)\n", deftempo, bswapBE16(pmsh->deftempo));
596 #endif
597 }
598 // Speed
599 m_nDefaultSpeed = pmsh->tempo2;
600 if (!m_nDefaultSpeed) m_nDefaultSpeed = 6;
601 if (deftempo < 0x21) deftempo = 0x21;
602 if (deftempo > 255)
603 {
604 while ((m_nDefaultSpeed > 3) && (deftempo > 260))
605 {
606 deftempo = (deftempo * (m_nDefaultSpeed - 1)) / m_nDefaultSpeed;
607 m_nDefaultSpeed--;
608 }
609 if (deftempo > 255) deftempo = 255;
610 }
611 m_nDefaultTempo = deftempo;
612 // Reading Samples
613 for (UINT iSHdr=0; iSHdr<m_nSamples; iSHdr++)
614 {
615 MODINSTRUMENT *pins = &Ins[iSHdr+1];
616 pins->nLoopStart = bswapBE16(pmsh->sample[iSHdr].rep) << 1;
617 pins->nLoopEnd = pins->nLoopStart + (bswapBE16(pmsh->sample[iSHdr].replen) << 1);
618 pins->nVolume = (pmsh->sample[iSHdr].svol << 2);
619 pins->nGlobalVol = 64;
620 if (pins->nVolume > 256) pins->nVolume = 256;
621 pins->RelativeTone = -12 * pmsh->sample[iSHdr].strans;
622 pins->nPan = 128;
623 if (pins->nLoopEnd) pins->uFlags |= CHN_LOOP;
624 }
625 // Common Flags
626 if (!(pmsh->flags & 0x20)) m_dwSongFlags |= SONG_FASTVOLSLIDES;
627 // Reading play sequence
628 if (version < '2')
629 {
630 UINT nbo = pmsh->songlen >> 8;
631 if (nbo >= MAX_ORDERS) nbo = MAX_ORDERS-1;
632 if (!nbo) nbo = 1;
633 memcpy(Order, pmsh->playseq, nbo);
634 playtransp = pmsh->playtransp;
635 } else
636 {
637 UINT nOrders, nSections;
638 UINT nTrks = bswapBE16(pmsh2->numtracks);
639 if ((nTrks >= 4) && (nTrks <= 32)) m_nChannels = nTrks;
640 DWORD playseqtable = bswapBE32(pmsh2->playseqtable);
641 UINT numplayseqs = bswapBE16(pmsh2->numpseqs);
642 if (!numplayseqs) numplayseqs = 1;
643 nOrders = 0;
644 nSections = bswapBE16(pmsh2->numsections);
645 DWORD sectiontable = bswapBE32(pmsh2->sectiontable);
646 if ((!nSections) || (!sectiontable) || (sectiontable >= dwMemLength-2)) nSections = 1;
647 nOrders = 0;
648 for (UINT iSection=0; iSection<nSections; iSection++)
649 {
650 UINT nplayseq = 0;
651 if ((sectiontable) && (sectiontable < dwMemLength-2))
652 {
653 nplayseq = lpStream[sectiontable+1];
654 sectiontable += 2; // WORDs
655 } else
656 {
657 nSections = 0;
658 }
659 UINT pseq = 0;
660
661 if ((playseqtable) && (playseqtable + nplayseq*4 < dwMemLength))
662 {
663 pseq = bswapBE32(((LPDWORD)(lpStream+playseqtable))[nplayseq]);
664 }
665 if ((pseq) && (pseq < dwMemLength - sizeof(MMD2PLAYSEQ)))
666 {
667 MMD2PLAYSEQ *pmps = (MMD2PLAYSEQ *)(lpStream + pseq);
668 if (!m_szNames[0][0]) memcpy(m_szNames[0], pmps->name, 31);
669 UINT n = bswapBE16(pmps->length);
670 if (pseq+n <= dwMemLength)
671 {
672 for (UINT i=0; i<n; i++)
673 {
674 UINT seqval = pmps->seq[i] >> 8;
675 if ((seqval < wNumBlocks) && (nOrders < MAX_ORDERS-1))
676 {
677 Order[nOrders++] = seqval;
678 }
679 }
680 }
681 }
682 }
683 playtransp = pmsh2->playtransp;
684 while (nOrders < MAX_ORDERS) Order[nOrders++] = 0xFF;
685 }
686 // Reading Expansion structure
687 if (pmex)
688 {
689 // Channel Split
690 if ((m_nChannels == 4) && (pmsh->flags & 0x40))
691 {
692 for (UINT i8ch=0; i8ch<4; i8ch++)
693 {
694 if (pmex->channelsplit[i8ch]) m_nChannels++;
695 }
696 }
697 // Song Comments
698 UINT annotxt = bswapBE32(pmex->annotxt);
699 UINT annolen = bswapBE32(pmex->annolen);
700 if ((annotxt) && (annolen) && (annotxt+annolen <= dwMemLength))
701 {
702 m_lpszSongComments = new char[annolen+1];
703 memcpy(m_lpszSongComments, lpStream+annotxt, annolen);
704 m_lpszSongComments[annolen] = 0;
705 }
706 // Song Name
707 UINT songname = bswapBE32(pmex->songname);
708 UINT songnamelen = bswapBE32(pmex->songnamelen);
709 if ((songname) && (songnamelen) && (songname+songnamelen <= dwMemLength))
710 {
711 if (songnamelen > 31) songnamelen = 31;
712 memcpy(m_szNames[0], lpStream+songname, songnamelen);
713 }
714 // Sample Names
715 DWORD smpinfoex = bswapBE32(pmex->iinfo);
716 if (smpinfoex)
717 {
718 DWORD iinfoptr = bswapBE32(pmex->iinfo);
719 UINT ientries = bswapBE16(pmex->i_ext_entries);
720 UINT ientrysz = bswapBE16(pmex->i_ext_entrsz);
721
722 if ((iinfoptr) && (ientrysz < 256) && (iinfoptr + ientries*ientrysz < dwMemLength))
723 {
724 LPCSTR psznames = (LPCSTR)(lpStream + iinfoptr);
725 UINT maxnamelen = ientrysz;
726 if (maxnamelen > 32) maxnamelen = 32;
727 for (UINT i=0; i<ientries; i++) if (i < m_nSamples)
728 {
729 lstrcpyn(m_szNames[i+1], psznames + i*ientrysz, maxnamelen);
730 }
731 }
732 }
733 // Track Names
734 DWORD trackinfo_ofs = bswapBE32(pmex->trackinfo_ofs);
735 if ((trackinfo_ofs) && (trackinfo_ofs + m_nChannels * 4 < dwMemLength))
736 {
737 DWORD *ptrktags = (DWORD *)(lpStream + trackinfo_ofs);
738 for (UINT i=0; i<m_nChannels; i++)
739 {
740 DWORD trknameofs = 0, trknamelen = 0;
741 DWORD trktagofs = bswapBE32(ptrktags[i]);
742 if (trktagofs)
743 {
744 while (trktagofs+8 < dwMemLength)
745 {
746 DWORD ntag = bswapBE32(*(DWORD *)(lpStream + trktagofs));
747 if (ntag == MMDTAG_END) break;
748 DWORD tagdata = bswapBE32(*(DWORD *)(lpStream + trktagofs + 4));
749 switch(ntag)
750 {
751 case MMDTAG_TRK_NAMELEN:trknamelen = tagdata; break;
752 case MMDTAG_TRK_NAME: trknameofs = tagdata; break;
753 }
754 trktagofs += 8;
755 }
756 if (trknamelen > MAX_CHANNELNAME) trknamelen = MAX_CHANNELNAME;
757 if ((trknameofs) && (trknameofs + trknamelen < dwMemLength))
758 {
759 lstrcpyn(ChnSettings[i].szName, (LPCSTR)(lpStream+trknameofs), MAX_CHANNELNAME);
760 }
761 }
762 }
763 }
764 }
765 // Reading samples
766 if (dwSmplArr > dwMemLength - 4*m_nSamples) return TRUE;
767 pdwTable = (LPDWORD)(lpStream + dwSmplArr);
768 for (UINT iSmp=0; iSmp<m_nSamples; iSmp++) if (pdwTable[iSmp])
769 {
770 UINT dwPos = bswapBE32(pdwTable[iSmp]);
771 if ((dwPos >= dwMemLength) || (dwPos + sizeof(MMDSAMPLEHEADER) >= dwMemLength)) continue;
772 MMDSAMPLEHEADER *psdh = (MMDSAMPLEHEADER *)(lpStream + dwPos);
773 UINT len = bswapBE32(psdh->length);
774 #ifdef MED_LOG
775 Log("SampleData %d: stype=0x%02X len=%d\n", iSmp, bswapBE16(psdh->type), len);
776 #endif
777 if ((len > MAX_SAMPLE_LENGTH) || (dwPos + len + 6 > dwMemLength)) len = 0;
778 UINT flags = RS_PCM8S, stype = bswapBE16(psdh->type);
779 LPSTR psdata = (LPSTR)(lpStream + dwPos + 6);
780 if (stype & 0x80)
781 {
782 psdata += (stype & 0x20) ? 14 : 6;
783 } else
784 {
785 if (stype & 0x10)
786 {
787 Ins[iSmp+1].uFlags |= CHN_16BIT;
788 len /= 2;
789 flags = (stype & 0x20) ? RS_STPCM16M : RS_PCM16M;
790 } else
791 {
792 flags = (stype & 0x20) ? RS_STPCM8S : RS_PCM8S;
793 }
794 if (stype & 0x20) len /= 2;
795 }
796 Ins[iSmp+1].nLength = len;
797 ReadSample(&Ins[iSmp+1], flags, psdata, dwMemLength - dwPos - 6);
798 }
799 // Reading patterns (blocks)
800 if (wNumBlocks > MAX_PATTERNS) wNumBlocks = MAX_PATTERNS;
801 if ((!dwBlockArr) || (dwBlockArr > dwMemLength - 4*wNumBlocks)) return TRUE;
802 pdwTable = (LPDWORD)(lpStream + dwBlockArr);
803 playtransp += (version == '3') ? 24 : 48;
804 for (UINT iBlk=0; iBlk<wNumBlocks; iBlk++)
805 {
806 UINT dwPos = bswapBE32(pdwTable[iBlk]);
807 if ((!dwPos) || (dwPos >= dwMemLength) || (dwPos >= dwMemLength - 8)) continue;
808 UINT lines = 64, tracks = 4;
809 if (version == '0')
810 {
811 const MMD0BLOCK *pmb = (const MMD0BLOCK *)(lpStream + dwPos);
812 lines = pmb->lines + 1;
813 tracks = pmb->numtracks;
814 if (!tracks) tracks = m_nChannels;
815 if ((Patterns[iBlk] = AllocatePattern(lines, m_nChannels)) == NULL) continue;
816 PatternSize[iBlk] = lines;
817 MODCOMMAND *p = Patterns[iBlk];
818 LPBYTE s = (LPBYTE)(lpStream + dwPos + 2);
819 UINT maxlen = tracks*lines*3;
820 if (maxlen + dwPos > dwMemLength - 2) break;
821 for (UINT y=0; y<lines; y++)
822 {
823 for (UINT x=0; x<tracks; x++, s+=3) if (x < m_nChannels)
824 {
825 BYTE note = s[0] & 0x3F;
826 BYTE instr = s[1] >> 4;
827 if (s[0] & 0x80) instr |= 0x10;
828 if (s[0] & 0x40) instr |= 0x20;
829 if ((note) && (note <= 132)) p->note = note + playtransp;
830 p->instr = instr;
831 p->command = s[1] & 0x0F;
832 p->param = s[2];
833 // if (!iBlk) Log("%02X.%02X.%02X | ", s[0], s[1], s[2]);
834 MedConvert(p, pmsh);
835 p++;
836 }
837 //if (!iBlk) Log("\n");
838 }
839 } else
840 {
841 MMD1BLOCK *pmb = (MMD1BLOCK *)(lpStream + dwPos);
842 #ifdef MED_LOG
843 Log("MMD1BLOCK: lines=%2d, tracks=%2d, offset=0x%04X\n",
844 bswapBE16(pmb->lines), bswapBE16(pmb->numtracks), bswapBE32(pmb->info));
845 #endif
846 MMD1BLOCKINFO *pbi = NULL;
847 BYTE *pcmdext = NULL;
848 lines = (pmb->lines >> 8) + 1;
849 tracks = pmb->numtracks >> 8;
850 if (!tracks) tracks = m_nChannels;
851 if ((Patterns[iBlk] = AllocatePattern(lines, m_nChannels)) == NULL) continue;
852 PatternSize[iBlk] = (WORD)lines;
853 DWORD dwBlockInfo = bswapBE32(pmb->info);
854 if ((dwBlockInfo) && (dwBlockInfo < dwMemLength - sizeof(MMD1BLOCKINFO)))
855 {
856 pbi = (MMD1BLOCKINFO *)(lpStream + dwBlockInfo);
857 #ifdef MED_LOG
858 Log(" BLOCKINFO: blockname=0x%04X namelen=%d pagetable=0x%04X &cmdexttable=0x%04X\n",
859 bswapBE32(pbi->blockname), bswapBE32(pbi->blocknamelen), bswapBE32(pbi->pagetable), bswapBE32(pbi->cmdexttable));
860 #endif
861 if ((pbi->blockname) && (pbi->blocknamelen))
862 {
863 DWORD nameofs = bswapBE32(pbi->blockname);
864 UINT namelen = bswapBE32(pbi->blocknamelen);
865 if ((nameofs < dwMemLength) && (nameofs+namelen < dwMemLength))
866 {
867 SetPatternName(iBlk, (LPCSTR)(lpStream+nameofs));
868 }
869 }
870 if (pbi->cmdexttable)
871 {
872 DWORD cmdexttable = bswapBE32(pbi->cmdexttable);
873 if (cmdexttable < dwMemLength - 4)
874 {
875 cmdexttable = bswapBE32(*(DWORD *)(lpStream + cmdexttable));
876 if ((cmdexttable) && (cmdexttable <= dwMemLength - lines*tracks))
877 {
878 pcmdext = (BYTE *)(lpStream + cmdexttable);
879 }
880 }
881 }
882 }
883 MODCOMMAND *p = Patterns[iBlk];
884 LPBYTE s = (LPBYTE)(lpStream + dwPos + 8);
885 UINT maxlen = tracks*lines*4;
886 if (maxlen + dwPos > dwMemLength - 8) break;
887 for (UINT y=0; y<lines; y++)
888 {
889 for (UINT x=0; x<tracks; x++, s+=4) if (x < m_nChannels)
890 {
891 BYTE note = s[0];
892 if ((note) && (note <= 132))
893 {
894 int rnote = note + playtransp;
895 if (rnote < 1) rnote = 1;
896 if (rnote > 120) rnote = 120;
897 p->note = (BYTE)rnote;
898 }
899 p->instr = s[1];
900 p->command = s[2];
901 p->param = s[3];
902 if (pcmdext) p->vol = pcmdext[x];
903 MedConvert(p, pmsh);
904 p++;
905 }
906 if (pcmdext) pcmdext += tracks;
907 }
908 }
909 }
910 // Setup channel pan positions
911 for (UINT iCh=0; iCh<m_nChannels; iCh++)
912 {
913 ChnSettings[iCh].nPan = (((iCh&3) == 1) || ((iCh&3) == 2)) ? 0xC0 : 0x40;
914 ChnSettings[iCh].nVolume = 64;
915 }
916 return TRUE;
917}
918
919
diff --git a/core/multimedia/opieplayer/modplug/load_mod.cpp b/core/multimedia/opieplayer/modplug/load_mod.cpp
new file mode 100644
index 0000000..3ca8e5b
--- a/dev/null
+++ b/core/multimedia/opieplayer/modplug/load_mod.cpp
@@ -0,0 +1,501 @@
1/*
2 * This program is free software; you can redistribute it and modify it
3 * under the terms of the GNU General Public License as published by the
4 * Free Software Foundation; either version 2 of the license or (at your
5 * option) any later version.
6 *
7 * Authors: Olivier Lapicque <olivierl@jps.net>,
8 * Adam Goode <adam@evdebs.org> (endian and char fixes for PPC)
9*/
10
11#include "stdafx.h"
12#include "sndfile.h"
13
14//#pragma warning(disable:4244)
15
16extern WORD ProTrackerPeriodTable[6*12];
17
18//////////////////////////////////////////////////////////
19// ProTracker / NoiseTracker MOD/NST file support
20
21void CSoundFile::ConvertModCommand(MODCOMMAND *m) const
22//-----------------------------------------------------
23{
24 UINT command = m->command, param = m->param;
25
26 switch(command)
27 {
28 case 0x00:if (param) command = CMD_ARPEGGIO; break;
29 case 0x01:command = CMD_PORTAMENTOUP; break;
30 case 0x02:command = CMD_PORTAMENTODOWN; break;
31 case 0x03:command = CMD_TONEPORTAMENTO; break;
32 case 0x04:command = CMD_VIBRATO; break;
33 case 0x05:command = CMD_TONEPORTAVOL; if (param & 0xF0) param &= 0xF0; break;
34 case 0x06:command = CMD_VIBRATOVOL; if (param & 0xF0) param &= 0xF0; break;
35 case 0x07:command = CMD_TREMOLO; break;
36 case 0x08:command = CMD_PANNING8; break;
37 case 0x09:command = CMD_OFFSET; break;
38 case 0x0A:command = CMD_VOLUMESLIDE; if (param & 0xF0) param &= 0xF0; break;
39 case 0x0B:command = CMD_POSITIONJUMP; break;
40 case 0x0C:command = CMD_VOLUME; break;
41 case 0x0D:command = CMD_PATTERNBREAK; param = ((param >> 4) * 10) + (param & 0x0F); break;
42 case 0x0E:command = CMD_MODCMDEX; break;
43 case 0x0F:command = (param <= (UINT)((m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2)) ? 0x1F : 0x20)) ? CMD_SPEED : CMD_TEMPO;
44 if ((param == 0xFF) && (m_nSamples == 15)) command = 0; break;
45 // Extension for XM extended effects
46 case 'G' - 55:command = CMD_GLOBALVOLUME; break;
47 case 'H' - 55:command = CMD_GLOBALVOLSLIDE; if (param & 0xF0) param &= 0xF0; break;
48 case 'K' - 55:command = CMD_KEYOFF; break;
49 case 'L' - 55:command = CMD_SETENVPOSITION; break;
50 case 'M' - 55:command = CMD_CHANNELVOLUME; break;
51 case 'N' - 55:command = CMD_CHANNELVOLSLIDE; break;
52 case 'P' - 55:command = CMD_PANNINGSLIDE; if (param & 0xF0) param &= 0xF0; break;
53 case 'R' - 55:command = CMD_RETRIG; break;
54 case 'T' - 55:command = CMD_TREMOR; break;
55 case 'X' - 55: command = CMD_XFINEPORTAUPDOWN;break;
56 case 'Y' - 55:command = CMD_PANBRELLO; break;
57 case 'Z' - 55: command = CMD_MIDI;break;
58 default:command = 0;
59 }
60 m->command = command;
61 m->param = param;
62}
63
64
65WORD CSoundFile::ModSaveCommand(const MODCOMMAND *m, BOOL bXM) const
66//------------------------------------------------------------------
67{
68 UINT command = m->command & 0x3F, param = m->param;
69
70 switch(command)
71 {
72 case 0: command = param = 0; break;
73 case CMD_ARPEGGIO: command = 0; break;
74 case CMD_PORTAMENTOUP:
75 if (m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT|MOD_TYPE_STM))
76 {
77 if ((param & 0xF0) == 0xE0) { command=0x0E; param=((param & 0x0F) >> 2)|0x10; break; }
78 else if ((param & 0xF0) == 0xF0) { command=0x0E; param &= 0x0F; param|=0x10; break; }
79 }
80 command = 0x01;
81 break;
82 case CMD_PORTAMENTODOWN:
83 if (m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT|MOD_TYPE_STM))
84 {
85 if ((param & 0xF0) == 0xE0) { command=0x0E; param=((param & 0x0F) >> 2)|0x20; break; }
86 else if ((param & 0xF0) == 0xF0) { command=0x0E; param &= 0x0F; param|=0x20; break; }
87 }
88 command = 0x02;
89 break;
90 case CMD_TONEPORTAMENTO:command = 0x03; break;
91 case CMD_VIBRATO: command = 0x04; break;
92 case CMD_TONEPORTAVOL: command = 0x05; break;
93 case CMD_VIBRATOVOL: command = 0x06; break;
94 case CMD_TREMOLO: command = 0x07; break;
95 case CMD_PANNING8:
96 command = 0x08;
97 if (bXM)
98 {
99 if ((m_nType != MOD_TYPE_IT) && (m_nType != MOD_TYPE_XM) && (param <= 0x80))
100 {
101 param <<= 1;
102 if (param > 255) param = 255;
103 }
104 } else
105 {
106 if ((m_nType == MOD_TYPE_IT) || (m_nType == MOD_TYPE_XM)) param >>= 1;
107 }
108 break;
109 case CMD_OFFSET: command = 0x09; break;
110 case CMD_VOLUMESLIDE: command = 0x0A; break;
111 case CMD_POSITIONJUMP: command = 0x0B; break;
112 case CMD_VOLUME: command = 0x0C; break;
113 case CMD_PATTERNBREAK: command = 0x0D; param = ((param / 10) << 4) | (param % 10); break;
114 case CMD_MODCMDEX: command = 0x0E; break;
115 case CMD_SPEED: command = 0x0F; if (param > 0x20) param = 0x20; break;
116 case CMD_TEMPO: if (param > 0x20) { command = 0x0F; break; }
117 case CMD_GLOBALVOLUME: command = 'G' - 55; break;
118 case CMD_GLOBALVOLSLIDE:command = 'H' - 55; break;
119 case CMD_KEYOFF: command = 'K' - 55; break;
120 case CMD_SETENVPOSITION:command = 'L' - 55; break;
121 case CMD_CHANNELVOLUME: command = 'M' - 55; break;
122 case CMD_CHANNELVOLSLIDE:command = 'N' - 55; break;
123 case CMD_PANNINGSLIDE: command = 'P' - 55; break;
124 case CMD_RETRIG: command = 'R' - 55; break;
125 case CMD_TREMOR: command = 'T' - 55; break;
126 case CMD_XFINEPORTAUPDOWN:command = 'X' - 55; break;
127 case CMD_PANBRELLO: command = 'Y' - 55; break;
128 case CMD_MIDI: command = 'Z' - 55; break;
129 case CMD_S3MCMDEX:
130 switch(param & 0xF0)
131 {
132 case 0x10:command = 0x0E; param = (param & 0x0F) | 0x30; break;
133 case 0x20:command = 0x0E; param = (param & 0x0F) | 0x50; break;
134 case 0x30:command = 0x0E; param = (param & 0x0F) | 0x40; break;
135 case 0x40:command = 0x0E; param = (param & 0x0F) | 0x70; break;
136 case 0x90:command = 'X' - 55; break;
137 case 0xB0:command = 0x0E; param = (param & 0x0F) | 0x60; break;
138 case 0xA0:
139 case 0x50:
140 case 0x70:
141 case 0x60:command = param = 0; break;
142 default:command = 0x0E; break;
143 }
144 break;
145 default: command = param = 0;
146 }
147 return (WORD)((command << 8) | (param));
148}
149
150
151#pragma pack(1)
152
153typedef struct _MODSAMPLE
154{
155 CHAR name[22];
156 WORD length;
157 BYTE finetune;
158 BYTE volume;
159 WORD loopstart;
160 WORD looplen;
161} Q_PACKED MODSAMPLE, *PMODSAMPLE;
162
163typedef struct _MODMAGIC
164{
165 BYTE nOrders;
166 BYTE nRestartPos;
167 BYTE Orders[128];
168 char Magic[4]; // changed from CHAR
169} Q_PACKED MODMAGIC, *PMODMAGIC;
170
171#pragma pack()
172
173BOOL IsMagic(LPCSTR s1, LPCSTR s2)
174{
175 return ((*(DWORD *)s1) == (*(DWORD *)s2)) ? TRUE : FALSE;
176}
177
178
179BOOL CSoundFile::ReadMod(const BYTE *lpStream, DWORD dwMemLength)
180//---------------------------------------------------------------
181{
182 char s[1024]; // changed from CHAR
183 DWORD dwMemPos, dwTotalSampleLen;
184 PMODMAGIC pMagic;
185 UINT nErr;
186
187 if ((!lpStream) || (dwMemLength < 0x600)) return FALSE;
188 dwMemPos = 20;
189 m_nSamples = 31;
190 m_nChannels = 4;
191 pMagic = (PMODMAGIC)(lpStream+dwMemPos+sizeof(MODSAMPLE)*31);
192 // Check Mod Magic
193 memcpy(s, pMagic->Magic, 4);
194 if ((IsMagic(s, "M.K.")) || (IsMagic(s, "M!K!"))
195 || (IsMagic(s, "M&K!")) || (IsMagic(s, "N.T."))) m_nChannels = 4; else
196 if ((IsMagic(s, "CD81")) || (IsMagic(s, "OKTA"))) m_nChannels = 8; else
197 if ((s[0]=='F') && (s[1]=='L') && (s[2]=='T') && (s[3]>='4') && (s[3]<='9')) m_nChannels = s[3] - '0'; else
198 if ((s[0]>='4') && (s[0]<='9') && (s[1]=='C') && (s[2]=='H') && (s[3]=='N')) m_nChannels = s[0] - '0'; else
199 if ((s[0]=='1') && (s[1]>='0') && (s[1]<='9') && (s[2]=='C') && (s[3]=='H')) m_nChannels = s[1] - '0' + 10; else
200 if ((s[0]=='2') && (s[1]>='0') && (s[1]<='9') && (s[2]=='C') && (s[3]=='H')) m_nChannels = s[1] - '0' + 20; else
201 if ((s[0]=='3') && (s[1]>='0') && (s[1]<='2') && (s[2]=='C') && (s[3]=='H')) m_nChannels = s[1] - '0' + 30; else
202 if ((s[0]=='T') && (s[1]=='D') && (s[2]=='Z') && (s[3]>='4') && (s[3]<='9')) m_nChannels = s[3] - '0'; else
203 if (IsMagic(s,"16CN")) m_nChannels = 16; else
204 if (IsMagic(s,"32CN")) m_nChannels = 32; else m_nSamples = 15;
205 // Load Samples
206 nErr = 0;
207 dwTotalSampleLen = 0;
208 for(UINT i=1; i<=m_nSamples; i++)
209 {
210 PMODSAMPLE pms = (PMODSAMPLE)(lpStream+dwMemPos);
211 MODINSTRUMENT *psmp = &Ins[i];
212 UINT loopstart, looplen;
213
214 memcpy(m_szNames[i], pms->name, 22);
215 m_szNames[i][22] = 0;
216 psmp->uFlags = 0;
217 psmp->nLength = bswapBE16(pms->length)*2;
218 dwTotalSampleLen += psmp->nLength;
219 psmp->nFineTune = MOD2XMFineTune(pms->finetune & 0x0F);
220 psmp->nVolume = 4*pms->volume;
221 if (psmp->nVolume > 256) { psmp->nVolume = 256; nErr++; }
222 psmp->nGlobalVol = 64;
223 psmp->nPan = 128;
224 loopstart = bswapBE16(pms->loopstart)*2;
225 looplen = bswapBE16(pms->looplen)*2;
226 // Fix loops
227 if ((looplen > 2) && (loopstart+looplen > psmp->nLength)
228 && (loopstart/2+looplen <= psmp->nLength))
229 {
230 loopstart /= 2;
231 }
232 psmp->nLoopStart = loopstart;
233 psmp->nLoopEnd = loopstart + looplen;
234 if (psmp->nLength < 4) psmp->nLength = 0;
235 if (psmp->nLength)
236 {
237 UINT derr = 0;
238 if (psmp->nLoopStart >= psmp->nLength) { psmp->nLoopStart = psmp->nLength-1; derr|=1; }
239 if (psmp->nLoopEnd > psmp->nLength) { psmp->nLoopEnd = psmp->nLength; derr |= 1; }
240 if (psmp->nLoopStart > psmp->nLoopEnd) derr |= 1;
241 if ((psmp->nLoopStart > psmp->nLoopEnd) || (psmp->nLoopEnd <= 8)
242 || (psmp->nLoopEnd - psmp->nLoopStart <= 4))
243 {
244 psmp->nLoopStart = 0;
245 psmp->nLoopEnd = 0;
246 }
247 if (psmp->nLoopEnd > psmp->nLoopStart)
248 {
249 psmp->uFlags |= CHN_LOOP;
250 }
251 }
252 dwMemPos += sizeof(MODSAMPLE);
253 }
254 if ((m_nSamples == 15) && (dwTotalSampleLen > dwMemLength * 4)) return FALSE;
255 pMagic = (PMODMAGIC)(lpStream+dwMemPos);
256 dwMemPos += sizeof(MODMAGIC);
257 if (m_nSamples == 15) dwMemPos -= 4;
258 memset(Order, 0,sizeof(Order));
259 memcpy(Order, pMagic->Orders, 128);
260
261 UINT nbp, nbpbuggy, nbpbuggy2, norders;
262
263 norders = pMagic->nOrders;
264 if ((!norders) || (norders > 0x80))
265 {
266 norders = 0x80;
267 while ((norders > 1) && (!Order[norders-1])) norders--;
268 }
269 nbpbuggy = 0;
270 nbpbuggy2 = 0;
271 nbp = 0;
272 for (UINT iord=0; iord<128; iord++)
273 {
274 UINT i = Order[iord];
275 if ((i < 0x80) && (nbp <= i))
276 {
277 nbp = i+1;
278 if (iord<norders) nbpbuggy = nbp;
279 }
280 if (i >= nbpbuggy2) nbpbuggy2 = i+1;
281 }
282 for (UINT iend=norders; iend<MAX_ORDERS; iend++) Order[iend] = 0xFF;
283 norders--;
284 m_nRestartPos = pMagic->nRestartPos;
285 if (m_nRestartPos >= 0x78) m_nRestartPos = 0;
286 if (m_nRestartPos + 1 >= (UINT)norders) m_nRestartPos = 0;
287 if (!nbp) return FALSE;
288 DWORD dwWowTest = dwTotalSampleLen+dwMemPos;
289 if ((IsMagic(pMagic->Magic, "M.K.")) && (dwWowTest + nbp*8*256 == dwMemLength)) m_nChannels = 8;
290 if ((nbp != nbpbuggy) && (dwWowTest + nbp*m_nChannels*256 != dwMemLength))
291 {
292 if (dwWowTest + nbpbuggy*m_nChannels*256 == dwMemLength) nbp = nbpbuggy;
293 else nErr += 8;
294 } else
295 if ((nbpbuggy2 > nbp) && (dwWowTest + nbpbuggy2*m_nChannels*256 == dwMemLength))
296 {
297 nbp = nbpbuggy2;
298 }
299 if ((dwWowTest < 0x600) || (dwWowTest > dwMemLength)) nErr += 8;
300 if ((m_nSamples == 15) && (nErr >= 16)) return FALSE;
301 // Default settings
302 m_nType = MOD_TYPE_MOD;
303 m_nDefaultSpeed = 6;
304 m_nDefaultTempo = 125;
305 m_nMinPeriod = 14 << 2;
306 m_nMaxPeriod = 3424 << 2;
307 memcpy(m_szNames, lpStream, 20);
308 // Setting channels pan
309 for (UINT ich=0; ich<m_nChannels; ich++)
310 {
311 ChnSettings[ich].nVolume = 64;
312 if (gdwSoundSetup & SNDMIX_MAXDEFAULTPAN)
313 ChnSettings[ich].nPan = (((ich&3)==1) || ((ich&3)==2)) ? 256 : 0;
314 else
315 ChnSettings[ich].nPan = (((ich&3)==1) || ((ich&3)==2)) ? 0xC0 : 0x40;
316 }
317 // Reading channels
318 for (UINT ipat=0; ipat<nbp; ipat++)
319 {
320 if (ipat < MAX_PATTERNS)
321 {
322 if ((Patterns[ipat] = AllocatePattern(64, m_nChannels)) == NULL) break;
323 PatternSize[ipat] = 64;
324 if (dwMemPos + m_nChannels*256 >= dwMemLength) break;
325 MODCOMMAND *m = Patterns[ipat];
326 LPCBYTE p = lpStream + dwMemPos;
327 for (UINT j=m_nChannels*64; j; m++,p+=4,j--)
328 {
329 BYTE A0=p[0], A1=p[1], A2=p[2], A3=p[3];
330 UINT n = ((((UINT)A0 & 0x0F) << 8) | (A1));
331 if ((n) && (n != 0xFFF)) m->note = GetNoteFromPeriod(n << 2);
332 m->instr = ((UINT)A2 >> 4) | (A0 & 0x10);
333 m->command = A2 & 0x0F;
334 m->param = A3;
335 if ((m->command) || (m->param)) ConvertModCommand(m);
336 }
337 }
338 dwMemPos += m_nChannels*256;
339 }
340 // Reading instruments
341 DWORD dwErrCheck = 0;
342 for (UINT ismp=1; ismp<=m_nSamples; ismp++) if (Ins[ismp].nLength)
343 {
344 LPSTR p = (LPSTR)(lpStream+dwMemPos);
345 UINT flags = 0;
346 if (dwMemPos + 5 >= dwMemLength) break;
347 if (!strnicmp(p, "ADPCM", 5))
348 {
349 flags = 3;
350 p += 5;
351 dwMemPos += 5;
352 }
353 DWORD dwSize = ReadSample(&Ins[ismp], flags, p, dwMemLength - dwMemPos);
354 if (dwSize)
355 {
356 dwMemPos += dwSize;
357 dwErrCheck++;
358 }
359 }
360#ifdef MODPLUG_TRACKER
361 return TRUE;
362#else
363 return (dwErrCheck) ? TRUE : FALSE;
364#endif
365}
366
367
368#ifndef MODPLUG_NO_FILESAVE
369#pragma warning(disable:4100)
370
371BOOL CSoundFile::SaveMod(LPCSTR lpszFileName, UINT nPacking)
372//----------------------------------------------------------
373{
374 BYTE insmap[32];
375 UINT inslen[32];
376 BYTE bTab[32];
377 BYTE ord[128];
378 FILE *f;
379
380 if ((!m_nChannels) || (!lpszFileName)) return FALSE;
381 if ((f = fopen(lpszFileName, "wb")) == NULL) return FALSE;
382 memset(ord, 0, sizeof(ord));
383 memset(inslen, 0, sizeof(inslen));
384 if (m_nInstruments)
385 {
386 memset(insmap, 0, sizeof(insmap));
387 for (UINT i=1; i<32; i++) if (Headers[i])
388 {
389 for (UINT j=0; j<128; j++) if (Headers[i]->Keyboard[j])
390 {
391 insmap[i] = Headers[i]->Keyboard[j];
392 break;
393 }
394 }
395 } else
396 {
397 for (UINT i=0; i<32; i++) insmap[i] = (BYTE)i;
398 }
399 // Writing song name
400 fwrite(m_szNames, 20, 1, f);
401 // Writing instrument definition
402 for (UINT iins=1; iins<=31; iins++)
403 {
404 MODINSTRUMENT *pins = &Ins[insmap[iins]];
405 memcpy(bTab, m_szNames[iins],22);
406 inslen[iins] = pins->nLength;
407 if (inslen[iins] > 0x1fff0) inslen[iins] = 0x1fff0;
408 bTab[22] = inslen[iins] >> 9;
409 bTab[23] = inslen[iins] >> 1;
410 if (pins->RelativeTone < 0) bTab[24] = 0x08; else
411 if (pins->RelativeTone > 0) bTab[24] = 0x07; else
412 bTab[24] = (BYTE)XM2MODFineTune(pins->nFineTune);
413 bTab[25] = pins->nVolume >> 2;
414 bTab[26] = pins->nLoopStart >> 9;
415 bTab[27] = pins->nLoopStart >> 1;
416 bTab[28] = (pins->nLoopEnd - pins->nLoopStart) >> 9;
417 bTab[29] = (pins->nLoopEnd - pins->nLoopStart) >> 1;
418 fwrite(bTab, 30, 1, f);
419 }
420 // Writing number of patterns
421 UINT nbp=0, norders=128;
422 for (UINT iord=0; iord<128; iord++)
423 {
424 if (Order[iord] == 0xFF)
425 {
426 norders = iord;
427 break;
428 }
429 if ((Order[iord] < 0x80) && (nbp<=Order[iord])) nbp = Order[iord]+1;
430 }
431 bTab[0] = norders;
432 bTab[1] = m_nRestartPos;
433 fwrite(bTab, 2, 1, f);
434 // Writing pattern list
435 if (norders) memcpy(ord, Order, norders);
436 fwrite(ord, 128, 1, f);
437 // Writing signature
438 if (m_nChannels == 4)
439 lstrcpy((LPSTR)&bTab, "M.K.");
440 else
441 wsprintf((LPSTR)&bTab, "%luCHN", m_nChannels);
442 fwrite(bTab, 4, 1, f);
443 // Writing patterns
444 for (UINT ipat=0; ipat<nbp; ipat++) if (Patterns[ipat])
445 {
446 BYTE s[64*4];
447 MODCOMMAND *m = Patterns[ipat];
448 for (UINT i=0; i<64; i++) if (i < PatternSize[ipat])
449 {
450 LPBYTE p=s;
451 for (UINT c=0; c<m_nChannels; c++,p+=4,m++)
452 {
453 UINT param = ModSaveCommand(m, FALSE);
454 UINT command = param >> 8;
455 param &= 0xFF;
456 if (command > 0x0F) command = param = 0;
457 if ((m->vol >= 0x10) && (m->vol <= 0x50) && (!command) && (!param)) { command = 0x0C; param = m->vol - 0x10; }
458 UINT period = m->note;
459 if (period)
460 {
461 if (period < 37) period = 37;
462 period -= 37;
463 if (period >= 6*12) period = 6*12-1;
464 period = ProTrackerPeriodTable[period];
465 }
466 UINT instr = (m->instr > 31) ? 0 : m->instr;
467 p[0] = ((period >> 8) & 0x0F) | (instr & 0x10);
468 p[1] = period & 0xFF;
469 p[2] = ((instr & 0x0F) << 4) | (command & 0x0F);
470 p[3] = param;
471 }
472 fwrite(s, m_nChannels, 4, f);
473 } else
474 {
475 memset(s, 0, m_nChannels*4);
476 fwrite(s, m_nChannels, 4, f);
477 }
478 }
479 // Writing instruments
480 for (UINT ismpd=1; ismpd<=31; ismpd++) if (inslen[ismpd])
481 {
482 MODINSTRUMENT *pins = &Ins[insmap[ismpd]];
483 UINT flags = RS_PCM8S;
484#ifndef NO_PACKING
485 if (!(pins->uFlags & (CHN_16BIT|CHN_STEREO)))
486 {
487 if ((nPacking) && (CanPackSample(pins->pSample, inslen[ismpd], nPacking)))
488 {
489 fwrite("ADPCM", 1, 5, f);
490 flags = RS_ADPCM4;
491 }
492 }
493#endif
494 WriteSample(f, pins, flags, inslen[ismpd]);
495 }
496 fclose(f);
497 return TRUE;
498}
499
500#pragma warning(default:4100)
501#endif // MODPLUG_NO_FILESAVE
diff --git a/core/multimedia/opieplayer/modplug/load_mt2.cpp b/core/multimedia/opieplayer/modplug/load_mt2.cpp
new file mode 100644
index 0000000..afa20d5
--- a/dev/null
+++ b/core/multimedia/opieplayer/modplug/load_mt2.cpp
@@ -0,0 +1,635 @@
1#include "stdafx.h"
2#include "sndfile.h"
3
4//#define MT2DEBUG
5
6#pragma pack(1)
7
8typedef struct _MT2FILEHEADER
9{
10 DWORD dwMT20;// 0x3032544D "MT20"
11 DWORD dwSpecial;
12 WORD wVersion;
13 CHAR szTrackerName[32];// "MadTracker 2.0"
14 CHAR szSongName[64];
15 WORD nOrders;
16 WORD wRestart;
17 WORD wPatterns;
18 WORD wChannels;
19 WORD wSamplesPerTick;
20 BYTE bTicksPerLine;
21 BYTE bLinesPerBeat;
22 DWORD fulFlags; // b0=packed patterns
23 WORD wInstruments;
24 WORD wSamples;
25 BYTE Orders[256];
26} Q_PACKED MT2FILEHEADER;
27
28typedef struct _MT2PATTERN
29{
30 WORD wLines;
31 DWORD wDataLen;
32} Q_PACKED MT2PATTERN;
33
34typedef struct _MT2COMMAND
35{
36 BYTE note;// 0=nothing, 97=note off
37 BYTE instr;
38 BYTE vol;
39 BYTE pan;
40 BYTE fxcmd;
41 BYTE fxparam1;
42 BYTE fxparam2;
43} Q_PACKED MT2COMMAND;
44
45typedef struct _MT2DRUMSDATA
46{
47 WORD wDrumPatterns;
48 WORD wDrumSamples[8];
49 BYTE DrumPatternOrder[256];
50} Q_PACKED MT2DRUMSDATA;
51
52typedef struct _MT2AUTOMATION
53{
54 DWORD dwFlags;
55 DWORD dwEffectId;
56 DWORD nEnvPoints;
57} Q_PACKED MT2AUTOMATION;
58
59typedef struct _MT2INSTRUMENT
60{
61 CHAR szName[32];
62 DWORD dwDataLen;
63 WORD wSamples;
64 BYTE GroupsMapping[96];
65 BYTE bVibType;
66 BYTE bVibSweep;
67 BYTE bVibDepth;
68 BYTE bVibRate;
69 WORD wFadeOut;
70 WORD wNNA;
71 WORD wInstrFlags;
72 WORD wEnvFlags1;
73 WORD wEnvFlags2;
74} Q_PACKED MT2INSTRUMENT;
75
76typedef struct _MT2ENVELOPE
77{
78 BYTE nFlags;
79 BYTE nPoints;
80 BYTE nSustainPos;
81 BYTE nLoopStart;
82 BYTE nLoopEnd;
83 BYTE bReserved[3];
84 BYTE EnvData[64];
85} Q_PACKED MT2ENVELOPE;
86
87typedef struct _MT2SYNTH
88{
89 BYTE nSynthId;
90 BYTE nFxId;
91 WORD wCutOff;
92 BYTE nResonance;
93 BYTE nAttack;
94 BYTE nDecay;
95 BYTE bReserved[25];
96} Q_PACKED MT2SYNTH;
97
98typedef struct _MT2SAMPLE
99{
100 CHAR szName[32];
101 DWORD dwDataLen;
102 DWORD dwLength;
103 DWORD dwFrequency;
104 BYTE nQuality;
105 BYTE nChannels;
106 BYTE nFlags;
107 BYTE nLoop;
108 DWORD dwLoopStart;
109 DWORD dwLoopEnd;
110 WORD wVolume;
111 BYTE nPan;
112 BYTE nBaseNote;
113 WORD wSamplesPerBeat;
114} Q_PACKED MT2SAMPLE;
115
116typedef struct _MT2GROUP
117{
118 BYTE nSmpNo;
119 BYTE nVolume;// 0-128
120 BYTE nFinePitch;
121 BYTE Reserved[5];
122} Q_PACKED MT2GROUP;
123
124#pragma pack()
125
126
127static VOID ConvertMT2Command(CSoundFile *that, MODCOMMAND *m, MT2COMMAND *p)
128//---------------------------------------------------------------------------
129{
130 // Note
131 m->note = 0;
132 if (p->note) m->note = (p->note > 96) ? 0xFF : p->note+12;
133 // Instrument
134 m->instr = p->instr;
135 // Volume Column
136 if ((p->vol >= 0x10) && (p->vol <= 0x90))
137 {
138 m->volcmd = VOLCMD_VOLUME;
139 m->vol = (p->vol - 0x10) >> 1;
140 } else
141 if ((p->vol >= 0xA0) && (p->vol <= 0xAF))
142 {
143 m->volcmd = VOLCMD_VOLSLIDEDOWN;
144 m->vol = (p->vol & 0x0f);
145 } else
146 if ((p->vol >= 0xB0) && (p->vol <= 0xBF))
147 {
148 m->volcmd = VOLCMD_VOLSLIDEUP;
149 m->vol = (p->vol & 0x0f);
150 } else
151 if ((p->vol >= 0xC0) && (p->vol <= 0xCF))
152 {
153 m->volcmd = VOLCMD_FINEVOLDOWN;
154 m->vol = (p->vol & 0x0f);
155 } else
156 if ((p->vol >= 0xD0) && (p->vol <= 0xDF))
157 {
158 m->volcmd = VOLCMD_FINEVOLUP;
159 m->vol = (p->vol & 0x0f);
160 } else
161 {
162 m->volcmd = 0;
163 m->vol = 0;
164 }
165 // Effects
166 m->command = 0;
167 m->param = 0;
168 if ((p->fxcmd) || (p->fxparam1) || (p->fxparam2))
169 {
170 if (!p->fxcmd)
171 {
172 m->command = p->fxparam2;
173 m->param = p->fxparam1;
174 that->ConvertModCommand(m);
175 } else
176 {
177 // TODO: MT2 Effects
178 }
179 }
180}
181
182
183BOOL CSoundFile::ReadMT2(LPCBYTE lpStream, DWORD dwMemLength)
184//-----------------------------------------------------------
185{
186 MT2FILEHEADER *pfh = (MT2FILEHEADER *)lpStream;
187 DWORD dwMemPos, dwDrumDataPos, dwExtraDataPos;
188 UINT nDrumDataLen, nExtraDataLen;
189 MT2DRUMSDATA *pdd;
190 MT2INSTRUMENT *InstrMap[255];
191 MT2SAMPLE *SampleMap[256];
192
193 if ((!lpStream) || (dwMemLength < sizeof(MT2FILEHEADER))
194 || (pfh->dwMT20 != 0x3032544D)
195 || (pfh->wVersion < 0x0200) || (pfh->wVersion >= 0x0300)
196 || (pfh->wChannels < 4) || (pfh->wChannels > 64)) return FALSE;
197 pdd = NULL;
198 m_nType = MOD_TYPE_MT2;
199 m_nChannels = pfh->wChannels;
200 m_nRestartPos = pfh->wRestart;
201 m_nDefaultSpeed = pfh->bTicksPerLine;
202 m_nDefaultTempo = 125;
203 if ((pfh->wSamplesPerTick > 100) && (pfh->wSamplesPerTick < 5000))
204 {
205 m_nDefaultTempo = 110250 / pfh->wSamplesPerTick;
206 }
207 for (UINT iOrd=0; iOrd<MAX_ORDERS; iOrd++)
208 {
209 Order[iOrd] = (BYTE)((iOrd < pfh->nOrders) ? pfh->Orders[iOrd] : 0xFF);
210 }
211 memcpy(m_szNames[0], pfh->szSongName, 32);
212 m_szNames[0][31] = 0;
213 dwMemPos = sizeof(MT2FILEHEADER);
214 nDrumDataLen = *(WORD *)(lpStream + dwMemPos);
215 dwDrumDataPos = dwMemPos + 2;
216 if (nDrumDataLen >= 2) pdd = (MT2DRUMSDATA *)(lpStream+dwDrumDataPos);
217 dwMemPos += 2 + nDrumDataLen;
218#ifdef MT2DEBUG
219
220 Log("MT2 v%03X: \"%s\" (flags=%04X)\n", pfh->wVersion, m_szNames[0], pfh->fulFlags);
221 Log("%d Channels, %d Patterns, %d Instruments, %d Samples\n", pfh->wChannels, pfh->wPatterns, pfh->wInstruments, pfh->wSamples);
222 Log("Drum Data: %d bytes @%04X\n", nDrumDataLen, dwDrumDataPos);
223#endif
224 if (dwMemPos >= dwMemLength-12) return TRUE;
225 if (!*(DWORD *)(lpStream+dwMemPos)) dwMemPos += 4;
226 if (!*(DWORD *)(lpStream+dwMemPos)) dwMemPos += 4;
227 nExtraDataLen = *(DWORD *)(lpStream+dwMemPos);
228 dwExtraDataPos = dwMemPos + 4;
229 dwMemPos += 4;
230#ifdef MT2DEBUG
231 Log("Extra Data: %d bytes @%04X\n", nExtraDataLen, dwExtraDataPos);
232#endif
233 if (dwMemPos + nExtraDataLen >= dwMemLength) return TRUE;
234 while (dwMemPos+8 < dwExtraDataPos + nExtraDataLen)
235 {
236 DWORD dwId = *(DWORD *)(lpStream+dwMemPos);
237 DWORD dwLen = *(DWORD *)(lpStream+dwMemPos+4);
238 dwMemPos += 8;
239 if (dwMemPos + dwLen > dwMemLength) return TRUE;
240#ifdef MT2DEBUG
241 CHAR s[5];
242 memcpy(s, &dwId, 4);
243 s[4] = 0;
244 Log("pos=0x%04X: %s: %d bytes\n", dwMemPos-8, s, dwLen);
245#endif
246 switch(dwId)
247 {
248 // MSG
249 case 0x0047534D:
250 if ((dwLen > 3) && (!m_lpszSongComments))
251 {
252 DWORD nTxtLen = dwLen;
253 if (nTxtLen > 32000) nTxtLen = 32000;
254 m_lpszSongComments = new char[nTxtLen]; // changed from CHAR
255 if (m_lpszSongComments)
256 {
257 memcpy(m_lpszSongComments, lpStream+dwMemPos+1, nTxtLen-1);
258 m_lpszSongComments[nTxtLen-1] = 0;
259 }
260 }
261 break;
262 // SUM -> author name (or "Unregistered")
263 // TMAP
264 // TRKS
265 case 0x534b5254:
266 break;
267 }
268 dwMemPos += dwLen;
269 }
270 // Load Patterns
271 dwMemPos = dwExtraDataPos + nExtraDataLen;
272 for (UINT iPat=0; iPat<pfh->wPatterns; iPat++) if (dwMemPos < dwMemLength-6)
273 {
274 MT2PATTERN *pmp = (MT2PATTERN *)(lpStream+dwMemPos);
275 UINT wDataLen = (pmp->wDataLen + 1) & ~1;
276 dwMemPos += 6;
277 if (dwMemPos + wDataLen > dwMemLength) break;
278 UINT nLines = pmp->wLines;
279 if ((iPat < MAX_PATTERNS) && (nLines > 0) && (nLines <= 256))
280 {
281 #ifdef MT2DEBUG
282 Log("Pattern #%d @%04X: %d lines, %d bytes\n", iPat, dwMemPos-6, nLines, pmp->wDataLen);
283 #endif
284 PatternSize[iPat] = nLines;
285 Patterns[iPat] = AllocatePattern(nLines, m_nChannels);
286 if (!Patterns[iPat]) return TRUE;
287 MODCOMMAND *m = Patterns[iPat];
288 UINT len = wDataLen;
289 if (pfh->fulFlags & 1) // Packed Patterns
290 {
291 BYTE *p = (BYTE *)(lpStream+dwMemPos);
292 UINT pos = 0, row=0, ch=0;
293 while (pos < len)
294 {
295 MT2COMMAND cmd;
296 UINT infobyte = p[pos++];
297 UINT rptcount = 0;
298 if (infobyte == 0xff)
299 {
300 rptcount = p[pos++];
301 infobyte = p[pos++];
302 #if 0
303 Log("(%d.%d) FF(%02X).%02X\n", row, ch, rptcount, infobyte);
304 } else
305 {
306 Log("(%d.%d) %02X\n", row, ch, infobyte);
307 #endif
308 }
309 if (infobyte & 0x7f)
310 {
311 UINT patpos = row*m_nChannels+ch;
312 cmd.note = cmd.instr = cmd.vol = cmd.pan = cmd.fxcmd = cmd.fxparam1 = cmd.fxparam2 = 0;
313 if (infobyte & 1) cmd.note = p[pos++];
314 if (infobyte & 2) cmd.instr = p[pos++];
315 if (infobyte & 4) cmd.vol = p[pos++];
316 if (infobyte & 8) cmd.pan = p[pos++];
317 if (infobyte & 16) cmd.fxcmd = p[pos++];
318 if (infobyte & 32) cmd.fxparam1 = p[pos++];
319 if (infobyte & 64) cmd.fxparam2 = p[pos++];
320 #ifdef MT2DEBUG
321 if (cmd.fxcmd)
322 {
323 Log("(%d.%d) MT2 FX=%02X.%02X.%02X\n", row, ch, cmd.fxcmd, cmd.fxparam1, cmd.fxparam2);
324 }
325 #endif
326 ConvertMT2Command(this, &m[patpos], &cmd);
327 }
328 row += rptcount+1;
329 while (row >= nLines) { row-=nLines; ch++; }
330 if (ch >= m_nChannels) break;
331 }
332 } else
333 {
334 MT2COMMAND *p = (MT2COMMAND *)(lpStream+dwMemPos);
335 UINT n = 0;
336 while ((len > sizeof(MT2COMMAND)) && (n < m_nChannels*nLines))
337 {
338 ConvertMT2Command(this, m, p);
339 len -= sizeof(MT2COMMAND);
340 n++;
341 p++;
342 m++;
343 }
344 }
345 }
346 dwMemPos += wDataLen;
347 }
348 // Skip Drum Patterns
349 if (pdd)
350 {
351 #ifdef MT2DEBUG
352 Log("%d Drum Patterns at offset 0x%08X\n", pdd->wDrumPatterns, dwMemPos);
353 #endif
354 for (UINT iDrm=0; iDrm<pdd->wDrumPatterns; iDrm++)
355 {
356 if (dwMemPos > dwMemLength-2) return TRUE;
357 UINT nLines = *(WORD *)(lpStream+dwMemPos);
358 #ifdef MT2DEBUG
359 if (nLines != 64) Log("Drum Pattern %d: %d Lines @%04X\n", iDrm, nLines, dwMemPos);
360 #endif
361 dwMemPos += 2 + nLines * 32;
362 }
363 }
364 // Automation
365 if (pfh->fulFlags & 2)
366 {
367 #ifdef MT2DEBUG
368 Log("Automation at offset 0x%08X\n", dwMemPos);
369 #endif
370 UINT nAutoCount = m_nChannels;
371 if (pfh->fulFlags & 0x10) nAutoCount++; // Master Automation
372 if ((pfh->fulFlags & 0x08) && (pdd)) nAutoCount += 8; // Drums Automation
373 nAutoCount *= pfh->wPatterns;
374 for (UINT iAuto=0; iAuto<nAutoCount; iAuto++)
375 {
376 if (dwMemPos+12 >= dwMemLength) return TRUE;
377 MT2AUTOMATION *pma = (MT2AUTOMATION *)(lpStream+dwMemPos);
378 dwMemPos += (pfh->wVersion <= 0x201) ? 4 : 8;
379 for (UINT iEnv=0; iEnv<14; iEnv++)
380 {
381 if (pma->dwFlags & (1 << iEnv))
382 {
383 #ifdef MT2DEBUG
384 UINT nPoints = *(DWORD *)(lpStream+dwMemPos);
385 Log(" Env[%d/%d] %04X @%04X: %d points\n", iAuto, nAutoCount, 1 << iEnv, dwMemPos-8, nPoints);
386 #endif
387 dwMemPos += 260;
388 }
389 }
390 }
391 }
392 // Load Instruments
393#ifdef MT2DEBUG
394 Log("Loading instruments at offset 0x%08X\n", dwMemPos);
395#endif
396 memset(InstrMap, 0, sizeof(InstrMap));
397 m_nInstruments = (pfh->wInstruments < MAX_INSTRUMENTS) ? pfh->wInstruments : MAX_INSTRUMENTS-1;
398 for (UINT iIns=1; iIns<=255; iIns++)
399 {
400 if (dwMemPos+36 > dwMemLength) return TRUE;
401 MT2INSTRUMENT *pmi = (MT2INSTRUMENT *)(lpStream+dwMemPos);
402 INSTRUMENTHEADER *penv = NULL;
403 if (iIns <= m_nInstruments)
404 {
405 penv = new INSTRUMENTHEADER;
406 Headers[iIns] = penv;
407 if (penv)
408 {
409 memset(penv, 0, sizeof(INSTRUMENTHEADER));
410 memcpy(penv->name, pmi->szName, 32);
411 penv->nGlobalVol = 64;
412 penv->nPan = 128;
413 for (UINT i=0; i<120; i++)
414 {
415 penv->NoteMap[i] = i+1;
416 }
417 }
418 }
419 #ifdef MT2DEBUG
420 if (iIns <= pfh->wInstruments) Log(" Instrument #%d at offset %04X: %d bytes\n", iIns, dwMemPos, pmi->dwDataLen);
421 #endif
422 if (((LONG)pmi->dwDataLen > 0) && (dwMemPos + pmi->dwDataLen + 40 <= dwMemLength))
423 {
424 InstrMap[iIns-1] = pmi;
425 if (penv)
426 {
427 penv->nFadeOut = pmi->wFadeOut;
428 penv->nNNA = pmi->wNNA & 3;
429 penv->nDCT = (pmi->wNNA>>8) & 3;
430 penv->nDNA = (pmi->wNNA>>12) & 3;
431 MT2ENVELOPE *pehdr[4];
432 WORD *pedata[4];
433 if (pfh->wVersion <= 0x201)
434 {
435 DWORD dwEnvPos = dwMemPos + sizeof(MT2INSTRUMENT) - 4;
436 pehdr[0] = (MT2ENVELOPE *)(lpStream+dwEnvPos);
437 pehdr[1] = (MT2ENVELOPE *)(lpStream+dwEnvPos+8);
438 pehdr[2] = pehdr[3] = NULL;
439 pedata[0] = (WORD *)(lpStream+dwEnvPos+16);
440 pedata[1] = (WORD *)(lpStream+dwEnvPos+16+64);
441 pedata[2] = pedata[3] = NULL;
442 } else
443 {
444 DWORD dwEnvPos = dwMemPos + sizeof(MT2INSTRUMENT);
445 for (UINT i=0; i<4; i++)
446 {
447 if (pmi->wEnvFlags1 & (1<<i))
448 {
449 pehdr[i] = (MT2ENVELOPE *)(lpStream+dwEnvPos);
450 pedata[i] = (WORD *)pehdr[i]->EnvData;
451 dwEnvPos += sizeof(MT2ENVELOPE);
452 } else
453 {
454 pehdr[i] = NULL;
455 pedata[i] = NULL;
456 }
457 }
458 }
459 // Load envelopes
460 for (UINT iEnv=0; iEnv<4; iEnv++) if (pehdr[iEnv])
461 {
462 MT2ENVELOPE *pme = pehdr[iEnv];
463 WORD *pEnvPoints = NULL;
464 BYTE *pEnvData = NULL;
465 #ifdef MT2DEBUG
466 Log(" Env %d.%d @%04X: %d points\n", iIns, iEnv, (UINT)(((BYTE *)pme)-lpStream), pme->nPoints);
467 #endif
468 switch(iEnv)
469 {
470 // Volume Envelope
471 case 0:
472 if (pme->nFlags & 1) penv->dwFlags |= ENV_VOLUME;
473 if (pme->nFlags & 2) penv->dwFlags |= ENV_VOLSUSTAIN;
474 if (pme->nFlags & 4) penv->dwFlags |= ENV_VOLLOOP;
475 penv->nVolEnv = (pme->nPoints > 16) ? 16 : pme->nPoints;
476 penv->nVolSustainBegin = penv->nVolSustainEnd = pme->nSustainPos;
477 penv->nVolLoopStart = pme->nLoopStart;
478 penv->nVolLoopEnd = pme->nLoopEnd;
479 pEnvPoints = penv->VolPoints;
480 pEnvData = penv->VolEnv;
481 break;
482
483 // Panning Envelope
484 case 1:
485 if (pme->nFlags & 1) penv->dwFlags |= ENV_PANNING;
486 if (pme->nFlags & 2) penv->dwFlags |= ENV_PANSUSTAIN;
487 if (pme->nFlags & 4) penv->dwFlags |= ENV_PANLOOP;
488 penv->nPanEnv = (pme->nPoints > 16) ? 16 : pme->nPoints;
489 penv->nPanSustainBegin = penv->nPanSustainEnd = pme->nSustainPos;
490 penv->nPanLoopStart = pme->nLoopStart;
491 penv->nPanLoopEnd = pme->nLoopEnd;
492 pEnvPoints = penv->PanPoints;
493 pEnvData = penv->PanEnv;
494 break;
495
496 // Pitch/Filter envelope
497 default:
498 if (pme->nFlags & 1) penv->dwFlags |= (iEnv==3) ? (ENV_PITCH|ENV_FILTER) : ENV_PITCH;
499 if (pme->nFlags & 2) penv->dwFlags |= ENV_PITCHSUSTAIN;
500 if (pme->nFlags & 4) penv->dwFlags |= ENV_PITCHLOOP;
501 penv->nPitchEnv = (pme->nPoints > 16) ? 16 : pme->nPoints;
502 penv->nPitchSustainBegin = penv->nPitchSustainEnd = pme->nSustainPos;
503 penv->nPitchLoopStart = pme->nLoopStart;
504 penv->nPitchLoopEnd = pme->nLoopEnd;
505 pEnvPoints = penv->PitchPoints;
506 pEnvData = penv->PitchEnv;
507 }
508 // Envelope data
509 if ((pEnvPoints) && (pEnvData) && (pedata[iEnv]))
510 {
511 WORD *psrc = pedata[iEnv];
512 for (UINT i=0; i<16; i++)
513 {
514 pEnvPoints[i] = psrc[i*2];
515 pEnvData[i] = (BYTE)psrc[i*2+1];
516 }
517 }
518 }
519 }
520 dwMemPos += pmi->dwDataLen + 36;
521 if (pfh->wVersion > 0x201) dwMemPos += 4; // ?
522 } else
523 {
524 dwMemPos += 36;
525 }
526 }
527#ifdef MT2DEBUG
528 Log("Loading samples at offset 0x%08X\n", dwMemPos);
529#endif
530 memset(SampleMap, 0, sizeof(SampleMap));
531 m_nSamples = (pfh->wSamples < MAX_SAMPLES) ? pfh->wSamples : MAX_SAMPLES-1;
532 for (UINT iSmp=1; iSmp<=256; iSmp++)
533 {
534 if (dwMemPos+36 > dwMemLength) return TRUE;
535 MT2SAMPLE *pms = (MT2SAMPLE *)(lpStream+dwMemPos);
536 #ifdef MT2DEBUG
537 if (iSmp <= m_nSamples) Log(" Sample #%d at offset %04X: %d bytes\n", iSmp, dwMemPos, pms->dwDataLen);
538 #endif
539 if (iSmp < MAX_SAMPLES)
540 {
541 memcpy(m_szNames[iSmp], pms->szName, 32);
542 }
543 if (pms->dwDataLen > 0)
544 {
545 SampleMap[iSmp-1] = pms;
546 if (iSmp < MAX_SAMPLES)
547 {
548 MODINSTRUMENT *psmp = &Ins[iSmp];
549 psmp->nGlobalVol = 64;
550 psmp->nVolume = (pms->wVolume >> 7);
551 psmp->nPan = (pms->nPan == 0x80) ? 128 : (pms->nPan^0x80);
552 psmp->nLength = pms->dwLength;
553 psmp->nC4Speed = pms->dwFrequency;
554 psmp->nLoopStart = pms->dwLoopStart;
555 psmp->nLoopEnd = pms->dwLoopEnd;
556 FrequencyToTranspose(psmp);
557 psmp->RelativeTone -= pms->nBaseNote - 49;
558 psmp->nC4Speed = TransposeToFrequency(psmp->RelativeTone, psmp->nFineTune);
559 if (pms->nQuality == 2) { psmp->uFlags |= CHN_16BIT; psmp->nLength >>= 1; }
560 if (pms->nChannels == 2) { psmp->nLength >>= 1; }
561 if (pms->nLoop == 1) psmp->uFlags |= CHN_LOOP;
562 if (pms->nLoop == 2) psmp->uFlags |= CHN_LOOP|CHN_PINGPONGLOOP;
563 }
564 dwMemPos += pms->dwDataLen + 36;
565 } else
566 {
567 dwMemPos += 36;
568 }
569 }
570#ifdef MT2DEBUG
571 Log("Loading groups at offset 0x%08X\n", dwMemPos);
572#endif
573 for (UINT iMap=0; iMap<255; iMap++) if (InstrMap[iMap])
574 {
575 if (dwMemPos+8 > dwMemLength) return TRUE;
576 MT2INSTRUMENT *pmi = InstrMap[iMap];
577 INSTRUMENTHEADER *penv = NULL;
578 if (iMap<m_nInstruments) penv = Headers[iMap+1];
579 for (UINT iGrp=0; iGrp<pmi->wSamples; iGrp++)
580 {
581 if (penv)
582 {
583 MT2GROUP *pmg = (MT2GROUP *)(lpStream+dwMemPos);
584 for (UINT i=0; i<96; i++)
585 {
586 if (pmi->GroupsMapping[i] == iGrp)
587 {
588 UINT nSmp = pmg->nSmpNo+1;
589 penv->Keyboard[i+12] = (BYTE)nSmp;
590 if (nSmp <= m_nSamples)
591 {
592 Ins[nSmp].nVibType = pmi->bVibType;
593 Ins[nSmp].nVibSweep = pmi->bVibSweep;
594 Ins[nSmp].nVibDepth = pmi->bVibDepth;
595 Ins[nSmp].nVibRate = pmi->bVibRate;
596 }
597 }
598 }
599 }
600 dwMemPos += 8;
601 }
602 }
603#ifdef MT2DEBUG
604 Log("Loading sample data at offset 0x%08X\n", dwMemPos);
605#endif
606 for (UINT iData=0; iData<256; iData++) if ((iData < m_nSamples) && (SampleMap[iData]))
607 {
608 MT2SAMPLE *pms = SampleMap[iData];
609 MODINSTRUMENT *psmp = &Ins[iData+1];
610 if (!(pms->nFlags & 5))
611 {
612 if (psmp->nLength > 0)
613 {
614 #ifdef MT2DEBUG
615 Log(" Reading sample #%d at offset 0x%04X (len=%d)\n", iData+1, dwMemPos, psmp->nLength);
616 #endif
617 UINT rsflags;
618
619 if (pms->nChannels == 2)
620 rsflags = (psmp->uFlags & CHN_16BIT) ? RS_STPCM16D : RS_STPCM8D;
621 else
622 rsflags = (psmp->uFlags & CHN_16BIT) ? RS_PCM16D : RS_PCM8D;
623
624 dwMemPos += ReadSample(psmp, rsflags, (LPCSTR)(lpStream+dwMemPos), dwMemLength-dwMemPos);
625 }
626 } else
627 if (dwMemPos+4 < dwMemLength)
628 {
629 UINT nNameLen = *(DWORD *)(lpStream+dwMemPos);
630 dwMemPos += nNameLen + 16;
631 }
632 if (dwMemPos+4 >= dwMemLength) break;
633 }
634 return TRUE;
635}
diff --git a/core/multimedia/opieplayer/modplug/load_mtm.cpp b/core/multimedia/opieplayer/modplug/load_mtm.cpp
new file mode 100644
index 0000000..7d40b1d
--- a/dev/null
+++ b/core/multimedia/opieplayer/modplug/load_mtm.cpp
@@ -0,0 +1,167 @@
1/*
2 * This program is free software; you can redistribute it and modify it
3 * under the terms of the GNU General Public License as published by the
4 * Free Software Foundation; either version 2 of the license or (at your
5 * option) any later version.
6 *
7 * Authors: Olivier Lapicque <olivierl@jps.net>
8*/
9
10#include "stdafx.h"
11#include "sndfile.h"
12
13//#pragma warning(disable:4244)
14
15//////////////////////////////////////////////////////////
16// MTM file support (import only)
17
18#pragma pack(1)
19
20
21typedef struct tagMTMSAMPLE
22{
23 char samplename[22]; // changed from CHAR
24 DWORD length;
25 DWORD reppos;
26 DWORD repend;
27 CHAR finetune;
28 BYTE volume;
29 BYTE attribute;
30} Q_PACKED MTMSAMPLE;
31
32
33typedef struct tagMTMHEADER
34{
35 char id[4]; // MTM file marker + version // changed from CHAR
36 char songname[20];// ASCIIZ songname // changed from CHAR
37 WORD numtracks; // number of tracks saved
38 BYTE lastpattern;// last pattern number saved
39 BYTE lastorder; // last order number to play (songlength-1)
40 WORD commentsize;// length of comment field
41 BYTE numsamples;// number of samples saved
42 BYTE attribute; // attribute byte (unused)
43 BYTE beatspertrack;
44 BYTE numchannels;// number of channels used
45 BYTE panpos[32];// voice pan positions
46} Q_PACKED MTMHEADER;
47
48
49#pragma pack()
50
51
52BOOL CSoundFile::ReadMTM(LPCBYTE lpStream, DWORD dwMemLength)
53//-----------------------------------------------------------
54{
55 MTMHEADER *pmh = (MTMHEADER *)lpStream;
56 DWORD dwMemPos = 66;
57
58 if ((!lpStream) || (dwMemLength < 0x100)) return FALSE;
59 if ((strncmp(pmh->id, "MTM", 3)) || (pmh->numchannels > 32)
60 || (pmh->numsamples >= MAX_SAMPLES) || (!pmh->numsamples)
61 || (!pmh->numtracks) || (!pmh->numchannels)
62 || (!pmh->lastpattern) || (pmh->lastpattern > MAX_PATTERNS)) return FALSE;
63 strncpy(m_szNames[0], pmh->songname, 20);
64 m_szNames[0][20] = 0;
65 if (dwMemPos + 37*pmh->numsamples + 128 + 192*pmh->numtracks
66 + 64 * (pmh->lastpattern+1) + pmh->commentsize >= dwMemLength) return FALSE;
67 m_nType = MOD_TYPE_MTM;
68 m_nSamples = pmh->numsamples;
69 m_nChannels = pmh->numchannels;
70 // Reading instruments
71 for(UINT i=1; i<=m_nSamples; i++)
72 {
73 MTMSAMPLE *pms = (MTMSAMPLE *)(lpStream + dwMemPos);
74 strncpy(m_szNames[i], pms->samplename, 22);
75 m_szNames[i][22] = 0;
76 Ins[i].nVolume = pms->volume << 2;
77 Ins[i].nGlobalVol = 64;
78 DWORD len = pms->length;
79 if ((len > 4) && (len <= MAX_SAMPLE_LENGTH))
80 {
81 Ins[i].nLength = len;
82 Ins[i].nLoopStart = pms->reppos;
83 Ins[i].nLoopEnd = pms->repend;
84 if (Ins[i].nLoopEnd > Ins[i].nLength) Ins[i].nLoopEnd = Ins[i].nLength;
85 if (Ins[i].nLoopStart + 4 >= Ins[i].nLoopEnd) Ins[i].nLoopStart = Ins[i].nLoopEnd = 0;
86 if (Ins[i].nLoopEnd) Ins[i].uFlags |= CHN_LOOP;
87 Ins[i].nFineTune = MOD2XMFineTune(pms->finetune);
88 if (pms->attribute & 0x01)
89 {
90 Ins[i].uFlags |= CHN_16BIT;
91 Ins[i].nLength >>= 1;
92 Ins[i].nLoopStart >>= 1;
93 Ins[i].nLoopEnd >>= 1;
94 }
95 Ins[i].nPan = 128;
96 }
97 dwMemPos += 37;
98 }
99 // Setting Channel Pan Position
100 for (UINT ich=0; ich<m_nChannels; ich++)
101 {
102 ChnSettings[ich].nPan = ((pmh->panpos[ich] & 0x0F) << 4) + 8;
103 ChnSettings[ich].nVolume = 64;
104 }
105 // Reading pattern order
106 memcpy(Order, lpStream + dwMemPos, pmh->lastorder+1);
107 dwMemPos += 128;
108 // Reading Patterns
109 LPCBYTE pTracks = lpStream + dwMemPos;
110 dwMemPos += 192 * pmh->numtracks;
111 LPWORD pSeq = (LPWORD)(lpStream + dwMemPos);
112 for (UINT pat=0; pat<=pmh->lastpattern; pat++)
113 {
114 PatternSize[pat] = 64;
115 if ((Patterns[pat] = AllocatePattern(64, m_nChannels)) == NULL) break;
116 for (UINT n=0; n<32; n++) if ((pSeq[n]) && (pSeq[n] <= pmh->numtracks) && (n < m_nChannels))
117 {
118 LPCBYTE p = pTracks + 192 * (pSeq[n]-1);
119 MODCOMMAND *m = Patterns[pat] + n;
120 for (UINT i=0; i<64; i++, m+=m_nChannels, p+=3)
121 {
122 if (p[0] & 0xFC) m->note = (p[0] >> 2) + 37;
123 m->instr = ((p[0] & 0x03) << 4) | (p[1] >> 4);
124 UINT cmd = p[1] & 0x0F;
125 UINT param = p[2];
126 if (cmd == 0x0A)
127 {
128 if (param & 0xF0) param &= 0xF0; else param &= 0x0F;
129 }
130 m->command = cmd;
131 m->param = param;
132 if ((cmd) || (param)) ConvertModCommand(m);
133 }
134 }
135 pSeq += 32;
136 }
137 dwMemPos += 64*(pmh->lastpattern+1);
138 if ((pmh->commentsize) && (dwMemPos + pmh->commentsize < dwMemLength))
139 {
140 UINT n = pmh->commentsize;
141 m_lpszSongComments = new char[n+1];
142 if (m_lpszSongComments)
143 {
144 memcpy(m_lpszSongComments, lpStream+dwMemPos, n);
145 m_lpszSongComments[n] = 0;
146 for (UINT i=0; i<n; i++)
147 {
148 if (!m_lpszSongComments[i])
149 {
150 m_lpszSongComments[i] = ((i+1) % 40) ? 0x20 : 0x0D;
151 }
152 }
153 }
154 }
155 dwMemPos += pmh->commentsize;
156 // Reading Samples
157 for (UINT ismp=1; ismp<=m_nSamples; ismp++)
158 {
159 if (dwMemPos >= dwMemLength) break;
160 dwMemPos += ReadSample(&Ins[ismp], (Ins[ismp].uFlags & CHN_16BIT) ? RS_PCM16U : RS_PCM8U,
161 (LPSTR)(lpStream + dwMemPos), dwMemLength - dwMemPos);
162 }
163 m_nMinPeriod = 64;
164 m_nMaxPeriod = 32767;
165 return TRUE;
166}
167
diff --git a/core/multimedia/opieplayer/modplug/load_okt.cpp b/core/multimedia/opieplayer/modplug/load_okt.cpp
new file mode 100644
index 0000000..4030bbd
--- a/dev/null
+++ b/core/multimedia/opieplayer/modplug/load_okt.cpp
@@ -0,0 +1,200 @@
1/*
2 * This program is free software; you can redistribute it and modify it
3 * under the terms of the GNU General Public License as published by the
4 * Free Software Foundation; either version 2 of the license or (at your
5 * option) any later version.
6 *
7 * Authors: Olivier Lapicque <olivierl@jps.net>,
8 * Adam Goode <adam@evdebs.org> (endian and char fixes for PPC)
9*/
10
11//////////////////////////////////////////////
12// Oktalyzer (OKT) module loader //
13//////////////////////////////////////////////
14#include "stdafx.h"
15#include "sndfile.h"
16
17//#pragma warning(disable:4244)
18
19typedef struct OKTFILEHEADER
20{
21 DWORD okta; // "OKTA"
22 DWORD song; // "SONG"
23 DWORD cmod; // "CMOD"
24 DWORD fixed8;
25 BYTE chnsetup[8];
26 DWORD samp; // "SAMP"
27 DWORD samplen;
28} Q_PACKED OKTFILEHEADER;
29
30
31typedef struct OKTSAMPLE
32{
33 CHAR name[20];
34 DWORD length;
35 WORD loopstart;
36 WORD looplen;
37 BYTE pad1;
38 BYTE volume;
39 BYTE pad2;
40 BYTE pad3;
41} Q_PACKED OKTSAMPLE;
42
43
44BOOL CSoundFile::ReadOKT(const BYTE *lpStream, DWORD dwMemLength)
45//---------------------------------------------------------------
46{
47 OKTFILEHEADER *pfh = (OKTFILEHEADER *)lpStream;
48 DWORD dwMemPos = sizeof(OKTFILEHEADER);
49 UINT nsamples = 0, npatterns = 0, norders = 0;
50
51 if ((!lpStream) || (dwMemLength < 1024)) return FALSE;
52 if ((pfh->okta != 0x41544B4F) || (pfh->song != 0x474E4F53)
53 || (pfh->cmod != 0x444F4D43) || (pfh->chnsetup[0]) || (pfh->chnsetup[2])
54 || (pfh->chnsetup[4]) || (pfh->chnsetup[6]) || (pfh->fixed8 != 0x08000000)
55 || (pfh->samp != 0x504D4153)) return FALSE;
56 m_nType = MOD_TYPE_OKT;
57 m_nChannels = 4 + pfh->chnsetup[1] + pfh->chnsetup[3] + pfh->chnsetup[5] + pfh->chnsetup[7];
58 if (m_nChannels > MAX_CHANNELS) m_nChannels = MAX_CHANNELS;
59 nsamples = bswapBE32(pfh->samplen) >> 5;
60 m_nSamples = nsamples;
61 if (m_nSamples >= MAX_SAMPLES) m_nSamples = MAX_SAMPLES-1;
62 // Reading samples
63 for (UINT smp=1; smp <= nsamples; smp++)
64 {
65 if (dwMemPos >= dwMemLength) return TRUE;
66 if (smp < MAX_SAMPLES)
67 {
68 OKTSAMPLE *psmp = (OKTSAMPLE *)(lpStream + dwMemPos);
69 MODINSTRUMENT *pins = &Ins[smp];
70
71 memcpy(m_szNames[smp], psmp->name, 20);
72 pins->uFlags = 0;
73 pins->nLength = bswapBE32(psmp->length) & ~1;
74 pins->nLoopStart = bswapBE16(psmp->loopstart);
75 pins->nLoopEnd = pins->nLoopStart + bswapBE16(psmp->looplen);
76 if (pins->nLoopStart + 2 < pins->nLoopEnd) pins->uFlags |= CHN_LOOP;
77 pins->nGlobalVol = 64;
78 pins->nVolume = psmp->volume << 2;
79 pins->nC4Speed = 8363;
80 }
81 dwMemPos += sizeof(OKTSAMPLE);
82 }
83 // SPEE
84 if (dwMemPos >= dwMemLength) return TRUE;
85 if (*((DWORD *)(lpStream + dwMemPos)) == 0x45455053)
86 {
87 m_nDefaultSpeed = lpStream[dwMemPos+9];
88 dwMemPos += bswapBE32(*((DWORD *)(lpStream + dwMemPos + 4))) + 8;
89 }
90 // SLEN
91 if (dwMemPos >= dwMemLength) return TRUE;
92 if (*((DWORD *)(lpStream + dwMemPos)) == 0x4E454C53)
93 {
94 npatterns = lpStream[dwMemPos+9];
95 dwMemPos += bswapBE32(*((DWORD *)(lpStream + dwMemPos + 4))) + 8;
96 }
97 // PLEN
98 if (dwMemPos >= dwMemLength) return TRUE;
99 if (*((DWORD *)(lpStream + dwMemPos)) == 0x4E454C50)
100 {
101 norders = lpStream[dwMemPos+9];
102 dwMemPos += bswapBE32(*((DWORD *)(lpStream + dwMemPos + 4))) + 8;
103 }
104 // PATT
105 if (dwMemPos >= dwMemLength) return TRUE;
106 if (*((DWORD *)(lpStream + dwMemPos)) == 0x54544150)
107 {
108 UINT orderlen = norders;
109 if (orderlen >= MAX_ORDERS) orderlen = MAX_ORDERS-1;
110 for (UINT i=0; i<orderlen; i++) Order[i] = lpStream[dwMemPos+10+i];
111 for (UINT j=orderlen; j>1; j--) { if (Order[j-1]) break; Order[j-1] = 0xFF; }
112 dwMemPos += bswapBE32(*((DWORD *)(lpStream + dwMemPos + 4))) + 8;
113 }
114 // PBOD
115 UINT npat = 0;
116 while ((dwMemPos+10 < dwMemLength) && (*((DWORD *)(lpStream + dwMemPos)) == 0x444F4250))
117 {
118 DWORD dwPos = dwMemPos + 10;
119 UINT rows = lpStream[dwMemPos+9];
120 if (!rows) rows = 64;
121 if (npat < MAX_PATTERNS)
122 {
123 if ((Patterns[npat] = AllocatePattern(rows, m_nChannels)) == NULL) return TRUE;
124 MODCOMMAND *m = Patterns[npat];
125 PatternSize[npat] = rows;
126 UINT imax = m_nChannels*rows;
127 for (UINT i=0; i<imax; i++, m++, dwPos+=4)
128 {
129 if (dwPos+4 > dwMemLength) break;
130 const BYTE *p = lpStream+dwPos;
131 UINT note = p[0];
132 if (note)
133 {
134 m->note = note + 48;
135 m->instr = p[1] + 1;
136 }
137 UINT command = p[2];
138 UINT param = p[3];
139 m->param = param;
140 switch(command)
141 {
142 // 0: no effect
143 case 0:
144 break;
145 // 1: Portamento Up
146 case 1:
147 case 17:
148 case 30:
149 if (param) m->command = CMD_PORTAMENTOUP;
150 break;
151 // 2: Portamento Down
152 case 2:
153 case 13:
154 case 21:
155 if (param) m->command = CMD_PORTAMENTODOWN;
156 break;
157 // 10: Arpeggio
158 case 10:
159 case 11:
160 case 12:
161 m->command = CMD_ARPEGGIO;
162 break;
163 // 15: Filter
164 case 15:
165 m->command = CMD_MODCMDEX;
166 m->param = param & 0x0F;
167 break;
168 // 25: Position Jump
169 case 25:
170 m->command = CMD_POSITIONJUMP;
171 break;
172 // 28: Set Speed
173 case 28:
174 m->command = CMD_SPEED;
175 break;
176 // 31: Volume Control
177 case 31:
178 if (param <= 0x40) m->command = CMD_VOLUME; else
179 if (param <= 0x50) { m->command = CMD_VOLUMESLIDE; m->param &= 0x0F; if (!m->param) m->param = 0x0F; } else
180 if (param <= 0x60) { m->command = CMD_VOLUMESLIDE; m->param = (param & 0x0F) << 4; if (!m->param) m->param = 0xF0; } else
181 if (param <= 0x70) { m->command = CMD_MODCMDEX; m->param = 0xB0 | (param & 0x0F); if (!(param & 0x0F)) m->param = 0xBF; } else
182 if (param <= 0x80) { m->command = CMD_MODCMDEX; m->param = 0xA0 | (param & 0x0F); if (!(param & 0x0F)) m->param = 0xAF; }
183 break;
184 }
185 }
186 }
187 npat++;
188 dwMemPos += bswapBE32(*((DWORD *)(lpStream + dwMemPos + 4))) + 8;
189 }
190 // SBOD
191 UINT nsmp = 1;
192 while ((dwMemPos+10 < dwMemLength) && (*((DWORD *)(lpStream + dwMemPos)) == 0x444F4253))
193 {
194 if (nsmp < MAX_SAMPLES) ReadSample(&Ins[nsmp], RS_PCM8S, (LPSTR)(lpStream+dwMemPos+8), dwMemLength-dwMemPos-8);
195 dwMemPos += bswapBE32(*((DWORD *)(lpStream + dwMemPos + 4))) + 8;
196 nsmp++;
197 }
198 return TRUE;
199}
200
diff --git a/core/multimedia/opieplayer/modplug/load_psm.cpp b/core/multimedia/opieplayer/modplug/load_psm.cpp
new file mode 100644
index 0000000..e6a6f8e
--- a/dev/null
+++ b/core/multimedia/opieplayer/modplug/load_psm.cpp
@@ -0,0 +1,842 @@
1/*
2 * This program is free software; you can redistribute it and modify it
3 * under the terms of the GNU General Public License as published by the
4 * Free Software Foundation; either version 2 of the license or (at your
5 * option) any later version.
6 *
7 * Authors: Olivier Lapicque <olivierl@jps.net>
8*/
9
10
11///////////////////////////////////////////////////
12//
13// PSM module loader
14//
15///////////////////////////////////////////////////
16#include "stdafx.h"
17#include "sndfile.h"
18
19//#define PSM_LOG
20
21 #define PSM_ID_NEW0x204d5350
22 #define PSM_ID_OLD0xfe4d5350
23 #define IFFID_FILE0x454c4946
24 #define IFFID_TITL0x4c544954
25 #define IFFID_SDFT0x54464453
26 #define IFFID_PBOD0x444f4250
27 #define IFFID_SONG0x474e4f53
28 #define IFFID_PATT0x54544150
29 #define IFFID_DSMP0x504d5344
30 #define IFFID_OPLH0x484c504f
31
32#pragma pack(1)
33
34typedef struct _PSMCHUNK
35{
36 DWORD id;
37 DWORD len;
38 DWORD listid;
39} Q_PACKED PSMCHUNK;
40
41typedef struct _PSMSONGHDR
42{
43 CHAR songname[8];// "MAINSONG"
44 BYTE reserved1;
45 BYTE reserved2;
46 BYTE channels;
47} Q_PACKED PSMSONGHDR;
48
49typedef struct _PSMPATTERN
50{
51 DWORD size;
52 DWORD name;
53 WORD rows;
54 WORD reserved1;
55 BYTE data[4];
56} Q_PACKED PSMPATTERN;
57
58typedef struct _PSMSAMPLE
59{
60 BYTE flags;
61 CHAR songname[8];
62 DWORD smpid;
63 CHAR samplename[34];
64 DWORD reserved1;
65 BYTE reserved2;
66 BYTE insno;
67 BYTE reserved3;
68 DWORD length;
69 DWORD loopstart;
70 DWORD loopend;
71 WORD reserved4;
72 BYTE defvol;
73 DWORD reserved5;
74 DWORD samplerate;
75 BYTE reserved6[19];
76} Q_PACKED PSMSAMPLE;
77
78#pragma pack()
79
80
81BOOL CSoundFile::ReadPSM(LPCBYTE lpStream, DWORD dwMemLength)
82//-----------------------------------------------------------
83{
84 PSMCHUNK *pfh = (PSMCHUNK *)lpStream;
85 DWORD dwMemPos, dwSongPos;
86 DWORD smpnames[MAX_SAMPLES];
87 DWORD patptrs[MAX_PATTERNS];
88 BYTE samplemap[MAX_SAMPLES];
89 UINT nPatterns;
90
91 // Chunk0: "PSM ",filesize,"FILE"
92 if (dwMemLength < 256) return FALSE;
93 if (pfh->id == PSM_ID_OLD)
94 {
95 #ifdef PSM_LOG
96 Log("Old PSM format not supported\n");
97 #endif
98 return FALSE;
99 }
100 if ((pfh->id != PSM_ID_NEW) || (pfh->len+12 > dwMemLength) || (pfh->listid != IFFID_FILE)) return FALSE;
101 m_nType = MOD_TYPE_PSM;
102 m_nChannels = 16;
103 m_nSamples = 0;
104 nPatterns = 0;
105 dwMemPos = 12;
106 dwSongPos = 0;
107 for (UINT iChPan=0; iChPan<16; iChPan++)
108 {
109 UINT pan = (((iChPan & 3) == 1) || ((iChPan&3)==2)) ? 0xC0 : 0x40;
110 ChnSettings[iChPan].nPan = pan;
111 }
112 while (dwMemPos+8 < dwMemLength)
113 {
114 PSMCHUNK *pchunk = (PSMCHUNK *)(lpStream+dwMemPos);
115 if ((pchunk->len >= dwMemLength - 8) || (dwMemPos + pchunk->len + 8 > dwMemLength)) break;
116 dwMemPos += 8;
117 PUCHAR pdata = (PUCHAR)(lpStream+dwMemPos);
118 ULONG len = pchunk->len;
119 if (len) switch(pchunk->id)
120 {
121 // "TITL": Song title
122 case IFFID_TITL:
123 if (!pdata[0]) { pdata++; len--; }
124 memcpy(m_szNames[0], pdata, (len>31) ? 31 : len);
125 m_szNames[0][31] = 0;
126 break;
127 // "PBOD": Pattern
128 case IFFID_PBOD:
129 if ((len >= 12) && (nPatterns < MAX_PATTERNS))
130 {
131 patptrs[nPatterns++] = dwMemPos-8;
132 }
133 break;
134 // "SONG": Song description
135 case IFFID_SONG:
136 if ((len >= sizeof(PSMSONGHDR)+8) && (!dwSongPos))
137 {
138 dwSongPos = dwMemPos - 8;
139 }
140 break;
141 // "DSMP": Sample Data
142 case IFFID_DSMP:
143 if ((len >= sizeof(PSMSAMPLE)) && (m_nSamples+1 < MAX_SAMPLES))
144 {
145 m_nSamples++;
146 MODINSTRUMENT *pins = &Ins[m_nSamples];
147 PSMSAMPLE *psmp = (PSMSAMPLE *)pdata;
148 smpnames[m_nSamples] = psmp->smpid;
149 memcpy(m_szNames[m_nSamples], psmp->samplename, 31);
150 m_szNames[m_nSamples][31] = 0;
151 samplemap[m_nSamples-1] = (BYTE)m_nSamples;
152 // Init sample
153 pins->nGlobalVol = 0x40;
154 pins->nC4Speed = psmp->samplerate;
155 pins->nLength = psmp->length;
156 pins->nLoopStart = psmp->loopstart;
157 pins->nLoopEnd = psmp->loopend;
158 pins->nPan = 128;
159 pins->nVolume = (psmp->defvol+1) * 2;
160 pins->uFlags = (psmp->flags & 0x80) ? CHN_LOOP : 0;
161 if (pins->nLoopStart > 0) pins->nLoopStart--;
162 // Point to sample data
163 pdata += 0x60;
164 len -= 0x60;
165 // Load sample data
166 if ((pins->nLength > 3) && (len > 3))
167 {
168 ReadSample(pins, RS_PCM8D, (LPCSTR)pdata, len);
169 } else
170 {
171 pins->nLength = 0;
172 }
173 }
174 break;
175 #if 0
176 default:
177 {
178 CHAR s[8], s2[64];
179 *(DWORD *)s = pchunk->id;
180 s[4] = 0;
181 wsprintf(s2, "%s: %4d bytes @ %4d\n", s, pchunk->len, dwMemPos);
182 OutputDebugString(s2);
183 }
184 #endif
185 }
186 dwMemPos += pchunk->len;
187 }
188 // Step #1: convert song structure
189 PSMSONGHDR *pSong = (PSMSONGHDR *)(lpStream+dwSongPos+8);
190 if ((!dwSongPos) || (pSong->channels < 2) || (pSong->channels > 32)) return TRUE;
191 m_nChannels = pSong->channels;
192 // Valid song header -> convert attached chunks
193 {
194 DWORD dwSongEnd = dwSongPos + 8 + *(DWORD *)(lpStream+dwSongPos+4);
195 dwMemPos = dwSongPos + 8 + 11; // sizeof(PSMCHUNK)+sizeof(PSMSONGHDR)
196 while (dwMemPos + 8 < dwSongEnd)
197 {
198 PSMCHUNK *pchunk = (PSMCHUNK *)(lpStream+dwMemPos);
199 dwMemPos += 8;
200 if ((pchunk->len > dwSongEnd) || (dwMemPos + pchunk->len > dwSongEnd)) break;
201 PUCHAR pdata = (PUCHAR)(lpStream+dwMemPos);
202 ULONG len = pchunk->len;
203 switch(pchunk->id)
204 {
205 case IFFID_OPLH:
206 if (len >= 0x20)
207 {
208 UINT pos = len - 3;
209 while (pos > 5)
210 {
211 BOOL bFound = FALSE;
212 pos -= 5;
213 DWORD dwName = *(DWORD *)(pdata+pos);
214 for (UINT i=0; i<nPatterns; i++)
215 {
216 DWORD dwPatName = ((PSMPATTERN *)(lpStream+patptrs[i]+8))->name;
217 if (dwName == dwPatName)
218 {
219 bFound = TRUE;
220 break;
221 }
222 }
223 if ((!bFound) && (pdata[pos+1] > 0) && (pdata[pos+1] <= 0x10)
224 && (pdata[pos+3] > 0x40) && (pdata[pos+3] < 0xC0))
225 {
226 m_nDefaultSpeed = pdata[pos+1];
227 m_nDefaultTempo = pdata[pos+3];
228 break;
229 }
230 }
231 UINT iOrd = 0;
232 while ((pos+5<len) && (iOrd < MAX_ORDERS))
233 {
234 DWORD dwName = *(DWORD *)(pdata+pos);
235 for (UINT i=0; i<nPatterns; i++)
236 {
237 DWORD dwPatName = ((PSMPATTERN *)(lpStream+patptrs[i]+8))->name;
238 if (dwName == dwPatName)
239 {
240 Order[iOrd++] = i;
241 break;
242 }
243 }
244 pos += 5;
245 }
246 }
247 break;
248 }
249 dwMemPos += pchunk->len;
250 }
251 }
252
253 // Step #2: convert patterns
254 for (UINT nPat=0; nPat<nPatterns; nPat++)
255 {
256 PSMPATTERN *pPsmPat = (PSMPATTERN *)(lpStream+patptrs[nPat]+8);
257 ULONG len = *(DWORD *)(lpStream+patptrs[nPat]+4) - 12;
258 UINT nRows = pPsmPat->rows;
259 if (len > pPsmPat->size) len = pPsmPat->size;
260 if ((nRows < 64) || (nRows > 256)) nRows = 64;
261 PatternSize[nPat] = nRows;
262 if ((Patterns[nPat] = AllocatePattern(nRows, m_nChannels)) == NULL) break;
263 MODCOMMAND *m = Patterns[nPat];
264 BYTE *p = pPsmPat->data;
265 UINT pos = 0;
266 UINT row = 0;
267 UINT oldch = 0;
268 BOOL bNewRow = FALSE;
269 #ifdef PSM_LOG
270 Log("Pattern %d at offset 0x%04X\n", nPat, (DWORD)(p - (BYTE *)lpStream));
271 #endif
272 while ((row < nRows) && (pos+1 < len))
273 {
274 UINT flags = p[pos++];
275 UINT ch = p[pos++];
276
277 #ifdef PSM_LOG
278 //Log("flags+ch: %02X.%02X\n", flags, ch);
279 #endif
280 if (((flags & 0xf0) == 0x10) && (ch <= oldch) /*&& (!bNewRow)*/)
281 {
282 if ((pos+1<len) && (!(p[pos] & 0x0f)) && (p[pos+1] < m_nChannels))
283 {
284 #ifdef PSM_LOG
285 //if (!nPat) Log("Continuing on new row\n");
286 #endif
287 row++;
288 m += m_nChannels;
289 oldch = ch;
290 continue;
291 }
292 }
293 if ((pos >= len) || (row >= nRows)) break;
294 if (!(flags & 0xf0))
295 {
296 #ifdef PSM_LOG
297 //if (!nPat) Log("EOR(%d): %02X.%02X\n", row, p[pos], p[pos+1]);
298 #endif
299 row++;
300 m += m_nChannels;
301 bNewRow = TRUE;
302 oldch = ch;
303 continue;
304 }
305 bNewRow = FALSE;
306 if (ch >= m_nChannels)
307 {
308 #ifdef PSM_LOG
309 if (!nPat) Log("Invalid channel row=%d (0x%02X.0x%02X)\n", row, flags, ch);
310 #endif
311 ch = 0;
312 }
313 // Note + Instr
314 if ((flags & 0x40) && (pos+1 < len))
315 {
316 UINT note = p[pos++];
317 UINT nins = p[pos++];
318 #ifdef PSM_LOG
319 //if (!nPat) Log("note+ins: %02X.%02X\n", note, nins);
320 if ((!nPat) && (nins >= m_nSamples)) Log("WARNING: invalid instrument number (%d)\n", nins);
321 #endif
322 if ((note) && (note < 0x80)) note = (note>>4)*12+(note&0x0f)+12+1;
323 m[ch].instr = samplemap[nins];
324 m[ch].note = note;
325 }
326 // Volume
327 if ((flags & 0x20) && (pos < len))
328 {
329 m[ch].volcmd = VOLCMD_VOLUME;
330 m[ch].vol = p[pos++] / 2;
331 }
332 // Effect
333 if ((flags & 0x10) && (pos+1 < len))
334 {
335 UINT command = p[pos++];
336 UINT param = p[pos++];
337 // Convert effects
338 switch(command)
339 {
340 // 01: fine volslide up
341 case 0x01:command = CMD_VOLUMESLIDE; param |= 0x0f; break;
342 // 04: fine volslide down
343 case 0x04:command = CMD_VOLUMESLIDE; param>>=4; param |= 0xf0; break;
344 // 0C: portamento up
345 case 0x0C:command = CMD_PORTAMENTOUP; param = (param+1)/2; break;
346 // 0E: portamento down
347 case 0x0E:command = CMD_PORTAMENTODOWN; param = (param+1)/2; break;
348 // 33: Position Jump
349 case 0x33:command = CMD_POSITIONJUMP; break;
350 // 34: Pattern break
351 case 0x34:command = CMD_PATTERNBREAK; break;
352 // 3D: speed
353 case 0x3D:command = CMD_SPEED; break;
354 // 3E: tempo
355 case 0x3E:command = CMD_TEMPO; break;
356 // Unknown
357 default:
358 #ifdef PSM_LOG
359 Log("Unknown PSM effect pat=%d row=%d ch=%d: %02X.%02X\n", nPat, row, ch, command, param);
360 #endif
361 command = param = 0;
362 }
363 m[ch].command = (BYTE)command;
364 m[ch].param = (BYTE)param;
365 }
366 oldch = ch;
367 }
368 #ifdef PSM_LOG
369 if (pos < len)
370 {
371 Log("Pattern %d: %d/%d[%d] rows (%d bytes) -> %d bytes left\n", nPat, row, nRows, pPsmPat->rows, pPsmPat->size, len-pos);
372 }
373 #endif
374 }
375
376 // Done (finally!)
377 return TRUE;
378}
379
380
381//////////////////////////////////////////////////////////////
382//
383// PSM Old Format
384//
385
386/*
387
388CONST
389 c_PSM_MaxOrder = $FF;
390 c_PSM_MaxSample = $FF;
391 c_PSM_MaxChannel = $0F;
392
393 TYPE
394 PPSM_Header = ^TPSM_Header;
395 TPSM_Header = RECORD
396 PSM_Sign : ARRAY[01..04] OF CHAR; { PSM + #254 }
397 PSM_SongName : ARRAY[01..58] OF CHAR;
398 PSM_Byte00 : BYTE;
399 PSM_Byte1A : BYTE;
400 PSM_Unknown00 : BYTE;
401 PSM_Unknown01 : BYTE;
402 PSM_Unknown02 : BYTE;
403 PSM_Speed : BYTE;
404 PSM_Tempo : BYTE;
405 PSM_Unknown03 : BYTE;
406 PSM_Unknown04 : WORD;
407 PSM_OrderLength : WORD;
408 PSM_PatternNumber : WORD;
409 PSM_SampleNumber : WORD;
410 PSM_ChannelNumber : WORD;
411 PSM_ChannelUsed : WORD;
412 PSM_OrderPosition : LONGINT;
413 PSM_ChannelSettingPosition : LONGINT;
414 PSM_PatternPosition : LONGINT;
415 PSM_SamplePosition : LONGINT;
416 { *** perhaps there are some more infos in a larger header,
417 but i have not decoded it and so it apears here NOT }
418 END;
419
420 PPSM_Sample = ^TPSM_Sample;
421 TPSM_Sample = RECORD
422 PSM_SampleFileName : ARRAY[01..12] OF CHAR;
423 PSM_SampleByte00 : BYTE;
424 PSM_SampleName : ARRAY[01..22] OF CHAR;
425 PSM_SampleUnknown00 : ARRAY[01..02] OF BYTE;
426 PSM_SamplePosition : LONGINT;
427 PSM_SampleUnknown01 : ARRAY[01..04] OF BYTE;
428 PSM_SampleNumber : BYTE;
429 PSM_SampleFlags : WORD;
430 PSM_SampleLength : LONGINT;
431 PSM_SampleLoopBegin : LONGINT;
432 PSM_SampleLoopEnd : LONGINT;
433 PSM_Unknown03 : BYTE;
434 PSM_SampleVolume : BYTE;
435 PSM_SampleC5Speed : WORD;
436 END;
437
438 PPSM_SampleList = ^TPSM_SampleList;
439 TPSM_SampleList = ARRAY[01..c_PSM_MaxSample] OF TPSM_Sample;
440
441 PPSM_Order = ^TPSM_Order;
442 TPSM_Order = ARRAY[00..c_PSM_MaxOrder] OF BYTE;
443
444 PPSM_ChannelSettings = ^TPSM_ChannelSettings;
445 TPSM_ChannelSettings = ARRAY[00..c_PSM_MaxChannel] OF BYTE;
446
447 CONST
448 PSM_NotesInPattern : BYTE = $00;
449 PSM_ChannelInPattern : BYTE = $00;
450
451 CONST
452 c_PSM_SetSpeed = 60;
453
454 FUNCTION PSM_Size(FileName : STRING;FilePosition : LONGINT) : LONGINT;
455 BEGIN
456 END;
457
458 PROCEDURE PSM_UnpackPattern(VAR Source,Destination;PatternLength : WORD);
459 VAR
460 Witz : ARRAY[00..04] OF WORD;
461 I1,I2 : WORD;
462 I3,I4 : WORD;
463 TopicalByte : ^BYTE;
464 Pattern : PUnpackedPattern;
465 ChannelP : BYTE;
466 NoteP : BYTE;
467 InfoByte : BYTE;
468 CodeByte : BYTE;
469 InfoWord : WORD;
470 Effect : BYTE;
471 Opperand : BYTE;
472 Panning : BYTE;
473 Volume : BYTE;
474 PrevInfo : BYTE;
475 InfoIndex : BYTE;
476 BEGIN
477 Pattern := @Destination;
478 TopicalByte := @Source;
479 { *** Initialize patttern }
480 FOR I2 := 0 TO c_Maximum_NoteIndex DO
481 FOR I3 := 0 TO c_Maximum_ChannelIndex DO
482 BEGIN
483 Pattern^[I2,I3,c_Pattern_NoteIndex] := $FF;
484 Pattern^[I2,I3,c_Pattern_SampleIndex] := $00;
485 Pattern^[I2,I3,c_Pattern_VolumeIndex] := $FF;
486 Pattern^[I2,I3,c_Pattern_PanningIndex] := $FF;
487 Pattern^[I2,I3,c_Pattern_EffectIndex] := $00;
488 Pattern^[I2,I3,c_Pattern_OpperandIndex] := $00;
489 END;
490 { *** Byte-pointer on first pattern-entry }
491 ChannelP := $00;
492 NoteP := $00;
493 InfoByte := $00;
494 PrevInfo := $00;
495 InfoIndex := $02;
496 { *** read notes in pattern }
497 PSM_NotesInPattern := TopicalByte^; INC(TopicalByte); DEC(PatternLength); INC(InfoIndex);
498 PSM_ChannelInPattern := TopicalByte^; INC(TopicalByte); DEC(PatternLength); INC(InfoIndex);
499 { *** unpack pattern }
500 WHILE (INTEGER(PatternLength) > 0) AND (NoteP < c_Maximum_NoteIndex) DO
501 BEGIN
502 { *** Read info-byte }
503 InfoByte := TopicalByte^; INC(TopicalByte); DEC(PatternLength); INC(InfoIndex);
504 IF InfoByte <> $00 THEN
505 BEGIN
506 ChannelP := InfoByte AND $0F;
507 IF InfoByte AND 128 = 128 THEN { note and sample }
508 BEGIN
509 { *** read note }
510 CodeByte := TopicalByte^; INC(TopicalByte); DEC(PatternLength);
511 DEC(CodeByte);
512 CodeByte := CodeByte MOD 12 * 16 + CodeByte DIV 12 + 2;
513 Pattern^[NoteP,ChannelP,c_Pattern_NoteIndex] := CodeByte;
514 { *** read sample }
515 CodeByte := TopicalByte^; INC(TopicalByte); DEC(PatternLength);
516 Pattern^[NoteP,ChannelP,c_Pattern_SampleIndex] := CodeByte;
517 END;
518 IF InfoByte AND 64 = 64 THEN { Volume }
519 BEGIN
520 CodeByte := TopicalByte^; INC(TopicalByte); DEC(PatternLength);
521 Pattern^[NoteP,ChannelP,c_Pattern_VolumeIndex] := CodeByte;
522 END;
523 IF InfoByte AND 32 = 32 THEN { effect AND opperand }
524 BEGIN
525 Effect := TopicalByte^; INC(TopicalByte); DEC(PatternLength);
526 Opperand := TopicalByte^; INC(TopicalByte); DEC(PatternLength);
527 CASE Effect OF
528 c_PSM_SetSpeed:
529 BEGIN
530 Effect := c_I_Set_Speed;
531 END;
532 ELSE
533 BEGIN
534 Effect := c_I_NoEffect;
535 Opperand := $00;
536 END;
537 END;
538 Pattern^[NoteP,ChannelP,c_Pattern_EffectIndex] := Effect;
539 Pattern^[NoteP,ChannelP,c_Pattern_OpperandIndex] := Opperand;
540 END;
541 END ELSE INC(NoteP);
542 END;
543 END;
544
545 PROCEDURE PSM_Load(FileName : STRING;FilePosition : LONGINT;VAR Module : PModule;VAR ErrorCode : WORD);
546 { *** caution : Module has to be inited before!!!! }
547 VAR
548 Header : PPSM_Header;
549 Sample : PPSM_SampleList;
550 Order : PPSM_Order;
551 ChannelSettings : PPSM_ChannelSettings;
552 MultiPurposeBuffer : PByteArray;
553 PatternBuffer : PUnpackedPattern;
554 TopicalParaPointer : WORD;
555
556 InFile : FILE;
557 I1,I2 : WORD;
558 I3,I4 : WORD;
559 TempW : WORD;
560 TempB : BYTE;
561 TempP : PByteArray;
562 TempI : INTEGER;
563 { *** copy-vars for loop-extension }
564 CopySource : LONGINT;
565 CopyDestination : LONGINT;
566 CopyLength : LONGINT;
567 BEGIN
568 { *** try to open file }
569 ASSIGN(InFile,FileName);
570{$I-}
571 RESET(InFile,1);
572{$I+}
573 IF IORESULT <> $00 THEN
574 BEGIN
575 EXIT;
576 END;
577{$I-}
578 { *** seek start of module }
579 IF FILESIZE(InFile) < FilePosition THEN
580 BEGIN
581 EXIT;
582 END;
583 SEEK(InFile,FilePosition);
584 { *** look for enough memory for temporary variables }
585 IF MEMAVAIL < SIZEOF(TPSM_Header) + SIZEOF(TPSM_SampleList) +
586 SIZEOF(TPSM_Order) + SIZEOF(TPSM_ChannelSettings) +
587 SIZEOF(TByteArray) + SIZEOF(TUnpackedPattern)
588 THEN
589 BEGIN
590 EXIT;
591 END;
592 { *** init dynamic variables }
593 NEW(Header);
594 NEW(Sample);
595 NEW(Order);
596 NEW(ChannelSettings);
597 NEW(MultiPurposeBuffer);
598 NEW(PatternBuffer);
599 { *** read header }
600 BLOCKREAD(InFile,Header^,SIZEOF(TPSM_Header));
601 { *** test if this is a DSM-file }
602 IF NOT ((Header^.PSM_Sign[1] = 'P') AND (Header^.PSM_Sign[2] = 'S') AND
603 (Header^.PSM_Sign[3] = 'M') AND (Header^.PSM_Sign[4] = #254)) THEN
604 BEGIN
605 ErrorCode := c_NoValidFileFormat;
606 CLOSE(InFile);
607 EXIT;
608 END;
609 { *** read order }
610 SEEK(InFile,FilePosition + Header^.PSM_OrderPosition);
611 BLOCKREAD(InFile,Order^,Header^.PSM_OrderLength);
612 { *** read channelsettings }
613 SEEK(InFile,FilePosition + Header^.PSM_ChannelSettingPosition);
614 BLOCKREAD(InFile,ChannelSettings^,SIZEOF(TPSM_ChannelSettings));
615 { *** read samplelist }
616 SEEK(InFile,FilePosition + Header^.PSM_SamplePosition);
617 BLOCKREAD(InFile,Sample^,Header^.PSM_SampleNumber * SIZEOF(TPSM_Sample));
618 { *** copy header to intern NTMIK-structure }
619 Module^.Module_Sign := 'MF';
620 Module^.Module_FileFormatVersion := $0100;
621 Module^.Module_SampleNumber := Header^.PSM_SampleNumber;
622 Module^.Module_PatternNumber := Header^.PSM_PatternNumber;
623 Module^.Module_OrderLength := Header^.PSM_OrderLength;
624 Module^.Module_ChannelNumber := Header^.PSM_ChannelNumber+1;
625 Module^.Module_Initial_GlobalVolume := 64;
626 Module^.Module_Initial_MasterVolume := $C0;
627 Module^.Module_Initial_Speed := Header^.PSM_Speed;
628 Module^.Module_Initial_Tempo := Header^.PSM_Tempo;
629{ *** paragraph 01 start }
630 Module^.Module_Flags := c_Module_Flags_ZeroVolume * BYTE(1) +
631 c_Module_Flags_Stereo * BYTE(1) +
632 c_Module_Flags_ForceAmigaLimits * BYTE(0) +
633 c_Module_Flags_Panning * BYTE(1) +
634 c_Module_Flags_Surround * BYTE(1) +
635 c_Module_Flags_QualityMixing * BYTE(1) +
636 c_Module_Flags_FastVolumeSlides * BYTE(0) +
637 c_Module_Flags_SpecialCustomData * BYTE(0) +
638 c_Module_Flags_SongName * BYTE(1);
639 I1 := $01;
640 WHILE (Header^.PSM_SongName[I1] > #00) AND (I1 < c_Module_SongNameLength) DO
641 BEGIN
642 Module^.Module_Name[I1] := Header^.PSM_SongName[I1];
643 INC(I1);
644 END;
645 Module^.Module_Name[c_Module_SongNameLength] := #00;
646 { *** Init channelsettings }
647 FOR I1 := 0 TO c_Maximum_ChannelIndex DO
648 BEGIN
649 IF I1 < Header^.PSM_ChannelUsed THEN
650 BEGIN
651 { *** channel enabled }
652 Module^.Module_ChannelSettingPointer^[I1].ChannelSettings_GlobalVolume := 64;
653 Module^.Module_ChannelSettingPointer^[I1].ChannelSettings_Panning := (ChannelSettings^[I1]) * $08;
654 Module^.Module_ChannelSettingPointer^[I1].ChannelSettings_Code := I1 + $10 * BYTE(ChannelSettings^[I1] > $08) +
655 c_ChannelSettings_Code_ChannelEnabled * BYTE(1) +
656 c_ChannelSettings_Code_ChannelDigital * BYTE(1);
657 Module^.Module_ChannelSettingPointer^[I1].ChannelSettings_Controls :=
658 c_ChannelSettings_Controls_EnhancedMode * BYTE(1) +
659 c_ChannelSettings_Controls_SurroundMode * BYTE(0);
660 END
661 ELSE
662 BEGIN
663 { *** channel disabled }
664 Module^.Module_ChannelSettingPointer^[I1].ChannelSettings_GlobalVolume := $00;
665 Module^.Module_ChannelSettingPointer^[I1].ChannelSettings_Panning := $00;
666 Module^.Module_ChannelSettingPointer^[I1].ChannelSettings_Code := $00;
667 Module^.Module_ChannelSettingPointer^[I1].ChannelSettings_Controls := $00;
668 END;
669 END;
670 { *** init and copy order }
671 FILLCHAR(Module^.Module_OrderPointer^,c_Maximum_OrderIndex+1,$FF);
672 MOVE(Order^,Module^.Module_OrderPointer^,Header^.PSM_OrderLength);
673 { *** read pattern }
674 SEEK(InFile,FilePosition + Header^.PSM_PatternPosition);
675 NTMIK_LoaderPatternNumber := Header^.PSM_PatternNumber-1;
676 FOR I1 := 0 TO Header^.PSM_PatternNumber-1 DO
677 BEGIN
678 NTMIK_LoadPatternProcedure;
679 { *** read length }
680 BLOCKREAD(InFile,TempW,2);
681 { *** read pattern }
682 BLOCKREAD(InFile,MultiPurposeBuffer^,TempW-2);
683 { *** unpack pattern and set notes per channel to 64 }
684 PSM_UnpackPattern(MultiPurposeBuffer^,PatternBuffer^,TempW);
685 NTMIK_PackPattern(MultiPurposeBuffer^,PatternBuffer^,PSM_NotesInPattern);
686 TempW := WORD(256) * MultiPurposeBuffer^[01] + MultiPurposeBuffer^[00];
687 GETMEM(Module^.Module_PatternPointer^[I1],TempW);
688 MOVE(MultiPurposeBuffer^,Module^.Module_PatternPointer^[I1]^,TempW);
689 { *** next pattern }
690 END;
691 { *** read samples }
692 NTMIK_LoaderSampleNumber := Header^.PSM_SampleNumber;
693 FOR I1 := 1 TO Header^.PSM_SampleNumber DO
694 BEGIN
695 NTMIK_LoadSampleProcedure;
696 { *** get index for sample }
697 I3 := Sample^[I1].PSM_SampleNumber;
698 { *** clip PSM-sample }
699 IF Sample^[I1].PSM_SampleLoopEnd > Sample^[I1].PSM_SampleLength
700 THEN Sample^[I1].PSM_SampleLoopEnd := Sample^[I1].PSM_SampleLength;
701 { *** init intern sample }
702 NEW(Module^.Module_SamplePointer^[I3]);
703 FILLCHAR(Module^.Module_SamplePointer^[I3]^,SIZEOF(TSample),$00);
704 FILLCHAR(Module^.Module_SamplePointer^[I3]^.Sample_SampleName,c_Sample_SampleNameLength,#32);
705 FILLCHAR(Module^.Module_SamplePointer^[I3]^.Sample_FileName,c_Sample_FileNameLength,#32);
706 { *** copy informations to intern sample }
707 I2 := $01;
708 WHILE (Sample^[I1].PSM_SampleName[I2] > #00) AND (I2 < c_Sample_SampleNameLength) DO
709 BEGIN
710 Module^.Module_SamplePointer^[I3]^.Sample_SampleName[I2] := Sample^[I1].PSM_SampleName[I2];
711 INC(I2);
712 END;
713 Module^.Module_SamplePointer^[I3]^.Sample_Sign := 'DF';
714 Module^.Module_SamplePointer^[I3]^.Sample_FileFormatVersion := $00100;
715 Module^.Module_SamplePointer^[I3]^.Sample_Position := $00000000;
716 Module^.Module_SamplePointer^[I3]^.Sample_Selector := $0000;
717 Module^.Module_SamplePointer^[I3]^.Sample_Volume := Sample^[I1].PSM_SampleVolume;
718 Module^.Module_SamplePointer^[I3]^.Sample_LoopCounter := $00;
719 Module^.Module_SamplePointer^[I3]^.Sample_C5Speed := Sample^[I1].PSM_SampleC5Speed;
720 Module^.Module_SamplePointer^[I3]^.Sample_Length := Sample^[I1].PSM_SampleLength;
721 Module^.Module_SamplePointer^[I3]^.Sample_LoopBegin := Sample^[I1].PSM_SampleLoopBegin;
722 Module^.Module_SamplePointer^[I3]^.Sample_LoopEnd := Sample^[I1].PSM_SampleLoopEnd;
723 { *** now it's time for the flags }
724 Module^.Module_SamplePointer^[I3]^.Sample_Flags :=
725 c_Sample_Flags_DigitalSample * BYTE(1) +
726 c_Sample_Flags_8BitSample * BYTE(1) +
727 c_Sample_Flags_UnsignedSampleData * BYTE(1) +
728 c_Sample_Flags_Packed * BYTE(0) +
729 c_Sample_Flags_LoopCounter * BYTE(0) +
730 c_Sample_Flags_SampleName * BYTE(1) +
731 c_Sample_Flags_LoopActive *
732 BYTE(Sample^[I1].PSM_SampleFlags AND (LONGINT(1) SHL 15) = (LONGINT(1) SHL 15));
733 { *** alloc memory for sample-data }
734 E_Getmem(Module^.Module_SamplePointer^[I3]^.Sample_Selector,
735 Module^.Module_SamplePointer^[I3]^.Sample_Position,
736 Module^.Module_SamplePointer^[I3]^.Sample_Length + c_LoopExtensionSize);
737 { *** read out data }
738 EPT(TempP).p_Selector := Module^.Module_SamplePointer^[I3]^.Sample_Selector;
739 EPT(TempP).p_Offset := $0000;
740 SEEK(InFile,Sample^[I1].PSM_SamplePosition);
741 E_BLOCKREAD(InFile,TempP^,Module^.Module_SamplePointer^[I3]^.Sample_Length);
742 { *** 'coz the samples are signed in a DSM-file -> PC-fy them }
743 IF Module^.Module_SamplePointer^[I3]^.Sample_Length > 4 THEN
744 BEGIN
745 CopyLength := Module^.Module_SamplePointer^[I3]^.Sample_Length;
746 { *** decode sample }
747 ASM
748 DB 066h; MOV CX,WORD PTR CopyLength
749 { *** load sample selector }
750 MOV ES,WORD PTR TempP[00002h]
751 DB 066h; XOR SI,SI
752 DB 066h; XOR DI,DI
753 XOR AH,AH
754 { *** conert all bytes }
755 @@MainLoop:
756 DB 026h; DB 067h; LODSB
757 ADD AL,AH
758 MOV AH,AL
759 DB 067h; STOSB
760 DB 066h; LOOP @@MainLoop
761 END;
762 { *** make samples unsigned }
763 ASM
764 DB 066h; MOV CX,WORD PTR CopyLength
765 { *** load sample selector }
766 MOV ES,WORD PTR TempP[00002h]
767 DB 066h; XOR SI,SI
768 DB 066h; XOR DI,DI
769 { *** conert all bytes }
770 @@MainLoop:
771 DB 026h; DB 067h; LODSB
772 SUB AL,080h
773 DB 067h; STOSB
774 DB 066h; LOOP @@MainLoop
775 END;
776 { *** Create Loop-Extension }
777 IF Module^.Module_SamplePointer^[I3]^.Sample_Flags AND c_Sample_Flags_LoopActive = c_Sample_Flags_LoopActive THEN
778 BEGIN
779 CopySource := Module^.Module_SamplePointer^[I3]^.Sample_LoopBegin;
780 CopyDestination := Module^.Module_SamplePointer^[I3]^.Sample_LoopEnd;
781 CopyLength := CopyDestination - CopySource;
782 ASM
783 { *** load sample-selector }
784 MOV ES,WORD PTR TempP[00002h]
785 DB 066h; MOV DI,WORD PTR CopyDestination
786 { *** calculate number of full sample-loops to copy }
787 XOR DX,DX
788 MOV AX,c_LoopExtensionSize
789 MOV BX,WORD PTR CopyLength
790 DIV BX
791 OR AX,AX
792 JE @@NoFullLoop
793 { *** copy some full-loops (size=bx) }
794 MOV CX,AX
795 @@InnerLoop:
796 PUSH CX
797 DB 066h; MOV SI,WORD PTR CopySource
798 MOV CX,BX
799 DB 0F3h; DB 026h,067h,0A4h { REP MOVS BYTE PTR ES:[EDI],ES:[ESI] }
800 POP CX
801 LOOP @@InnerLoop
802 @@NoFullLoop:
803 { *** calculate number of rest-bytes to copy }
804 DB 066h; MOV SI,WORD PTR CopySource
805 MOV CX,DX
806 DB 0F3h; DB 026h,067h,0A4h { REP MOVS BYTE PTR ES:[EDI],ES:[ESI] }
807 END;
808 END
809 ELSE
810 BEGIN
811 CopyDestination := Module^.Module_SamplePointer^[I3]^.Sample_Length;
812 ASM
813 { *** load sample-selector }
814 MOV ES,WORD PTR TempP[00002h]
815 DB 066h; MOV DI,WORD PTR CopyDestination
816 { *** clear extension }
817 MOV CX,c_LoopExtensionSize
818 MOV AL,080h
819 DB 0F3h; DB 067h,0AAh { REP STOS BYTE PTR ES:[EDI] }
820 END;
821 END;
822 END;
823 { *** next sample }
824 END;
825 { *** init period-ranges }
826 NTMIK_MaximumPeriod := $0000D600 SHR 1;
827 NTMIK_MinimumPeriod := $0000D600 SHR 8;
828 { *** close file }
829 CLOSE(InFile);
830 { *** dispose all dynamic variables }
831 DISPOSE(Header);
832 DISPOSE(Sample);
833 DISPOSE(Order);
834 DISPOSE(ChannelSettings);
835 DISPOSE(MultiPurposeBuffer);
836 DISPOSE(PatternBuffer);
837 { *** set errorcode to noerror }
838 ErrorCode := c_NoError;
839 END;
840
841*/
842
diff --git a/core/multimedia/opieplayer/modplug/load_ptm.cpp b/core/multimedia/opieplayer/modplug/load_ptm.cpp
new file mode 100644
index 0000000..636ae56
--- a/dev/null
+++ b/core/multimedia/opieplayer/modplug/load_ptm.cpp
@@ -0,0 +1,210 @@
1/*
2 * This program is free software; you can redistribute it and modify it
3 * under the terms of the GNU General Public License as published by the
4 * Free Software Foundation; either version 2 of the license or (at your
5 * option) any later version.
6 *
7 * Authors: Olivier Lapicque <olivierl@jps.net>,
8 * Adam Goode <adam@evdebs.org> (endian and char fixes for PPC)
9*/
10
11//////////////////////////////////////////////
12// PTM PolyTracker module loader //
13//////////////////////////////////////////////
14#include "stdafx.h"
15#include "sndfile.h"
16
17//#pragma warning(disable:4244)
18
19#pragma pack(1)
20
21typedef struct PTMFILEHEADER
22{
23 CHAR songname[28]; // name of song, asciiz string
24 CHAR eof; // 26
25 BYTE version_lo; // 03 version of file, currently 0203h
26 BYTE version_hi; // 02
27 BYTE reserved1; // reserved, set to 0
28 WORD norders; // number of orders (0..256)
29 WORD nsamples; // number of instruments (1..255)
30 WORD npatterns; // number of patterns (1..128)
31 WORD nchannels; // number of channels (voices) used (1..32)
32 WORD fileflags; // set to 0
33 WORD reserved2; // reserved, set to 0
34 DWORD ptmf_id; // song identification, 'PTMF' or 0x464d5450
35 BYTE reserved3[16]; // reserved, set to 0
36 BYTE chnpan[32]; // channel panning settings, 0..15, 0 = left, 7 = middle, 15 = right
37 BYTE orders[256]; // order list, valid entries 0..nOrders-1
38 WORD patseg[128]; // pattern offsets (*16)
39} Q_PACKED PTMFILEHEADER, *LPPTMFILEHEADER;
40
41 #define SIZEOF_PTMFILEHEADER608
42
43
44typedef struct PTMSAMPLE
45{
46 BYTE sampletype; // sample type (bit array)
47 CHAR filename[12]; // name of external sample file
48 BYTE volume; // default volume
49 WORD nC4Spd; // C4 speed
50 WORD sampleseg; // sample segment (used internally)
51 WORD fileofs[2]; // offset of sample data
52 WORD length[2]; // sample size (in bytes)
53 WORD loopbeg[2]; // start of loop
54 WORD loopend[2]; // end of loop
55 WORD gusdata[8];
56 char samplename[28];// name of sample, asciiz // changed from CHAR
57 DWORD ptms_id; // sample identification, 'PTMS' or 0x534d5450
58} Q_PACKED PTMSAMPLE;
59
60 #define SIZEOF_PTMSAMPLE80
61
62#pragma pack()
63
64
65BOOL CSoundFile::ReadPTM(const BYTE *lpStream, DWORD dwMemLength)
66//---------------------------------------------------------------
67{
68 PTMFILEHEADER pfh = *(LPPTMFILEHEADER)lpStream;
69 DWORD dwMemPos;
70 UINT nOrders;
71
72 pfh.norders = bswapLE16(pfh.norders);
73 pfh.nsamples = bswapLE16(pfh.nsamples);
74 pfh.npatterns = bswapLE16(pfh.npatterns);
75 pfh.nchannels = bswapLE16(pfh.nchannels);
76 pfh.fileflags = bswapLE16(pfh.fileflags);
77 pfh.reserved2 = bswapLE16(pfh.reserved2);
78 pfh.ptmf_id = bswapLE32(pfh.ptmf_id);
79 for (UINT j=0; j<128; j++)
80 {
81 pfh.patseg[j] = bswapLE16(pfh.patseg[j]);
82 }
83
84 if ((!lpStream) || (dwMemLength < 1024)) return FALSE;
85 if ((pfh.ptmf_id != 0x464d5450) || (!pfh.nchannels)
86 || (pfh.nchannels > 32)
87 || (pfh.norders > 256) || (!pfh.norders)
88 || (!pfh.nsamples) || (pfh.nsamples > 255)
89 || (!pfh.npatterns) || (pfh.npatterns > 128)
90 || (SIZEOF_PTMFILEHEADER+pfh.nsamples*SIZEOF_PTMSAMPLE >= (int)dwMemLength)) return FALSE;
91 memcpy(m_szNames[0], pfh.songname, 28);
92 m_szNames[0][28] = 0;
93 m_nType = MOD_TYPE_PTM;
94 m_nChannels = pfh.nchannels;
95 m_nSamples = (pfh.nsamples < MAX_SAMPLES) ? pfh.nsamples : MAX_SAMPLES-1;
96 dwMemPos = SIZEOF_PTMFILEHEADER;
97 nOrders = (pfh.norders < MAX_ORDERS) ? pfh.norders : MAX_ORDERS-1;
98 memcpy(Order, pfh.orders, nOrders);
99 for (UINT ipan=0; ipan<m_nChannels; ipan++)
100 {
101 ChnSettings[ipan].nVolume = 64;
102 ChnSettings[ipan].nPan = ((pfh.chnpan[ipan] & 0x0F) << 4) + 4;
103 }
104 for (UINT ismp=0; ismp<m_nSamples; ismp++, dwMemPos += SIZEOF_PTMSAMPLE)
105 {
106 MODINSTRUMENT *pins = &Ins[ismp+1];
107 PTMSAMPLE *psmp = (PTMSAMPLE *)(lpStream+dwMemPos);
108
109 lstrcpyn(m_szNames[ismp+1], psmp->samplename, 28);
110 memcpy(pins->name, psmp->filename, 12);
111 pins->name[12] = 0;
112 pins->nGlobalVol = 64;
113 pins->nPan = 128;
114 pins->nVolume = psmp->volume << 2;
115 pins->nC4Speed = bswapLE16(psmp->nC4Spd) << 1;
116 pins->uFlags = 0;
117 if ((psmp->sampletype & 3) == 1)
118 {
119 UINT smpflg = RS_PCM8D;
120 DWORD samplepos;
121 pins->nLength = bswapLE32(*(LPDWORD)(psmp->length));
122 pins->nLoopStart = bswapLE32(*(LPDWORD)(psmp->loopbeg));
123 pins->nLoopEnd = bswapLE32(*(LPDWORD)(psmp->loopend));
124 samplepos = bswapLE32(*(LPDWORD)(&psmp->fileofs));
125 if (psmp->sampletype & 4) pins->uFlags |= CHN_LOOP;
126 if (psmp->sampletype & 8) pins->uFlags |= CHN_PINGPONGLOOP;
127 if (psmp->sampletype & 16)
128 {
129 pins->uFlags |= CHN_16BIT;
130 pins->nLength >>= 1;
131 pins->nLoopStart >>= 1;
132 pins->nLoopEnd >>= 1;
133 smpflg = RS_PTM8DTO16;
134 }
135 if ((pins->nLength) && (samplepos) && (samplepos < dwMemLength))
136 {
137 ReadSample(pins, smpflg, (LPSTR)(lpStream+samplepos), dwMemLength-samplepos);
138 }
139 }
140 }
141 // Reading Patterns
142 for (UINT ipat=0; ipat<pfh.npatterns; ipat++)
143 {
144 dwMemPos = ((UINT)pfh.patseg[ipat]) << 4;
145 if ((!dwMemPos) || (dwMemPos >= dwMemLength)) continue;
146 PatternSize[ipat] = 64;
147 if ((Patterns[ipat] = AllocatePattern(64, m_nChannels)) == NULL) break;
148 //
149 MODCOMMAND *m = Patterns[ipat];
150 for (UINT row=0; ((row < 64) && (dwMemPos < dwMemLength)); )
151 {
152 UINT b = lpStream[dwMemPos++];
153
154 if (dwMemPos >= dwMemLength) break;
155 if (b)
156 {
157 UINT nChn = b & 0x1F;
158
159 if (b & 0x20)
160 {
161 if (dwMemPos + 2 > dwMemLength) break;
162 m[nChn].note = lpStream[dwMemPos++];
163 m[nChn].instr = lpStream[dwMemPos++];
164 }
165 if (b & 0x40)
166 {
167 if (dwMemPos + 2 > dwMemLength) break;
168 m[nChn].command = lpStream[dwMemPos++];
169 m[nChn].param = lpStream[dwMemPos++];
170 if ((m[nChn].command == 0x0E) && ((m[nChn].param & 0xF0) == 0x80))
171 {
172 m[nChn].command = CMD_S3MCMDEX;
173 } else
174 if (m[nChn].command < 0x10)
175 {
176 ConvertModCommand(&m[nChn]);
177 } else
178 {
179 switch(m[nChn].command)
180 {
181 case 16:
182 m[nChn].command = CMD_GLOBALVOLUME;
183 break;
184 case 17:
185 m[nChn].command = CMD_RETRIG;
186 break;
187 case 18:
188 m[nChn].command = CMD_FINEVIBRATO;
189 break;
190 default:
191 m[nChn].command = 0;
192 }
193 }
194 }
195 if (b & 0x80)
196 {
197 if (dwMemPos >= dwMemLength) break;
198 m[nChn].volcmd = VOLCMD_VOLUME;
199 m[nChn].vol = lpStream[dwMemPos++];
200 }
201 } else
202 {
203 row++;
204 m += m_nChannels;
205 }
206 }
207 }
208 return TRUE;
209}
210
diff --git a/core/multimedia/opieplayer/modplug/load_s3m.cpp b/core/multimedia/opieplayer/modplug/load_s3m.cpp
new file mode 100644
index 0000000..e33be1c
--- a/dev/null
+++ b/core/multimedia/opieplayer/modplug/load_s3m.cpp
@@ -0,0 +1,653 @@
1/*
2 * This program is free software; you can redistribute it and modify it
3 * under the terms of the GNU General Public License as published by the
4 * Free Software Foundation; either version 2 of the license or (at your
5 * option) any later version.
6 *
7 * Authors: Olivier Lapicque <olivierl@jps.net>,
8 * Adam Goode <adam@evdebs.org> (endian and char fixes for PPC)
9*/
10
11#include "stdafx.h"
12#include "sndfile.h"
13
14//#pragma warning(disable:4244)
15
16extern WORD S3MFineTuneTable[16];
17
18//////////////////////////////////////////////////////
19// ScreamTracker S3M file support
20
21typedef struct tagS3MSAMPLESTRUCT
22{
23 BYTE type;
24 CHAR dosname[12];
25 BYTE hmem;
26 WORD memseg;
27 DWORD length;
28 DWORD loopbegin;
29 DWORD loopend;
30 BYTE vol;
31 BYTE bReserved;
32 BYTE pack;
33 BYTE flags;
34 DWORD finetune;
35 DWORD dwReserved;
36 WORD intgp;
37 WORD int512;
38 DWORD lastused;
39 CHAR name[28];
40 CHAR scrs[4];
41} Q_PACKED S3MSAMPLESTRUCT;
42
43
44typedef struct tagS3MFILEHEADER
45{
46 CHAR name[28];
47 BYTE b1A;
48 BYTE type;
49 WORD reserved1;
50 WORD ordnum;
51 WORD insnum;
52 WORD patnum;
53 WORD flags;
54 WORD cwtv;
55 WORD version;
56 DWORD scrm;// "SCRM" = 0x4D524353
57 BYTE globalvol;
58 BYTE speed;
59 BYTE tempo;
60 BYTE mastervol;
61 BYTE ultraclicks;
62 BYTE panning_present;
63 BYTE reserved2[8];
64 WORD special;
65 BYTE channels[32];
66} Q_PACKED S3MFILEHEADER;
67
68
69void CSoundFile::S3MConvert(MODCOMMAND *m, BOOL bIT) const
70//--------------------------------------------------------
71{
72 UINT command = m->command;
73 UINT param = m->param;
74 switch (command + 0x40)
75 {
76 case 'A':command = CMD_SPEED; break;
77 case 'B':command = CMD_POSITIONJUMP; break;
78 case 'C':command = CMD_PATTERNBREAK; if (!bIT) param = (param >> 4) * 10 + (param & 0x0F); break;
79 case 'D':command = CMD_VOLUMESLIDE; break;
80 case 'E':command = CMD_PORTAMENTODOWN; break;
81 case 'F':command = CMD_PORTAMENTOUP; break;
82 case 'G':command = CMD_TONEPORTAMENTO; break;
83 case 'H':command = CMD_VIBRATO; break;
84 case 'I':command = CMD_TREMOR; break;
85 case 'J':command = CMD_ARPEGGIO; break;
86 case 'K':command = CMD_VIBRATOVOL; break;
87 case 'L':command = CMD_TONEPORTAVOL; break;
88 case 'M':command = CMD_CHANNELVOLUME; break;
89 case 'N':command = CMD_CHANNELVOLSLIDE; break;
90 case 'O':command = CMD_OFFSET; break;
91 case 'P':command = CMD_PANNINGSLIDE; break;
92 case 'Q':command = CMD_RETRIG; break;
93 case 'R':command = CMD_TREMOLO; break;
94 case 'S':command = CMD_S3MCMDEX; break;
95 case 'T':command = CMD_TEMPO; break;
96 case 'U':command = CMD_FINEVIBRATO; break;
97 case 'V':command = CMD_GLOBALVOLUME; break;
98 case 'W':command = CMD_GLOBALVOLSLIDE; break;
99 case 'X':command = CMD_PANNING8; break;
100 case 'Y':command = CMD_PANBRELLO; break;
101 case 'Z':command = CMD_MIDI; break;
102 default:command = 0;
103 }
104 m->command = command;
105 m->param = param;
106}
107
108
109void CSoundFile::S3MSaveConvert(UINT *pcmd, UINT *pprm, BOOL bIT) const
110//---------------------------------------------------------------------
111{
112 UINT command = *pcmd;
113 UINT param = *pprm;
114 switch(command)
115 {
116 case CMD_SPEED: command = 'A'; break;
117 case CMD_POSITIONJUMP: command = 'B'; break;
118 case CMD_PATTERNBREAK: command = 'C'; if (!bIT) param = ((param / 10) << 4) + (param % 10); break;
119 case CMD_VOLUMESLIDE: command = 'D'; break;
120 case CMD_PORTAMENTODOWN:command = 'E'; if ((param >= 0xE0) && (m_nType & (MOD_TYPE_MOD|MOD_TYPE_XM))) param = 0xDF; break;
121 case CMD_PORTAMENTOUP: command = 'F'; if ((param >= 0xE0) && (m_nType & (MOD_TYPE_MOD|MOD_TYPE_XM))) param = 0xDF; break;
122 case CMD_TONEPORTAMENTO:command = 'G'; break;
123 case CMD_VIBRATO: command = 'H'; break;
124 case CMD_TREMOR: command = 'I'; break;
125 case CMD_ARPEGGIO: command = 'J'; break;
126 case CMD_VIBRATOVOL: command = 'K'; break;
127 case CMD_TONEPORTAVOL: command = 'L'; break;
128 case CMD_CHANNELVOLUME: command = 'M'; break;
129 case CMD_CHANNELVOLSLIDE:command = 'N'; break;
130 case CMD_OFFSET: command = 'O'; break;
131 case CMD_PANNINGSLIDE: command = 'P'; break;
132 case CMD_RETRIG: command = 'Q'; break;
133 case CMD_TREMOLO: command = 'R'; break;
134 case CMD_S3MCMDEX: command = 'S'; break;
135 case CMD_TEMPO: command = 'T'; break;
136 case CMD_FINEVIBRATO: command = 'U'; break;
137 case CMD_GLOBALVOLUME: command = 'V'; break;
138 case CMD_GLOBALVOLSLIDE:command = 'W'; break;
139 case CMD_PANNING8:
140 command = 'X';
141 if ((bIT) && (m_nType != MOD_TYPE_IT) && (m_nType != MOD_TYPE_XM))
142 {
143 if (param == 0xA4) { command = 'S'; param = 0x91; }else
144 if (param <= 0x80) { param <<= 1; if (param > 255) param = 255; } else
145 command = param = 0;
146 } else
147 if ((!bIT) && ((m_nType == MOD_TYPE_IT) || (m_nType == MOD_TYPE_XM)))
148 {
149 param >>= 1;
150 }
151 break;
152 case CMD_PANBRELLO: command = 'Y'; break;
153 case CMD_MIDI: command = 'Z'; break;
154 case CMD_XFINEPORTAUPDOWN:
155 if (param & 0x0F) switch(param & 0xF0)
156 {
157 case 0x10:command = 'F'; param = (param & 0x0F) | 0xE0; break;
158 case 0x20:command = 'E'; param = (param & 0x0F) | 0xE0; break;
159 case 0x90:command = 'S'; break;
160 default:command = param = 0;
161 } else command = param = 0;
162 break;
163 case CMD_MODCMDEX:
164 command = 'S';
165 switch(param & 0xF0)
166 {
167 case 0x00:command = param = 0; break;
168 case 0x10:command = 'F'; param |= 0xF0; break;
169 case 0x20:command = 'E'; param |= 0xF0; break;
170 case 0x30:param = (param & 0x0F) | 0x10; break;
171 case 0x40:param = (param & 0x0F) | 0x30; break;
172 case 0x50:param = (param & 0x0F) | 0x20; break;
173 case 0x60:param = (param & 0x0F) | 0xB0; break;
174 case 0x70:param = (param & 0x0F) | 0x40; break;
175 case 0x90:command = 'Q'; param &= 0x0F; break;
176 case 0xA0:if (param & 0x0F) { command = 'D'; param = (param << 4) | 0x0F; } else command=param=0; break;
177 case 0xB0:if (param & 0x0F) { command = 'D'; param |= 0xF0; } else command=param=0; break;
178 }
179 break;
180 default:command = param = 0;
181 }
182 command &= ~0x40;
183 *pcmd = command;
184 *pprm = param;
185}
186
187
188BOOL CSoundFile::ReadS3M(const BYTE *lpStream, DWORD dwMemLength)
189//---------------------------------------------------------------
190{
191 UINT insnum,patnum,nins,npat;
192 DWORD insfile[128];
193 WORD ptr[256];
194 BYTE s[1024];
195 DWORD dwMemPos;
196 BYTE insflags[128], inspack[128];
197 S3MFILEHEADER psfh = *(S3MFILEHEADER *)lpStream;
198
199 psfh.reserved1 = bswapLE16(psfh.reserved1);
200 psfh.ordnum = bswapLE16(psfh.ordnum);
201 psfh.insnum = bswapLE16(psfh.insnum);
202 psfh.patnum = bswapLE16(psfh.patnum);
203 psfh.flags = bswapLE16(psfh.flags);
204 psfh.cwtv = bswapLE16(psfh.cwtv);
205 psfh.version = bswapLE16(psfh.version);
206 psfh.scrm = bswapLE32(psfh.scrm);
207 psfh.special = bswapLE16(psfh.special);
208
209 if ((!lpStream) || (dwMemLength <= sizeof(S3MFILEHEADER)+sizeof(S3MSAMPLESTRUCT)+64)) return FALSE;
210 if (psfh.scrm != 0x4D524353) return FALSE;
211 dwMemPos = 0x60;
212 m_nType = MOD_TYPE_S3M;
213 memset(m_szNames,0,sizeof(m_szNames));
214 memcpy(m_szNames[0], psfh.name, 28);
215 // Speed
216 m_nDefaultSpeed = psfh.speed;
217 if (m_nDefaultSpeed < 1) m_nDefaultSpeed = 6;
218 if (m_nDefaultSpeed > 0x1F) m_nDefaultSpeed = 0x1F;
219 // Tempo
220 m_nDefaultTempo = psfh.tempo;
221 if (m_nDefaultTempo < 40) m_nDefaultTempo = 40;
222 if (m_nDefaultTempo > 240) m_nDefaultTempo = 240;
223 // Global Volume
224 m_nDefaultGlobalVolume = psfh.globalvol << 2;
225 if ((!m_nDefaultGlobalVolume) || (m_nDefaultGlobalVolume > 256)) m_nDefaultGlobalVolume = 256;
226 m_nSongPreAmp = psfh.mastervol & 0x7F;
227 // Channels
228 m_nChannels = 4;
229 for (UINT ich=0; ich<32; ich++)
230 {
231 ChnSettings[ich].nPan = 128;
232 ChnSettings[ich].nVolume = 64;
233
234 ChnSettings[ich].dwFlags = CHN_MUTE;
235 if (psfh.channels[ich] != 0xFF)
236 {
237 m_nChannels = ich+1;
238 UINT b = psfh.channels[ich] & 0x0F;
239 ChnSettings[ich].nPan = (b & 8) ? 0xC0 : 0x40;
240 ChnSettings[ich].dwFlags = 0;
241 }
242 }
243 if (m_nChannels < 4) m_nChannels = 4;
244 if ((psfh.cwtv < 0x1320) || (psfh.flags & 0x40)) m_dwSongFlags |= SONG_FASTVOLSLIDES;
245 // Reading pattern order
246 UINT iord = psfh.ordnum;
247 if (iord<1) iord = 1;
248 if (iord > MAX_ORDERS) iord = MAX_ORDERS;
249 if (iord)
250 {
251 memcpy(Order, lpStream+dwMemPos, iord);
252 dwMemPos += iord;
253 }
254 if ((iord & 1) && (lpStream[dwMemPos] == 0xFF)) dwMemPos++;
255 // Reading file pointers
256 insnum = nins = psfh.insnum;
257 if (insnum >= MAX_SAMPLES) insnum = MAX_SAMPLES-1;
258 m_nSamples = insnum;
259 patnum = npat = psfh.patnum;
260 if (patnum > MAX_PATTERNS) patnum = MAX_PATTERNS;
261 memset(ptr, 0, sizeof(ptr));
262 if (nins+npat)
263 {
264 memcpy(ptr, lpStream+dwMemPos, 2*(nins+npat));
265 dwMemPos += 2*(nins+npat);
266 for (UINT j = 0; j < (nins+npat); ++j) {
267 ptr[j] = bswapLE16(ptr[j]);
268 }
269 if (psfh.panning_present == 252)
270 {
271 const BYTE *chnpan = lpStream+dwMemPos;
272 for (UINT i=0; i<32; i++) if (chnpan[i] & 0x20)
273 {
274 ChnSettings[i].nPan = ((chnpan[i] & 0x0F) << 4) + 8;
275 }
276 }
277 }
278 if (!m_nChannels) return TRUE;
279 // Reading instrument headers
280 memset(insfile, 0, sizeof(insfile));
281 for (UINT iSmp=1; iSmp<=insnum; iSmp++)
282 {
283 UINT nInd = ((DWORD)ptr[iSmp-1])*16;
284 if ((!nInd) || (nInd + 0x50 > dwMemLength)) continue;
285 memcpy(s, lpStream+nInd, 0x50);
286 memcpy(Ins[iSmp].name, s+1, 12);
287 insflags[iSmp-1] = s[0x1F];
288 inspack[iSmp-1] = s[0x1E];
289 s[0x4C] = 0;
290 lstrcpy(m_szNames[iSmp], (LPCSTR)&s[0x30]);
291 if ((s[0]==1) && (s[0x4E]=='R') && (s[0x4F]=='S'))
292 {
293 UINT j = bswapLE32(*((LPDWORD)(s+0x10)));
294 if (j > MAX_SAMPLE_LENGTH) j = MAX_SAMPLE_LENGTH;
295 if (j < 4) j = 0;
296 Ins[iSmp].nLength = j;
297 j = bswapLE32(*((LPDWORD)(s+0x14)));
298 if (j >= Ins[iSmp].nLength) j = Ins[iSmp].nLength - 1;
299 Ins[iSmp].nLoopStart = j;
300 j = bswapLE32(*((LPDWORD)(s+0x18)));
301 if (j > MAX_SAMPLE_LENGTH) j = MAX_SAMPLE_LENGTH;
302 if (j < 4) j = 0;
303 if (j > Ins[iSmp].nLength) j = Ins[iSmp].nLength;
304 Ins[iSmp].nLoopEnd = j;
305 j = s[0x1C];
306 if (j > 64) j = 64;
307 Ins[iSmp].nVolume = j << 2;
308 Ins[iSmp].nGlobalVol = 64;
309 if (s[0x1F]&1) Ins[iSmp].uFlags |= CHN_LOOP;
310 j = bswapLE32(*((LPDWORD)(s+0x20)));
311 if (!j) j = 8363;
312 if (j < 1024) j = 1024;
313 Ins[iSmp].nC4Speed = j;
314 insfile[iSmp] = ((DWORD)bswapLE16(*((LPWORD)(s+0x0E)))) << 4;
315 insfile[iSmp] += ((DWORD)(BYTE)s[0x0D]) << 20;
316 if (insfile[iSmp] > dwMemLength) insfile[iSmp] &= 0xFFFF;
317 if ((Ins[iSmp].nLoopStart >= Ins[iSmp].nLoopEnd) || (Ins[iSmp].nLoopEnd - Ins[iSmp].nLoopStart < 8))
318 Ins[iSmp].nLoopStart = Ins[iSmp].nLoopEnd = 0;
319 Ins[iSmp].nPan = 0x80;
320 }
321 }
322 // Reading patterns
323 for (UINT iPat=0; iPat<patnum; iPat++)
324 {
325 UINT nInd = ((DWORD)ptr[nins+iPat]) << 4;
326 if (nInd + 0x40 > dwMemLength) continue;
327 WORD len = bswapLE16(*((WORD *)(lpStream+nInd)));
328 nInd += 2;
329 PatternSize[iPat] = 64;
330 if ((!len) || (nInd + len > dwMemLength - 6)
331 || ((Patterns[iPat] = AllocatePattern(64, m_nChannels)) == NULL)) continue;
332 LPBYTE src = (LPBYTE)(lpStream+nInd);
333 // Unpacking pattern
334 MODCOMMAND *p = Patterns[iPat];
335 UINT row = 0;
336 UINT j = 0;
337 while (j < len)
338 {
339 BYTE b = src[j++];
340 if (!b)
341 {
342 if (++row >= 64) break;
343 } else
344 {
345 UINT chn = b & 0x1F;
346 if (chn < m_nChannels)
347 {
348 MODCOMMAND *m = &p[row*m_nChannels+chn];
349 if (b & 0x20)
350 {
351 m->note = src[j++];
352 if (m->note < 0xF0) m->note = (m->note & 0x0F) + 12*(m->note >> 4) + 13;
353 else if (m->note == 0xFF) m->note = 0;
354 m->instr = src[j++];
355 }
356 if (b & 0x40)
357 {
358 UINT vol = src[j++];
359 if ((vol >= 128) && (vol <= 192))
360 {
361 vol -= 128;
362 m->volcmd = VOLCMD_PANNING;
363 } else
364 {
365 if (vol > 64) vol = 64;
366 m->volcmd = VOLCMD_VOLUME;
367 }
368 m->vol = vol;
369 }
370 if (b & 0x80)
371 {
372 m->command = src[j++];
373 m->param = src[j++];
374 if (m->command) S3MConvert(m, FALSE);
375 }
376 } else
377 {
378 if (b & 0x20) j += 2;
379 if (b & 0x40) j++;
380 if (b & 0x80) j += 2;
381 }
382 if (j >= len) break;
383 }
384 }
385 }
386 // Reading samples
387 for (UINT iRaw=1; iRaw<=insnum; iRaw++) if ((Ins[iRaw].nLength) && (insfile[iRaw]))
388 {
389 UINT flags = (psfh.version == 1) ? RS_PCM8S : RS_PCM8U;
390 if (insflags[iRaw-1] & 4) flags += 5;
391 if (insflags[iRaw-1] & 2) flags |= RSF_STEREO;
392 if (inspack[iRaw-1] == 4) flags = RS_ADPCM4;
393 dwMemPos = insfile[iRaw];
394 dwMemPos += ReadSample(&Ins[iRaw], flags, (LPSTR)(lpStream + dwMemPos), dwMemLength - dwMemPos);
395 }
396 m_nMinPeriod = 64;
397 m_nMaxPeriod = 32767;
398 if (psfh.flags & 0x10) m_dwSongFlags |= SONG_AMIGALIMITS;
399 return TRUE;
400}
401
402
403#ifndef MODPLUG_NO_FILESAVE
404#pragma warning(disable:4100)
405
406static const BYTE S3MFiller[16] =
407{
408 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
409 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80
410};
411
412
413BOOL CSoundFile::SaveS3M(LPCSTR lpszFileName, UINT nPacking)
414//----------------------------------------------------------
415{
416 FILE *f;
417 BYTE header[0x60];
418 UINT nbo,nbi,nbp,i;
419 WORD patptr[128];
420 WORD insptr[128];
421 BYTE buffer[5*1024];
422 S3MSAMPLESTRUCT insex[128];
423
424 if ((!m_nChannels) || (!lpszFileName)) return FALSE;
425 if ((f = fopen(lpszFileName, "wb")) == NULL) return FALSE;
426 // Writing S3M header
427 memset(header, 0, sizeof(header));
428 memset(insex, 0, sizeof(insex));
429 memcpy(header, m_szNames[0], 0x1C);
430 header[0x1B] = 0;
431 header[0x1C] = 0x1A;
432 header[0x1D] = 0x10;
433 nbo = (GetNumPatterns() + 15) & 0xF0;
434 if (!nbo) nbo = 16;
435 header[0x20] = nbo & 0xFF;
436 header[0x21] = nbo >> 8;
437 nbi = m_nInstruments;
438 if (!nbi) nbi = m_nSamples;
439 if (nbi > 99) nbi = 99;
440 header[0x22] = nbi & 0xFF;
441 header[0x23] = nbi >> 8;
442 nbp = 0;
443 for (i=0; Patterns[i]; i++) { nbp = i+1; if (nbp >= MAX_PATTERNS) break; }
444 for (i=0; i<MAX_ORDERS; i++) if ((Order[i] < MAX_PATTERNS) && (Order[i] >= nbp)) nbp = Order[i] + 1;
445 header[0x24] = nbp & 0xFF;
446 header[0x25] = nbp >> 8;
447 if (m_dwSongFlags & SONG_FASTVOLSLIDES) header[0x26] |= 0x40;
448 if ((m_nMaxPeriod < 20000) || (m_dwSongFlags & SONG_AMIGALIMITS)) header[0x26] |= 0x10;
449 header[0x28] = 0x20;
450 header[0x29] = 0x13;
451 header[0x2A] = 0x02; // Version = 1 => Signed samples
452 header[0x2B] = 0x00;
453 header[0x2C] = 'S';
454 header[0x2D] = 'C';
455 header[0x2E] = 'R';
456 header[0x2F] = 'M';
457 header[0x30] = m_nDefaultGlobalVolume >> 2;
458 header[0x31] = m_nDefaultSpeed;
459 header[0x32] = m_nDefaultTempo;
460 header[0x33] = ((m_nSongPreAmp < 0x20) ? 0x20 : m_nSongPreAmp) | 0x80;// Stereo
461 header[0x35] = 0xFC;
462 for (i=0; i<32; i++)
463 {
464 if (i < m_nChannels)
465 {
466 UINT tmp = (i & 0x0F) >> 1;
467 header[0x40+i] = (i & 0x10) | ((i & 1) ? 8+tmp : tmp);
468 } else header[0x40+i] = 0xFF;
469 }
470 fwrite(header, 0x60, 1, f);
471 fwrite(Order, nbo, 1, f);
472 memset(patptr, 0, sizeof(patptr));
473 memset(insptr, 0, sizeof(insptr));
474 UINT ofs0 = 0x60 + nbo;
475 UINT ofs1 = ((0x60 + nbo + nbi*2 + nbp*2 + 15) & 0xFFF0) + 0x20;
476 UINT ofs = ofs1;
477
478 for (i=0; i<nbi; i++) insptr[i] = (WORD)((ofs + i*0x50) / 16);
479 for (i=0; i<nbp; i++) patptr[i] = (WORD)((ofs + nbi*0x50) / 16);
480 fwrite(insptr, nbi, 2, f);
481 fwrite(patptr, nbp, 2, f);
482 if (header[0x35] == 0xFC)
483 {
484 BYTE chnpan[32];
485 for (i=0; i<32; i++)
486 {
487 chnpan[i] = 0x20 | (ChnSettings[i].nPan >> 4);
488 }
489 fwrite(chnpan, 0x20, 1, f);
490 }
491 if ((nbi*2+nbp*2) & 0x0F)
492 {
493 fwrite(S3MFiller, 0x10 - ((nbi*2+nbp*2) & 0x0F), 1, f);
494 }
495 ofs1 = ftell(f);
496 fwrite(insex, nbi, 0x50, f);
497 // Packing patterns
498 ofs += nbi*0x50;
499 for (i=0; i<nbp; i++)
500 {
501 WORD len = 64;
502 memset(buffer, 0, sizeof(buffer));
503 patptr[i] = ofs / 16;
504 if (Patterns[i])
505 {
506 len = 2;
507 MODCOMMAND *p = Patterns[i];
508 for (int row=0; row<64; row++) if (row < PatternSize[i])
509 {
510 for (UINT j=0; j<m_nChannels; j++)
511 {
512 UINT b = j;
513 MODCOMMAND *m = &p[row*m_nChannels+j];
514 UINT note = m->note;
515 UINT volcmd = m->volcmd;
516 UINT vol = m->vol;
517 UINT command = m->command;
518 UINT param = m->param;
519
520 if ((note) || (m->instr)) b |= 0x20;
521 if (!note) note = 0xFF; else
522 if (note >= 0xFE) note = 0xFE; else
523 if (note < 13) note = 0; else note -= 13;
524 if (note < 0xFE) note = (note % 12) + ((note / 12) << 4);
525 if (command == CMD_VOLUME)
526 {
527 command = 0;
528 if (param > 64) param = 64;
529 volcmd = VOLCMD_VOLUME;
530 vol = param;
531 }
532 if (volcmd == VOLCMD_VOLUME) b |= 0x40; else
533 if (volcmd == VOLCMD_PANNING) { vol |= 0x80; b |= 0x40; }
534 if (command)
535 {
536 S3MSaveConvert(&command, &param, FALSE);
537 if (command) b |= 0x80;
538 }
539 if (b & 0xE0)
540 {
541 buffer[len++] = b;
542 if (b & 0x20)
543 {
544 buffer[len++] = note;
545 buffer[len++] = m->instr;
546 }
547 if (b & 0x40)
548 {
549 buffer[len++] = vol;
550 }
551 if (b & 0x80)
552 {
553 buffer[len++] = command;
554 buffer[len++] = param;
555 }
556 if (len > sizeof(buffer) - 20) break;
557 }
558 }
559 buffer[len++] = 0;
560 if (len > sizeof(buffer) - 20) break;
561 }
562 }
563 buffer[0] = (len - 2) & 0xFF;
564 buffer[1] = (len - 2) >> 8;
565 len = (len+15) & (~0x0F);
566 fwrite(buffer, len, 1, f);
567 ofs += len;
568 }
569 // Writing samples
570 for (i=1; i<=nbi; i++)
571 {
572 MODINSTRUMENT *pins = &Ins[i];
573 if (m_nInstruments)
574 {
575 pins = Ins;
576 if (Headers[i])
577 {
578 for (UINT j=0; j<128; j++)
579 {
580 UINT n = Headers[i]->Keyboard[j];
581 if ((n) && (n < MAX_INSTRUMENTS))
582 {
583 pins = &Ins[n];
584 break;
585 }
586 }
587 }
588 }
589 memcpy(insex[i-1].dosname, pins->name, 12);
590 memcpy(insex[i-1].name, m_szNames[i], 28);
591 memcpy(insex[i-1].scrs, "SCRS", 4);
592 insex[i-1].hmem = (BYTE)((DWORD)ofs >> 20);
593 insex[i-1].memseg = (WORD)((DWORD)ofs >> 4);
594 if (pins->pSample)
595 {
596 insex[i-1].type = 1;
597 insex[i-1].length = pins->nLength;
598 insex[i-1].loopbegin = pins->nLoopStart;
599 insex[i-1].loopend = pins->nLoopEnd;
600 insex[i-1].vol = pins->nVolume / 4;
601 insex[i-1].flags = (pins->uFlags & CHN_LOOP) ? 1 : 0;
602 if (pins->nC4Speed)
603 insex[i-1].finetune = pins->nC4Speed;
604 else
605 insex[i-1].finetune = TransposeToFrequency(pins->RelativeTone, pins->nFineTune);
606 UINT flags = RS_PCM8U;
607#ifndef NO_PACKING
608 if (nPacking)
609 {
610 if ((!(pins->uFlags & (CHN_16BIT|CHN_STEREO)))
611 && (CanPackSample(pins->pSample, pins->nLength, nPacking)))
612 {
613 insex[i-1].pack = 4;
614 flags = RS_ADPCM4;
615 }
616 } else
617#endif // NO_PACKING
618 {
619 if (pins->uFlags & CHN_16BIT)
620 {
621 insex[i-1].flags |= 4;
622 flags = RS_PCM16U;
623 }
624 if (pins->uFlags & CHN_STEREO)
625 {
626 insex[i-1].flags |= 2;
627 flags = (pins->uFlags & CHN_16BIT) ? RS_STPCM16U : RS_STPCM8U;
628 }
629 }
630 DWORD len = WriteSample(f, pins, flags);
631 if (len & 0x0F)
632 {
633 fwrite(S3MFiller, 0x10 - (len & 0x0F), 1, f);
634 }
635 ofs += (len + 15) & (~0x0F);
636 } else
637 {
638 insex[i-1].length = 0;
639 }
640 }
641 // Updating parapointers
642 fseek(f, ofs0, SEEK_SET);
643 fwrite(insptr, nbi, 2, f);
644 fwrite(patptr, nbp, 2, f);
645 fseek(f, ofs1, SEEK_SET);
646 fwrite(insex, 0x50, nbi, f);
647 fclose(f);
648 return TRUE;
649}
650
651#pragma warning(default:4100)
652#endif // MODPLUG_NO_FILESAVE
653
diff --git a/core/multimedia/opieplayer/modplug/load_stm.cpp b/core/multimedia/opieplayer/modplug/load_stm.cpp
new file mode 100644
index 0000000..3f79c27
--- a/dev/null
+++ b/core/multimedia/opieplayer/modplug/load_stm.cpp
@@ -0,0 +1,189 @@
1/*
2 * This program is free software; you can redistribute it and modify it
3 * under the terms of the GNU General Public License as published by the
4 * Free Software Foundation; either version 2 of the license or (at your
5 * option) any later version.
6 *
7 * Authors: Olivier Lapicque <olivierl@jps.net>
8*/
9
10#include "stdafx.h"
11#include "sndfile.h"
12
13//#pragma warning(disable:4244)
14
15#pragma pack(1)
16
17typedef struct tagSTMNOTE
18{
19 BYTE note;
20 BYTE insvol;
21 BYTE volcmd;
22 BYTE cmdinf;
23} Q_PACKED STMNOTE;
24
25
26// Raw STM sampleinfo struct:
27typedef struct tagSTMSAMPLE
28{
29 CHAR filename[14];// Can't have long comments - just filename comments :)
30 WORD reserved; // ISA in memory when in ST 2
31 WORD length; // Sample length
32 WORD loopbeg; // Loop start point
33 WORD loopend; // Loop end point
34 BYTE volume; // Volume
35 BYTE reserved2; // More reserved crap
36 WORD c2spd; // Good old c2spd
37 BYTE reserved3[6];// Yet more of PSi's reserved crap
38} Q_PACKED STMSAMPLE;
39
40
41// Raw STM header struct:
42typedef struct tagSTMHEADER
43{
44 char songname[20]; // changed from CHAR
45 char trackername[8];// !SCREAM! for ST 2.xx // changed from CHAR
46 CHAR unused; // 0x1A
47 CHAR filetype; // 1=song, 2=module (only 2 is supported, of course) :)
48 CHAR ver_major; // Like 2
49 CHAR ver_minor; // "ditto"
50 BYTE inittempo; // initspeed= stm inittempo>>4
51 BYTE numpat; // number of patterns
52 BYTE globalvol; // <- WoW! a RiGHT TRiANGLE =8*)
53 BYTE reserved[13]; // More of PSi's internal crap
54 STMSAMPLE sample[31];// STM sample data
55 BYTE patorder[128]; // Docs say 64 - actually 128
56} Q_PACKED STMHEADER;
57
58#pragma pack()
59
60
61
62BOOL CSoundFile::ReadSTM(const BYTE *lpStream, DWORD dwMemLength)
63//---------------------------------------------------------------
64{
65 STMHEADER *phdr = (STMHEADER *)lpStream;
66 DWORD dwMemPos = 0;
67
68 if ((!lpStream) || (dwMemLength < sizeof(STMHEADER))) return FALSE;
69 if ((phdr->filetype != 2) || (phdr->unused != 0x1A)
70 || ((strnicmp(phdr->trackername, "!SCREAM!", 8))
71 && (strnicmp(phdr->trackername, "BMOD2STM", 8)))) return FALSE;
72 memcpy(m_szNames[0], phdr->songname, 20);
73 // Read STM header
74 m_nType = MOD_TYPE_STM;
75 m_nSamples = 31;
76 m_nChannels = 4;
77 m_nInstruments = 0;
78 m_nMinPeriod = 64;
79 m_nMaxPeriod = 0x7FFF;
80 m_nDefaultSpeed = phdr->inittempo >> 4;
81 if (m_nDefaultSpeed < 1) m_nDefaultSpeed = 1;
82 m_nDefaultTempo = 125;
83 m_nDefaultGlobalVolume = phdr->globalvol << 2;
84 if (m_nDefaultGlobalVolume > 256) m_nDefaultGlobalVolume = 256;
85 memcpy(Order, phdr->patorder, 128);
86 // Setting up channels
87 for (UINT nSet=0; nSet<4; nSet++)
88 {
89 ChnSettings[nSet].dwFlags = 0;
90 ChnSettings[nSet].nVolume = 64;
91 ChnSettings[nSet].nPan = (nSet & 1) ? 0x40 : 0xC0;
92 }
93 // Reading samples
94 for (UINT nIns=0; nIns<31; nIns++)
95 {
96 MODINSTRUMENT *pIns = &Ins[nIns+1];
97 STMSAMPLE *pStm = &phdr->sample[nIns]; // STM sample data
98 memcpy(pIns->name, pStm->filename, 13);
99 memcpy(m_szNames[nIns+1], pStm->filename, 12);
100 pIns->nC4Speed = pStm->c2spd;
101 pIns->nGlobalVol = 64;
102 pIns->nVolume = pStm->volume << 2;
103 if (pIns->nVolume > 256) pIns->nVolume = 256;
104 pIns->nLength = pStm->length;
105 if ((pIns->nLength < 4) || (!pIns->nVolume)) pIns->nLength = 0;
106 pIns->nLoopStart = pStm->loopbeg;
107 pIns->nLoopEnd = pStm->loopend;
108 if ((pIns->nLoopEnd > pIns->nLoopStart) && (pIns->nLoopEnd != 0xFFFF)) pIns->uFlags |= CHN_LOOP;
109 }
110 dwMemPos = sizeof(STMHEADER);
111 for (UINT nOrd=0; nOrd<MAX_ORDERS; nOrd++) if (Order[nOrd] >= 99) Order[nOrd] = 0xFF;
112 UINT nPatterns = phdr->numpat;
113 for (UINT nPat=0; nPat<nPatterns; nPat++)
114 {
115 if (dwMemPos + 64*4*4 > dwMemLength) return TRUE;
116 PatternSize[nPat] = 64;
117 if ((Patterns[nPat] = AllocatePattern(64, m_nChannels)) == NULL) return TRUE;
118 MODCOMMAND *m = Patterns[nPat];
119 STMNOTE *p = (STMNOTE *)(lpStream + dwMemPos);
120 for (UINT n=0; n<64*4; n++, p++, m++)
121 {
122 UINT note,ins,vol,cmd;
123 // extract the various information from the 4 bytes that
124 // make up a single note
125 note = p->note;
126 ins = p->insvol >> 3;
127 vol = (p->insvol & 0x07) + (p->volcmd >> 1);
128 cmd = p->volcmd & 0x0F;
129 if ((ins) && (ins < 32)) m->instr = ins;
130 // special values of [SBYTE0] are handled here ->
131 // we have no idea if these strange values will ever be encountered
132 // but it appears as though stms sound correct.
133 if ((note == 0xFE) || (note == 0xFC)) m->note = 0xFE; else
134 // if note < 251, then all three bytes are stored in the file
135 if (note < 0xFC) m->note = (note >> 4)*12 + (note&0xf) + 37;
136 if (vol <= 64) { m->volcmd = VOLCMD_VOLUME; m->vol = vol; }
137 m->param = p->cmdinf;
138 switch(cmd)
139 {
140 // Axx set speed to xx
141 case 1:m->command = CMD_SPEED; m->param >>= 4; break;
142 // Bxx position jump
143 case 2:m->command = CMD_POSITIONJUMP; break;
144 // Cxx patternbreak to row xx
145 case 3: m->command = CMD_PATTERNBREAK; m->param = (m->param & 0xF0) * 10 + (m->param & 0x0F);break;
146 // Dxy volumeslide
147 case 4:m->command = CMD_VOLUMESLIDE; break;
148 // Exy toneslide down
149 case 5:m->command = CMD_PORTAMENTODOWN; break;
150 // Fxy toneslide up
151 case 6:m->command = CMD_PORTAMENTOUP; break;
152 // Gxx Tone portamento,speed xx
153 case 7:m->command = CMD_TONEPORTAMENTO; break;
154 // Hxy vibrato
155 case 8:m->command = CMD_VIBRATO; break;
156 // Ixy tremor, ontime x, offtime y
157 case 9:m->command = CMD_TREMOR; break;
158 // Jxy arpeggio
159 case 10: m->command = CMD_ARPEGGIO; break;
160 // Kxy Dual command H00 & Dxy
161 case 11: m->command = CMD_VIBRATOVOL; break;
162 // Lxy Dual command G00 & Dxy
163 case 12: m->command = CMD_TONEPORTAVOL; break;
164 // Xxx amiga command 8xx
165 case 0x18:m->command = CMD_PANNING8; break;
166 default:
167 m->command = m->param = 0;
168 }
169 }
170 dwMemPos += 64*4*4;
171 }
172 // Reading Samples
173 for (UINT nSmp=1; nSmp<=31; nSmp++)
174 {
175 MODINSTRUMENT *pIns = &Ins[nSmp];
176 dwMemPos = (dwMemPos + 15) & (~15);
177 if (pIns->nLength)
178 {
179 UINT nPos = ((UINT)phdr->sample[nSmp-1].reserved) << 4;
180 if ((nPos >= sizeof(STMHEADER)) && (nPos+pIns->nLength <= dwMemLength)) dwMemPos = nPos;
181 if (dwMemPos < dwMemLength)
182 {
183 dwMemPos += ReadSample(pIns, RS_PCM8S, (LPSTR)(lpStream+dwMemPos),dwMemLength-dwMemPos);
184 }
185 }
186 }
187 return TRUE;
188}
189
diff --git a/core/multimedia/opieplayer/modplug/load_ult.cpp b/core/multimedia/opieplayer/modplug/load_ult.cpp
new file mode 100644
index 0000000..c9b7118
--- a/dev/null
+++ b/core/multimedia/opieplayer/modplug/load_ult.cpp
@@ -0,0 +1,225 @@
1/*
2 * This program is free software; you can redistribute it and modify it
3 * under the terms of the GNU General Public License as published by the
4 * Free Software Foundation; either version 2 of the license or (at your
5 * option) any later version.
6 *
7 * Authors: Olivier Lapicque <olivierl@jps.net>
8*/
9
10#include "stdafx.h"
11#include "sndfile.h"
12
13//#pragma warning(disable:4244)
14
15#define ULT_16BIT 0x04
16#define ULT_LOOP 0x08
17#define ULT_BIDI 0x10
18
19#pragma pack(1)
20
21// Raw ULT header struct:
22typedef struct tagULTHEADER
23{
24 char id[15]; // changed from CHAR
25 char songtitle[32]; // changed from CHAR
26 BYTE reserved;
27} Q_PACKED ULTHEADER;
28
29
30// Raw ULT sampleinfo struct:
31typedef struct tagULTSAMPLE
32{
33 CHAR samplename[32];
34 CHAR dosname[12];
35 LONG loopstart;
36 LONG loopend;
37 LONG sizestart;
38 LONG sizeend;
39 BYTE volume;
40 BYTE flags;
41 WORD finetune;
42} Q_PACKED ULTSAMPLE;
43
44#pragma pack()
45
46
47BOOL CSoundFile::ReadUlt(const BYTE *lpStream, DWORD dwMemLength)
48//---------------------------------------------------------------
49{
50 ULTHEADER *pmh = (ULTHEADER *)lpStream;
51 ULTSAMPLE *pus;
52 UINT nos, nop;
53 DWORD dwMemPos = 0;
54
55 // try to read module header
56 if ((!lpStream) || (dwMemLength < 0x100)) return FALSE;
57 if (strncmp(pmh->id,"MAS_UTrack_V00",14)) return FALSE;
58 // Warning! Not supported ULT format, trying anyway
59 // if ((pmh->id[14] < '1') || (pmh->id[14] > '4')) return FALSE;
60 m_nType = MOD_TYPE_ULT;
61 m_nDefaultSpeed = 6;
62 m_nDefaultTempo = 125;
63 memcpy(m_szNames[0], pmh->songtitle, 32);
64 // read songtext
65 dwMemPos = sizeof(ULTHEADER);
66 if ((pmh->reserved) && (dwMemPos + pmh->reserved * 32 < dwMemLength))
67 {
68 UINT len = pmh->reserved * 32;
69 m_lpszSongComments = new char[len + 1 + pmh->reserved];
70 if (m_lpszSongComments)
71 {
72 for (UINT l=0; l<pmh->reserved; l++)
73 {
74 memcpy(m_lpszSongComments+l*33, lpStream+dwMemPos+l*32, 32);
75 m_lpszSongComments[l*33+32] = 0x0D;
76 }
77 m_lpszSongComments[len] = 0;
78 }
79 dwMemPos += len;
80 }
81 if (dwMemPos >= dwMemLength) return TRUE;
82 nos = lpStream[dwMemPos++];
83 m_nSamples = nos;
84 if (m_nSamples >= MAX_SAMPLES) m_nSamples = MAX_SAMPLES-1;
85 UINT smpsize = 64;
86 if (pmh->id[14] >= '4')smpsize += 2;
87 if (dwMemPos + nos*smpsize + 256 + 2 > dwMemLength) return TRUE;
88 for (UINT ins=1; ins<=nos; ins++, dwMemPos+=smpsize) if (ins<=m_nSamples)
89 {
90 pus= (ULTSAMPLE *)(lpStream+dwMemPos);
91 MODINSTRUMENT *pins = &Ins[ins];
92 memcpy(m_szNames[ins], pus->samplename, 32);
93 memcpy(pins->name, pus->dosname, 12);
94 pins->nLoopStart = pus->loopstart;
95 pins->nLoopEnd = pus->loopend;
96 pins->nLength = pus->sizeend - pus->sizestart;
97 pins->nVolume = pus->volume;
98 pins->nGlobalVol = 64;
99 pins->nC4Speed = 8363;
100 if (pmh->id[14] >= '4')
101 {
102 pins->nC4Speed = pus->finetune;
103 }
104 if (pus->flags & ULT_LOOP) pins->uFlags |= CHN_LOOP;
105 if (pus->flags & ULT_BIDI) pins->uFlags |= CHN_PINGPONGLOOP;
106 if (pus->flags & ULT_16BIT)
107 {
108 pins->uFlags |= CHN_16BIT;
109 pins->nLoopStart >>= 1;
110 pins->nLoopEnd >>= 1;
111 }
112 }
113 memcpy(Order, lpStream+dwMemPos, 256);
114 dwMemPos += 256;
115 m_nChannels = lpStream[dwMemPos] + 1;
116 nop = lpStream[dwMemPos+1] + 1;
117 dwMemPos += 2;
118 if (m_nChannels > 32) m_nChannels = 32;
119 // Default channel settings
120 for (UINT nSet=0; nSet<m_nChannels; nSet++)
121 {
122 ChnSettings[nSet].nVolume = 64;
123 ChnSettings[nSet].nPan = (nSet & 1) ? 0x40 : 0xC0;
124 }
125 // read pan position table for v1.5 and higher
126 if(pmh->id[14]>='3')
127 {
128 if (dwMemPos + m_nChannels > dwMemLength) return TRUE;
129 for(UINT t=0; t<m_nChannels; t++)
130 {
131 ChnSettings[t].nPan = (lpStream[dwMemPos++] << 4) + 8;
132 if (ChnSettings[t].nPan > 256) ChnSettings[t].nPan = 256;
133 }
134 }
135 // Allocating Patterns
136 for (UINT nAllocPat=0; nAllocPat<nop; nAllocPat++)
137 {
138 if (nAllocPat < MAX_PATTERNS)
139 {
140 PatternSize[nAllocPat] = 64;
141 Patterns[nAllocPat] = AllocatePattern(64, m_nChannels);
142 }
143 }
144 // Reading Patterns
145 for (UINT nChn=0; nChn<m_nChannels; nChn++)
146 {
147 for (UINT nPat=0; nPat<nop; nPat++)
148 {
149 MODCOMMAND *pat = NULL;
150
151 if (nPat < MAX_PATTERNS)
152 {
153 pat = Patterns[nPat];
154 if (pat) pat += nChn;
155 }
156 UINT row = 0;
157 while (row < 64)
158 {
159 if (dwMemPos + 6 > dwMemLength) return TRUE;
160 UINT rep = 1;
161 UINT note = lpStream[dwMemPos++];
162 if (note == 0xFC)
163 {
164 rep = lpStream[dwMemPos];
165 note = lpStream[dwMemPos+1];
166 dwMemPos += 2;
167 }
168 UINT instr = lpStream[dwMemPos++];
169 UINT eff = lpStream[dwMemPos++];
170 UINT dat1 = lpStream[dwMemPos++];
171 UINT dat2 = lpStream[dwMemPos++];
172 UINT cmd1 = eff & 0x0F;
173 UINT cmd2 = eff >> 4;
174 if (cmd1 == 0x0C) dat1 >>= 2; else
175 if (cmd1 == 0x0B) { cmd1 = dat1 = 0; }
176 if (cmd2 == 0x0C) dat2 >>= 2; else
177 if (cmd2 == 0x0B) { cmd2 = dat2 = 0; }
178 while ((rep != 0) && (row < 64))
179 {
180 if (pat)
181 {
182 pat->instr = instr;
183 if (note) pat->note = note + 36;
184 if (cmd1 | dat1)
185 {
186 if (cmd1 == 0x0C)
187 {
188 pat->volcmd = VOLCMD_VOLUME;
189 pat->vol = dat1;
190 } else
191 {
192 pat->command = cmd1;
193 pat->param = dat1;
194 ConvertModCommand(pat);
195 }
196 }
197 if (cmd2 == 0x0C)
198 {
199 pat->volcmd = VOLCMD_VOLUME;
200 pat->vol = dat2;
201 } else
202 if ((cmd2 | dat2) && (!pat->command))
203 {
204 pat->command = cmd2;
205 pat->param = dat2;
206 ConvertModCommand(pat);
207 }
208 pat += m_nChannels;
209 }
210 row++;
211 rep--;
212 }
213 }
214 }
215 }
216 // Reading Instruments
217 for (UINT smp=1; smp<=m_nSamples; smp++) if (Ins[smp].nLength)
218 {
219 if (dwMemPos >= dwMemLength) return TRUE;
220 UINT flags = (Ins[smp].uFlags & CHN_16BIT) ? RS_PCM16S : RS_PCM8S;
221 dwMemPos += ReadSample(&Ins[smp], flags, (LPSTR)(lpStream+dwMemPos), dwMemLength - dwMemPos);
222 }
223 return TRUE;
224}
225
diff --git a/core/multimedia/opieplayer/modplug/load_umx.cpp b/core/multimedia/opieplayer/modplug/load_umx.cpp
new file mode 100644
index 0000000..4c54fcf
--- a/dev/null
+++ b/core/multimedia/opieplayer/modplug/load_umx.cpp
@@ -0,0 +1,56 @@
1/*
2 * This program is free software; you can redistribute it and modify it
3 * under the terms of the GNU General Public License as published by the
4 * Free Software Foundation; either version 2 of the license or (at your
5 * option) any later version.
6 *
7 * Authors: Olivier Lapicque <olivierl@jps.net>
8*/
9
10#include "stdafx.h"
11#include "sndfile.h"
12
13 #define MODMAGIC_OFFSET(20+31*30+130)
14
15
16BOOL CSoundFile::ReadUMX(const BYTE *lpStream, DWORD dwMemLength)
17//---------------------------------------------------------------
18{
19 if ((!lpStream) || (dwMemLength < 0x800)) return FALSE;
20 // Rip Mods from UMX
21 if ((bswapLE32(*((DWORD *)(lpStream+0x20))) < dwMemLength)
22 && (bswapLE32(*((DWORD *)(lpStream+0x18))) <= dwMemLength - 0x10)
23 && (bswapLE32(*((DWORD *)(lpStream+0x18))) >= dwMemLength - 0x200))
24 {
25 for (UINT uscan=0x40; uscan<0x500; uscan++)
26 {
27 DWORD dwScan = bswapLE32(*((DWORD *)(lpStream+uscan)));
28 // IT
29 if (dwScan == 0x4D504D49)
30 {
31 DWORD dwRipOfs = uscan;
32 return ReadIT(lpStream + dwRipOfs, dwMemLength - dwRipOfs);
33 }
34 // S3M
35 if (dwScan == 0x4D524353)
36 {
37 DWORD dwRipOfs = uscan - 44;
38 return ReadS3M(lpStream + dwRipOfs, dwMemLength - dwRipOfs);
39 }
40 // XM
41 if (!strnicmp((LPCSTR)(lpStream+uscan), "Extended Module", 15))
42 {
43 DWORD dwRipOfs = uscan;
44 return ReadXM(lpStream + dwRipOfs, dwMemLength - dwRipOfs);
45 }
46 // MOD
47 if ((uscan > MODMAGIC_OFFSET) && (dwScan == 0x2e4b2e4d))
48 {
49 DWORD dwRipOfs = uscan - MODMAGIC_OFFSET;
50 return ReadMod(lpStream+dwRipOfs, dwMemLength-dwRipOfs);
51 }
52 }
53 }
54 return FALSE;
55}
56
diff --git a/core/multimedia/opieplayer/modplug/load_wav.cpp b/core/multimedia/opieplayer/modplug/load_wav.cpp
new file mode 100644
index 0000000..f445273
--- a/dev/null
+++ b/core/multimedia/opieplayer/modplug/load_wav.cpp
@@ -0,0 +1,223 @@
1/*
2 * This program is free software; you can redistribute it and modify it
3 * under the terms of the GNU General Public License as published by the
4 * Free Software Foundation; either version 2 of the license or (at your
5 * option) any later version.
6 *
7 * Authors: Olivier Lapicque <olivierl@jps.net>
8*/
9
10#include "stdafx.h"
11#include "sndfile.h"
12
13#ifndef WAVE_FORMAT_EXTENSIBLE
14 #define WAVE_FORMAT_EXTENSIBLE0xFFFE
15#endif
16
17/////////////////////////////////////////////////////////////
18// WAV file support
19
20BOOL CSoundFile::ReadWav(const BYTE *lpStream, DWORD dwMemLength)
21//---------------------------------------------------------------
22{
23 DWORD dwMemPos = 0;
24 WAVEFILEHEADER *phdr = (WAVEFILEHEADER *)lpStream;
25 WAVEFORMATHEADER *pfmt = (WAVEFORMATHEADER *)(lpStream + sizeof(WAVEFILEHEADER));
26 if ((!lpStream) || (dwMemLength < (DWORD)sizeof(WAVEFILEHEADER))) return FALSE;
27 if ((phdr->id_RIFF != IFFID_RIFF) || (phdr->id_WAVE != IFFID_WAVE)
28 || (pfmt->id_fmt != IFFID_fmt)) return FALSE;
29 dwMemPos = sizeof(WAVEFILEHEADER) + 8 + pfmt->hdrlen;
30 if ((dwMemPos + 8 >= dwMemLength)
31 || ((pfmt->format != WAVE_FORMAT_PCM) && (pfmt->format != WAVE_FORMAT_EXTENSIBLE))
32 || (pfmt->channels > 4)
33 || (!pfmt->channels)
34 || (!pfmt->freqHz)
35 || (pfmt->bitspersample & 7)
36 || (pfmt->bitspersample < 8)
37 || (pfmt->bitspersample > 32)) return FALSE;
38 WAVEDATAHEADER *pdata;
39 for (;;)
40 {
41 pdata = (WAVEDATAHEADER *)(lpStream + dwMemPos);
42 if (pdata->id_data == IFFID_data) break;
43 dwMemPos += pdata->length + 8;
44 if (dwMemPos + 8 >= dwMemLength) return FALSE;
45 }
46 m_nType = MOD_TYPE_WAV;
47 m_nSamples = 0;
48 m_nInstruments = 0;
49 m_nChannels = 4;
50 m_nDefaultSpeed = 8;
51 m_nDefaultTempo = 125;
52 m_dwSongFlags |= SONG_LINEARSLIDES; // For no resampling
53 Order[0] = 0;
54 Order[1] = 0xFF;
55 PatternSize[0] = PatternSize[1] = 64;
56 if ((Patterns[0] = AllocatePattern(64, 4)) == NULL) return TRUE;
57 if ((Patterns[1] = AllocatePattern(64, 4)) == NULL) return TRUE;
58 UINT samplesize = (pfmt->channels * pfmt->bitspersample) >> 3;
59 UINT len = pdata->length, bytelen;
60 if (dwMemPos + len > dwMemLength - 8) len = dwMemLength - dwMemPos - 8;
61 len /= samplesize;
62 bytelen = len;
63 if (pfmt->bitspersample >= 16) bytelen *= 2;
64 if (len > MAX_SAMPLE_LENGTH) len = MAX_SAMPLE_LENGTH;
65 if (!len) return TRUE;
66 // Setting up module length
67 DWORD dwTime = ((len * 50) / pfmt->freqHz) + 1;
68 DWORD framesperrow = (dwTime + 63) / 63;
69 if (framesperrow < 4) framesperrow = 4;
70 UINT norders = 1;
71 while (framesperrow >= 0x20)
72 {
73 Order[norders++] = 1;
74 Order[norders] = 0xFF;
75 framesperrow = (dwTime + (64 * norders - 1)) / (64 * norders);
76 if (norders >= MAX_ORDERS-1) break;
77 }
78 m_nDefaultSpeed = framesperrow;
79 for (UINT iChn=0; iChn<4; iChn++)
80 {
81 ChnSettings[iChn].nPan = (iChn & 1) ? 256 : 0;
82 ChnSettings[iChn].nVolume = 64;
83 ChnSettings[iChn].dwFlags = 0;
84 }
85 // Setting up speed command
86 MODCOMMAND *pcmd = Patterns[0];
87 pcmd[0].command = CMD_SPEED;
88 pcmd[0].param = (BYTE)m_nDefaultSpeed;
89 pcmd[0].note = 5*12+1;
90 pcmd[0].instr = 1;
91 pcmd[1].note = pcmd[0].note;
92 pcmd[1].instr = pcmd[0].instr;
93 m_nSamples = pfmt->channels;
94 // Support for Multichannel Wave
95 for (UINT nChn=0; nChn<m_nSamples; nChn++)
96 {
97 MODINSTRUMENT *pins = &Ins[nChn+1];
98 pcmd[nChn].note = pcmd[0].note;
99 pcmd[nChn].instr = (BYTE)(nChn+1);
100 pins->nLength = len;
101 pins->nC4Speed = pfmt->freqHz;
102 pins->nVolume = 256;
103 pins->nPan = 128;
104 pins->nGlobalVol = 64;
105 pins->uFlags = (WORD)((pfmt->bitspersample >= 16) ? CHN_16BIT : 0);
106 pins->uFlags |= CHN_PANNING;
107 if (m_nSamples > 1)
108 {
109 switch(nChn)
110 {
111 case 0:pins->nPan = 0; break;
112 case 1:pins->nPan = 256; break;
113 case 2: pins->nPan = (WORD)((m_nSamples == 3) ? 128 : 64); pcmd[nChn].command = CMD_S3MCMDEX; pcmd[nChn].param = 0x91; break;
114 case 3: pins->nPan = 192; pcmd[nChn].command = CMD_S3MCMDEX; pcmd[nChn].param = 0x91; break;
115 default: pins->nPan = 128; break;
116 }
117 }
118 if ((pins->pSample = AllocateSample(bytelen+8)) == NULL) return TRUE;
119 if (pfmt->bitspersample >= 16)
120 {
121 int slsize = pfmt->bitspersample >> 3;
122 signed short *p = (signed short *)pins->pSample;
123 signed char *psrc = (signed char *)(lpStream+dwMemPos+8+nChn*slsize+slsize-2);
124 for (UINT i=0; i<len; i++)
125 {
126 p[i] = *((signed short *)psrc);
127 psrc += samplesize;
128 }
129 p[len+1] = p[len] = p[len-1];
130 } else
131 {
132 signed char *p = (signed char *)pins->pSample;
133 signed char *psrc = (signed char *)(lpStream+dwMemPos+8+nChn);
134 for (UINT i=0; i<len; i++)
135 {
136 p[i] = (signed char)((*psrc) + 0x80);
137 psrc += samplesize;
138 }
139 p[len+1] = p[len] = p[len-1];
140 }
141 }
142 return TRUE;
143}
144
145
146////////////////////////////////////////////////////////////////////////
147// IMA ADPCM Support
148
149#pragma pack(1)
150
151typedef struct IMAADPCMBLOCK
152{
153 WORD sample;
154 BYTE index;
155 BYTE Reserved;
156} Q_PACKED DVI_ADPCMBLOCKHEADER;
157
158#pragma pack()
159
160static const int gIMAUnpackTable[90] =
161{
162 7, 8, 9, 10, 11, 12, 13, 14,
163 16, 17, 19, 21, 23, 25, 28, 31,
164 34, 37, 41, 45, 50, 55, 60, 66,
165 73, 80, 88, 97, 107, 118, 130, 143,
166 157, 173, 190, 209, 230, 253, 279, 307,
167 337, 371, 408, 449, 494, 544, 598, 658,
168 724, 796, 876, 963, 1060, 1166, 1282, 1411,
169 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024,
170 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484,
171 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
172 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794,
173 32767, 0
174};
175
176
177BOOL IMAADPCMUnpack16(signed short *pdest, UINT nLen, LPBYTE psrc, DWORD dwBytes, UINT pkBlkAlign)
178//------------------------------------------------------------------------------------------------
179{
180 static const int gIMAIndexTab[8] = { -1, -1, -1, -1, 2, 4, 6, 8 };
181 UINT nPos;
182 int value;
183
184 if ((nLen < 4) || (!pdest) || (!psrc)
185 || (pkBlkAlign < 5) || (pkBlkAlign > dwBytes)) return FALSE;
186 nPos = 0;
187 while ((nPos < nLen) && (dwBytes > 4))
188 {
189 int nIndex;
190 value = *((short int *)psrc);
191 nIndex = psrc[2];
192 psrc += 4;
193 dwBytes -= 4;
194 pdest[nPos++] = (short int)value;
195 for (UINT i=0; ((i<(pkBlkAlign-4)*2) && (nPos < nLen) && (dwBytes)); i++)
196 {
197 BYTE delta;
198 if (i & 1)
199 {
200 delta = (BYTE)(((*(psrc++)) >> 4) & 0x0F);
201 dwBytes--;
202 } else
203 {
204 delta = (BYTE)((*psrc) & 0x0F);
205 }
206 int v = gIMAUnpackTable[nIndex] >> 3;
207 if (delta & 1) v += gIMAUnpackTable[nIndex] >> 2;
208 if (delta & 2) v += gIMAUnpackTable[nIndex] >> 1;
209 if (delta & 4) v += gIMAUnpackTable[nIndex];
210 if (delta & 8) value -= v; else value += v;
211 nIndex += gIMAIndexTab[delta & 7];
212 if (nIndex < 0) nIndex = 0; else
213 if (nIndex > 88) nIndex = 88;
214 if (value > 32767) value = 32767; else
215 if (value < -32768) value = -32768;
216 pdest[nPos++] = (short int)value;
217 }
218 }
219 return TRUE;
220}
221
222
223
diff --git a/core/multimedia/opieplayer/modplug/load_xm.cpp b/core/multimedia/opieplayer/modplug/load_xm.cpp
new file mode 100644
index 0000000..171e5f6
--- a/dev/null
+++ b/core/multimedia/opieplayer/modplug/load_xm.cpp
@@ -0,0 +1,912 @@
1/*
2 * This program is free software; you can redistribute it and modify it
3 * under the terms of the GNU General Public License as published by the
4 * Free Software Foundation; either version 2 of the license or (at your
5 * option) any later version.
6 *
7 * Authors: Olivier Lapicque <olivierl@jps.net>,
8 * Adam Goode <adam@evdebs.org> (endian and char fixes for PPC)
9*/
10
11#include "stdafx.h"
12#include "sndfile.h"
13
14////////////////////////////////////////////////////////
15// FastTracker II XM file support
16
17#ifdef WIN32
18#pragma warning(disable:4244)
19#endif
20
21#pragma pack(1)
22typedef struct tagXMFILEHEADER
23{
24 DWORD size;
25 WORD norder;
26 WORD restartpos;
27 WORD channels;
28 WORD patterns;
29 WORD instruments;
30 WORD flags;
31 WORD speed;
32 WORD tempo;
33 BYTE order[256];
34} Q_PACKED XMFILEHEADER;
35
36
37typedef struct tagXMINSTRUMENTHEADER
38{
39 DWORD size;
40 CHAR name[22];
41 BYTE type;
42 BYTE samples;
43 BYTE samplesh;
44} Q_PACKED XMINSTRUMENTHEADER;
45
46
47typedef struct tagXMSAMPLEHEADER
48{
49 DWORD shsize;
50 BYTE snum[96];
51 WORD venv[24];
52 WORD penv[24];
53 BYTE vnum, pnum;
54 BYTE vsustain, vloops, vloope, psustain, ploops, ploope;
55 BYTE vtype, ptype;
56 BYTE vibtype, vibsweep, vibdepth, vibrate;
57 WORD volfade;
58 WORD res;
59 BYTE reserved1[20];
60} Q_PACKED XMSAMPLEHEADER;
61
62typedef struct tagXMSAMPLESTRUCT
63{
64 DWORD samplen;
65 DWORD loopstart;
66 DWORD looplen;
67 BYTE vol;
68 signed char finetune;
69 BYTE type;
70 BYTE pan;
71 signed char relnote;
72 BYTE res;
73 char name[22];
74} Q_PACKED XMSAMPLESTRUCT;
75
76typedef struct tagXMPATTERNHEADER
77{
78 DWORD size;
79 BYTE packing;
80 WORD rows;
81 WORD packsize;
82} Q_PACKED XMPATTERNHEADER;
83
84#pragma pack()
85
86
87BOOL CSoundFile::ReadXM(const BYTE *lpStream, DWORD dwMemLength)
88//--------------------------------------------------------------
89{
90 XMSAMPLEHEADER xmsh;
91 XMSAMPLESTRUCT xmss;
92 DWORD dwMemPos, dwHdrSize;
93 WORD norders=0, restartpos=0, channels=0, patterns=0, instruments=0;
94 WORD xmflags=0, deftempo=125, defspeed=6;
95 BOOL InstUsed[256];
96 BYTE channels_used[MAX_CHANNELS];
97 BYTE pattern_map[256];
98 BOOL samples_used[MAX_SAMPLES];
99 UINT unused_samples;
100
101 m_nChannels = 0;
102 if ((!lpStream) || (dwMemLength < 0x200)) return FALSE;
103 if (strnicmp((LPCSTR)lpStream, "Extended Module", 15)) return FALSE;
104
105 memcpy(m_szNames[0], lpStream+17, 20);
106 dwHdrSize = bswapLE32(*((DWORD *)(lpStream+60)));
107 norders = bswapLE16(*((WORD *)(lpStream+64)));
108 if ((!norders) || (norders > MAX_ORDERS)) return FALSE;
109 restartpos = bswapLE16(*((WORD *)(lpStream+66)));
110 channels = bswapLE16(*((WORD *)(lpStream+68)));
111 if ((!channels) || (channels > 64)) return FALSE;
112 m_nType = MOD_TYPE_XM;
113 m_nMinPeriod = 27;
114 m_nMaxPeriod = 54784;
115 m_nChannels = channels;
116 if (restartpos < norders) m_nRestartPos = restartpos;
117 patterns = bswapLE16(*((WORD *)(lpStream+70)));
118 if (patterns > 256) patterns = 256;
119 instruments = bswapLE16(*((WORD *)(lpStream+72)));
120 if (instruments >= MAX_INSTRUMENTS) instruments = MAX_INSTRUMENTS-1;
121 m_nInstruments = instruments;
122 m_nSamples = 0;
123 memcpy(&xmflags, lpStream+74, 2);
124 xmflags = bswapLE16(xmflags);
125 if (xmflags & 1) m_dwSongFlags |= SONG_LINEARSLIDES;
126 if (xmflags & 0x1000) m_dwSongFlags |= SONG_EXFILTERRANGE;
127 defspeed = bswapLE16(*((WORD *)(lpStream+76)));
128 deftempo = bswapLE16(*((WORD *)(lpStream+78)));
129 if ((deftempo >= 32) && (deftempo < 256)) m_nDefaultTempo = deftempo;
130 if ((defspeed > 0) && (defspeed < 40)) m_nDefaultSpeed = defspeed;
131 memcpy(Order, lpStream+80, norders);
132 memset(InstUsed, 0, sizeof(InstUsed));
133 if (patterns > MAX_PATTERNS)
134 {
135 UINT i, j;
136 for (i=0; i<norders; i++)
137 {
138 if (Order[i] < patterns) InstUsed[Order[i]] = TRUE;
139 }
140 j = 0;
141 for (i=0; i<256; i++)
142 {
143 if (InstUsed[i]) pattern_map[i] = j++;
144 }
145 for (i=0; i<256; i++)
146 {
147 if (!InstUsed[i])
148 {
149 pattern_map[i] = (j < MAX_PATTERNS) ? j : 0xFE;
150 j++;
151 }
152 }
153 for (i=0; i<norders; i++)
154 {
155 Order[i] = pattern_map[Order[i]];
156 }
157 } else
158 {
159 for (UINT i=0; i<256; i++) pattern_map[i] = i;
160 }
161 memset(InstUsed, 0, sizeof(InstUsed));
162 dwMemPos = dwHdrSize + 60;
163 if (dwMemPos + 8 >= dwMemLength) return TRUE;
164 // Reading patterns
165 memset(channels_used, 0, sizeof(channels_used));
166 for (UINT ipat=0; ipat<patterns; ipat++)
167 {
168 UINT ipatmap = pattern_map[ipat];
169 DWORD dwSize = 0;
170 WORD rows=64, packsize=0;
171 XMPATTERNHEADER *patternHeader = (XMPATTERNHEADER *)(lpStream+dwMemPos);
172 //dwSize = bswapLE32(*((DWORD *)(lpStream+dwMemPos)));
173 dwSize = bswapLE32(patternHeader->size);
174 /*
175 while ((dwMemPos + dwSize >= dwMemLength) || (dwSize & 0xFFFFFF00))
176 {
177 if (dwMemPos + 4 >= dwMemLength) break;
178 dwMemPos++;
179 dwSize = bswapLE32(*((DWORD *)(lpStream+dwMemPos)));
180 }
181 */
182 //rows = bswapLE16(*((WORD *)(lpStream+dwMemPos+5)));
183 rows = bswapLE16(patternHeader->rows);
184 if ((!rows) || (rows > 256)) rows = 64;
185 //packsize = bswapLE16(*((WORD *)(lpStream+dwMemPos+7)));
186 packsize = bswapLE16(patternHeader->packsize);
187 if (dwMemPos + dwSize + 4 > dwMemLength) return TRUE;
188 dwMemPos += dwSize;
189 if (dwMemPos + packsize + 4 > dwMemLength) return TRUE;
190 MODCOMMAND *p;
191 if (ipatmap < MAX_PATTERNS)
192 {
193 PatternSize[ipatmap] = rows;
194 if ((Patterns[ipatmap] = AllocatePattern(rows, m_nChannels)) == NULL) return TRUE;
195 if (!packsize) continue;
196 p = Patterns[ipatmap];
197 } else p = NULL;
198 const BYTE *src = lpStream+dwMemPos;
199 UINT j=0;
200 for (UINT row=0; row<rows; row++)
201 {
202 for (UINT chn=0; chn<m_nChannels; chn++)
203 {
204 if ((p) && (j < packsize))
205 {
206 BYTE b = src[j++];
207 UINT vol = 0;
208 if (b & 0x80)
209 {
210 if (b & 1) p->note = src[j++];
211 if (b & 2) p->instr = src[j++];
212 if (b & 4) vol = src[j++];
213 if (b & 8) p->command = src[j++];
214 if (b & 16) p->param = src[j++];
215 } else
216 {
217 p->note = b;
218 p->instr = src[j++];
219 vol = src[j++];
220 p->command = src[j++];
221 p->param = src[j++];
222 }
223 if (p->note == 97) p->note = 0xFF; else
224 if ((p->note) && (p->note < 97)) p->note += 12;
225 if (p->note) channels_used[chn] = 1;
226 if (p->command | p->param) ConvertModCommand(p);
227 if (p->instr == 0xff) p->instr = 0;
228 if (p->instr) InstUsed[p->instr] = TRUE;
229 if ((vol >= 0x10) && (vol <= 0x50))
230 {
231 p->volcmd = VOLCMD_VOLUME;
232 p->vol = vol - 0x10;
233 } else
234 if (vol >= 0x60)
235 {
236 UINT v = vol & 0xF0;
237 vol &= 0x0F;
238 p->vol = vol;
239 switch(v)
240 {
241 // 60-6F: Volume Slide Down
242 case 0x60:p->volcmd = VOLCMD_VOLSLIDEDOWN; break;
243 // 70-7F: Volume Slide Up:
244 case 0x70:p->volcmd = VOLCMD_VOLSLIDEUP; break;
245 // 80-8F: Fine Volume Slide Down
246 case 0x80:p->volcmd = VOLCMD_FINEVOLDOWN; break;
247 // 90-9F: Fine Volume Slide Up
248 case 0x90:p->volcmd = VOLCMD_FINEVOLUP; break;
249 // A0-AF: Set Vibrato Speed
250 case 0xA0:p->volcmd = VOLCMD_VIBRATOSPEED; break;
251 // B0-BF: Vibrato
252 case 0xB0:p->volcmd = VOLCMD_VIBRATO; break;
253 // C0-CF: Set Panning
254 case 0xC0:p->volcmd = VOLCMD_PANNING; p->vol = (vol << 2) + 2; break;
255 // D0-DF: Panning Slide Left
256 case 0xD0:p->volcmd = VOLCMD_PANSLIDELEFT; break;
257 // E0-EF: Panning Slide Right
258 case 0xE0:p->volcmd = VOLCMD_PANSLIDERIGHT; break;
259 // F0-FF: Tone Portamento
260 case 0xF0:p->volcmd = VOLCMD_TONEPORTAMENTO; break;
261 }
262 }
263 p++;
264 } else
265 if (j < packsize)
266 {
267 BYTE b = src[j++];
268 if (b & 0x80)
269 {
270 if (b & 1) j++;
271 if (b & 2) j++;
272 if (b & 4) j++;
273 if (b & 8) j++;
274 if (b & 16) j++;
275 } else j += 4;
276 } else break;
277 }
278 }
279 dwMemPos += packsize;
280 }
281 /*
282 // Wrong offset check
283 while (dwMemPos + 4 < dwMemLength)
284 {
285 DWORD d = bswapLE32(*((DWORD *)(lpStream+dwMemPos)));
286 if (d < 0x300) break;
287 dwMemPos++;
288 }
289 */
290 memset(samples_used, 0, sizeof(samples_used));
291 unused_samples = 0;
292 // Reading instruments
293 for (UINT iIns=1; iIns<=instruments; iIns++)
294 {
295 XMINSTRUMENTHEADER *pih;
296 BYTE flags[32];
297 DWORD samplesize[32];
298 UINT samplemap[32];
299 WORD nsamples;
300
301 if (dwMemPos + sizeof(XMINSTRUMENTHEADER) >= dwMemLength) return TRUE;
302 pih = (XMINSTRUMENTHEADER *)(lpStream+dwMemPos);
303 if (dwMemPos + bswapLE32(pih->size) > dwMemLength) return TRUE;
304 if ((Headers[iIns] = new INSTRUMENTHEADER) == NULL) continue;
305 memset(Headers[iIns], 0, sizeof(INSTRUMENTHEADER));
306 memcpy(Headers[iIns]->name, pih->name, 22);
307 if ((nsamples = pih->samples) > 0)
308 {
309 if (dwMemPos + sizeof(XMSAMPLEHEADER) > dwMemLength) return TRUE;
310 memcpy(&xmsh, lpStream+dwMemPos+sizeof(XMINSTRUMENTHEADER), sizeof(XMSAMPLEHEADER));
311 xmsh.shsize = bswapLE32(xmsh.shsize);
312 for (int i = 0; i < 24; ++i) {
313 xmsh.venv[i] = bswapLE16(xmsh.venv[i]);
314 xmsh.penv[i] = bswapLE16(xmsh.penv[i]);
315 }
316 xmsh.volfade = bswapLE16(xmsh.volfade);
317 xmsh.res = bswapLE16(xmsh.res);
318 dwMemPos += bswapLE32(pih->size);
319 } else
320 {
321 if (bswapLE32(pih->size)) dwMemPos += bswapLE32(pih->size);
322 else dwMemPos += sizeof(XMINSTRUMENTHEADER);
323 continue;
324 }
325 memset(samplemap, 0, sizeof(samplemap));
326 if (nsamples > 32) return TRUE;
327 UINT newsamples = m_nSamples;
328 for (UINT nmap=0; nmap<nsamples; nmap++)
329 {
330 UINT n = m_nSamples+nmap+1;
331 if (n >= MAX_SAMPLES)
332 {
333 n = m_nSamples;
334 while (n > 0)
335 {
336 if (!Ins[n].pSample)
337 {
338 for (UINT xmapchk=0; xmapchk < nmap; xmapchk++)
339 {
340 if (samplemap[xmapchk] == n) goto alreadymapped;
341 }
342 for (UINT clrs=1; clrs<iIns; clrs++) if (Headers[clrs])
343 {
344 INSTRUMENTHEADER *pks = Headers[clrs];
345 for (UINT ks=0; ks<128; ks++)
346 {
347 if (pks->Keyboard[ks] == n) pks->Keyboard[ks] = 0;
348 }
349 }
350 break;
351 }
352 alreadymapped:
353 n--;
354 }
355#ifndef FASTSOUNDLIB
356 // Damn! more than 200 samples: look for duplicates
357 if (!n)
358 {
359 if (!unused_samples)
360 {
361 unused_samples = DetectUnusedSamples(samples_used);
362 if (!unused_samples) unused_samples = 0xFFFF;
363 }
364 if ((unused_samples) && (unused_samples != 0xFFFF))
365 {
366 for (UINT iext=m_nSamples; iext>=1; iext--) if (!samples_used[iext])
367 {
368 unused_samples--;
369 samples_used[iext] = TRUE;
370 DestroySample(iext);
371 n = iext;
372 for (UINT mapchk=0; mapchk<nmap; mapchk++)
373 {
374 if (samplemap[mapchk] == n) samplemap[mapchk] = 0;
375 }
376 for (UINT clrs=1; clrs<iIns; clrs++) if (Headers[clrs])
377 {
378 INSTRUMENTHEADER *pks = Headers[clrs];
379 for (UINT ks=0; ks<128; ks++)
380 {
381 if (pks->Keyboard[ks] == n) pks->Keyboard[ks] = 0;
382 }
383 }
384 memset(&Ins[n], 0, sizeof(Ins[0]));
385 break;
386 }
387 }
388 }
389#endif // FASTSOUNDLIB
390 }
391 if (newsamples < n) newsamples = n;
392 samplemap[nmap] = n;
393 }
394 m_nSamples = newsamples;
395 // Reading Volume Envelope
396 INSTRUMENTHEADER *penv = Headers[iIns];
397 penv->nMidiProgram = pih->type;
398 penv->nFadeOut = xmsh.volfade;
399 penv->nPan = 128;
400 penv->nPPC = 5*12;
401 if (xmsh.vtype & 1) penv->dwFlags |= ENV_VOLUME;
402 if (xmsh.vtype & 2) penv->dwFlags |= ENV_VOLSUSTAIN;
403 if (xmsh.vtype & 4) penv->dwFlags |= ENV_VOLLOOP;
404 if (xmsh.ptype & 1) penv->dwFlags |= ENV_PANNING;
405 if (xmsh.ptype & 2) penv->dwFlags |= ENV_PANSUSTAIN;
406 if (xmsh.ptype & 4) penv->dwFlags |= ENV_PANLOOP;
407 if (xmsh.vnum > 12) xmsh.vnum = 12;
408 if (xmsh.pnum > 12) xmsh.pnum = 12;
409 penv->nVolEnv = xmsh.vnum;
410 if (!xmsh.vnum) penv->dwFlags &= ~ENV_VOLUME;
411 if (!xmsh.pnum) penv->dwFlags &= ~ENV_PANNING;
412 penv->nPanEnv = xmsh.pnum;
413 penv->nVolSustainBegin = penv->nVolSustainEnd = xmsh.vsustain;
414 if (xmsh.vsustain >= 12) penv->dwFlags &= ~ENV_VOLSUSTAIN;
415 penv->nVolLoopStart = xmsh.vloops;
416 penv->nVolLoopEnd = xmsh.vloope;
417 if (penv->nVolLoopEnd >= 12) penv->nVolLoopEnd = 0;
418 if (penv->nVolLoopStart >= penv->nVolLoopEnd) penv->dwFlags &= ~ENV_VOLLOOP;
419 penv->nPanSustainBegin = penv->nPanSustainEnd = xmsh.psustain;
420 if (xmsh.psustain >= 12) penv->dwFlags &= ~ENV_PANSUSTAIN;
421 penv->nPanLoopStart = xmsh.ploops;
422 penv->nPanLoopEnd = xmsh.ploope;
423 if (penv->nPanLoopEnd >= 12) penv->nPanLoopEnd = 0;
424 if (penv->nPanLoopStart >= penv->nPanLoopEnd) penv->dwFlags &= ~ENV_PANLOOP;
425 penv->nGlobalVol = 64;
426 for (UINT ienv=0; ienv<12; ienv++)
427 {
428 penv->VolPoints[ienv] = (WORD)xmsh.venv[ienv*2];
429 penv->VolEnv[ienv] = (BYTE)xmsh.venv[ienv*2+1];
430 penv->PanPoints[ienv] = (WORD)xmsh.penv[ienv*2];
431 penv->PanEnv[ienv] = (BYTE)xmsh.penv[ienv*2+1];
432 if (ienv)
433 {
434 if (penv->VolPoints[ienv] < penv->VolPoints[ienv-1])
435 {
436 penv->VolPoints[ienv] &= 0xFF;
437 penv->VolPoints[ienv] += penv->VolPoints[ienv-1] & 0xFF00;
438 if (penv->VolPoints[ienv] < penv->VolPoints[ienv-1]) penv->VolPoints[ienv] += 0x100;
439 }
440 if (penv->PanPoints[ienv] < penv->PanPoints[ienv-1])
441 {
442 penv->PanPoints[ienv] &= 0xFF;
443 penv->PanPoints[ienv] += penv->PanPoints[ienv-1] & 0xFF00;
444 if (penv->PanPoints[ienv] < penv->PanPoints[ienv-1]) penv->PanPoints[ienv] += 0x100;
445 }
446 }
447 }
448 for (UINT j=0; j<96; j++)
449 {
450 penv->NoteMap[j+12] = j+1+12;
451 if (xmsh.snum[j] < nsamples)
452 penv->Keyboard[j+12] = samplemap[xmsh.snum[j]];
453 }
454 // Reading samples
455 for (UINT ins=0; ins<nsamples; ins++)
456 {
457 if ((dwMemPos + sizeof(xmss) > dwMemLength)
458 || (dwMemPos + xmsh.shsize > dwMemLength)) return TRUE;
459 memcpy(&xmss, lpStream+dwMemPos, sizeof(xmss));
460 xmss.samplen = bswapLE32(xmss.samplen);
461 xmss.loopstart = bswapLE32(xmss.loopstart);
462 xmss.looplen = bswapLE32(xmss.looplen);
463 dwMemPos += xmsh.shsize;
464 flags[ins] = (xmss.type & 0x10) ? RS_PCM16D : RS_PCM8D;
465 if (xmss.type & 0x20) flags[ins] = (xmss.type & 0x10) ? RS_STPCM16D : RS_STPCM8D;
466 samplesize[ins] = xmss.samplen;
467 if (!samplemap[ins]) continue;
468 if (xmss.type & 0x10)
469 {
470 xmss.looplen >>= 1;
471 xmss.loopstart >>= 1;
472 xmss.samplen >>= 1;
473 }
474 if (xmss.type & 0x20)
475 {
476 xmss.looplen >>= 1;
477 xmss.loopstart >>= 1;
478 xmss.samplen >>= 1;
479 }
480 if (xmss.samplen > MAX_SAMPLE_LENGTH) xmss.samplen = MAX_SAMPLE_LENGTH;
481 if (xmss.loopstart >= xmss.samplen) xmss.type &= ~3;
482 xmss.looplen += xmss.loopstart;
483 if (xmss.looplen > xmss.samplen) xmss.looplen = xmss.samplen;
484 if (!xmss.looplen) xmss.type &= ~3;
485 UINT imapsmp = samplemap[ins];
486 memcpy(m_szNames[imapsmp], xmss.name, 22);
487 m_szNames[imapsmp][22] = 0;
488 MODINSTRUMENT *pins = &Ins[imapsmp];
489 pins->nLength = (xmss.samplen > MAX_SAMPLE_LENGTH) ? MAX_SAMPLE_LENGTH : xmss.samplen;
490 pins->nLoopStart = xmss.loopstart;
491 pins->nLoopEnd = xmss.looplen;
492 if (pins->nLoopEnd > pins->nLength) pins->nLoopEnd = pins->nLength;
493 if (pins->nLoopStart >= pins->nLoopEnd)
494 {
495 pins->nLoopStart = pins->nLoopEnd = 0;
496 }
497 if (xmss.type & 3) pins->uFlags |= CHN_LOOP;
498 if (xmss.type & 2) pins->uFlags |= CHN_PINGPONGLOOP;
499 pins->nVolume = xmss.vol << 2;
500 if (pins->nVolume > 256) pins->nVolume = 256;
501 pins->nGlobalVol = 64;
502 if ((xmss.res == 0xAD) && (!(xmss.type & 0x30)))
503 {
504 flags[ins] = RS_ADPCM4;
505 samplesize[ins] = (samplesize[ins]+1)/2 + 16;
506 }
507 pins->nFineTune = xmss.finetune;
508 pins->RelativeTone = (int)xmss.relnote;
509 pins->nPan = xmss.pan;
510 pins->uFlags |= CHN_PANNING;
511 pins->nVibType = xmsh.vibtype;
512 pins->nVibSweep = xmsh.vibsweep;
513 pins->nVibDepth = xmsh.vibdepth;
514 pins->nVibRate = xmsh.vibrate;
515 memcpy(pins->name, xmss.name, 22);
516 pins->name[21] = 0;
517 }
518#if 0
519 if ((xmsh.reserved2 > nsamples) && (xmsh.reserved2 <= 16))
520 {
521 dwMemPos += (((UINT)xmsh.reserved2) - nsamples) * xmsh.shsize;
522 }
523#endif
524 for (UINT ismpd=0; ismpd<nsamples; ismpd++)
525 {
526 if ((samplemap[ismpd]) && (samplesize[ismpd]) && (dwMemPos < dwMemLength))
527 {
528 ReadSample(&Ins[samplemap[ismpd]], flags[ismpd], (LPSTR)(lpStream + dwMemPos), dwMemLength - dwMemPos);
529 }
530 dwMemPos += samplesize[ismpd];
531 if (dwMemPos >= dwMemLength) break;
532 }
533 }
534 // Read song comments: "TEXT"
535 if ((dwMemPos + 8 < dwMemLength) && (bswapLE32(*((DWORD *)(lpStream+dwMemPos))) == 0x74786574))
536 {
537 UINT len = *((DWORD *)(lpStream+dwMemPos+4));
538 dwMemPos += 8;
539 if ((dwMemPos + len <= dwMemLength) && (len < 16384))
540 {
541 m_lpszSongComments = new char[len+1];
542 if (m_lpszSongComments)
543 {
544 memcpy(m_lpszSongComments, lpStream+dwMemPos, len);
545 m_lpszSongComments[len] = 0;
546 }
547 dwMemPos += len;
548 }
549 }
550 // Read midi config: "MIDI"
551 if ((dwMemPos + 8 < dwMemLength) && (bswapLE32(*((DWORD *)(lpStream+dwMemPos))) == 0x4944494D))
552 {
553 UINT len = *((DWORD *)(lpStream+dwMemPos+4));
554 dwMemPos += 8;
555 if (len == sizeof(MODMIDICFG))
556 {
557 memcpy(&m_MidiCfg, lpStream+dwMemPos, len);
558 m_dwSongFlags |= SONG_EMBEDMIDICFG;
559 }
560 }
561 // Read pattern names: "PNAM"
562 if ((dwMemPos + 8 < dwMemLength) && (bswapLE32(*((DWORD *)(lpStream+dwMemPos))) == 0x4d414e50))
563 {
564 UINT len = *((DWORD *)(lpStream+dwMemPos+4));
565 dwMemPos += 8;
566 if ((dwMemPos + len <= dwMemLength) && (len <= MAX_PATTERNS*MAX_PATTERNNAME) && (len >= MAX_PATTERNNAME))
567 {
568 m_lpszPatternNames = new char[len];
569
570 if (m_lpszPatternNames)
571 {
572 m_nPatternNames = len / MAX_PATTERNNAME;
573 memcpy(m_lpszPatternNames, lpStream+dwMemPos, len);
574 }
575 dwMemPos += len;
576 }
577 }
578 // Read channel names: "CNAM"
579 if ((dwMemPos + 8 < dwMemLength) && (bswapLE32(*((DWORD *)(lpStream+dwMemPos))) == 0x4d414e43))
580 {
581 UINT len = *((DWORD *)(lpStream+dwMemPos+4));
582 dwMemPos += 8;
583 if ((dwMemPos + len <= dwMemLength) && (len <= MAX_BASECHANNELS*MAX_CHANNELNAME))
584 {
585 UINT n = len / MAX_CHANNELNAME;
586 for (UINT i=0; i<n; i++)
587 {
588 memcpy(ChnSettings[i].szName, (lpStream+dwMemPos+i*MAX_CHANNELNAME), MAX_CHANNELNAME);
589 ChnSettings[i].szName[MAX_CHANNELNAME-1] = 0;
590 }
591 dwMemPos += len;
592 }
593 }
594 // Read mix plugins information
595 if (dwMemPos + 8 < dwMemLength)
596 {
597 dwMemPos += LoadMixPlugins(lpStream+dwMemPos, dwMemLength-dwMemPos);
598 }
599 return TRUE;
600}
601
602
603#ifndef MODPLUG_NO_FILESAVE
604
605BOOL CSoundFile::SaveXM(LPCSTR lpszFileName, UINT nPacking)
606//---------------------------------------------------------
607{
608 BYTE s[64*64*5];
609 XMFILEHEADER header;
610 XMINSTRUMENTHEADER xmih;
611 XMSAMPLEHEADER xmsh;
612 XMSAMPLESTRUCT xmss;
613 BYTE smptable[32];
614 BYTE xmph[9];
615 FILE *f;
616 int i;
617
618 if ((!m_nChannels) || (!lpszFileName)) return FALSE;
619 if ((f = fopen(lpszFileName, "wb")) == NULL) return FALSE;
620 fwrite("Extended Module: ", 17, 1, f);
621 fwrite(m_szNames[0], 20, 1, f);
622 s[0] = 0x1A;
623 lstrcpy((LPSTR)&s[1], (nPacking) ? "MOD Plugin packed " : "FastTracker v2.00 ");
624 s[21] = 0x04;
625 s[22] = 0x01;
626 fwrite(s, 23, 1, f);
627 // Writing song header
628 memset(&header, 0, sizeof(header));
629 header.size = sizeof(XMFILEHEADER);
630 header.norder = 0;
631 header.restartpos = m_nRestartPos;
632 header.channels = m_nChannels;
633 header.patterns = 0;
634 for (i=0; i<MAX_ORDERS; i++)
635 {
636 if (Order[i] == 0xFF) break;
637 header.norder++;
638 if ((Order[i] >= header.patterns) && (Order[i] < MAX_PATTERNS)) header.patterns = Order[i]+1;
639 }
640 header.instruments = m_nInstruments;
641 if (!header.instruments) header.instruments = m_nSamples;
642 header.flags = (m_dwSongFlags & SONG_LINEARSLIDES) ? 0x01 : 0x00;
643 if (m_dwSongFlags & SONG_EXFILTERRANGE) header.flags |= 0x1000;
644 header.tempo = m_nDefaultTempo;
645 header.speed = m_nDefaultSpeed;
646 memcpy(header.order, Order, header.norder);
647 fwrite(&header, 1, sizeof(header), f);
648 // Writing patterns
649 for (i=0; i<header.patterns; i++) if (Patterns[i])
650 {
651 MODCOMMAND *p = Patterns[i];
652 UINT len = 0;
653
654 memset(&xmph, 0, sizeof(xmph));
655 xmph[0] = 9;
656 xmph[5] = (BYTE)(PatternSize[i] & 0xFF);
657 xmph[6] = (BYTE)(PatternSize[i] >> 8);
658 for (UINT j=m_nChannels*PatternSize[i]; j; j--,p++)
659 {
660 UINT note = p->note;
661 UINT param = ModSaveCommand(p, TRUE);
662 UINT command = param >> 8;
663 param &= 0xFF;
664 if (note >= 0xFE) note = 97; else
665 if ((note <= 12) || (note > 96+12)) note = 0; else
666 note -= 12;
667 UINT vol = 0;
668 if (p->volcmd)
669 {
670 UINT volcmd = p->volcmd;
671 switch(volcmd)
672 {
673 case VOLCMD_VOLUME: vol = 0x10 + p->vol; break;
674 case VOLCMD_VOLSLIDEDOWN:vol = 0x60 + (p->vol & 0x0F); break;
675 case VOLCMD_VOLSLIDEUP: vol = 0x70 + (p->vol & 0x0F); break;
676 case VOLCMD_FINEVOLDOWN:vol = 0x80 + (p->vol & 0x0F); break;
677 case VOLCMD_FINEVOLUP: vol = 0x90 + (p->vol & 0x0F); break;
678 case VOLCMD_VIBRATOSPEED:vol = 0xA0 + (p->vol & 0x0F); break;
679 case VOLCMD_VIBRATO: vol = 0xB0 + (p->vol & 0x0F); break;
680 case VOLCMD_PANNING: vol = 0xC0 + (p->vol >> 2); if (vol > 0xCF) vol = 0xCF; break;
681 case VOLCMD_PANSLIDELEFT:vol = 0xD0 + (p->vol & 0x0F); break;
682 case VOLCMD_PANSLIDERIGHT:vol = 0xE0 + (p->vol & 0x0F); break;
683 case VOLCMD_TONEPORTAMENTO:vol = 0xF0 + (p->vol & 0x0F); break;
684 }
685 }
686 if ((note) && (p->instr) && (vol > 0x0F) && (command) && (param))
687 {
688 s[len++] = note;
689 s[len++] = p->instr;
690 s[len++] = vol;
691 s[len++] = command;
692 s[len++] = param;
693 } else
694 {
695 BYTE b = 0x80;
696 if (note) b |= 0x01;
697 if (p->instr) b |= 0x02;
698 if (vol >= 0x10) b |= 0x04;
699 if (command) b |= 0x08;
700 if (param) b |= 0x10;
701 s[len++] = b;
702 if (b & 1) s[len++] = note;
703 if (b & 2) s[len++] = p->instr;
704 if (b & 4) s[len++] = vol;
705 if (b & 8) s[len++] = command;
706 if (b & 16) s[len++] = param;
707 }
708 if (len > sizeof(s) - 5) break;
709 }
710 xmph[7] = (BYTE)(len & 0xFF);
711 xmph[8] = (BYTE)(len >> 8);
712 fwrite(xmph, 1, 9, f);
713 fwrite(s, 1, len, f);
714 } else
715 {
716 memset(&xmph, 0, sizeof(xmph));
717 xmph[0] = 9;
718 xmph[5] = (BYTE)(PatternSize[i] & 0xFF);
719 xmph[6] = (BYTE)(PatternSize[i] >> 8);
720 fwrite(xmph, 1, 9, f);
721 }
722 // Writing instruments
723 for (i=1; i<=header.instruments; i++)
724 {
725 MODINSTRUMENT *pins;
726 BYTE flags[32];
727
728 memset(&xmih, 0, sizeof(xmih));
729 memset(&xmsh, 0, sizeof(xmsh));
730 xmih.size = sizeof(xmih) + sizeof(xmsh);
731 memcpy(xmih.name, m_szNames[i], 22);
732 xmih.type = 0;
733 xmih.samples = 0;
734 if (m_nInstruments)
735 {
736 INSTRUMENTHEADER *penv = Headers[i];
737 if (penv)
738 {
739 memcpy(xmih.name, penv->name, 22);
740 xmih.type = penv->nMidiProgram;
741 xmsh.volfade = penv->nFadeOut;
742 xmsh.vnum = (BYTE)penv->nVolEnv;
743 xmsh.pnum = (BYTE)penv->nPanEnv;
744 if (xmsh.vnum > 12) xmsh.vnum = 12;
745 if (xmsh.pnum > 12) xmsh.pnum = 12;
746 for (UINT ienv=0; ienv<12; ienv++)
747 {
748 xmsh.venv[ienv*2] = penv->VolPoints[ienv];
749 xmsh.venv[ienv*2+1] = penv->VolEnv[ienv];
750 xmsh.penv[ienv*2] = penv->PanPoints[ienv];
751 xmsh.penv[ienv*2+1] = penv->PanEnv[ienv];
752 }
753 if (penv->dwFlags & ENV_VOLUME) xmsh.vtype |= 1;
754 if (penv->dwFlags & ENV_VOLSUSTAIN) xmsh.vtype |= 2;
755 if (penv->dwFlags & ENV_VOLLOOP) xmsh.vtype |= 4;
756 if (penv->dwFlags & ENV_PANNING) xmsh.ptype |= 1;
757 if (penv->dwFlags & ENV_PANSUSTAIN) xmsh.ptype |= 2;
758 if (penv->dwFlags & ENV_PANLOOP) xmsh.ptype |= 4;
759 xmsh.vsustain = (BYTE)penv->nVolSustainBegin;
760 xmsh.vloops = (BYTE)penv->nVolLoopStart;
761 xmsh.vloope = (BYTE)penv->nVolLoopEnd;
762 xmsh.psustain = (BYTE)penv->nPanSustainBegin;
763 xmsh.ploops = (BYTE)penv->nPanLoopStart;
764 xmsh.ploope = (BYTE)penv->nPanLoopEnd;
765 for (UINT j=0; j<96; j++) if (penv->Keyboard[j+12])
766 {
767 UINT k;
768 for (k=0; k<xmih.samples; k++)if (smptable[k] == penv->Keyboard[j+12]) break;
769 if (k == xmih.samples)
770 {
771 smptable[xmih.samples++] = penv->Keyboard[j+12];
772 }
773 if (xmih.samples >= 32) break;
774 xmsh.snum[j] = k;
775 }
776 // xmsh.reserved2 = xmih.samples;
777 }
778 } else
779 {
780 xmih.samples = 1;
781 // xmsh.reserved2 = 1;
782 smptable[0] = i;
783 }
784 xmsh.shsize = (xmih.samples) ? 40 : 0;
785 fwrite(&xmih, 1, sizeof(xmih), f);
786 if (smptable[0])
787 {
788 MODINSTRUMENT *pvib = &Ins[smptable[0]];
789 xmsh.vibtype = pvib->nVibType;
790 xmsh.vibsweep = pvib->nVibSweep;
791 xmsh.vibdepth = pvib->nVibDepth;
792 xmsh.vibrate = pvib->nVibRate;
793 }
794 fwrite(&xmsh, 1, xmih.size - sizeof(xmih), f);
795 if (!xmih.samples) continue;
796 for (UINT ins=0; ins<xmih.samples; ins++)
797 {
798 memset(&xmss, 0, sizeof(xmss));
799 if (smptable[ins]) memcpy(xmss.name, m_szNames[smptable[ins]], 22);
800 pins = &Ins[smptable[ins]];
801 xmss.samplen = pins->nLength;
802 xmss.loopstart = pins->nLoopStart;
803 xmss.looplen = pins->nLoopEnd - pins->nLoopStart;
804 xmss.vol = pins->nVolume / 4;
805 xmss.finetune = (char)pins->nFineTune;
806 xmss.type = 0;
807 if (pins->uFlags & CHN_LOOP) xmss.type = (pins->uFlags & CHN_PINGPONGLOOP) ? 2 : 1;
808 flags[ins] = RS_PCM8D;
809#ifndef NO_PACKING
810 if (nPacking)
811 {
812 if ((!(pins->uFlags & (CHN_16BIT|CHN_STEREO)))
813 && (CanPackSample(pins->pSample, pins->nLength, nPacking)))
814 {
815 flags[ins] = RS_ADPCM4;
816 xmss.res = 0xAD;
817 }
818 } else
819#endif
820 {
821 if (pins->uFlags & CHN_16BIT)
822 {
823 flags[ins] = RS_PCM16D;
824 xmss.type |= 0x10;
825 xmss.looplen *= 2;
826 xmss.loopstart *= 2;
827 xmss.samplen *= 2;
828 }
829 if (pins->uFlags & CHN_STEREO)
830 {
831 flags[ins] = (pins->uFlags & CHN_16BIT) ? RS_STPCM16D : RS_STPCM8D;
832 xmss.type |= 0x20;
833 xmss.looplen *= 2;
834 xmss.loopstart *= 2;
835 xmss.samplen *= 2;
836 }
837 }
838 xmss.pan = 255;
839 if (pins->nPan < 256) xmss.pan = (BYTE)pins->nPan;
840 xmss.relnote = (signed char)pins->RelativeTone;
841 fwrite(&xmss, 1, xmsh.shsize, f);
842 }
843 for (UINT ismpd=0; ismpd<xmih.samples; ismpd++)
844 {
845 pins = &Ins[smptable[ismpd]];
846 if (pins->pSample)
847 {
848#ifndef NO_PACKING
849 if ((flags[ismpd] == RS_ADPCM4) && (xmih.samples>1)) CanPackSample(pins->pSample, pins->nLength, nPacking);
850#endif // NO_PACKING
851 WriteSample(f, pins, flags[ismpd]);
852 }
853 }
854 }
855 // Writing song comments
856 if ((m_lpszSongComments) && (m_lpszSongComments[0]))
857 {
858 DWORD d = 0x74786574;
859 fwrite(&d, 1, 4, f);
860 d = strlen(m_lpszSongComments);
861 fwrite(&d, 1, 4, f);
862 fwrite(m_lpszSongComments, 1, d, f);
863 }
864 // Writing midi cfg
865 if (m_dwSongFlags & SONG_EMBEDMIDICFG)
866 {
867 DWORD d = 0x4944494D;
868 fwrite(&d, 1, 4, f);
869 d = sizeof(MODMIDICFG);
870 fwrite(&d, 1, 4, f);
871 fwrite(&m_MidiCfg, 1, sizeof(MODMIDICFG), f);
872 }
873 // Writing Pattern Names
874 if ((m_nPatternNames) && (m_lpszPatternNames))
875 {
876 DWORD dwLen = m_nPatternNames * MAX_PATTERNNAME;
877 while ((dwLen >= MAX_PATTERNNAME) && (!m_lpszPatternNames[dwLen-MAX_PATTERNNAME])) dwLen -= MAX_PATTERNNAME;
878 if (dwLen >= MAX_PATTERNNAME)
879 {
880 DWORD d = 0x4d414e50;
881 fwrite(&d, 1, 4, f);
882 fwrite(&dwLen, 1, 4, f);
883 fwrite(m_lpszPatternNames, 1, dwLen, f);
884 }
885 }
886 // Writing Channel Names
887 {
888 UINT nChnNames = 0;
889 for (UINT inam=0; inam<m_nChannels; inam++)
890 {
891 if (ChnSettings[inam].szName[0]) nChnNames = inam+1;
892 }
893 // Do it!
894 if (nChnNames)
895 {
896 DWORD dwLen = nChnNames * MAX_CHANNELNAME;
897 DWORD d = 0x4d414e43;
898 fwrite(&d, 1, 4, f);
899 fwrite(&dwLen, 1, 4, f);
900 for (UINT inam=0; inam<nChnNames; inam++)
901 {
902 fwrite(ChnSettings[inam].szName, 1, MAX_CHANNELNAME, f);
903 }
904 }
905 }
906 // Save mix plugins information
907 SaveMixPlugins(f);
908 fclose(f);
909 return TRUE;
910}
911
912#endif // MODPLUG_NO_FILESAVE
diff --git a/core/multimedia/opieplayer/modplug/memfile.cpp b/core/multimedia/opieplayer/modplug/memfile.cpp
new file mode 100644
index 0000000..8a29997
--- a/dev/null
+++ b/core/multimedia/opieplayer/modplug/memfile.cpp
@@ -0,0 +1,76 @@
1/* This file is part of the KDE project
2 Copyright (C) 2002 Simon Hausmann <hausmann@kde.org>
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; see the file COPYING. If not, write to
16 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 Boston, MA 02111-1307, USA.
18*/
19
20#include "memfile.h"
21
22#include <unistd.h>
23#include <sys/mman.h>
24
25MemFile::MemFile()
26{
27}
28
29MemFile::MemFile( const QString &name )
30 : QFile( name )
31{
32}
33
34MemFile::~MemFile()
35{
36 close();
37}
38
39void MemFile::close()
40{
41 unmap();
42 QFile::close();
43}
44
45void MemFile::unmap()
46{
47#if defined(Q_WS_X11) || defined(Q_WS_QWS)
48 if ( m_data.data() )
49 {
50 munmap( m_data.data(), m_data.size() );
51 m_data.resetRawData( m_data.data(), m_data.size() );
52 }
53#endif
54}
55
56QByteArray &MemFile::data()
57{
58 if ( !m_data.data() )
59 {
60#if defined(Q_WS_X11) || defined(Q_WS_QWS)
61 const char *rawData = (const char *)mmap( 0, size(), PROT_READ,
62 MAP_SHARED, handle(), 0 );
63 if ( rawData )
64 {
65 m_data.setRawData( rawData, size() );
66 return m_data;
67 }
68 else
69 qDebug( "MemFile: mmap() failed!" );
70 // fallback
71#endif
72 m_data = readAll();
73 }
74 return m_data;
75}
76
diff --git a/core/multimedia/opieplayer/modplug/memfile.h b/core/multimedia/opieplayer/modplug/memfile.h
new file mode 100644
index 0000000..2227f26
--- a/dev/null
+++ b/core/multimedia/opieplayer/modplug/memfile.h
@@ -0,0 +1,42 @@
1/* This file is part of the KDE project
2 Copyright (C) 2002 Simon Hausmann <hausmann@kde.org>
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; see the file COPYING. If not, write to
16 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 Boston, MA 02111-1307, USA.
18*/
19#ifndef __memfile_h__
20#define __memfile_h__
21
22#include <qfile.h>
23
24class MemFile : public QFile
25{
26public:
27 MemFile();
28 MemFile( const QString &name );
29 virtual ~MemFile();
30
31 virtual void close();
32
33 QByteArray &data();
34
35private:
36 void unmap();
37 QByteArray m_data;
38};
39
40#endif
41/* vim: et sw=4
42 */
diff --git a/core/multimedia/opieplayer/modplug/mmcmp.cpp b/core/multimedia/opieplayer/modplug/mmcmp.cpp
new file mode 100644
index 0000000..8c32eb2
--- a/dev/null
+++ b/core/multimedia/opieplayer/modplug/mmcmp.cpp
@@ -0,0 +1,409 @@
1/*
2 * This program is free software; you can redistribute it and modify it
3 * under the terms of the GNU General Public License as published by the
4 * Free Software Foundation; either version 2 of the license or (at your
5 * option) any later version.
6 *
7 * Authors: Olivier Lapicque <olivierl@jps.net>
8*/
9
10#include "stdafx.h"
11#include "sndfile.h"
12
13BOOL PP20_Unpack(LPCBYTE *ppMemFile, LPDWORD pdwMemLength);
14
15typedef struct MMCMPFILEHEADER
16{
17 DWORD id_ziRC;// "ziRC"
18 DWORD id_ONia;// "ONia"
19 WORD hdrsize;
20} Q_PACKED MMCMPFILEHEADER, *LPMMCMPFILEHEADER;
21
22typedef struct MMCMPHEADER
23{
24 WORD version;
25 WORD nblocks;
26 DWORD filesize;
27 DWORD blktable;
28 BYTE glb_comp;
29 BYTE fmt_comp;
30} Q_PACKED MMCMPHEADER, *LPMMCMPHEADER;
31
32typedef struct MMCMPBLOCK
33{
34 DWORD unpk_size;
35 DWORD pk_size;
36 DWORD xor_chk;
37 WORD sub_blk;
38 WORD flags;
39 WORD tt_entries;
40 WORD num_bits;
41} Q_PACKED MMCMPBLOCK, *LPMMCMPBLOCK;
42
43typedef struct MMCMPSUBBLOCK
44{
45 DWORD unpk_pos;
46 DWORD unpk_size;
47} Q_PACKED MMCMPSUBBLOCK, *LPMMCMPSUBBLOCK;
48
49 #define MMCMP_COMP 0x0001
50 #define MMCMP_DELTA 0x0002
51 #define MMCMP_16BIT 0x0004
52 #define MMCMP_STEREO0x0100
53 #define MMCMP_ABS16 0x0200
54 #define MMCMP_ENDIAN0x0400
55
56typedef struct MMCMPBITBUFFER
57{
58 UINT bitcount;
59 DWORD bitbuffer;
60 LPCBYTE pSrc;
61 LPCBYTE pEnd;
62
63 DWORD GetBits(UINT nBits);
64} Q_PACKED MMCMPBITBUFFER;
65
66
67DWORD MMCMPBITBUFFER::GetBits(UINT nBits)
68//---------------------------------------
69{
70 DWORD d;
71 if (!nBits) return 0;
72 while (bitcount < 24)
73 {
74 bitbuffer |= ((pSrc < pEnd) ? *pSrc++ : 0) << bitcount;
75 bitcount += 8;
76 }
77 d = bitbuffer & ((1 << nBits) - 1);
78 bitbuffer >>= nBits;
79 bitcount -= nBits;
80 return d;
81}
82
83//#define MMCMP_LOG
84
85#ifdef MMCMP_LOG
86extern void Log(LPCSTR s, ...);
87#endif
88
89const DWORD MMCMP8BitCommands[8] =
90{
91 0x01, 0x03, 0x07, 0x0F, 0x1E, 0x3C,0x78, 0xF8
92};
93
94const UINT MMCMP8BitFetch[8] =
95{
96 3, 3, 3, 3, 2, 1, 0, 0
97};
98
99const DWORD MMCMP16BitCommands[16] =
100{
101 0x01, 0x03, 0x07, 0x0F, 0x1E, 0x3C,0x78, 0xF0,
102 0x1F0, 0x3F0, 0x7F0, 0xFF0, 0x1FF0, 0x3FF0, 0x7FF0, 0xFFF0
103};
104
105const UINT MMCMP16BitFetch[16] =
106{
107 4, 4, 4, 4, 3, 2, 1, 0,
108 0, 0, 0, 0, 0, 0, 0, 0
109};
110
111
112BOOL MMCMP_Unpack(LPCBYTE *ppMemFile, LPDWORD pdwMemLength)
113//---------------------------------------------------------
114{
115 DWORD dwMemLength = *pdwMemLength;
116 LPCBYTE lpMemFile = *ppMemFile;
117 LPBYTE pBuffer;
118 LPMMCMPFILEHEADER pmfh = (LPMMCMPFILEHEADER)(lpMemFile);
119 LPMMCMPHEADER pmmh = (LPMMCMPHEADER)(lpMemFile+10);
120 LPDWORD pblk_table;
121 DWORD dwFileSize;
122
123 if (PP20_Unpack(ppMemFile, pdwMemLength))
124 {
125 return TRUE;
126 }
127 if ((dwMemLength < 256) || (!pmfh) || (pmfh->id_ziRC != 0x4352697A) || (pmfh->id_ONia != 0x61694e4f) || (pmfh->hdrsize < 14)
128 || (!pmmh->nblocks) || (pmmh->filesize < 16) || (pmmh->filesize > 0x8000000)
129 || (pmmh->blktable >= dwMemLength) || (pmmh->blktable + 4*pmmh->nblocks > dwMemLength)) return FALSE;
130 dwFileSize = pmmh->filesize;
131 if ((pBuffer = (LPBYTE)GlobalAllocPtr(GHND, (dwFileSize + 31) & ~15)) == NULL) return FALSE;
132 pblk_table = (LPDWORD)(lpMemFile+pmmh->blktable);
133 for (UINT nBlock=0; nBlock<pmmh->nblocks; nBlock++)
134 {
135 DWORD dwMemPos = pblk_table[nBlock];
136 LPMMCMPBLOCK pblk = (LPMMCMPBLOCK)(lpMemFile+dwMemPos);
137 LPMMCMPSUBBLOCK psubblk = (LPMMCMPSUBBLOCK)(lpMemFile+dwMemPos+20);
138
139 if ((dwMemPos + 20 >= dwMemLength) || (dwMemPos + 20 + pblk->sub_blk*8 >= dwMemLength)) break;
140 dwMemPos += 20 + pblk->sub_blk*8;
141#ifdef MMCMP_LOG
142 Log("block %d: flags=%04X sub_blocks=%d", nBlock, (UINT)pblk->flags, (UINT)pblk->sub_blk);
143 Log(" pksize=%d unpksize=%d", pblk->pk_size, pblk->unpk_size);
144 Log(" tt_entries=%d num_bits=%d\n", pblk->tt_entries, pblk->num_bits);
145#endif
146 // Data is not packed
147 if (!(pblk->flags & MMCMP_COMP))
148 {
149 for (UINT i=0; i<pblk->sub_blk; i++)
150 {
151 if ((psubblk->unpk_pos > dwFileSize) || (psubblk->unpk_pos + psubblk->unpk_size > dwFileSize)) break;
152#ifdef MMCMP_LOG
153 Log(" Unpacked sub-block %d: offset %d, size=%d\n", i, psubblk->unpk_pos, psubblk->unpk_size);
154#endif
155 memcpy(pBuffer+psubblk->unpk_pos, lpMemFile+dwMemPos, psubblk->unpk_size);
156 dwMemPos += psubblk->unpk_size;
157 psubblk++;
158 }
159 } else
160 // Data is 16-bit packed
161 if (pblk->flags & MMCMP_16BIT)
162 {
163 MMCMPBITBUFFER bb;
164 LPWORD pDest = (LPWORD)(pBuffer + psubblk->unpk_pos);
165 DWORD dwSize = psubblk->unpk_size >> 1;
166 DWORD dwPos = 0;
167 UINT numbits = pblk->num_bits;
168 UINT subblk = 0, oldval = 0;
169
170#ifdef MMCMP_LOG
171 Log(" 16-bit block: pos=%d size=%d ", psubblk->unpk_pos, psubblk->unpk_size);
172 if (pblk->flags & MMCMP_DELTA) Log("DELTA ");
173 if (pblk->flags & MMCMP_ABS16) Log("ABS16 ");
174 Log("\n");
175#endif
176 bb.bitcount = 0;
177 bb.bitbuffer = 0;
178 bb.pSrc = lpMemFile+dwMemPos+pblk->tt_entries;
179 bb.pEnd = lpMemFile+dwMemPos+pblk->pk_size;
180 while (subblk < pblk->sub_blk)
181 {
182 UINT newval = 0x10000;
183 DWORD d = bb.GetBits(numbits+1);
184
185 if (d >= MMCMP16BitCommands[numbits])
186 {
187 UINT nFetch = MMCMP16BitFetch[numbits];
188 UINT newbits = bb.GetBits(nFetch) + ((d - MMCMP16BitCommands[numbits]) << nFetch);
189 if (newbits != numbits)
190 {
191 numbits = newbits & 0x0F;
192 } else
193 {
194 if ((d = bb.GetBits(4)) == 0x0F)
195 {
196 if (bb.GetBits(1)) break;
197 newval = 0xFFFF;
198 } else
199 {
200 newval = 0xFFF0 + d;
201 }
202 }
203 } else
204 {
205 newval = d;
206 }
207 if (newval < 0x10000)
208 {
209 newval = (newval & 1) ? (UINT)(-(LONG)((newval+1) >> 1)) : (UINT)(newval >> 1);
210 if (pblk->flags & MMCMP_DELTA)
211 {
212 newval += oldval;
213 oldval = newval;
214 } else
215 if (!(pblk->flags & MMCMP_ABS16))
216 {
217 newval ^= 0x8000;
218 }
219 pDest[dwPos++] = (WORD)newval;
220 }
221 if (dwPos >= dwSize)
222 {
223 subblk++;
224 dwPos = 0;
225 dwSize = psubblk[subblk].unpk_size >> 1;
226 pDest = (LPWORD)(pBuffer + psubblk[subblk].unpk_pos);
227 }
228 }
229 } else
230 // Data is 8-bit packed
231 {
232 MMCMPBITBUFFER bb;
233 LPBYTE pDest = pBuffer + psubblk->unpk_pos;
234 DWORD dwSize = psubblk->unpk_size;
235 DWORD dwPos = 0;
236 UINT numbits = pblk->num_bits;
237 UINT subblk = 0, oldval = 0;
238 LPCBYTE ptable = lpMemFile+dwMemPos;
239
240 bb.bitcount = 0;
241 bb.bitbuffer = 0;
242 bb.pSrc = lpMemFile+dwMemPos+pblk->tt_entries;
243 bb.pEnd = lpMemFile+dwMemPos+pblk->pk_size;
244 while (subblk < pblk->sub_blk)
245 {
246 UINT newval = 0x100;
247 DWORD d = bb.GetBits(numbits+1);
248
249 if (d >= MMCMP8BitCommands[numbits])
250 {
251 UINT nFetch = MMCMP8BitFetch[numbits];
252 UINT newbits = bb.GetBits(nFetch) + ((d - MMCMP8BitCommands[numbits]) << nFetch);
253 if (newbits != numbits)
254 {
255 numbits = newbits & 0x07;
256 } else
257 {
258 if ((d = bb.GetBits(3)) == 7)
259 {
260 if (bb.GetBits(1)) break;
261 newval = 0xFF;
262 } else
263 {
264 newval = 0xF8 + d;
265 }
266 }
267 } else
268 {
269 newval = d;
270 }
271 if (newval < 0x100)
272 {
273 int n = ptable[newval];
274 if (pblk->flags & MMCMP_DELTA)
275 {
276 n += oldval;
277 oldval = n;
278 }
279 pDest[dwPos++] = (BYTE)n;
280 }
281 if (dwPos >= dwSize)
282 {
283 subblk++;
284 dwPos = 0;
285 dwSize = psubblk[subblk].unpk_size;
286 pDest = pBuffer + psubblk[subblk].unpk_pos;
287 }
288 }
289 }
290 }
291 *ppMemFile = pBuffer;
292 *pdwMemLength = dwFileSize;
293 return TRUE;
294}
295
296
297//////////////////////////////////////////////////////////////////////////////
298//
299// PowerPack PP20 Unpacker
300//
301
302typedef struct _PPBITBUFFER
303{
304 UINT bitcount;
305 ULONG bitbuffer;
306 LPCBYTE pStart;
307 LPCBYTE pSrc;
308
309 ULONG GetBits(UINT n);
310} Q_PACKED PPBITBUFFER;
311
312
313ULONG PPBITBUFFER::GetBits(UINT n)
314{
315 ULONG result = 0;
316
317 for (UINT i=0; i<n; i++)
318 {
319 if (!bitcount)
320 {
321 bitcount = 8;
322 if (pSrc != pStart) pSrc--;
323 bitbuffer = *pSrc;
324 }
325 result = (result<<1) | (bitbuffer&1);
326 bitbuffer >>= 1;
327 bitcount--;
328 }
329 return result;
330}
331
332
333VOID PP20_DoUnpack(const BYTE *pSrc, UINT nSrcLen, BYTE *pDst, UINT nDstLen)
334{
335 PPBITBUFFER BitBuffer;
336 ULONG nBytesLeft;
337
338 BitBuffer.pStart = pSrc;
339 BitBuffer.pSrc = pSrc + nSrcLen - 4;
340 BitBuffer.bitbuffer = 0;
341 BitBuffer.bitcount = 0;
342 BitBuffer.GetBits(pSrc[nSrcLen-1]);
343 nBytesLeft = nDstLen;
344 while (nBytesLeft > 0)
345 {
346 if (!BitBuffer.GetBits(1))
347 {
348 UINT n = 1;
349 while (n < nBytesLeft)
350 {
351 UINT code = BitBuffer.GetBits(2);
352 n += code;
353 if (code != 3) break;
354 }
355 for (UINT i=0; i<n; i++)
356 {
357 pDst[--nBytesLeft] = (BYTE)BitBuffer.GetBits(8);
358 }
359 if (!nBytesLeft) break;
360 }
361 {
362 UINT n = BitBuffer.GetBits(2)+1;
363 UINT nbits = pSrc[n-1];
364 UINT nofs;
365 if (n==4)
366 {
367 nofs = BitBuffer.GetBits( (BitBuffer.GetBits(1)) ? nbits : 7 );
368 while (n < nBytesLeft)
369 {
370 UINT code = BitBuffer.GetBits(3);
371 n += code;
372 if (code != 7) break;
373 }
374 } else
375 {
376 nofs = BitBuffer.GetBits(nbits);
377 }
378 for (UINT i=0; i<=n; i++)
379 {
380 pDst[nBytesLeft-1] = (nBytesLeft+nofs < nDstLen) ? pDst[nBytesLeft+nofs] : 0;
381 if (!--nBytesLeft) break;
382 }
383 }
384 }
385}
386
387
388BOOL PP20_Unpack(LPCBYTE *ppMemFile, LPDWORD pdwMemLength)
389{
390 DWORD dwMemLength = *pdwMemLength;
391 LPCBYTE lpMemFile = *ppMemFile;
392 DWORD dwDstLen;
393 LPBYTE pBuffer;
394
395 if ((!lpMemFile) || (dwMemLength < 256) || (*(DWORD *)lpMemFile != 0x30325050)) return FALSE;
396 dwDstLen = (lpMemFile[dwMemLength-4]<<16) | (lpMemFile[dwMemLength-3]<<8) | (lpMemFile[dwMemLength-2]);
397 //Log("PP20 detected: Packed length=%d, Unpacked length=%d\n", dwMemLength, dwDstLen);
398 if ((dwDstLen < 512) || (dwDstLen > 0x400000) || (dwDstLen > 16*dwMemLength)) return FALSE;
399 if ((pBuffer = (LPBYTE)GlobalAllocPtr(GHND, (dwDstLen + 31) & ~15)) == NULL) return FALSE;
400 PP20_DoUnpack(lpMemFile+4, dwMemLength-4, pBuffer, dwDstLen);
401 *ppMemFile = pBuffer;
402 *pdwMemLength = dwDstLen;
403 return TRUE;
404}
405
406
407
408
409
diff --git a/core/multimedia/opieplayer/modplug/modplug.pro b/core/multimedia/opieplayer/modplug/modplug.pro
new file mode 100644
index 0000000..13b8927
--- a/dev/null
+++ b/core/multimedia/opieplayer/modplug/modplug.pro
@@ -0,0 +1,19 @@
1 TEMPLATE= lib
2 CONFIG += qt warn_on release
3 HEADERS = it_defs.h modplugin.h modpluginimpl.h sndfile.h stdafx.h memfile.h
4 SOURCES = fastmix.cpp load_669.cpp load_amf.cpp load_ams.cpp \
5 load_dbm.cpp load_dmf.cpp load_dsm.cpp load_far.cpp \
6 load_it.cpp load_j2b.cpp load_mdl.cpp load_med.cpp \
7 load_mod.cpp load_mt2.cpp load_mtm.cpp load_okt.cpp \
8 load_psm.cpp load_ptm.cpp load_s3m.cpp load_stm.cpp \
9 load_ult.cpp load_umx.cpp load_xm.cpp \
10 mmcmp.cpp modplugin.cpp modpluginimpl.cpp snd_dsp.cpp \
11 snd_flt.cpp snd_fx.cpp sndfile.cpp sndmix.cpp tables.cpp \
12 memfile.cpp
13 TARGET = modplugin
14 DESTDIR = $(OPIEDIR)/plugins/codecs
15 INCLUDEPATH += $(OPIEDIR)/include
16DEPENDPATH += $(OPIEDIR)/include
17LIBS += -lqpe -lm
18 VERSION = 1.0.0
19
diff --git a/core/multimedia/opieplayer/modplug/modplugin.cpp b/core/multimedia/opieplayer/modplug/modplugin.cpp
new file mode 100644
index 0000000..e606c52
--- a/dev/null
+++ b/core/multimedia/opieplayer/modplug/modplugin.cpp
@@ -0,0 +1,263 @@
1/* This file is part of the KDE project
2 Copyright (C) 2002 Simon Hausmann <hausmann@kde.org>
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; see the file COPYING. If not, write to
16 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 Boston, MA 02111-1307, USA.
18*/
19
20#include "modplugin.h"
21
22#include "memfile.h"
23
24#include <qfileinfo.h>
25
26ModPlugin::ModPlugin()
27{
28}
29
30ModPlugin::~ModPlugin()
31{
32 close();
33}
34
35const char *ModPlugin::pluginName()
36{
37 return "ModPlugin";
38}
39
40const char *ModPlugin::pluginComment()
41{
42 return "LibModPlug based MOD/XM/S3M/IT module player plugin";
43}
44
45double ModPlugin::pluginVersion()
46{
47 return 1.0;
48}
49
50bool ModPlugin::isFileSupported( const QString &file )
51{
52 static const char * const patterns [] =
53 {
54 "669", "amf", "apun", "dsm", "far", "gdm", "imf", "it",
55 "med", "mod", "mtm", "nst", "s3m", "stm", "stx", "ult",
56 "uni", "xm"
57 };
58 static const uchar patternCount = sizeof( patterns ) / sizeof( patterns[ 0 ] );
59
60 QString ext = QFileInfo( file ).extension( false /* complete */ ).lower();
61 for ( uchar i = 0; i < patternCount; ++i )
62 if ( QString::fromLatin1( patterns[ i ] ) == ext )
63 return true;
64
65 return false;
66}
67
68bool ModPlugin::open( const QString &_file )
69{
70 MemFile f( _file );
71 if ( !f.open( IO_ReadOnly ) )
72 return false;
73
74 CSoundFile::SetWaveConfig( s_frequency, s_bytesPerSample * 8, s_channels );
75
76 CSoundFile::SetWaveConfigEx( false, /* surround */
77 true, /* no oversampling */
78 false, /* reverb */
79 true, /* high quality resampler */
80 true, /* megabass ;) */
81 true, /* noise reduction */
82 false /* some eq stuff I didn't really understand..*/ );
83
84 CSoundFile::SetResamplingMode( SRCMODE_POLYPHASE );
85
86 QByteArray &rawData = f.data();
87 if ( !Create( reinterpret_cast<BYTE *>( rawData.data() ), rawData.size() ) )
88 return false;
89
90 m_songTime = GetSongTime();
91 m_maxPosition = GetMaxPosition();
92 return true;
93}
94
95bool ModPlugin::close()
96{
97 return Destroy();
98}
99
100bool ModPlugin::isOpen()
101{
102 return m_nType != MOD_TYPE_NONE;
103}
104
105const QString &ModPlugin::fileInfo()
106{
107 return QString::null; // ###
108}
109
110int ModPlugin::audioStreams()
111{
112 return 1;
113}
114
115int ModPlugin::audioChannels( int )
116{
117 return s_channels;
118}
119
120int ModPlugin::audioFrequency( int )
121{
122 return s_frequency;
123}
124
125int ModPlugin::audioSamples( int )
126{
127 return m_songTime * s_frequency;
128}
129
130bool ModPlugin::audioSetSample( long sample, int )
131{
132 float position = ( sample / s_frequency ) * m_maxPosition / m_songTime;
133 SetCurrentPos( (int)position );
134 return true;
135}
136
137long ModPlugin::audioGetSample( int )
138{
139 return GetCurrentPos() * s_frequency;
140}
141
142bool ModPlugin::audioReadSamples( short *output, int /*channels*/, long samples,
143 long &samplesRead, int )
144{
145 unsigned long totalAmountInBytes = samples * s_bytesPerSample * s_channels;
146 samplesRead = Read( output, totalAmountInBytes );
147 // it can happen that our prediction about the total amount of samples
148 // is wrong. The mediaplayer can't handle the situation of returning 0 read bytes
149 // very well. So instead let's fill up the remaining bytes with zeroes.
150 if ( samplesRead == 0 )
151 {
152 memset( reinterpret_cast<char *>( output ), 0, totalAmountInBytes );
153 samplesRead = samples;
154 }
155
156 return true;
157}
158
159int ModPlugin::videoStreams()
160{
161 return 0;
162}
163
164int ModPlugin::videoWidth( int )
165{
166 return 0;
167}
168
169int ModPlugin::videoHeight( int )
170{
171 return 0;
172}
173
174double ModPlugin::videoFrameRate( int )
175{
176 return 0;
177}
178
179int ModPlugin::videoFrames( int )
180{
181 return 0;
182}
183
184bool ModPlugin::videoSetFrame( long, int )
185{
186 return 0;
187}
188
189long ModPlugin::videoGetFrame( int )
190{
191 return 0;
192}
193
194bool ModPlugin::videoReadFrame( unsigned char **, int, int, int, int,
195 ColorFormat, int )
196{
197 return false;
198}
199
200bool ModPlugin::videoReadScaledFrame( unsigned char **, int, int, int, int,
201 int, int, ColorFormat, int )
202{
203 return false;
204}
205
206bool ModPlugin::videoReadYUVFrame( char *, char *, char *, int, int, int,
207 int, int )
208{
209 return false;
210}
211
212double ModPlugin::getTime()
213{
214 return 0.0; // ###
215}
216
217bool ModPlugin::setSMP( int )
218{
219 return false;
220}
221
222bool ModPlugin::setMMX( bool )
223{
224 return false;
225}
226
227bool ModPlugin::supportsAudio()
228{
229 return true;
230}
231
232bool ModPlugin::supportsVideo()
233{
234 return false;
235}
236
237bool ModPlugin::supportsYUV()
238{
239 return false;
240}
241
242bool ModPlugin::supportsMMX()
243{
244 return false;
245}
246
247bool ModPlugin::supportsSMP()
248{
249 return false;
250}
251
252bool ModPlugin::supportsStereo()
253{
254 return true;
255}
256
257bool ModPlugin::supportsScaling()
258{
259 return false;
260}
261
262/* vim: et sw=4
263 */
diff --git a/core/multimedia/opieplayer/modplug/modplugin.h b/core/multimedia/opieplayer/modplug/modplugin.h
new file mode 100644
index 0000000..a778223
--- a/dev/null
+++ b/core/multimedia/opieplayer/modplug/modplugin.h
@@ -0,0 +1,95 @@
1/* This file is part of the KDE project
2 Copyright (C) 2002 Simon Hausmann <hausmann@kde.org>
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; see the file COPYING. If not, write to
16 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 Boston, MA 02111-1307, USA.
18*/
19#ifndef MOD_PLUGIN_H
20#define MOD_PLUGIN_H
21
22//#include "../mediaplayerplugininterface.h"
23#include <qpe/mediaplayerplugininterface.h>
24
25#include "stdafx.h"
26#include "sndfile.h"
27
28class ModPlugin : public MediaPlayerDecoder,
29 public CSoundFile
30{
31public:
32 ModPlugin();
33 virtual ~ModPlugin();
34
35 virtual const char *pluginName();
36 virtual const char *pluginComment();
37 virtual double pluginVersion();
38
39 virtual bool isFileSupported( const QString &file );
40 virtual bool open( const QString &file );
41 virtual bool close();
42 virtual bool isOpen();
43 virtual const QString &fileInfo();
44
45 virtual int audioStreams();
46 virtual int audioChannels( int stream );
47 virtual int audioFrequency( int stream );
48 virtual int audioSamples( int stream );
49 virtual bool audioSetSample( long sample, int stream );
50 virtual long audioGetSample( int stream );
51 virtual bool audioReadSamples( short *output, int channels, long samples,
52 long &samplesRead, int stream );
53
54 virtual int videoStreams();
55 virtual int videoWidth( int stream );
56 virtual int videoHeight( int stream );
57 virtual double videoFrameRate( int stream );
58 virtual int videoFrames( int stream );
59 virtual bool videoSetFrame( long sample, int stream );
60 virtual long videoGetFrame( int stream );
61 virtual bool videoReadFrame( unsigned char **outputRows, int inX, int inY,
62 int inW, int inH, ColorFormat colorModel, int stream );
63 virtual bool videoReadScaledFrame( unsigned char **outputRows, int inX, int inY,
64 int inW, int inH, int outW, int outH,
65 ColorFormat colorModel, int stream );
66 virtual bool videoReadYUVFrame( char *yOutput, char *uOutput, char *vOutput,
67 int inX, int inY, int inW, int inH, int stream );
68
69 virtual double getTime();
70
71 virtual bool setSMP( int cpus );
72 virtual bool setMMX( bool useMMX );
73
74 virtual bool supportsAudio();
75 virtual bool supportsVideo();
76 virtual bool supportsYUV();
77 virtual bool supportsMMX();
78 virtual bool supportsSMP();
79 virtual bool supportsStereo();
80 virtual bool supportsScaling();
81
82private:
83 int m_songTime;
84 int m_maxPosition;
85
86 static const int s_channels = 2;
87 static const int s_bytesPerSample = 2;
88 static const int s_maxChannels = 128;
89 static const int s_frequency = 44100;
90 static const int s_audioBufferSize = 32768;
91};
92
93#endif
94/* vim: et sw=4
95 */
diff --git a/core/multimedia/opieplayer/modplug/modpluginimpl.cpp b/core/multimedia/opieplayer/modplug/modpluginimpl.cpp
new file mode 100644
index 0000000..6e64e76
--- a/dev/null
+++ b/core/multimedia/opieplayer/modplug/modpluginimpl.cpp
@@ -0,0 +1,60 @@
1/* This file is part of the KDE project
2 Copyright (C) 2002 Simon Hausmann <hausmann@kde.org>
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; see the file COPYING. If not, write to
16 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 Boston, MA 02111-1307, USA.
18*/
19
20#include "modplugin.h"
21#include "modpluginimpl.h"
22
23ModPluginImpl::ModPluginImpl()
24 :m_plugin( 0 ), ref( 0 )
25{
26}
27
28ModPluginImpl::~ModPluginImpl()
29{
30 delete m_plugin;
31}
32
33#ifndef QT_NO_COMPONENT
34
35QRESULT ModPluginImpl::queryInterface( const QUuid &uuid, QUnknownInterface **iface )
36{
37 *iface = 0;
38 if ( ( uuid == IID_QUnknown ) || ( uuid == IID_MediaPlayerPlugin ) )
39 *iface = this, (*iface)->addRef();
40 return QS_OK;
41}
42
43Q_EXPORT_INTERFACE()
44{
45 Q_CREATE_INSTANCE( ModPluginImpl )
46}
47
48#endif
49
50MediaPlayerDecoder *ModPluginImpl::decoder()
51{
52 if ( !m_plugin )
53 m_plugin = new ModPlugin;
54 return m_plugin;
55}
56
57MediaPlayerEncoder *ModPluginImpl::encoder()
58{
59 return 0;
60}
diff --git a/core/multimedia/opieplayer/modplug/modpluginimpl.h b/core/multimedia/opieplayer/modplug/modpluginimpl.h
new file mode 100644
index 0000000..c306a71
--- a/dev/null
+++ b/core/multimedia/opieplayer/modplug/modpluginimpl.h
@@ -0,0 +1,46 @@
1/* This file is part of the KDE project
2 Copyright (C) 2002 Simon Hausmann <hausmann@kde.org>
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; see the file COPYING. If not, write to
16 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 Boston, MA 02111-1307, USA.
18*/
19#ifndef MOD_PLUGIN_IMPL_H
20#define MOD_PLUGIN_IMPL_H
21
22#include <qpe/mediaplayerplugininterface.h>
23
24class ModPlugin;
25
26class ModPluginImpl : public MediaPlayerPluginInterface
27{
28public:
29 ModPluginImpl();
30 virtual ~ModPluginImpl();
31#ifndef QT_NO_COMPONENT
32
33 QRESULT queryInterface( const QUuid &uuid, QUnknownInterface **iface );
34 Q_REFCOUNT
35
36#endif
37
38 virtual MediaPlayerDecoder *decoder();
39 virtual MediaPlayerEncoder *encoder();
40
41private:
42 ModPlugin *m_plugin;
43 ulong ref;
44};
45
46#endif
diff --git a/core/multimedia/opieplayer/modplug/opie-modplugin.control b/core/multimedia/opieplayer/modplug/opie-modplugin.control
new file mode 100644
index 0000000..2754ccf
--- a/dev/null
+++ b/core/multimedia/opieplayer/modplug/opie-modplugin.control
@@ -0,0 +1,9 @@
1Files: plugins/codecs/libmodplugin.so*
2Priority: optional
3Section: opie/plugins
4Maintainer: Simon Hausmann <hausmann@kde.org>, L.J. Potter <llornkcor@handhelds.org>
5Architecture: arm
6Version: 2.0.2
7Depends: opie-base opie-player
8Description: MOD/XM/S3M/IT plugin using libmodplug
9 Plugin to play MOD/XM/S3M/IT amiga tracker modules with the mediaplayer in the Opie environment.
diff --git a/core/multimedia/opieplayer/modplug/opie-modplugin.postinst b/core/multimedia/opieplayer/modplug/opie-modplugin.postinst
new file mode 100755
index 0000000..c6ba49b
--- a/dev/null
+++ b/core/multimedia/opieplayer/modplug/opie-modplugin.postinst
@@ -0,0 +1,24 @@
1#!/bin/sh
2
3OPIEDIR=/opt/QtPalmtop
4MIMEFILE=$OPIEDIR/etc/mime.types
5MEDIAPLAYER=$OPIEDIR/apps/Applications/opieplayer.desktop
6MIMETYPE="audio/x-mod"
7 MIMELINE="$MIMETYPE669 amf apun dsm far gdm imf it med mod mtm nst s3m stm stx ult uni xm"
8
9grep -q "$MIMELINE" $MIMEFILE
10if [ $? != 0 ]; then
11 echo "appending mod/s3m/etc to $MIMEFILE"
12
13 echo "$MIMELINE" >> $MIMEFILE
14fi
15
16grep -q "$MIMETYPE" $MEDIAPLAYER
17if [ $? != 0 ]; then
18 echo "appending $MIMETYPE to $MEDIAPLAYER"
19
20 tmpfile=/tmp/qpe-modplugin-$$.tmp
21 cat $MEDIAPLAYER | sed -e "s,^MimeType=\(.*\)\$,MimeType=\\1;$MIMETYPE," > $tmpfile
22 mv $tmpfile $MEDIAPLAYER
23fi
24
diff --git a/core/multimedia/opieplayer/modplug/opie-modplugin.postrm b/core/multimedia/opieplayer/modplug/opie-modplugin.postrm
new file mode 100755
index 0000000..c043682
--- a/dev/null
+++ b/core/multimedia/opieplayer/modplug/opie-modplugin.postrm
@@ -0,0 +1,26 @@
1#!/bin/sh
2
3QPEDIR=/opt/QtPalmtop
4MIMEFILE=$OPIEDIR/etc/mime.types
5MEDIAPLAYER=$OPIEDIR/apps/Applications/opieplayer.desktop
6MIMETYPE="audio/x-mod"
7 MIMELINE="$MIMETYPE669 amf apun dsm far gdm imf it med mod mtm nst s3m stm stx ult uni xm"
8
9tmpfile=/tmp/qpe-modplugin$$.tmp
10
11grep -q "$MIMELINE" $MIMEFILE
12if [ $? == 0 ]; then
13 echo "removing mod/s3m/etc from $MIMEFILE"
14
15 grep -v "$MIMELINE" $MIMEFILE > $tmpfile
16 mv $tmpfile $MIMEFILE
17fi
18
19grep -q "$MIMETYPE" $MEDIAPLAYER
20if [ $? == 0 ]; then
21 echo "removing $MIMETYPE from $MEDIAPLAYER"
22
23 cat $MEDIAPLAYER | sed -e "s,^MimeType=\(.*\);$MIMETYPE\(\.*\)\$,MimeType=\\1\\2," > $tmpfile
24 mv $tmpfile $MEDIAPLAYER
25fi
26
diff --git a/core/multimedia/opieplayer/modplug/snd_dsp.cpp b/core/multimedia/opieplayer/modplug/snd_dsp.cpp
new file mode 100644
index 0000000..c14194e
--- a/dev/null
+++ b/core/multimedia/opieplayer/modplug/snd_dsp.cpp
@@ -0,0 +1,488 @@
1/*
2 * This program is free software; you can redistribute it and modify it
3 * under the terms of the GNU General Public License as published by the
4 * Free Software Foundation; either version 2 of the license or (at your
5 * option) any later version.
6 *
7 * Authors: Olivier Lapicque <olivierl@jps.net>
8*/
9
10#include "stdafx.h"
11#include "sndfile.h"
12
13#ifdef FASTSOUNDLIB
14#define NO_REVERB
15#endif
16
17
18// Delayed Surround Filters
19#ifndef FASTSOUNDLIB
20 #define nDolbyHiFltAttn 6
21 #define nDolbyHiFltMask 3
22 #define DOLBYATTNROUNDUP31
23#else
24 #define nDolbyHiFltAttn 3
25 #define nDolbyHiFltMask 3
26 #define DOLBYATTNROUNDUP3
27#endif
28
29// Bass Expansion
30 #define XBASS_DELAY 14// 2.5 ms
31
32// Buffer Sizes
33 #define XBASSBUFFERSIZE 64 // 2 ms at 50KHz
34 #define FILTERBUFFERSIZE 64 // 1.25 ms
35 #define SURROUNDBUFFERSIZE((MAX_SAMPLE_RATE * 50) / 1000)
36 #define REVERBBUFFERSIZE((MAX_SAMPLE_RATE * 200) / 1000)
37 #define REVERBBUFFERSIZE2((REVERBBUFFERSIZE*13) / 17)
38 #define REVERBBUFFERSIZE3((REVERBBUFFERSIZE*7) / 13)
39 #define REVERBBUFFERSIZE4((REVERBBUFFERSIZE*7) / 19)
40
41
42// DSP Effects: PUBLIC members
43UINT CSoundFile::m_nXBassDepth = 6;
44UINT CSoundFile::m_nXBassRange = XBASS_DELAY;
45UINT CSoundFile::m_nReverbDepth = 1;
46UINT CSoundFile::m_nReverbDelay = 100;
47UINT CSoundFile::m_nProLogicDepth = 12;
48UINT CSoundFile::m_nProLogicDelay = 20;
49
50////////////////////////////////////////////////////////////////////
51// DSP Effects internal state
52
53// Bass Expansion: low-pass filter
54static LONG nXBassSum = 0;
55static LONG nXBassBufferPos = 0;
56static LONG nXBassDlyPos = 0;
57static LONG nXBassMask = 0;
58
59// Noise Reduction: simple low-pass filter
60static LONG nLeftNR = 0;
61static LONG nRightNR = 0;
62
63// Surround Encoding: 1 delay line + low-pass filter + high-pass filter
64static LONG nSurroundSize = 0;
65static LONG nSurroundPos = 0;
66static LONG nDolbyDepth = 0;
67static LONG nDolbyLoDlyPos = 0;
68static LONG nDolbyLoFltPos = 0;
69static LONG nDolbyLoFltSum = 0;
70static LONG nDolbyHiFltPos = 0;
71static LONG nDolbyHiFltSum = 0;
72
73// Reverb: 4 delay lines + high-pass filter + low-pass filter
74#ifndef NO_REVERB
75static LONG nReverbSize = 0;
76static LONG nReverbBufferPos = 0;
77static LONG nReverbSize2 = 0;
78static LONG nReverbBufferPos2 = 0;
79static LONG nReverbSize3 = 0;
80static LONG nReverbBufferPos3 = 0;
81static LONG nReverbSize4 = 0;
82static LONG nReverbBufferPos4 = 0;
83static LONG nReverbLoFltSum = 0;
84static LONG nReverbLoFltPos = 0;
85static LONG nReverbLoDlyPos = 0;
86static LONG nFilterAttn = 0;
87static LONG gRvbLowPass[8];
88static LONG gRvbLPPos = 0;
89static LONG gRvbLPSum = 0;
90static LONG ReverbLoFilterBuffer[XBASSBUFFERSIZE];
91static LONG ReverbLoFilterDelay[XBASSBUFFERSIZE];
92static LONG ReverbBuffer[REVERBBUFFERSIZE];
93static LONG ReverbBuffer2[REVERBBUFFERSIZE2];
94static LONG ReverbBuffer3[REVERBBUFFERSIZE3];
95static LONG ReverbBuffer4[REVERBBUFFERSIZE4];
96#endif
97static LONG XBassBuffer[XBASSBUFFERSIZE];
98static LONG XBassDelay[XBASSBUFFERSIZE];
99static LONG DolbyLoFilterBuffer[XBASSBUFFERSIZE];
100static LONG DolbyLoFilterDelay[XBASSBUFFERSIZE];
101static LONG DolbyHiFilterBuffer[FILTERBUFFERSIZE];
102static LONG SurroundBuffer[SURROUNDBUFFERSIZE];
103
104// Access the main temporary mix buffer directly: avoids an extra pointer
105extern int MixSoundBuffer[MIXBUFFERSIZE*2];
106//cextern int MixReverbBuffer[MIXBUFFERSIZE*2];
107extern int MixReverbBuffer[MIXBUFFERSIZE*2];
108
109static UINT GetMaskFromSize(UINT len)
110//-----------------------------------
111{
112 UINT n = 2;
113 while (n <= len) n <<= 1;
114 return ((n >> 1) - 1);
115}
116
117
118void CSoundFile::InitializeDSP(BOOL bReset)
119//-----------------------------------------
120{
121 if (!m_nReverbDelay) m_nReverbDelay = 100;
122 if (!m_nXBassRange) m_nXBassRange = XBASS_DELAY;
123 if (!m_nProLogicDelay) m_nProLogicDelay = 20;
124 if (m_nXBassDepth > 8) m_nXBassDepth = 8;
125 if (m_nXBassDepth < 2) m_nXBassDepth = 2;
126 if (bReset)
127 {
128 // Noise Reduction
129 nLeftNR = nRightNR = 0;
130 }
131 // Pro-Logic Surround
132 nSurroundPos = nSurroundSize = 0;
133 nDolbyLoFltPos = nDolbyLoFltSum = nDolbyLoDlyPos = 0;
134 nDolbyHiFltPos = nDolbyHiFltSum = 0;
135 if (gdwSoundSetup & SNDMIX_SURROUND)
136 {
137 memset(DolbyLoFilterBuffer, 0, sizeof(DolbyLoFilterBuffer));
138 memset(DolbyHiFilterBuffer, 0, sizeof(DolbyHiFilterBuffer));
139 memset(DolbyLoFilterDelay, 0, sizeof(DolbyLoFilterDelay));
140 memset(SurroundBuffer, 0, sizeof(SurroundBuffer));
141 nSurroundSize = (gdwMixingFreq * m_nProLogicDelay) / 1000;
142 if (nSurroundSize > SURROUNDBUFFERSIZE) nSurroundSize = SURROUNDBUFFERSIZE;
143 if (m_nProLogicDepth < 8) nDolbyDepth = (32 >> m_nProLogicDepth) + 32;
144 else nDolbyDepth = (m_nProLogicDepth < 16) ? (8 + (m_nProLogicDepth - 8) * 7) : 64;
145 nDolbyDepth >>= 2;
146 }
147 // Reverb Setup
148#ifndef NO_REVERB
149 if (gdwSoundSetup & SNDMIX_REVERB)
150 {
151 UINT nrs = (gdwMixingFreq * m_nReverbDelay) / 1000;
152 UINT nfa = m_nReverbDepth+1;
153 if (nrs > REVERBBUFFERSIZE) nrs = REVERBBUFFERSIZE;
154 if ((bReset) || (nrs != (UINT)nReverbSize) || (nfa != (UINT)nFilterAttn))
155 {
156 nFilterAttn = nfa;
157 nReverbSize = nrs;
158 nReverbBufferPos = nReverbBufferPos2 = nReverbBufferPos3 = nReverbBufferPos4 = 0;
159 nReverbLoFltSum = nReverbLoFltPos = nReverbLoDlyPos = 0;
160 gRvbLPSum = gRvbLPPos = 0;
161 nReverbSize2 = (nReverbSize * 13) / 17;
162 if (nReverbSize2 > REVERBBUFFERSIZE2) nReverbSize2 = REVERBBUFFERSIZE2;
163 nReverbSize3 = (nReverbSize * 7) / 13;
164 if (nReverbSize3 > REVERBBUFFERSIZE3) nReverbSize3 = REVERBBUFFERSIZE3;
165 nReverbSize4 = (nReverbSize * 7) / 19;
166 if (nReverbSize4 > REVERBBUFFERSIZE4) nReverbSize4 = REVERBBUFFERSIZE4;
167 memset(ReverbLoFilterBuffer, 0, sizeof(ReverbLoFilterBuffer));
168 memset(ReverbLoFilterDelay, 0, sizeof(ReverbLoFilterDelay));
169 memset(ReverbBuffer, 0, sizeof(ReverbBuffer));
170 memset(ReverbBuffer2, 0, sizeof(ReverbBuffer2));
171 memset(ReverbBuffer3, 0, sizeof(ReverbBuffer3));
172 memset(ReverbBuffer4, 0, sizeof(ReverbBuffer4));
173 memset(gRvbLowPass, 0, sizeof(gRvbLowPass));
174 }
175 } else nReverbSize = 0;
176#endif
177 BOOL bResetBass = FALSE;
178 // Bass Expansion Reset
179 if (gdwSoundSetup & SNDMIX_MEGABASS)
180 {
181 UINT nXBassSamples = (gdwMixingFreq * m_nXBassRange) / 10000;
182 if (nXBassSamples > XBASSBUFFERSIZE) nXBassSamples = XBASSBUFFERSIZE;
183 UINT mask = GetMaskFromSize(nXBassSamples);
184 if ((bReset) || (mask != (UINT)nXBassMask))
185 {
186 nXBassMask = mask;
187 bResetBass = TRUE;
188 }
189 } else
190 {
191 nXBassMask = 0;
192 bResetBass = TRUE;
193 }
194 if (bResetBass)
195 {
196 nXBassSum = nXBassBufferPos = nXBassDlyPos = 0;
197 memset(XBassBuffer, 0, sizeof(XBassBuffer));
198 memset(XBassDelay, 0, sizeof(XBassDelay));
199 }
200}
201
202
203void CSoundFile::ProcessStereoDSP(int count)
204//------------------------------------------
205{
206#ifndef NO_REVERB
207 // Reverb
208 if (gdwSoundSetup & SNDMIX_REVERB)
209 {
210 int *pr = MixSoundBuffer, *pin = MixReverbBuffer, rvbcount = count;
211 do
212 {
213 int echo = ReverbBuffer[nReverbBufferPos] + ReverbBuffer2[nReverbBufferPos2]
214 + ReverbBuffer3[nReverbBufferPos3] + ReverbBuffer4[nReverbBufferPos4];// echo = reverb signal
215 // Delay line and remove Low Frequencies // v = original signal
216 int echodly = ReverbLoFilterDelay[nReverbLoDlyPos];// echodly = delayed signal
217 ReverbLoFilterDelay[nReverbLoDlyPos] = echo >> 1;
218 nReverbLoDlyPos++;
219 nReverbLoDlyPos &= 0x1F;
220 int n = nReverbLoFltPos;
221 nReverbLoFltSum -= ReverbLoFilterBuffer[n];
222 int tmp = echo / 128;
223 ReverbLoFilterBuffer[n] = tmp;
224 nReverbLoFltSum += tmp;
225 echodly -= nReverbLoFltSum;
226 nReverbLoFltPos = (n + 1) & 0x3F;
227 // Reverb
228 int v = (pin[0]+pin[1]) >> nFilterAttn;
229 pr[0] += pin[0] + echodly;
230 pr[1] += pin[1] + echodly;
231 v += echodly >> 2;
232 ReverbBuffer3[nReverbBufferPos3] = v;
233 ReverbBuffer4[nReverbBufferPos4] = v;
234 v += echodly >> 4;
235 v >>= 1;
236 gRvbLPSum -= gRvbLowPass[gRvbLPPos];
237 gRvbLPSum += v;
238 gRvbLowPass[gRvbLPPos] = v;
239 gRvbLPPos++;
240 gRvbLPPos &= 7;
241 int vlp = gRvbLPSum >> 2;
242 ReverbBuffer[nReverbBufferPos] = vlp;
243 ReverbBuffer2[nReverbBufferPos2] = vlp;
244 if (++nReverbBufferPos >= nReverbSize) nReverbBufferPos = 0;
245 if (++nReverbBufferPos2 >= nReverbSize2) nReverbBufferPos2 = 0;
246 if (++nReverbBufferPos3 >= nReverbSize3) nReverbBufferPos3 = 0;
247 if (++nReverbBufferPos4 >= nReverbSize4) nReverbBufferPos4 = 0;
248 pr += 2;
249 pin += 2;
250 } while (--rvbcount);
251 }
252#endif
253 // Dolby Pro-Logic Surround
254 if (gdwSoundSetup & SNDMIX_SURROUND)
255 {
256 int *pr = MixSoundBuffer, n = nDolbyLoFltPos;
257 for (int r=count; r; r--)
258 {
259 int v = (pr[0]+pr[1]+DOLBYATTNROUNDUP) >> (nDolbyHiFltAttn+1);
260#ifndef FASTSOUNDLIB
261 v *= (int)nDolbyDepth;
262#endif
263 // Low-Pass Filter
264 nDolbyHiFltSum -= DolbyHiFilterBuffer[nDolbyHiFltPos];
265 DolbyHiFilterBuffer[nDolbyHiFltPos] = v;
266 nDolbyHiFltSum += v;
267 v = nDolbyHiFltSum;
268 nDolbyHiFltPos++;
269 nDolbyHiFltPos &= nDolbyHiFltMask;
270 // Surround
271 int secho = SurroundBuffer[nSurroundPos];
272 SurroundBuffer[nSurroundPos] = v;
273 // Delay line and remove low frequencies
274 v = DolbyLoFilterDelay[nDolbyLoDlyPos]; // v = delayed signal
275 DolbyLoFilterDelay[nDolbyLoDlyPos] = secho;// secho = signal
276 nDolbyLoDlyPos++;
277 nDolbyLoDlyPos &= 0x1F;
278 nDolbyLoFltSum -= DolbyLoFilterBuffer[n];
279 int tmp = secho / 64;
280 DolbyLoFilterBuffer[n] = tmp;
281 nDolbyLoFltSum += tmp;
282 v -= nDolbyLoFltSum;
283 n++;
284 n &= 0x3F;
285 // Add echo
286 pr[0] += v;
287 pr[1] -= v;
288 if (++nSurroundPos >= nSurroundSize) nSurroundPos = 0;
289 pr += 2;
290 }
291 nDolbyLoFltPos = n;
292 }
293 // Bass Expansion
294 if (gdwSoundSetup & SNDMIX_MEGABASS)
295 {
296 int *px = MixSoundBuffer;
297 int xba = m_nXBassDepth+1, xbamask = (1 << xba) - 1;
298 int n = nXBassBufferPos;
299 for (int x=count; x; x--)
300 {
301 nXBassSum -= XBassBuffer[n];
302 int tmp0 = px[0] + px[1];
303 int tmp = (tmp0 + ((tmp0 >> 31) & xbamask)) >> xba;
304 XBassBuffer[n] = tmp;
305 nXBassSum += tmp;
306 int v = XBassDelay[nXBassDlyPos];
307 XBassDelay[nXBassDlyPos] = px[0];
308 px[0] = v + nXBassSum;
309 v = XBassDelay[nXBassDlyPos+1];
310 XBassDelay[nXBassDlyPos+1] = px[1];
311 px[1] = v + nXBassSum;
312 nXBassDlyPos = (nXBassDlyPos + 2) & nXBassMask;
313 px += 2;
314 n++;
315 n &= nXBassMask;
316 }
317 nXBassBufferPos = n;
318 }
319 // Noise Reduction
320 if (gdwSoundSetup & SNDMIX_NOISEREDUCTION)
321 {
322 int n1 = nLeftNR, n2 = nRightNR;
323 int *pnr = MixSoundBuffer;
324 for (int nr=count; nr; nr--)
325 {
326 int vnr = pnr[0] >> 1;
327 pnr[0] = vnr + n1;
328 n1 = vnr;
329 vnr = pnr[1] >> 1;
330 pnr[1] = vnr + n2;
331 n2 = vnr;
332 pnr += 2;
333 }
334 nLeftNR = n1;
335 nRightNR = n2;
336 }
337}
338
339
340void CSoundFile::ProcessMonoDSP(int count)
341//----------------------------------------
342{
343#ifndef NO_REVERB
344 // Reverb
345 if (gdwSoundSetup & SNDMIX_REVERB)
346 {
347 int *pr = MixSoundBuffer, rvbcount = count, *pin = MixReverbBuffer;
348 do
349 {
350 int echo = ReverbBuffer[nReverbBufferPos] + ReverbBuffer2[nReverbBufferPos2]
351 + ReverbBuffer3[nReverbBufferPos3] + ReverbBuffer4[nReverbBufferPos4];// echo = reverb signal
352 // Delay line and remove Low Frequencies // v = original signal
353 int echodly = ReverbLoFilterDelay[nReverbLoDlyPos];// echodly = delayed signal
354 ReverbLoFilterDelay[nReverbLoDlyPos] = echo >> 1;
355 nReverbLoDlyPos++;
356 nReverbLoDlyPos &= 0x1F;
357 int n = nReverbLoFltPos;
358 nReverbLoFltSum -= ReverbLoFilterBuffer[n];
359 int tmp = echo / 128;
360 ReverbLoFilterBuffer[n] = tmp;
361 nReverbLoFltSum += tmp;
362 echodly -= nReverbLoFltSum;
363 nReverbLoFltPos = (n + 1) & 0x3F;
364 // Reverb
365 int v = pin[0] >> (nFilterAttn-1);
366 *pr++ += pin[0] + echodly;
367 pin++;
368 v += echodly >> 2;
369 ReverbBuffer3[nReverbBufferPos3] = v;
370 ReverbBuffer4[nReverbBufferPos4] = v;
371 v += echodly >> 4;
372 v >>= 1;
373 gRvbLPSum -= gRvbLowPass[gRvbLPPos];
374 gRvbLPSum += v;
375 gRvbLowPass[gRvbLPPos] = v;
376 gRvbLPPos++;
377 gRvbLPPos &= 7;
378 int vlp = gRvbLPSum >> 2;
379 ReverbBuffer[nReverbBufferPos] = vlp;
380 ReverbBuffer2[nReverbBufferPos2] = vlp;
381 if (++nReverbBufferPos >= nReverbSize) nReverbBufferPos = 0;
382 if (++nReverbBufferPos2 >= nReverbSize2) nReverbBufferPos2 = 0;
383 if (++nReverbBufferPos3 >= nReverbSize3) nReverbBufferPos3 = 0;
384 if (++nReverbBufferPos4 >= nReverbSize4) nReverbBufferPos4 = 0;
385 } while (--rvbcount);
386 }
387#endif
388 // Bass Expansion
389 if (gdwSoundSetup & SNDMIX_MEGABASS)
390 {
391 int *px = MixSoundBuffer;
392 int xba = m_nXBassDepth, xbamask = (1 << xba)-1;
393 int n = nXBassBufferPos;
394 for (int x=count; x; x--)
395 {
396 nXBassSum -= XBassBuffer[n];
397 int tmp0 = *px;
398 int tmp = (tmp0 + ((tmp0 >> 31) & xbamask)) >> xba;
399 XBassBuffer[n] = tmp;
400 nXBassSum += tmp;
401 int v = XBassDelay[nXBassDlyPos];
402 XBassDelay[nXBassDlyPos] = *px;
403 *px++ = v + nXBassSum;
404 nXBassDlyPos = (nXBassDlyPos + 2) & nXBassMask;
405 n++;
406 n &= nXBassMask;
407 }
408 nXBassBufferPos = n;
409 }
410 // Noise Reduction
411 if (gdwSoundSetup & SNDMIX_NOISEREDUCTION)
412 {
413 int n = nLeftNR;
414 int *pnr = MixSoundBuffer;
415 for (int nr=count; nr; pnr++, nr--)
416 {
417 int vnr = *pnr >> 1;
418 *pnr = vnr + n;
419 n = vnr;
420 }
421 nLeftNR = n;
422 }
423}
424
425
426/////////////////////////////////////////////////////////////////
427// Clean DSP Effects interface
428
429// [Reverb level 0(quiet)-100(loud)], [delay in ms, usually 40-200ms]
430BOOL CSoundFile::SetReverbParameters(UINT nDepth, UINT nDelay)
431//------------------------------------------------------------
432{
433 if (nDepth > 100) nDepth = 100;
434 UINT gain = nDepth / 20;
435 if (gain > 4) gain = 4;
436 m_nReverbDepth = 4 - gain;
437 if (nDelay < 40) nDelay = 40;
438 if (nDelay > 250) nDelay = 250;
439 m_nReverbDelay = nDelay;
440 return TRUE;
441}
442
443
444// [XBass level 0(quiet)-100(loud)], [cutoff in Hz 20-100]
445BOOL CSoundFile::SetXBassParameters(UINT nDepth, UINT nRange)
446//-----------------------------------------------------------
447{
448 if (nDepth > 100) nDepth = 100;
449 UINT gain = nDepth / 20;
450 if (gain > 4) gain = 4;
451 m_nXBassDepth = 8 - gain;// filter attenuation 1/256 .. 1/16
452 UINT range = nRange / 5;
453 if (range > 5) range -= 5; else range = 0;
454 if (nRange > 16) nRange = 16;
455 m_nXBassRange = 21 - range;// filter average on 0.5-1.6ms
456 return TRUE;
457}
458
459
460// [Surround level 0(quiet)-100(heavy)] [delay in ms, usually 5-50ms]
461BOOL CSoundFile::SetSurroundParameters(UINT nDepth, UINT nDelay)
462//--------------------------------------------------------------
463{
464 UINT gain = (nDepth * 16) / 100;
465 if (gain > 16) gain = 16;
466 if (gain < 1) gain = 1;
467 m_nProLogicDepth = gain;
468 if (nDelay < 4) nDelay = 4;
469 if (nDelay > 50) nDelay = 50;
470 m_nProLogicDelay = nDelay;
471 return TRUE;
472}
473
474BOOL CSoundFile::SetWaveConfigEx(BOOL bSurround,BOOL bNoOverSampling,BOOL bReverb,BOOL hqido,BOOL bMegaBass,BOOL bNR,BOOL bEQ)
475//----------------------------------------------------------------------------------------------------------------------------
476{
477 DWORD d = gdwSoundSetup & ~(SNDMIX_SURROUND | SNDMIX_NORESAMPLING | SNDMIX_REVERB | SNDMIX_HQRESAMPLER | SNDMIX_MEGABASS | SNDMIX_NOISEREDUCTION | SNDMIX_EQ);
478 if (bSurround) d |= SNDMIX_SURROUND;
479 if (bNoOverSampling) d |= SNDMIX_NORESAMPLING;
480 if (bReverb) d |= SNDMIX_REVERB;
481 if (hqido) d |= SNDMIX_HQRESAMPLER;
482 if (bMegaBass) d |= SNDMIX_MEGABASS;
483 if (bNR) d |= SNDMIX_NOISEREDUCTION;
484 if (bEQ) d |= SNDMIX_EQ;
485 gdwSoundSetup = d;
486 InitPlayer(FALSE);
487 return TRUE;
488}
diff --git a/core/multimedia/opieplayer/modplug/snd_flt.cpp b/core/multimedia/opieplayer/modplug/snd_flt.cpp
new file mode 100644
index 0000000..5ac241e
--- a/dev/null
+++ b/core/multimedia/opieplayer/modplug/snd_flt.cpp
@@ -0,0 +1,104 @@
1/*
2 * This program is free software; you can redistribute it and modify it
3 * under the terms of the GNU General Public License as published by the
4 * Free Software Foundation; either version 2 of the license or (at your
5 * option) any later version.
6 *
7 * Authors: Olivier Lapicque <olivierl@jps.net>
8*/
9
10#include "stdafx.h"
11#include "sndfile.h"
12
13// AWE32: cutoff = reg[0-255] * 31.25 + 100 -> [100Hz-8060Hz]
14// EMU10K1 docs: cutoff = reg[0-127]*62+100
15 #define FILTER_PRECISION8192
16
17#ifndef NO_FILTER
18
19#ifdef WIN32
20#define _ASM_MATH
21#endif
22
23#ifdef _ASM_MATH
24
25// pow(a,b) returns a^^b -> 2^^(b.log2(a))
26static float pow(float a, float b)
27{
28 long tmpint;
29 float result;
30 _asm {
31 fld b // Load b
32 fld a // Load a
33 fyl2x // ST(0) = b.log2(a)
34 fist tmpint // Store integer exponent
35 fisub tmpint // ST(0) = -1 <= (b*log2(a)) <= 1
36 f2xm1 // ST(0) = 2^(x)-1
37 fild tmpint // load integer exponent
38 fld1 // Load 1
39 fscale // ST(0) = 2^ST(1)
40 fstp ST(1) // Remove the integer from the stack
41 fmul ST(1), ST(0)// multiply with fractional part
42 faddp ST(1), ST(0)// add integer_part
43 fstp result // Store the result
44 }
45 return result;
46}
47
48
49#else
50
51#include <math.h>
52
53#endif // _ASM_MATH
54
55
56DWORD CSoundFile::CutOffToFrequency(UINT nCutOff, int flt_modifier) const
57//-----------------------------------------------------------------------
58{
59 float Fc;
60
61 if (m_dwSongFlags & SONG_EXFILTERRANGE)
62 Fc = 110.0f * pow(2.0f, 0.25f + ((float)(nCutOff*(flt_modifier+256)))/(21.0f*512.0f));
63 else
64 Fc = 110.0f * pow(2.0f, 0.25f + ((float)(nCutOff*(flt_modifier+256)))/(24.0f*512.0f));
65 LONG freq = (LONG)Fc;
66 if (freq < 120) return 120;
67 if (freq > 10000) return 10000;
68 if (freq*2 > (LONG)gdwMixingFreq) freq = gdwMixingFreq>>1;
69 return (DWORD)freq;
70}
71
72
73// Simple 2-poles resonant filter
74void CSoundFile::SetupChannelFilter(MODCHANNEL *pChn, BOOL bReset, int flt_modifier) const
75//----------------------------------------------------------------------------------------
76{
77 float fc = (float)CutOffToFrequency(pChn->nCutOff, flt_modifier);
78 float fs = (float)gdwMixingFreq;
79 float fg, fb0, fb1;
80
81 fc *= (float)(2.0*3.14159265358/fs);
82 float dmpfac = pow(10.0f, -((24.0f / 128.0f)*(float)pChn->nResonance) / 20.0f);
83 float d = (1.0f-2.0f*dmpfac)* fc;
84 if (d>2.0) d = 2.0;
85 d = (2.0f*dmpfac - d)/fc;
86 float e = pow(1.0f/fc,2.0);
87
88 fg=1/(1+d+e);
89 fb0=(d+e+e)/(1+d+e);
90 fb1=-e/(1+d+e);
91
92 pChn->nFilter_A0 = (int)(fg * FILTER_PRECISION);
93 pChn->nFilter_B0 = (int)(fb0 * FILTER_PRECISION);
94 pChn->nFilter_B1 = (int)(fb1 * FILTER_PRECISION);
95
96 if (bReset)
97 {
98 pChn->nFilter_Y1 = pChn->nFilter_Y2 = 0;
99 pChn->nFilter_Y3 = pChn->nFilter_Y4 = 0;
100 }
101 pChn->dwFlags |= CHN_FILTER;
102}
103
104#endif // NO_FILTER
diff --git a/core/multimedia/opieplayer/modplug/snd_fx.cpp b/core/multimedia/opieplayer/modplug/snd_fx.cpp
new file mode 100644
index 0000000..149cd60
--- a/dev/null
+++ b/core/multimedia/opieplayer/modplug/snd_fx.cpp
@@ -0,0 +1,2394 @@
1/*
2 * This program is free software; you can redistribute it and modify it
3 * under the terms of the GNU General Public License as published by the
4 * Free Software Foundation; either version 2 of the license or (at your
5 * option) any later version.
6 *
7 * Authors: Olivier Lapicque <olivierl@jps.net>
8*/
9
10#include "stdafx.h"
11#include "sndfile.h"
12
13#ifdef WIN32
14#pragma warning(disable:4244)
15#endif
16
17// Tables defined in tables.cpp
18extern const BYTE ImpulseTrackerPortaVolCmd[16];
19extern const WORD S3MFineTuneTable[16];
20extern const WORD ProTrackerPeriodTable[6*12];
21extern const WORD ProTrackerTunedPeriods[15*12];
22extern const WORD FreqS3MTable[];
23extern const WORD XMPeriodTable[96+8];
24extern const UINT XMLinearTable[768];
25extern const DWORD FineLinearSlideUpTable[16];
26extern const DWORD FineLinearSlideDownTable[16];
27extern const DWORD LinearSlideUpTable[256];
28extern const DWORD LinearSlideDownTable[256];
29extern const signed char retrigTable1[16];
30extern const signed char retrigTable2[16];
31extern const short int ModRandomTable[64];
32
33
34////////////////////////////////////////////////////////////
35// Length
36
37DWORD CSoundFile::GetLength(BOOL bAdjust, BOOL bTotal)
38//----------------------------------------------------
39{
40 UINT dwElapsedTime=0, nRow=0, nCurrentPattern=0, nNextPattern=0, nPattern=Order[0];
41 UINT nMusicSpeed=m_nDefaultSpeed, nMusicTempo=m_nDefaultTempo, nNextRow=0;
42 UINT nMaxRow = 0, nMaxPattern = 0;
43 LONG nGlbVol = m_nDefaultGlobalVolume, nOldGlbVolSlide = 0;
44 BYTE samples[MAX_CHANNELS];
45 BYTE instr[MAX_CHANNELS];
46 BYTE notes[MAX_CHANNELS];
47 BYTE vols[MAX_CHANNELS];
48 BYTE oldparam[MAX_CHANNELS];
49 BYTE chnvols[MAX_CHANNELS];
50 DWORD patloop[MAX_CHANNELS];
51
52 memset(instr, 0, sizeof(instr));
53 memset(notes, 0, sizeof(notes));
54 memset(vols, 0xFF, sizeof(vols));
55 memset(patloop, 0, sizeof(patloop));
56 memset(oldparam, 0, sizeof(oldparam));
57 memset(chnvols, 64, sizeof(chnvols));
58 memset(samples, 0, sizeof(samples));
59 for (UINT icv=0; icv<m_nChannels; icv++) chnvols[icv] = ChnSettings[icv].nVolume;
60 nMaxRow = m_nNextRow;
61 nMaxPattern = m_nNextPattern;
62 nCurrentPattern = nNextPattern = 0;
63 nPattern = Order[0];
64 nRow = nNextRow = 0;
65 for (;;)
66 {
67 UINT nSpeedCount = 0;
68 nRow = nNextRow;
69 nCurrentPattern = nNextPattern;
70 // Check if pattern is valid
71 nPattern = Order[nCurrentPattern];
72 while (nPattern >= MAX_PATTERNS)
73 {
74 // End of song ?
75 if ((nPattern == 0xFF) || (nCurrentPattern >= MAX_ORDERS))
76 {
77 goto EndMod;
78 } else
79 {
80 nCurrentPattern++;
81 nPattern = (nCurrentPattern < MAX_ORDERS) ? Order[nCurrentPattern] : 0xFF;
82 }
83 nNextPattern = nCurrentPattern;
84 }
85 // Weird stuff?
86 if ((nPattern >= MAX_PATTERNS) || (!Patterns[nPattern])) break;
87 // Should never happen
88 if (nRow >= PatternSize[nPattern]) nRow = 0;
89 // Update next position
90 nNextRow = nRow + 1;
91 if (nNextRow >= PatternSize[nPattern])
92 {
93 nNextPattern = nCurrentPattern + 1;
94 nNextRow = 0;
95 }
96 if (!nRow)
97 {
98 for (UINT ipck=0; ipck<m_nChannels; ipck++) patloop[ipck] = dwElapsedTime;
99 }
100 if (!bTotal)
101 {
102 if ((nCurrentPattern > nMaxPattern) || ((nCurrentPattern == nMaxPattern) && (nRow >= nMaxRow)))
103 {
104 if (bAdjust)
105 {
106 m_nMusicSpeed = nMusicSpeed;
107 m_nMusicTempo = nMusicTempo;
108 }
109 break;
110 }
111 }
112 MODCHANNEL *pChn = Chn;
113 MODCOMMAND *p = Patterns[nPattern] + nRow * m_nChannels;
114 for (UINT nChn=0; nChn<m_nChannels; p++,pChn++, nChn++) if (*((DWORD *)p))
115 {
116 UINT command = p->command;
117 UINT param = p->param;
118 UINT note = p->note;
119 if (p->instr) { instr[nChn] = p->instr; notes[nChn] = 0; vols[nChn] = 0xFF; }
120 if ((note) && (note <= 120)) notes[nChn] = note;
121 if (p->volcmd == VOLCMD_VOLUME){ vols[nChn] = p->vol; }
122 if (command) switch (command)
123 {
124 // Position Jump
125 case CMD_POSITIONJUMP:
126 if (param <= nCurrentPattern) goto EndMod;
127 nNextPattern = param;
128 nNextRow = 0;
129 if (bAdjust)
130 {
131 pChn->nPatternLoopCount = 0;
132 pChn->nPatternLoop = 0;
133 }
134 break;
135 // Pattern Break
136 case CMD_PATTERNBREAK:
137 nNextRow = param;
138 nNextPattern = nCurrentPattern + 1;
139 if (bAdjust)
140 {
141 pChn->nPatternLoopCount = 0;
142 pChn->nPatternLoop = 0;
143 }
144 break;
145 // Set Speed
146 case CMD_SPEED:
147 if (!param) break;
148 if ((param <= 0x20) || (m_nType != MOD_TYPE_MOD))
149 {
150 if (param < 128) nMusicSpeed = param;
151 }
152 break;
153 // Set Tempo
154 case CMD_TEMPO:
155 if ((bAdjust) && (m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT)))
156 {
157 if (param) pChn->nOldTempo = param; else param = pChn->nOldTempo;
158 }
159 if (param >= 0x20) nMusicTempo = param; else
160 // Tempo Slide
161 if ((param & 0xF0) == 0x10)
162 {
163 nMusicTempo += param & 0x0F;
164 if (nMusicTempo > 255) nMusicTempo = 255;
165 } else
166 {
167 nMusicTempo -= param & 0x0F;
168 if (nMusicTempo < 32) nMusicTempo = 32;
169 }
170 break;
171 // Pattern Delay
172 case CMD_S3MCMDEX:
173 if ((param & 0xF0) == 0x60) { nSpeedCount = param & 0x0F; break; } else
174 if ((param & 0xF0) == 0xB0) { param &= 0x0F; param |= 0x60; }
175 case CMD_MODCMDEX:
176 if ((param & 0xF0) == 0xE0) nSpeedCount = (param & 0x0F) * nMusicSpeed; else
177 if ((param & 0xF0) == 0x60)
178 {
179 if (param & 0x0F) dwElapsedTime += (dwElapsedTime - patloop[nChn]) * (param & 0x0F);
180 else patloop[nChn] = dwElapsedTime;
181 }
182 break;
183 }
184 if (!bAdjust) continue;
185 switch(command)
186 {
187 // Portamento Up/Down
188 case CMD_PORTAMENTOUP:
189 case CMD_PORTAMENTODOWN:
190 if (param) pChn->nOldPortaUpDown = param;
191 break;
192 // Tone-Portamento
193 case CMD_TONEPORTAMENTO:
194 if (param) pChn->nPortamentoSlide = param << 2;
195 break;
196 // Offset
197 case CMD_OFFSET:
198 if (param) pChn->nOldOffset = param;
199 break;
200 // Volume Slide
201 case CMD_VOLUMESLIDE:
202 case CMD_TONEPORTAVOL:
203 case CMD_VIBRATOVOL:
204 if (param) pChn->nOldVolumeSlide = param;
205 break;
206 // Set Volume
207 case CMD_VOLUME:
208 vols[nChn] = param;
209 break;
210 // Global Volume
211 case CMD_GLOBALVOLUME:
212 if (m_nType != MOD_TYPE_IT) param <<= 1;
213 if (param > 128) param = 128;
214 nGlbVol = param << 1;
215 break;
216 // Global Volume Slide
217 case CMD_GLOBALVOLSLIDE:
218 if (param) nOldGlbVolSlide = param; else param = nOldGlbVolSlide;
219 if (((param & 0x0F) == 0x0F) && (param & 0xF0))
220 {
221 param >>= 4;
222 if (m_nType != MOD_TYPE_IT) param <<= 1;
223 nGlbVol += param << 1;
224 } else
225 if (((param & 0xF0) == 0xF0) && (param & 0x0F))
226 {
227 param = (param & 0x0F) << 1;
228 if (m_nType != MOD_TYPE_IT) param <<= 1;
229 nGlbVol -= param;
230 } else
231 if (param & 0xF0)
232 {
233 param >>= 4;
234 param <<= 1;
235 if (m_nType != MOD_TYPE_IT) param <<= 1;
236 nGlbVol += param * nMusicSpeed;
237 } else
238 {
239 param = (param & 0x0F) << 1;
240 if (m_nType != MOD_TYPE_IT) param <<= 1;
241 nGlbVol -= param * nMusicSpeed;
242 }
243 if (nGlbVol < 0) nGlbVol = 0;
244 if (nGlbVol > 256) nGlbVol = 256;
245 break;
246 case CMD_CHANNELVOLUME:
247 if (param <= 64) chnvols[nChn] = param;
248 break;
249 case CMD_CHANNELVOLSLIDE:
250 if (param) oldparam[nChn] = param; else param = oldparam[nChn];
251 pChn->nOldChnVolSlide = param;
252 if (((param & 0x0F) == 0x0F) && (param & 0xF0))
253 {
254 param = (param >> 4) + chnvols[nChn];
255 } else
256 if (((param & 0xF0) == 0xF0) && (param & 0x0F))
257 {
258 if (chnvols[nChn] > (int)(param & 0x0F)) param = chnvols[nChn] - (param & 0x0F);
259 else param = 0;
260 } else
261 if (param & 0x0F)
262 {
263 param = (param & 0x0F) * nMusicSpeed;
264 param = (chnvols[nChn] > param) ? chnvols[nChn] - param : 0;
265 } else param = ((param & 0xF0) >> 4) * nMusicSpeed + chnvols[nChn];
266 if (param > 64) param = 64;
267 chnvols[nChn] = param;
268 break;
269 }
270 }
271 nSpeedCount += nMusicSpeed;
272 dwElapsedTime += (2500 * nSpeedCount) / nMusicTempo;
273 }
274EndMod:
275 if ((bAdjust) && (!bTotal))
276 {
277 m_nGlobalVolume = nGlbVol;
278 m_nOldGlbVolSlide = nOldGlbVolSlide;
279 for (UINT n=0; n<m_nChannels; n++)
280 {
281 Chn[n].nGlobalVol = chnvols[n];
282 if (notes[n]) Chn[n].nNewNote = notes[n];
283 if (instr[n]) Chn[n].nNewIns = instr[n];
284 if (vols[n] != 0xFF)
285 {
286 if (vols[n] > 64) vols[n] = 64;
287 Chn[n].nVolume = vols[n] << 2;
288 }
289 }
290 }
291 return (dwElapsedTime+500) / 1000;
292}
293
294
295//////////////////////////////////////////////////////////////////////////////////////////////////
296// Effects
297
298void CSoundFile::InstrumentChange(MODCHANNEL *pChn, UINT instr, BOOL bPorta, BOOL bUpdVol, BOOL bResetEnv)
299//--------------------------------------------------------------------------------------------------------
300{
301 BOOL bInstrumentChanged = FALSE;
302
303 if (instr >= MAX_INSTRUMENTS) return;
304 INSTRUMENTHEADER *penv = Headers[instr];
305 MODINSTRUMENT *psmp = &Ins[instr];
306 UINT note = pChn->nNewNote;
307 if ((penv) && (note) && (note <= 128))
308 {
309 if (penv->NoteMap[note-1] >= 0xFE) return;
310 UINT n = penv->Keyboard[note-1];
311 psmp = ((n) && (n < MAX_SAMPLES)) ? &Ins[n] : NULL;
312 } else
313 if (m_nInstruments)
314 {
315 if (note >= 0xFE) return;
316 psmp = NULL;
317 }
318 // Update Volume
319 if (bUpdVol) pChn->nVolume = (psmp) ? psmp->nVolume : 0;
320 // bInstrumentChanged is used for IT carry-on env option
321 if (penv != pChn->pHeader)
322 {
323 bInstrumentChanged = TRUE;
324 pChn->pHeader = penv;
325 } else
326 // Special XM hack
327 if ((bPorta) && (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2)) && (penv)
328 && (pChn->pInstrument) && (psmp != pChn->pInstrument))
329 {
330 // FT2 doesn't change the sample in this case,
331 // but still uses the sample info from the old one (bug?)
332 return;
333 }
334 // Instrument adjust
335 pChn->nNewIns = 0;
336 if (psmp)
337 {
338 if (penv)
339 {
340 pChn->nInsVol = (psmp->nGlobalVol * penv->nGlobalVol) >> 6;
341 if (penv->dwFlags & ENV_SETPANNING) pChn->nPan = penv->nPan;
342 pChn->nNNA = penv->nNNA;
343 } else
344 {
345 pChn->nInsVol = psmp->nGlobalVol;
346 }
347 if (psmp->uFlags & CHN_PANNING) pChn->nPan = psmp->nPan;
348 }
349 // Reset envelopes
350 if (bResetEnv)
351 {
352 if ((!bPorta) || (!(m_nType & MOD_TYPE_IT)) || (m_dwSongFlags & SONG_ITCOMPATMODE)
353 || (!pChn->nLength) || ((pChn->dwFlags & CHN_NOTEFADE) && (!pChn->nFadeOutVol)))
354 {
355 pChn->dwFlags |= CHN_FASTVOLRAMP;
356 if ((m_nType & MOD_TYPE_IT) && (!bInstrumentChanged) && (penv) && (!(pChn->dwFlags & (CHN_KEYOFF|CHN_NOTEFADE))))
357 {
358 if (!(penv->dwFlags & ENV_VOLCARRY)) pChn->nVolEnvPosition = 0;
359 if (!(penv->dwFlags & ENV_PANCARRY)) pChn->nPanEnvPosition = 0;
360 if (!(penv->dwFlags & ENV_PITCHCARRY)) pChn->nPitchEnvPosition = 0;
361 } else
362 {
363 pChn->nVolEnvPosition = 0;
364 pChn->nPanEnvPosition = 0;
365 pChn->nPitchEnvPosition = 0;
366 }
367 pChn->nAutoVibDepth = 0;
368 pChn->nAutoVibPos = 0;
369 } else
370 if ((penv) && (!(penv->dwFlags & ENV_VOLUME)))
371 {
372 pChn->nVolEnvPosition = 0;
373 pChn->nAutoVibDepth = 0;
374 pChn->nAutoVibPos = 0;
375 }
376 }
377 // Invalid sample ?
378 if (!psmp)
379 {
380 pChn->pInstrument = NULL;
381 pChn->nInsVol = 0;
382 return;
383 }
384 // Tone-Portamento doesn't reset the pingpong direction flag
385 if ((bPorta) && (psmp == pChn->pInstrument))
386 {
387 if (m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT)) return;
388 pChn->dwFlags &= ~(CHN_KEYOFF|CHN_NOTEFADE);
389 pChn->dwFlags = (pChn->dwFlags & (0xFFFFFF00 | CHN_PINGPONGFLAG)) | (psmp->uFlags);
390 } else
391 {
392 pChn->dwFlags &= ~(CHN_KEYOFF|CHN_NOTEFADE|CHN_VOLENV|CHN_PANENV|CHN_PITCHENV);
393 pChn->dwFlags = (pChn->dwFlags & 0xFFFFFF00) | (psmp->uFlags);
394 if (penv)
395 {
396 if (penv->dwFlags & ENV_VOLUME) pChn->dwFlags |= CHN_VOLENV;
397 if (penv->dwFlags & ENV_PANNING) pChn->dwFlags |= CHN_PANENV;
398 if (penv->dwFlags & ENV_PITCH) pChn->dwFlags |= CHN_PITCHENV;
399 if ((penv->dwFlags & ENV_PITCH) && (penv->dwFlags & ENV_FILTER))
400 {
401 if (!pChn->nCutOff) pChn->nCutOff = 0x7F;
402 }
403 if (penv->nIFC & 0x80) pChn->nCutOff = penv->nIFC & 0x7F;
404 if (penv->nIFR & 0x80) pChn->nResonance = penv->nIFR & 0x7F;
405 }
406 pChn->nVolSwing = pChn->nPanSwing = 0;
407 }
408 pChn->pInstrument = psmp;
409 pChn->nLength = psmp->nLength;
410 pChn->nLoopStart = psmp->nLoopStart;
411 pChn->nLoopEnd = psmp->nLoopEnd;
412 pChn->nC4Speed = psmp->nC4Speed;
413 pChn->pSample = psmp->pSample;
414 pChn->nTranspose = psmp->RelativeTone;
415 pChn->nFineTune = psmp->nFineTune;
416 if (pChn->dwFlags & CHN_SUSTAINLOOP)
417 {
418 pChn->nLoopStart = psmp->nSustainStart;
419 pChn->nLoopEnd = psmp->nSustainEnd;
420 pChn->dwFlags |= CHN_LOOP;
421 if (pChn->dwFlags & CHN_PINGPONGSUSTAIN) pChn->dwFlags |= CHN_PINGPONGLOOP;
422 }
423 if ((pChn->dwFlags & CHN_LOOP) && (pChn->nLoopEnd < pChn->nLength)) pChn->nLength = pChn->nLoopEnd;
424}
425
426
427void CSoundFile::NoteChange(UINT nChn, int note, BOOL bPorta, BOOL bResetEnv)
428//---------------------------------------------------------------------------
429{
430 if (note < 1) return;
431 MODCHANNEL * const pChn = &Chn[nChn];
432 MODINSTRUMENT *pins = pChn->pInstrument;
433 INSTRUMENTHEADER *penv = pChn->pHeader;
434 if ((penv) && (note <= 0x80))
435 {
436 UINT n = penv->Keyboard[note - 1];
437 if ((n) && (n < MAX_SAMPLES)) pins = &Ins[n];
438 note = penv->NoteMap[note-1];
439 }
440 // Key Off
441 if (note >= 0x80)// 0xFE or invalid note => key off
442 {
443 // Key Off
444 KeyOff(nChn);
445 // Note Cut
446 if (note == 0xFE)
447 {
448 pChn->dwFlags |= (CHN_NOTEFADE|CHN_FASTVOLRAMP);
449 if ((!(m_nType & MOD_TYPE_IT)) || (m_nInstruments)) pChn->nVolume = 0;
450 pChn->nFadeOutVol = 0;
451 }
452 return;
453 }
454 if (!pins) return;
455 if ((!bPorta) && (m_nType & (MOD_TYPE_XM|MOD_TYPE_MED|MOD_TYPE_MT2)))
456 {
457 pChn->nTranspose = pins->RelativeTone;
458 pChn->nFineTune = pins->nFineTune;
459 }
460 if (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2|MOD_TYPE_MED)) note += pChn->nTranspose;
461 if (note < 1) note = 1;
462 if (note > 132) note = 132;
463 pChn->nNote = note;
464 if ((!bPorta) || (m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT))) pChn->nNewIns = 0;
465 UINT period = GetPeriodFromNote(note, pChn->nFineTune, pChn->nC4Speed);
466 if (period)
467 {
468 if ((!bPorta) || (!pChn->nPeriod)) pChn->nPeriod = period;
469 pChn->nPortamentoDest = period;
470 if ((!bPorta) || ((!pChn->nLength) && (!(m_nType & MOD_TYPE_S3M))))
471 {
472 pChn->pInstrument = pins;
473 pChn->pSample = pins->pSample;
474 pChn->nLength = pins->nLength;
475 pChn->nLoopEnd = pins->nLength;
476 pChn->nLoopStart = 0;
477 pChn->dwFlags = (pChn->dwFlags & 0xFFFFFF00) | (pins->uFlags);
478 if (pChn->dwFlags & CHN_SUSTAINLOOP)
479 {
480 pChn->nLoopStart = pins->nSustainStart;
481 pChn->nLoopEnd = pins->nSustainEnd;
482 pChn->dwFlags &= ~CHN_PINGPONGLOOP;
483 pChn->dwFlags |= CHN_LOOP;
484 if (pChn->dwFlags & CHN_PINGPONGSUSTAIN) pChn->dwFlags |= CHN_PINGPONGLOOP;
485 if (pChn->nLength > pChn->nLoopEnd) pChn->nLength = pChn->nLoopEnd;
486 } else
487 if (pChn->dwFlags & CHN_LOOP)
488 {
489 pChn->nLoopStart = pins->nLoopStart;
490 pChn->nLoopEnd = pins->nLoopEnd;
491 if (pChn->nLength > pChn->nLoopEnd) pChn->nLength = pChn->nLoopEnd;
492 }
493 pChn->nPos = 0;
494 pChn->nPosLo = 0;
495 if (pChn->nVibratoType < 4) pChn->nVibratoPos = ((m_nType & MOD_TYPE_IT) && (!(m_dwSongFlags & SONG_ITOLDEFFECTS))) ? 0x10 : 0;
496 if (pChn->nTremoloType < 4) pChn->nTremoloPos = 0;
497 }
498 if (pChn->nPos >= pChn->nLength) pChn->nPos = pChn->nLoopStart;
499 } else bPorta = FALSE;
500 if ((!bPorta) || (!(m_nType & MOD_TYPE_IT))
501 || ((pChn->dwFlags & CHN_NOTEFADE) && (!pChn->nFadeOutVol))
502 || ((m_dwSongFlags & SONG_ITCOMPATMODE) && (pChn->nRowInstr)))
503 {
504 if ((m_nType & MOD_TYPE_IT) && (pChn->dwFlags & CHN_NOTEFADE) && (!pChn->nFadeOutVol))
505 {
506 pChn->nVolEnvPosition = 0;
507 pChn->nPanEnvPosition = 0;
508 pChn->nPitchEnvPosition = 0;
509 pChn->nAutoVibDepth = 0;
510 pChn->nAutoVibPos = 0;
511 pChn->dwFlags &= ~CHN_NOTEFADE;
512 pChn->nFadeOutVol = 65536;
513 }
514 if ((!bPorta) || (!(m_dwSongFlags & SONG_ITCOMPATMODE)) || (pChn->nRowInstr))
515 {
516 if ((!(m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))) || (pChn->nRowInstr))
517 {
518 pChn->dwFlags &= ~CHN_NOTEFADE;
519 pChn->nFadeOutVol = 65536;
520 }
521 }
522 }
523 pChn->dwFlags &= ~(CHN_EXTRALOUD|CHN_KEYOFF);
524 // Enable Ramping
525 if (!bPorta)
526 {
527 pChn->nVUMeter = 0x100;
528 pChn->nLeftVU = pChn->nRightVU = 0xFF;
529 pChn->dwFlags &= ~CHN_FILTER;
530 pChn->dwFlags |= CHN_FASTVOLRAMP;
531 pChn->nRetrigCount = 0;
532 pChn->nTremorCount = 0;
533 if (bResetEnv)
534 {
535 pChn->nVolSwing = pChn->nPanSwing = 0;
536 if (penv)
537 {
538 if (!(penv->dwFlags & ENV_VOLCARRY)) pChn->nVolEnvPosition = 0;
539 if (!(penv->dwFlags & ENV_PANCARRY)) pChn->nPanEnvPosition = 0;
540 if (!(penv->dwFlags & ENV_PITCHCARRY)) pChn->nPitchEnvPosition = 0;
541 if (m_nType & MOD_TYPE_IT)
542 {
543 // Volume Swing
544 if (penv->nVolSwing)
545 {
546 int d = ((LONG)penv->nVolSwing*(LONG)((rand() & 0xFF) - 0x7F)) / 128;
547 pChn->nVolSwing = (signed short)((d * pChn->nVolume + 1)/128);
548 }
549 // Pan Swing
550 if (penv->nPanSwing)
551 {
552 int d = ((LONG)penv->nPanSwing*(LONG)((rand() & 0xFF) - 0x7F)) / 128;
553 pChn->nPanSwing = (signed short)d;
554 }
555 }
556 }
557 pChn->nAutoVibDepth = 0;
558 pChn->nAutoVibPos = 0;
559 }
560 pChn->nLeftVol = pChn->nRightVol = 0;
561 BOOL bFlt = (m_dwSongFlags & SONG_MPTFILTERMODE) ? FALSE : TRUE;
562 // Setup Initial Filter for this note
563 if (penv)
564 {
565 if (penv->nIFR & 0x80) { pChn->nResonance = penv->nIFR & 0x7F; bFlt = TRUE; }
566 if (penv->nIFC & 0x80) { pChn->nCutOff = penv->nIFC & 0x7F; bFlt = TRUE; }
567 } else
568 {
569 pChn->nVolSwing = pChn->nPanSwing = 0;
570 }
571#ifndef NO_FILTER
572 if ((pChn->nCutOff < 0x7F) && (bFlt)) SetupChannelFilter(pChn, TRUE);
573#endif // NO_FILTER
574 }
575}
576
577
578UINT CSoundFile::GetNNAChannel(UINT nChn) const
579//---------------------------------------------
580{
581 const MODCHANNEL *pChn = &Chn[nChn];
582 // Check for empty channel
583 const MODCHANNEL *pi = &Chn[m_nChannels];
584 for (UINT i=m_nChannels; i<MAX_CHANNELS; i++, pi++) if (!pi->nLength) return i;
585 if (!pChn->nFadeOutVol) return 0;
586 // All channels are used: check for lowest volume
587 UINT result = 0;
588 DWORD vol = 64*65536;// 25%
589 DWORD envpos = 0xFFFFFF;
590 const MODCHANNEL *pj = &Chn[m_nChannels];
591 for (UINT j=m_nChannels; j<MAX_CHANNELS; j++, pj++)
592 {
593 if (!pj->nFadeOutVol) return j;
594 DWORD v = pj->nVolume;
595 if (pj->dwFlags & CHN_NOTEFADE)
596 v = v * pj->nFadeOutVol;
597 else
598 v <<= 16;
599 if (pj->dwFlags & CHN_LOOP) v >>= 1;
600 if ((v < vol) || ((v == vol) && (pj->nVolEnvPosition > envpos)))
601 {
602 envpos = pj->nVolEnvPosition;
603 vol = v;
604 result = j;
605 }
606 }
607 return result;
608}
609
610
611void CSoundFile::CheckNNA(UINT nChn, UINT instr, int note, BOOL bForceCut)
612//------------------------------------------------------------------------
613{
614 MODCHANNEL *pChn = &Chn[nChn];
615 INSTRUMENTHEADER *penv = pChn->pHeader, *pHeader;
616 signed char *pSample;
617 if (note > 0x80) note = 0;
618 if (note < 1) return;
619 // Always NNA cut - using
620 if ((!(m_nType & (MOD_TYPE_IT|MOD_TYPE_MT2))) || (!m_nInstruments) || (bForceCut))
621 {
622 if ((m_dwSongFlags & SONG_CPUVERYHIGH)
623 || (!pChn->nLength) || (pChn->dwFlags & CHN_MUTE)
624 || ((!pChn->nLeftVol) && (!pChn->nRightVol))) return;
625 UINT n = GetNNAChannel(nChn);
626 if (!n) return;
627 MODCHANNEL *p = &Chn[n];
628 // Copy Channel
629 *p = *pChn;
630 p->dwFlags &= ~(CHN_VIBRATO|CHN_TREMOLO|CHN_PANBRELLO|CHN_MUTE|CHN_PORTAMENTO);
631 p->nMasterChn = nChn+1;
632 p->nCommand = 0;
633 // Cut the note
634 p->nFadeOutVol = 0;
635 p->dwFlags |= (CHN_NOTEFADE|CHN_FASTVOLRAMP);
636 // Stop this channel
637 pChn->nLength = pChn->nPos = pChn->nPosLo = 0;
638 pChn->nROfs = pChn->nLOfs = 0;
639 pChn->nLeftVol = pChn->nRightVol = 0;
640 return;
641 }
642 if (instr >= MAX_INSTRUMENTS) instr = 0;
643 pSample = pChn->pSample;
644 pHeader = pChn->pHeader;
645 if ((instr) && (note))
646 {
647 pHeader = Headers[instr];
648 if (pHeader)
649 {
650 UINT n = 0;
651 if (note <= 0x80)
652 {
653 n = pHeader->Keyboard[note-1];
654 note = pHeader->NoteMap[note-1];
655 if ((n) && (n < MAX_SAMPLES)) pSample = Ins[n].pSample;
656 }
657 } else pSample = NULL;
658 }
659 if (!penv) return;
660 MODCHANNEL *p = pChn;
661 for (UINT i=nChn; i<MAX_CHANNELS; p++, i++)
662 if ((i >= m_nChannels) || (p == pChn))
663 {
664 if (((p->nMasterChn == nChn+1) || (p == pChn)) && (p->pHeader))
665 {
666 BOOL bOk = FALSE;
667 // Duplicate Check Type
668 switch(p->pHeader->nDCT)
669 {
670 // Note
671 case DCT_NOTE:
672 if ((note) && (p->nNote == note) && (pHeader == p->pHeader)) bOk = TRUE;
673 break;
674 // Sample
675 case DCT_SAMPLE:
676 if ((pSample) && (pSample == p->pSample)) bOk = TRUE;
677 break;
678 // Instrument
679 case DCT_INSTRUMENT:
680 if (pHeader == p->pHeader) bOk = TRUE;
681 break;
682 }
683 // Duplicate Note Action
684 if (bOk)
685 {
686 switch(p->pHeader->nDNA)
687 {
688 // Cut
689 case DNA_NOTECUT:
690 KeyOff(i);
691 p->nVolume = 0;
692 break;
693 // Note Off
694 case DNA_NOTEOFF:
695 KeyOff(i);
696 break;
697 // Note Fade
698 case DNA_NOTEFADE:
699 p->dwFlags |= CHN_NOTEFADE;
700 break;
701 }
702 if (!p->nVolume)
703 {
704 p->nFadeOutVol = 0;
705 p->dwFlags |= (CHN_NOTEFADE|CHN_FASTVOLRAMP);
706 }
707 }
708 }
709 }
710 if (pChn->dwFlags & CHN_MUTE) return;
711 // New Note Action
712 if ((pChn->nVolume) && (pChn->nLength))
713 {
714 UINT n = GetNNAChannel(nChn);
715 if (n)
716 {
717 MODCHANNEL *p = &Chn[n];
718 // Copy Channel
719 *p = *pChn;
720 p->dwFlags &= ~(CHN_VIBRATO|CHN_TREMOLO|CHN_PANBRELLO|CHN_MUTE|CHN_PORTAMENTO);
721 p->nMasterChn = nChn+1;
722 p->nCommand = 0;
723 // Key Off the note
724 switch(pChn->nNNA)
725 {
726 case NNA_NOTEOFF:KeyOff(n); break;
727 case NNA_NOTECUT:
728 p->nFadeOutVol = 0;
729 case NNA_NOTEFADE:p->dwFlags |= CHN_NOTEFADE; break;
730 }
731 if (!p->nVolume)
732 {
733 p->nFadeOutVol = 0;
734 p->dwFlags |= (CHN_NOTEFADE|CHN_FASTVOLRAMP);
735 }
736 // Stop this channel
737 pChn->nLength = pChn->nPos = pChn->nPosLo = 0;
738 pChn->nROfs = pChn->nLOfs = 0;
739 }
740 }
741}
742
743
744BOOL CSoundFile::ProcessEffects()
745//-------------------------------
746{
747 int nBreakRow = -1, nPosJump = -1, nPatLoopRow = -1;
748 MODCHANNEL *pChn = Chn;
749 for (UINT nChn=0; nChn<m_nChannels; nChn++, pChn++)
750 {
751 UINT instr = pChn->nRowInstr;
752 UINT volcmd = pChn->nRowVolCmd;
753 UINT vol = pChn->nRowVolume;
754 UINT cmd = pChn->nRowCommand;
755 UINT param = pChn->nRowParam;
756 BOOL bPorta = ((cmd != CMD_TONEPORTAMENTO) && (cmd != CMD_TONEPORTAVOL) && (volcmd != VOLCMD_TONEPORTAMENTO)) ? FALSE : TRUE;
757 UINT nStartTick = 0;
758
759 pChn->dwFlags &= ~CHN_FASTVOLRAMP;
760 // Process special effects (note delay, pattern delay, pattern loop)
761 if ((cmd == CMD_MODCMDEX) || (cmd == CMD_S3MCMDEX))
762 {
763 if ((!param) && (m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT))) param = pChn->nOldCmdEx; else pChn->nOldCmdEx = param;
764 // Note Delay ?
765 if ((param & 0xF0) == 0xD0)
766 {
767 nStartTick = param & 0x0F;
768 } else
769 if (!m_nTickCount)
770 {
771 // Pattern Loop ?
772 if ((((param & 0xF0) == 0x60) && (cmd == CMD_MODCMDEX))
773 || (((param & 0xF0) == 0xB0) && (cmd == CMD_S3MCMDEX)))
774 {
775 int nloop = PatternLoop(pChn, param & 0x0F);
776 if (nloop >= 0) nPatLoopRow = nloop;
777 } else
778 // Pattern Delay
779 if ((param & 0xF0) == 0xE0)
780 {
781 m_nPatternDelay = param & 0x0F;
782 }
783 }
784 }
785
786 // Handles note/instrument/volume changes
787 if (m_nTickCount == nStartTick) // can be delayed by a note delay effect
788 {
789 UINT note = pChn->nRowNote;
790 if (instr) pChn->nNewIns = instr;
791 // XM: Key-Off + Sample == Note Cut
792 if (m_nType & (MOD_TYPE_MOD|MOD_TYPE_XM|MOD_TYPE_MT2))
793 {
794 if ((note == 0xFF) && ((!pChn->pHeader) || (!(pChn->pHeader->dwFlags & ENV_VOLUME))))
795 {
796 pChn->dwFlags |= CHN_FASTVOLRAMP;
797 pChn->nVolume = 0;
798 note = instr = 0;
799 }
800 }
801 if ((!note) && (instr))
802 {
803 if (m_nInstruments)
804 {
805 if (pChn->pInstrument) pChn->nVolume = pChn->pInstrument->nVolume;
806 if (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))
807 {
808 pChn->dwFlags |= CHN_FASTVOLRAMP;
809 pChn->nVolEnvPosition = 0;
810 pChn->nPanEnvPosition = 0;
811 pChn->nPitchEnvPosition = 0;
812 pChn->nAutoVibDepth = 0;
813 pChn->nAutoVibPos = 0;
814 pChn->dwFlags &= ~CHN_NOTEFADE;
815 pChn->nFadeOutVol = 65536;
816 }
817 } else
818 {
819 if (instr < MAX_SAMPLES) pChn->nVolume = Ins[instr].nVolume;
820 }
821 if (!(m_nType & MOD_TYPE_IT)) instr = 0;
822 }
823 // Invalid Instrument ?
824 if (instr >= MAX_INSTRUMENTS) instr = 0;
825 // Note Cut/Off => ignore instrument
826 if (note >= 0xFE) instr = 0;
827 if ((note) && (note <= 128)) pChn->nNewNote = note;
828 // New Note Action ?
829 if ((note) && (note <= 128) && (!bPorta))
830 {
831 CheckNNA(nChn, instr, note, FALSE);
832 }
833 // Instrument Change ?
834 if (instr)
835 {
836 MODINSTRUMENT *psmp = pChn->pInstrument;
837 InstrumentChange(pChn, instr, bPorta, TRUE);
838 pChn->nNewIns = 0;
839 // Special IT case: portamento+note causes sample change -> ignore portamento
840 if ((m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT))
841 && (psmp != pChn->pInstrument) && (note) && (note < 0x80))
842 {
843 bPorta = FALSE;
844 }
845 }
846 // New Note ?
847 if (note)
848 {
849 if ((!instr) && (pChn->nNewIns) && (note < 0x80))
850 {
851 InstrumentChange(pChn, pChn->nNewIns, bPorta, FALSE, (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2)) ? FALSE : TRUE);
852 pChn->nNewIns = 0;
853 }
854 NoteChange(nChn, note, bPorta, (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2)) ? FALSE : TRUE);
855 if ((bPorta) && (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2)) && (instr))
856 {
857 pChn->dwFlags |= CHN_FASTVOLRAMP;
858 pChn->nVolEnvPosition = 0;
859 pChn->nPanEnvPosition = 0;
860 pChn->nPitchEnvPosition = 0;
861 pChn->nAutoVibDepth = 0;
862 pChn->nAutoVibPos = 0;
863 }
864 }
865 // Tick-0 only volume commands
866 if (volcmd == VOLCMD_VOLUME)
867 {
868 if (vol > 64) vol = 64;
869 pChn->nVolume = vol << 2;
870 pChn->dwFlags |= CHN_FASTVOLRAMP;
871 } else
872 if (volcmd == VOLCMD_PANNING)
873 {
874 if (vol > 64) vol = 64;
875 pChn->nPan = vol << 2;
876 pChn->dwFlags |= CHN_FASTVOLRAMP;
877 }
878 }
879
880 // Volume Column Effect (except volume & panning)
881 if ((volcmd > VOLCMD_PANNING) && (m_nTickCount >= nStartTick))
882 {
883 if (volcmd == VOLCMD_TONEPORTAMENTO)
884 {
885 if (m_nType & MOD_TYPE_IT)
886 TonePortamento(pChn, ImpulseTrackerPortaVolCmd[vol & 0x0F]);
887 else
888 TonePortamento(pChn, vol * 16);
889 } else
890 {
891 if (vol) pChn->nOldVolParam = vol; else vol = pChn->nOldVolParam;
892 switch(volcmd)
893 {
894 case VOLCMD_VOLSLIDEUP:
895 VolumeSlide(pChn, vol << 4);
896 break;
897
898 case VOLCMD_VOLSLIDEDOWN:
899 VolumeSlide(pChn, vol);
900 break;
901
902 case VOLCMD_FINEVOLUP:
903 if (m_nType & MOD_TYPE_IT)
904 {
905 if (m_nTickCount == nStartTick) VolumeSlide(pChn, (vol << 4) | 0x0F);
906 } else
907 FineVolumeUp(pChn, vol);
908 break;
909
910 case VOLCMD_FINEVOLDOWN:
911 if (m_nType & MOD_TYPE_IT)
912 {
913 if (m_nTickCount == nStartTick) VolumeSlide(pChn, 0xF0 | vol);
914 } else
915 FineVolumeDown(pChn, vol);
916 break;
917
918 case VOLCMD_VIBRATOSPEED:
919 Vibrato(pChn, vol << 4);
920 break;
921
922 case VOLCMD_VIBRATO:
923 Vibrato(pChn, vol);
924 break;
925
926 case VOLCMD_PANSLIDELEFT:
927 PanningSlide(pChn, vol);
928 break;
929
930 case VOLCMD_PANSLIDERIGHT:
931 PanningSlide(pChn, vol << 4);
932 break;
933
934 case VOLCMD_PORTAUP:
935 PortamentoUp(pChn, vol << 2);
936 break;
937
938 case VOLCMD_PORTADOWN:
939 PortamentoDown(pChn, vol << 2);
940 break;
941 }
942 }
943 }
944
945 // Effects
946 if (cmd) switch (cmd)
947 {
948 // Set Volume
949 case CMD_VOLUME:
950 if (!m_nTickCount)
951 {
952 pChn->nVolume = (param < 64) ? param*4 : 256;
953 pChn->dwFlags |= CHN_FASTVOLRAMP;
954 }
955 break;
956
957 // Portamento Up
958 case CMD_PORTAMENTOUP:
959 if ((!param) && (m_nType & MOD_TYPE_MOD)) break;
960 PortamentoUp(pChn, param);
961 break;
962
963 // Portamento Down
964 case CMD_PORTAMENTODOWN:
965 if ((!param) && (m_nType & MOD_TYPE_MOD)) break;
966 PortamentoDown(pChn, param);
967 break;
968
969 // Volume Slide
970 case CMD_VOLUMESLIDE:
971 if ((param) || (m_nType != MOD_TYPE_MOD)) VolumeSlide(pChn, param);
972 break;
973
974 // Tone-Portamento
975 case CMD_TONEPORTAMENTO:
976 TonePortamento(pChn, param);
977 break;
978
979 // Tone-Portamento + Volume Slide
980 case CMD_TONEPORTAVOL:
981 if ((param) || (m_nType != MOD_TYPE_MOD)) VolumeSlide(pChn, param);
982 TonePortamento(pChn, 0);
983 break;
984
985 // Vibrato
986 case CMD_VIBRATO:
987 Vibrato(pChn, param);
988 break;
989
990 // Vibrato + Volume Slide
991 case CMD_VIBRATOVOL:
992 if ((param) || (m_nType != MOD_TYPE_MOD)) VolumeSlide(pChn, param);
993 Vibrato(pChn, 0);
994 break;
995
996 // Set Speed
997 case CMD_SPEED:
998 if (!m_nTickCount) SetSpeed(param);
999 break;
1000
1001 // Set Tempo
1002 case CMD_TEMPO:
1003 if (!m_nTickCount)
1004 {
1005 if (m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT))
1006 {
1007 if (param) pChn->nOldTempo = param; else param = pChn->nOldTempo;
1008 }
1009 SetTempo(param);
1010 }
1011 break;
1012
1013 // Set Offset
1014 case CMD_OFFSET:
1015 if (m_nTickCount) break;
1016 if (param) pChn->nOldOffset = param; else param = pChn->nOldOffset;
1017 param <<= 8;
1018 param |= (UINT)(pChn->nOldHiOffset) << 16;
1019 if ((pChn->nRowNote) && (pChn->nRowNote < 0x80))
1020 {
1021 if (bPorta)
1022 pChn->nPos = param;
1023 else
1024 pChn->nPos += param;
1025 if (pChn->nPos >= pChn->nLength)
1026 {
1027 if (!(m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2)))
1028 {
1029 pChn->nPos = pChn->nLoopStart;
1030 if ((m_dwSongFlags & SONG_ITOLDEFFECTS) && (pChn->nLength > 4))
1031 {
1032 pChn->nPos = pChn->nLength - 2;
1033 }
1034 }
1035 }
1036 } else
1037 if ((param < pChn->nLength) && (m_nType & (MOD_TYPE_MTM|MOD_TYPE_DMF)))
1038 {
1039 pChn->nPos = param;
1040 }
1041 break;
1042
1043 // Arpeggio
1044 case CMD_ARPEGGIO:
1045 if ((m_nTickCount) || (!pChn->nPeriod) || (!pChn->nNote)) break;
1046 if ((!param) && (!(m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT)))) break;
1047 pChn->nCommand = CMD_ARPEGGIO;
1048 if (param) pChn->nArpeggio = param;
1049 break;
1050
1051 // Retrig
1052 case CMD_RETRIG:
1053 if (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))
1054 {
1055 if (!(param & 0xF0)) param |= pChn->nRetrigParam & 0xF0;
1056 if (!(param & 0x0F)) param |= pChn->nRetrigParam & 0x0F;
1057 param |= 0x100; // increment retrig count on first row
1058 }
1059 if (param) pChn->nRetrigParam = (BYTE)(param & 0xFF); else param = pChn->nRetrigParam;
1060 RetrigNote(nChn, param);
1061 break;
1062
1063 // Tremor
1064 case CMD_TREMOR:
1065 if (m_nTickCount) break;
1066 pChn->nCommand = CMD_TREMOR;
1067 if (param) pChn->nTremorParam = param;
1068 break;
1069
1070 // Set Global Volume
1071 case CMD_GLOBALVOLUME:
1072 if (m_nTickCount) break;
1073 if (m_nType != MOD_TYPE_IT) param <<= 1;
1074 if (param > 128) param = 128;
1075 m_nGlobalVolume = param << 1;
1076 break;
1077
1078 // Global Volume Slide
1079 case CMD_GLOBALVOLSLIDE:
1080 GlobalVolSlide(param);
1081 break;
1082
1083 // Set 8-bit Panning
1084 case CMD_PANNING8:
1085 if (m_nTickCount) break;
1086 if (!(m_dwSongFlags & SONG_SURROUNDPAN)) pChn->dwFlags &= ~CHN_SURROUND;
1087 if (m_nType & (MOD_TYPE_IT|MOD_TYPE_XM|MOD_TYPE_MT2))
1088 {
1089 pChn->nPan = param;
1090 } else
1091 if (param <= 0x80)
1092 {
1093 pChn->nPan = param << 1;
1094 } else
1095 if (param == 0xA4)
1096 {
1097 pChn->dwFlags |= CHN_SURROUND;
1098 pChn->nPan = 0x80;
1099 }
1100 pChn->dwFlags |= CHN_FASTVOLRAMP;
1101 break;
1102
1103 // Panning Slide
1104 case CMD_PANNINGSLIDE:
1105 PanningSlide(pChn, param);
1106 break;
1107
1108 // Tremolo
1109 case CMD_TREMOLO:
1110 Tremolo(pChn, param);
1111 break;
1112
1113 // Fine Vibrato
1114 case CMD_FINEVIBRATO:
1115 FineVibrato(pChn, param);
1116 break;
1117
1118 // MOD/XM Exx Extended Commands
1119 case CMD_MODCMDEX:
1120 ExtendedMODCommands(nChn, param);
1121 break;
1122
1123 // S3M/IT Sxx Extended Commands
1124 case CMD_S3MCMDEX:
1125 ExtendedS3MCommands(nChn, param);
1126 break;
1127
1128 // Key Off
1129 case CMD_KEYOFF:
1130 if (!m_nTickCount) KeyOff(nChn);
1131 break;
1132
1133 // Extra-fine porta up/down
1134 case CMD_XFINEPORTAUPDOWN:
1135 switch(param & 0xF0)
1136 {
1137 case 0x10: ExtraFinePortamentoUp(pChn, param & 0x0F); break;
1138 case 0x20: ExtraFinePortamentoDown(pChn, param & 0x0F); break;
1139 // Modplug XM Extensions
1140 case 0x50:
1141 case 0x60:
1142 case 0x70:
1143 case 0x90:
1144 case 0xA0: ExtendedS3MCommands(nChn, param); break;
1145 }
1146 break;
1147
1148 // Set Channel Global Volume
1149 case CMD_CHANNELVOLUME:
1150 if (m_nTickCount) break;
1151 if (param <= 64)
1152 {
1153 pChn->nGlobalVol = param;
1154 pChn->dwFlags |= CHN_FASTVOLRAMP;
1155 }
1156 break;
1157
1158 // Channel volume slide
1159 case CMD_CHANNELVOLSLIDE:
1160 ChannelVolSlide(pChn, param);
1161 break;
1162
1163 // Panbrello (IT)
1164 case CMD_PANBRELLO:
1165 Panbrello(pChn, param);
1166 break;
1167
1168 // Set Envelope Position
1169 case CMD_SETENVPOSITION:
1170 if (!m_nTickCount)
1171 {
1172 pChn->nVolEnvPosition = param;
1173 pChn->nPanEnvPosition = param;
1174 pChn->nPitchEnvPosition = param;
1175 if (pChn->pHeader)
1176 {
1177 INSTRUMENTHEADER *penv = pChn->pHeader;
1178 if ((pChn->dwFlags & CHN_PANENV) && (penv->nPanEnv) && (param > penv->PanPoints[penv->nPanEnv-1]))
1179 {
1180 pChn->dwFlags &= ~CHN_PANENV;
1181 }
1182 }
1183 }
1184 break;
1185
1186 // Position Jump
1187 case CMD_POSITIONJUMP:
1188 nPosJump = param;
1189 break;
1190
1191 // Pattern Break
1192 case CMD_PATTERNBREAK:
1193 nBreakRow = param;
1194 break;
1195
1196 // Midi Controller
1197 case CMD_MIDI:
1198 if (m_nTickCount) break;
1199 if (param < 0x80)
1200 {
1201 ProcessMidiMacro(nChn, &m_MidiCfg.szMidiSFXExt[pChn->nActiveMacro << 5], param);
1202 } else
1203 {
1204 ProcessMidiMacro(nChn, &m_MidiCfg.szMidiZXXExt[(param & 0x7F) << 5], 0);
1205 }
1206 break;
1207 }
1208 }
1209
1210 // Navigation Effects
1211 if (!m_nTickCount)
1212 {
1213 // Pattern Loop
1214 if (nPatLoopRow >= 0)
1215 {
1216 m_nNextPattern = m_nCurrentPattern;
1217 m_nNextRow = nPatLoopRow;
1218 if (m_nPatternDelay) m_nNextRow++;
1219 } else
1220 // Pattern Break / Position Jump only if no loop running
1221 if ((nBreakRow >= 0) || (nPosJump >= 0))
1222 {
1223 BOOL bNoLoop = FALSE;
1224 if (nPosJump < 0) nPosJump = m_nCurrentPattern+1;
1225 if (nBreakRow < 0) nBreakRow = 0;
1226 // Modplug Tracker & ModPlugin allow backward jumps
1227 #ifndef FASTSOUNDLIB
1228 if ((nPosJump < (int)m_nCurrentPattern)
1229 || ((nPosJump == (int)m_nCurrentPattern) && (nBreakRow <= (int)m_nRow)))
1230 {
1231 if (!IsValidBackwardJump(m_nCurrentPattern, m_nRow, nPosJump, nBreakRow))
1232 {
1233 if (m_nRepeatCount)
1234 {
1235 if (m_nRepeatCount > 0) m_nRepeatCount--;
1236 } else
1237 {
1238 #ifdef MODPLUG_TRACKER
1239 if (gdwSoundSetup & SNDMIX_NOBACKWARDJUMPS)
1240 #endif
1241 // Backward jump disabled
1242 bNoLoop = TRUE;
1243 //reset repeat count incase there are multiple loops.
1244 //(i.e. Unreal tracks)
1245 m_nRepeatCount = m_nInitialRepeatCount;
1246 }
1247 }
1248 }
1249 #endif// FASTSOUNDLIB
1250 if (((!bNoLoop) && (nPosJump < MAX_ORDERS))
1251 && ((nPosJump != (int)m_nCurrentPattern) || (nBreakRow != (int)m_nRow)))
1252 {
1253 if (nPosJump != (int)m_nCurrentPattern)
1254 {
1255 for (UINT i=0; i<m_nChannels; i++) Chn[i].nPatternLoopCount = 0;
1256 }
1257 m_nNextPattern = nPosJump;
1258 m_nNextRow = (UINT)nBreakRow;
1259 }
1260 }
1261 }
1262 return TRUE;
1263}
1264
1265
1266////////////////////////////////////////////////////////////
1267// Channels effects
1268
1269void CSoundFile::PortamentoUp(MODCHANNEL *pChn, UINT param)
1270//---------------------------------------------------------
1271{
1272 if (param) pChn->nOldPortaUpDown = param; else param = pChn->nOldPortaUpDown;
1273 if ((m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT|MOD_TYPE_STM)) && ((param & 0xF0) >= 0xE0))
1274 {
1275 if (param & 0x0F)
1276 {
1277 if ((param & 0xF0) == 0xF0)
1278 {
1279 FinePortamentoUp(pChn, param & 0x0F);
1280 } else
1281 if ((param & 0xF0) == 0xE0)
1282 {
1283 ExtraFinePortamentoUp(pChn, param & 0x0F);
1284 }
1285 }
1286 return;
1287 }
1288 // Regular Slide
1289 if (!(m_dwSongFlags & SONG_FIRSTTICK))
1290 {
1291 DoFreqSlide(pChn, -(int)(param * 4));
1292 }
1293}
1294
1295
1296void CSoundFile::PortamentoDown(MODCHANNEL *pChn, UINT param)
1297//-----------------------------------------------------------
1298{
1299 if (param) pChn->nOldPortaUpDown = param; else param = pChn->nOldPortaUpDown;
1300 if ((m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT|MOD_TYPE_STM)) && ((param & 0xF0) >= 0xE0))
1301 {
1302 if (param & 0x0F)
1303 {
1304 if ((param & 0xF0) == 0xF0)
1305 {
1306 FinePortamentoDown(pChn, param & 0x0F);
1307 } else
1308 if ((param & 0xF0) == 0xE0)
1309 {
1310 ExtraFinePortamentoDown(pChn, param & 0x0F);
1311 }
1312 }
1313 return;
1314 }
1315 if (!(m_dwSongFlags & SONG_FIRSTTICK)) DoFreqSlide(pChn, (int)(param << 2));
1316}
1317
1318
1319void CSoundFile::FinePortamentoUp(MODCHANNEL *pChn, UINT param)
1320//-------------------------------------------------------------
1321{
1322 if (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))
1323 {
1324 if (param) pChn->nOldFinePortaUpDown = param; else param = pChn->nOldFinePortaUpDown;
1325 }
1326 if (m_dwSongFlags & SONG_FIRSTTICK)
1327 {
1328 if ((pChn->nPeriod) && (param))
1329 {
1330 if ((m_dwSongFlags & SONG_LINEARSLIDES) && (!(m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))))
1331 {
1332 pChn->nPeriod = _muldivr(pChn->nPeriod, LinearSlideDownTable[param & 0x0F], 65536);
1333 } else
1334 {
1335 pChn->nPeriod -= (int)(param * 4);
1336 }
1337 if (pChn->nPeriod < 1) pChn->nPeriod = 1;
1338 }
1339 }
1340}
1341
1342
1343void CSoundFile::FinePortamentoDown(MODCHANNEL *pChn, UINT param)
1344//---------------------------------------------------------------
1345{
1346 if (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))
1347 {
1348 if (param) pChn->nOldFinePortaUpDown = param; else param = pChn->nOldFinePortaUpDown;
1349 }
1350 if (m_dwSongFlags & SONG_FIRSTTICK)
1351 {
1352 if ((pChn->nPeriod) && (param))
1353 {
1354 if ((m_dwSongFlags & SONG_LINEARSLIDES) && (!(m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))))
1355 {
1356 pChn->nPeriod = _muldivr(pChn->nPeriod, LinearSlideUpTable[param & 0x0F], 65536);
1357 } else
1358 {
1359 pChn->nPeriod += (int)(param * 4);
1360 }
1361 if (pChn->nPeriod > 0xFFFF) pChn->nPeriod = 0xFFFF;
1362 }
1363 }
1364}
1365
1366
1367void CSoundFile::ExtraFinePortamentoUp(MODCHANNEL *pChn, UINT param)
1368//------------------------------------------------------------------
1369{
1370 if (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))
1371 {
1372 if (param) pChn->nOldFinePortaUpDown = param; else param = pChn->nOldFinePortaUpDown;
1373 }
1374 if (m_dwSongFlags & SONG_FIRSTTICK)
1375 {
1376 if ((pChn->nPeriod) && (param))
1377 {
1378 if ((m_dwSongFlags & SONG_LINEARSLIDES) && (!(m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))))
1379 {
1380 pChn->nPeriod = _muldivr(pChn->nPeriod, FineLinearSlideDownTable[param & 0x0F], 65536);
1381 } else
1382 {
1383 pChn->nPeriod -= (int)(param);
1384 }
1385 if (pChn->nPeriod < 1) pChn->nPeriod = 1;
1386 }
1387 }
1388}
1389
1390
1391void CSoundFile::ExtraFinePortamentoDown(MODCHANNEL *pChn, UINT param)
1392//--------------------------------------------------------------------
1393{
1394 if (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))
1395 {
1396 if (param) pChn->nOldFinePortaUpDown = param; else param = pChn->nOldFinePortaUpDown;
1397 }
1398 if (m_dwSongFlags & SONG_FIRSTTICK)
1399 {
1400 if ((pChn->nPeriod) && (param))
1401 {
1402 if ((m_dwSongFlags & SONG_LINEARSLIDES) && (!(m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))))
1403 {
1404 pChn->nPeriod = _muldivr(pChn->nPeriod, FineLinearSlideUpTable[param & 0x0F], 65536);
1405 } else
1406 {
1407 pChn->nPeriod += (int)(param);
1408 }
1409 if (pChn->nPeriod > 0xFFFF) pChn->nPeriod = 0xFFFF;
1410 }
1411 }
1412}
1413
1414
1415// Portamento Slide
1416void CSoundFile::TonePortamento(MODCHANNEL *pChn, UINT param)
1417//-----------------------------------------------------------
1418{
1419 if (param) pChn->nPortamentoSlide = param * 4;
1420 pChn->dwFlags |= CHN_PORTAMENTO;
1421 if ((pChn->nPeriod) && (pChn->nPortamentoDest) && (!(m_dwSongFlags & SONG_FIRSTTICK)))
1422 {
1423 if (pChn->nPeriod < pChn->nPortamentoDest)
1424 {
1425 LONG delta = (int)pChn->nPortamentoSlide;
1426 if ((m_dwSongFlags & SONG_LINEARSLIDES) && (!(m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))))
1427 {
1428 UINT n = pChn->nPortamentoSlide >> 2;
1429 if (n > 255) n = 255;
1430 delta = _muldivr(pChn->nPeriod, LinearSlideUpTable[n], 65536) - pChn->nPeriod;
1431 if (delta < 1) delta = 1;
1432 }
1433 pChn->nPeriod += delta;
1434 if (pChn->nPeriod > pChn->nPortamentoDest) pChn->nPeriod = pChn->nPortamentoDest;
1435 } else
1436 if (pChn->nPeriod > pChn->nPortamentoDest)
1437 {
1438 LONG delta = - (int)pChn->nPortamentoSlide;
1439 if ((m_dwSongFlags & SONG_LINEARSLIDES) && (!(m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))))
1440 {
1441 UINT n = pChn->nPortamentoSlide >> 2;
1442 if (n > 255) n = 255;
1443 delta = _muldivr(pChn->nPeriod, LinearSlideDownTable[n], 65536) - pChn->nPeriod;
1444 if (delta > -1) delta = -1;
1445 }
1446 pChn->nPeriod += delta;
1447 if (pChn->nPeriod < pChn->nPortamentoDest) pChn->nPeriod = pChn->nPortamentoDest;
1448 }
1449 }
1450}
1451
1452
1453void CSoundFile::Vibrato(MODCHANNEL *p, UINT param)
1454//-------------------------------------------------
1455{
1456 if (param & 0x0F) p->nVibratoDepth = (param & 0x0F) * 4;
1457 if (param & 0xF0) p->nVibratoSpeed = (param >> 4) & 0x0F;
1458 p->dwFlags |= CHN_VIBRATO;
1459}
1460
1461
1462void CSoundFile::FineVibrato(MODCHANNEL *p, UINT param)
1463//-----------------------------------------------------
1464{
1465 if (param & 0x0F) p->nVibratoDepth = param & 0x0F;
1466 if (param & 0xF0) p->nVibratoSpeed = (param >> 4) & 0x0F;
1467 p->dwFlags |= CHN_VIBRATO;
1468}
1469
1470
1471void CSoundFile::Panbrello(MODCHANNEL *p, UINT param)
1472//---------------------------------------------------
1473{
1474 if (param & 0x0F) p->nPanbrelloDepth = param & 0x0F;
1475 if (param & 0xF0) p->nPanbrelloSpeed = (param >> 4) & 0x0F;
1476 p->dwFlags |= CHN_PANBRELLO;
1477}
1478
1479
1480void CSoundFile::VolumeSlide(MODCHANNEL *pChn, UINT param)
1481//--------------------------------------------------------
1482{
1483 if (param) pChn->nOldVolumeSlide = param; else param = pChn->nOldVolumeSlide;
1484 LONG newvolume = pChn->nVolume;
1485 if (m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT|MOD_TYPE_STM|MOD_TYPE_AMF))
1486 {
1487 if ((param & 0x0F) == 0x0F)
1488 {
1489 if (param & 0xF0)
1490 {
1491 FineVolumeUp(pChn, (param >> 4));
1492 return;
1493 } else
1494 {
1495 if ((m_dwSongFlags & SONG_FIRSTTICK) && (!(m_dwSongFlags & SONG_FASTVOLSLIDES)))
1496 {
1497 newvolume -= 0x0F * 4;
1498 }
1499 }
1500 } else
1501 if ((param & 0xF0) == 0xF0)
1502 {
1503 if (param & 0x0F)
1504 {
1505 FineVolumeDown(pChn, (param & 0x0F));
1506 return;
1507 } else
1508 {
1509 if ((m_dwSongFlags & SONG_FIRSTTICK) && (!(m_dwSongFlags & SONG_FASTVOLSLIDES)))
1510 {
1511 newvolume += 0x0F * 4;
1512 }
1513 }
1514 }
1515 }
1516 if ((!(m_dwSongFlags & SONG_FIRSTTICK)) || (m_dwSongFlags & SONG_FASTVOLSLIDES))
1517 {
1518 if (param & 0x0F) newvolume -= (int)((param & 0x0F) * 4);
1519 else newvolume += (int)((param & 0xF0) >> 2);
1520 if (m_nType & MOD_TYPE_MOD) pChn->dwFlags |= CHN_FASTVOLRAMP;
1521 }
1522 if (newvolume < 0) newvolume = 0;
1523 if (newvolume > 256) newvolume = 256;
1524 pChn->nVolume = newvolume;
1525}
1526
1527
1528void CSoundFile::PanningSlide(MODCHANNEL *pChn, UINT param)
1529//---------------------------------------------------------
1530{
1531 LONG nPanSlide = 0;
1532 if (param) pChn->nOldPanSlide = param; else param = pChn->nOldPanSlide;
1533 if (m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT|MOD_TYPE_STM))
1534 {
1535 if (((param & 0x0F) == 0x0F) && (param & 0xF0))
1536 {
1537 if (m_dwSongFlags & SONG_FIRSTTICK)
1538 {
1539 param = (param & 0xF0) >> 2;
1540 nPanSlide = - (int)param;
1541 }
1542 } else
1543 if (((param & 0xF0) == 0xF0) && (param & 0x0F))
1544 {
1545 if (m_dwSongFlags & SONG_FIRSTTICK)
1546 {
1547 nPanSlide = (param & 0x0F) << 2;
1548 }
1549 } else
1550 {
1551 if (!(m_dwSongFlags & SONG_FIRSTTICK))
1552 {
1553 if (param & 0x0F) nPanSlide = (int)((param & 0x0F) << 2);
1554 else nPanSlide = -(int)((param & 0xF0) >> 2);
1555 }
1556 }
1557 } else
1558 {
1559 if (!(m_dwSongFlags & SONG_FIRSTTICK))
1560 {
1561 if (param & 0x0F) nPanSlide = -(int)((param & 0x0F) << 2);
1562 else nPanSlide = (int)((param & 0xF0) >> 2);
1563 }
1564 }
1565 if (nPanSlide)
1566 {
1567 nPanSlide += pChn->nPan;
1568 if (nPanSlide < 0) nPanSlide = 0;
1569 if (nPanSlide > 256) nPanSlide = 256;
1570 pChn->nPan = nPanSlide;
1571 }
1572}
1573
1574
1575void CSoundFile::FineVolumeUp(MODCHANNEL *pChn, UINT param)
1576//---------------------------------------------------------
1577{
1578 if (param) pChn->nOldFineVolUpDown = param; else param = pChn->nOldFineVolUpDown;
1579 if (m_dwSongFlags & SONG_FIRSTTICK)
1580 {
1581 pChn->nVolume += param * 4;
1582 if (pChn->nVolume > 256) pChn->nVolume = 256;
1583 if (m_nType & MOD_TYPE_MOD) pChn->dwFlags |= CHN_FASTVOLRAMP;
1584 }
1585}
1586
1587
1588void CSoundFile::FineVolumeDown(MODCHANNEL *pChn, UINT param)
1589//-----------------------------------------------------------
1590{
1591 if (param) pChn->nOldFineVolUpDown = param; else param = pChn->nOldFineVolUpDown;
1592 if (m_dwSongFlags & SONG_FIRSTTICK)
1593 {
1594 pChn->nVolume -= param * 4;
1595 if (pChn->nVolume < 0) pChn->nVolume = 0;
1596 if (m_nType & MOD_TYPE_MOD) pChn->dwFlags |= CHN_FASTVOLRAMP;
1597 }
1598}
1599
1600
1601void CSoundFile::Tremolo(MODCHANNEL *p, UINT param)
1602//-------------------------------------------------
1603{
1604 if (param & 0x0F) p->nTremoloDepth = (param & 0x0F) << 2;
1605 if (param & 0xF0) p->nTremoloSpeed = (param >> 4) & 0x0F;
1606 p->dwFlags |= CHN_TREMOLO;
1607}
1608
1609
1610void CSoundFile::ChannelVolSlide(MODCHANNEL *pChn, UINT param)
1611//------------------------------------------------------------
1612{
1613 LONG nChnSlide = 0;
1614 if (param) pChn->nOldChnVolSlide = param; else param = pChn->nOldChnVolSlide;
1615 if (((param & 0x0F) == 0x0F) && (param & 0xF0))
1616 {
1617 if (m_dwSongFlags & SONG_FIRSTTICK) nChnSlide = param >> 4;
1618 } else
1619 if (((param & 0xF0) == 0xF0) && (param & 0x0F))
1620 {
1621 if (m_dwSongFlags & SONG_FIRSTTICK) nChnSlide = - (int)(param & 0x0F);
1622 } else
1623 {
1624 if (!(m_dwSongFlags & SONG_FIRSTTICK))
1625 {
1626 if (param & 0x0F) nChnSlide = -(int)(param & 0x0F);
1627 else nChnSlide = (int)((param & 0xF0) >> 4);
1628 }
1629 }
1630 if (nChnSlide)
1631 {
1632 nChnSlide += pChn->nGlobalVol;
1633 if (nChnSlide < 0) nChnSlide = 0;
1634 if (nChnSlide > 64) nChnSlide = 64;
1635 pChn->nGlobalVol = nChnSlide;
1636 }
1637}
1638
1639
1640void CSoundFile::ExtendedMODCommands(UINT nChn, UINT param)
1641//---------------------------------------------------------
1642{
1643 MODCHANNEL *pChn = &Chn[nChn];
1644 UINT command = param & 0xF0;
1645 param &= 0x0F;
1646 switch(command)
1647 {
1648 // E0x: Set Filter
1649 // E1x: Fine Portamento Up
1650 case 0x10:if ((param) || (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))) FinePortamentoUp(pChn, param); break;
1651 // E2x: Fine Portamento Down
1652 case 0x20:if ((param) || (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))) FinePortamentoDown(pChn, param); break;
1653 // E3x: Set Glissando Control
1654 case 0x30:pChn->dwFlags &= ~CHN_GLISSANDO; if (param) pChn->dwFlags |= CHN_GLISSANDO; break;
1655 // E4x: Set Vibrato WaveForm
1656 case 0x40:pChn->nVibratoType = param & 0x07; break;
1657 // E5x: Set FineTune
1658 case 0x50:if (m_nTickCount) break;
1659 pChn->nC4Speed = S3MFineTuneTable[param];
1660 if (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))
1661 pChn->nFineTune = param*2;
1662 else
1663 pChn->nFineTune = MOD2XMFineTune(param);
1664 if (pChn->nPeriod) pChn->nPeriod = GetPeriodFromNote(pChn->nNote, pChn->nFineTune, pChn->nC4Speed);
1665 break;
1666 // E6x: Pattern Loop
1667 // E7x: Set Tremolo WaveForm
1668 case 0x70:pChn->nTremoloType = param & 0x07; break;
1669 // E8x: Set 4-bit Panning
1670 case 0x80:if (!m_nTickCount) { pChn->nPan = (param << 4) + 8; pChn->dwFlags |= CHN_FASTVOLRAMP; } break;
1671 // E9x: Retrig
1672 case 0x90:RetrigNote(nChn, param); break;
1673 // EAx: Fine Volume Up
1674 case 0xA0:if ((param) || (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))) FineVolumeUp(pChn, param); break;
1675 // EBx: Fine Volume Down
1676 case 0xB0:if ((param) || (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))) FineVolumeDown(pChn, param); break;
1677 // ECx: Note Cut
1678 case 0xC0:NoteCut(nChn, param); break;
1679 // EDx: Note Delay
1680 // EEx: Pattern Delay
1681 // EFx: MOD: Invert Loop, XM: Set Active Midi Macro
1682 case 0xF0: pChn->nActiveMacro = param;break;
1683 }
1684}
1685
1686
1687void CSoundFile::ExtendedS3MCommands(UINT nChn, UINT param)
1688//---------------------------------------------------------
1689{
1690 MODCHANNEL *pChn = &Chn[nChn];
1691 UINT command = param & 0xF0;
1692 param &= 0x0F;
1693 switch(command)
1694 {
1695 // S0x: Set Filter
1696 // S1x: Set Glissando Control
1697 case 0x10:pChn->dwFlags &= ~CHN_GLISSANDO; if (param) pChn->dwFlags |= CHN_GLISSANDO; break;
1698 // S2x: Set FineTune
1699 case 0x20:if (m_nTickCount) break;
1700 pChn->nC4Speed = S3MFineTuneTable[param & 0x0F];
1701 pChn->nFineTune = MOD2XMFineTune(param);
1702 if (pChn->nPeriod) pChn->nPeriod = GetPeriodFromNote(pChn->nNote, pChn->nFineTune, pChn->nC4Speed);
1703 break;
1704 // S3x: Set Vibrato WaveForm
1705 case 0x30:pChn->nVibratoType = param & 0x07; break;
1706 // S4x: Set Tremolo WaveForm
1707 case 0x40:pChn->nTremoloType = param & 0x07; break;
1708 // S5x: Set Panbrello WaveForm
1709 case 0x50:pChn->nPanbrelloType = param & 0x07; break;
1710 // S6x: Pattern Delay for x frames
1711 case 0x60:m_nFrameDelay = param; break;
1712 // S7x: Envelope Control
1713 case 0x70:if (m_nTickCount) break;
1714 switch(param)
1715 {
1716 case 0:
1717 case 1:
1718 case 2:
1719 {
1720 MODCHANNEL *bkp = &Chn[m_nChannels];
1721 for (UINT i=m_nChannels; i<MAX_CHANNELS; i++, bkp++)
1722 {
1723 if (bkp->nMasterChn == nChn+1)
1724 {
1725 if (param == 1) KeyOff(i); else
1726 if (param == 2) bkp->dwFlags |= CHN_NOTEFADE; else
1727 { bkp->dwFlags |= CHN_NOTEFADE; bkp->nFadeOutVol = 0; }
1728 }
1729 }
1730 }
1731 break;
1732 case 3: pChn->nNNA = NNA_NOTECUT; break;
1733 case 4: pChn->nNNA = NNA_CONTINUE; break;
1734 case 5: pChn->nNNA = NNA_NOTEOFF; break;
1735 case 6: pChn->nNNA = NNA_NOTEFADE; break;
1736 case 7: pChn->dwFlags &= ~CHN_VOLENV; break;
1737 case 8: pChn->dwFlags |= CHN_VOLENV; break;
1738 case 9: pChn->dwFlags &= ~CHN_PANENV; break;
1739 case 10:pChn->dwFlags |= CHN_PANENV; break;
1740 case 11:pChn->dwFlags &= ~CHN_PITCHENV; break;
1741 case 12:pChn->dwFlags |= CHN_PITCHENV; break;
1742 }
1743 break;
1744 // S8x: Set 4-bit Panning
1745 case 0x80:if (!m_nTickCount) { pChn->nPan = (param << 4) + 8; pChn->dwFlags |= CHN_FASTVOLRAMP; } break;
1746 // S9x: Set Surround
1747 case 0x90:ExtendedChannelEffect(pChn, param & 0x0F); break;
1748 // SAx: Set 64k Offset
1749 case 0xA0:if (!m_nTickCount)
1750 {
1751 pChn->nOldHiOffset = param;
1752 if ((pChn->nRowNote) && (pChn->nRowNote < 0x80))
1753 {
1754 DWORD pos = param << 16;
1755 if (pos < pChn->nLength) pChn->nPos = pos;
1756 }
1757 }
1758 break;
1759 // SBx: Pattern Loop
1760 // SCx: Note Cut
1761 case 0xC0:NoteCut(nChn, param); break;
1762 // SDx: Note Delay
1763 // case 0xD0:break;
1764 // SEx: Pattern Delay for x rows
1765 // SFx: S3M: Funk Repeat, IT: Set Active Midi Macro
1766 case 0xF0:pChn->nActiveMacro = param; break;
1767 }
1768}
1769
1770
1771void CSoundFile::ExtendedChannelEffect(MODCHANNEL *pChn, UINT param)
1772//------------------------------------------------------------------
1773{
1774 // S9x and X9x commands (S3M/XM/IT only)
1775 if (m_nTickCount) return;
1776 switch(param & 0x0F)
1777 {
1778 // S90: Surround Off
1779 case 0x00: pChn->dwFlags &= ~CHN_SURROUND;break;
1780 // S91: Surround On
1781 case 0x01:pChn->dwFlags |= CHN_SURROUND; pChn->nPan = 128; break;
1782 ////////////////////////////////////////////////////////////
1783 // Modplug Extensions
1784 // S98: Reverb Off
1785 case 0x08:
1786 pChn->dwFlags &= ~CHN_REVERB;
1787 pChn->dwFlags |= CHN_NOREVERB;
1788 break;
1789 // S99: Reverb On
1790 case 0x09:
1791 pChn->dwFlags &= ~CHN_NOREVERB;
1792 pChn->dwFlags |= CHN_REVERB;
1793 break;
1794 // S9A: 2-Channels surround mode
1795 case 0x0A:
1796 m_dwSongFlags &= ~SONG_SURROUNDPAN;
1797 break;
1798 // S9B: 4-Channels surround mode
1799 case 0x0B:
1800 m_dwSongFlags |= SONG_SURROUNDPAN;
1801 break;
1802 // S9C: IT Filter Mode
1803 case 0x0C:
1804 m_dwSongFlags &= ~SONG_MPTFILTERMODE;
1805 break;
1806 // S9D: MPT Filter Mode
1807 case 0x0D:
1808 m_dwSongFlags |= SONG_MPTFILTERMODE;
1809 break;
1810 // S9E: Go forward
1811 case 0x0E:
1812 pChn->dwFlags &= ~(CHN_PINGPONGFLAG);
1813 break;
1814 // S9F: Go backward (set position at the end for non-looping samples)
1815 case 0x0F:
1816 if ((!(pChn->dwFlags & CHN_LOOP)) && (!pChn->nPos) && (pChn->nLength))
1817 {
1818 pChn->nPos = pChn->nLength - 1;
1819 pChn->nPosLo = 0xFFFF;
1820 }
1821 pChn->dwFlags |= CHN_PINGPONGFLAG;
1822 break;
1823 }
1824}
1825
1826
1827void CSoundFile::ProcessMidiMacro(UINT nChn, LPCSTR pszMidiMacro, UINT param)
1828//---------------------------------------------------------------------------
1829{
1830 MODCHANNEL *pChn = &Chn[nChn];
1831 DWORD dwMacro = (*((LPDWORD)pszMidiMacro)) & 0x7F5F7F5F;
1832 // Not Internal Device ?
1833 if (dwMacro != 0x30463046)
1834 {
1835 UINT pos = 0, nNib = 0, nBytes = 0;
1836 DWORD dwMidiCode = 0, dwByteCode = 0;
1837 while (pos+6 <= 32)
1838 {
1839 CHAR cData = pszMidiMacro[pos++];
1840 if (!cData) break;
1841 if ((cData >= '0') && (cData <= '9')) { dwByteCode = (dwByteCode<<4) | (cData-'0'); nNib++; } else
1842 if ((cData >= 'A') && (cData <= 'F')) { dwByteCode = (dwByteCode<<4) | (cData-'A'+10); nNib++; } else
1843 if ((cData >= 'a') && (cData <= 'f')) { dwByteCode = (dwByteCode<<4) | (cData-'a'+10); nNib++; } else
1844 if ((cData == 'z') || (cData == 'Z')) { dwByteCode = param & 0x7f; nNib = 2; } else
1845 if ((cData == 'x') || (cData == 'X')) { dwByteCode = param & 0x70; nNib = 2; } else
1846 if ((cData == 'y') || (cData == 'Y')) { dwByteCode = (param & 0x0f)<<3; nNib = 2; } else
1847 if (nNib >= 2)
1848 {
1849 nNib = 0;
1850 dwMidiCode |= dwByteCode << (nBytes*8);
1851 dwByteCode = 0;
1852 nBytes++;
1853 if (nBytes >= 3)
1854 {
1855 UINT nMasterCh = (nChn < m_nChannels) ? nChn+1 : pChn->nMasterChn;
1856 if ((nMasterCh) && (nMasterCh <= m_nChannels))
1857 {
1858 UINT nPlug = ChnSettings[nMasterCh-1].nMixPlugin;
1859 if ((nPlug) && (nPlug <= MAX_MIXPLUGINS))
1860 {
1861 IMixPlugin *pPlugin = m_MixPlugins[nPlug-1].pMixPlugin;
1862 if ((pPlugin) && (m_MixPlugins[nPlug-1].pMixState))
1863 {
1864 pPlugin->MidiSend(dwMidiCode);
1865 }
1866 }
1867 }
1868 nBytes = 0;
1869 dwMidiCode = 0;
1870 }
1871 }
1872
1873 }
1874 return;
1875 }
1876 // Internal device
1877 pszMidiMacro += 4;
1878 // Filter ?
1879 if (pszMidiMacro[0] == '0')
1880 {
1881 CHAR cData1 = pszMidiMacro[2];
1882 DWORD dwParam = 0;
1883 if ((cData1 == 'z') || (cData1 == 'Z'))
1884 {
1885 dwParam = param;
1886 } else
1887 {
1888 CHAR cData2 = pszMidiMacro[3];
1889 if ((cData1 >= '0') && (cData1 <= '9')) dwParam += (cData1 - '0') << 4; else
1890 if ((cData1 >= 'A') && (cData1 <= 'F')) dwParam += (cData1 - 'A' + 0x0A) << 4;
1891 if ((cData2 >= '0') && (cData2 <= '9')) dwParam += (cData2 - '0'); else
1892 if ((cData2 >= 'A') && (cData2 <= 'F')) dwParam += (cData2 - 'A' + 0x0A);
1893 }
1894 switch(pszMidiMacro[1])
1895 {
1896 // F0.F0.00.xx: Set CutOff
1897 case '0':
1898 {
1899 int oldcutoff = pChn->nCutOff;
1900 if (dwParam < 0x80) pChn->nCutOff = dwParam;
1901#ifndef NO_FILTER
1902 oldcutoff -= pChn->nCutOff;
1903
1904 if (oldcutoff < 0) oldcutoff = -oldcutoff;
1905 if ((pChn->nVolume > 0) || (oldcutoff < 0x10)
1906 || (!(pChn->dwFlags & CHN_FILTER)) || (!(pChn->nLeftVol|pChn->nRightVol)))
1907 SetupChannelFilter(pChn, (pChn->dwFlags & CHN_FILTER) ? FALSE : TRUE);
1908#endif // NO_FILTER
1909 }
1910 break;
1911
1912 // F0.F0.01.xx: Set Resonance
1913 case '1':
1914 if (dwParam < 0x80) pChn->nResonance = dwParam;
1915#ifndef NO_FILTER
1916 SetupChannelFilter(pChn, (pChn->dwFlags & CHN_FILTER) ? FALSE : TRUE);
1917#endif // NO_FILTER
1918
1919 break;
1920 }
1921
1922 }
1923}
1924
1925
1926void CSoundFile::RetrigNote(UINT nChn, UINT param)
1927//------------------------------------------------
1928{
1929 // Retrig: bit 8 is set if it's the new XM retrig
1930 MODCHANNEL *pChn = &Chn[nChn];
1931 UINT nRetrigSpeed = param & 0x0F;
1932 UINT nRetrigCount = pChn->nRetrigCount;
1933 BOOL bDoRetrig = FALSE;
1934
1935 if (m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT))
1936 {
1937 if (!nRetrigSpeed) nRetrigSpeed = 1;
1938 if ((nRetrigCount) && (!(nRetrigCount % nRetrigSpeed))) bDoRetrig = TRUE;
1939 nRetrigCount++;
1940 } else
1941 {
1942 UINT realspeed = nRetrigSpeed;
1943 if ((param & 0x100) && (pChn->nRowVolCmd == VOLCMD_VOLUME) && (pChn->nRowParam & 0xF0)) realspeed++;
1944 if ((m_nTickCount) || (param & 0x100))
1945 {
1946 if (!realspeed) realspeed = 1;
1947 if ((!(param & 0x100)) && (m_nMusicSpeed) && (!(m_nTickCount % realspeed))) bDoRetrig = TRUE;
1948 nRetrigCount++;
1949 } else if (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2)) nRetrigCount = 0;
1950 if (nRetrigCount >= realspeed)
1951 {
1952 if ((m_nTickCount) || ((param & 0x100) && (!pChn->nRowNote))) bDoRetrig = TRUE;
1953 }
1954 }
1955 if (bDoRetrig)
1956 {
1957 UINT dv = (param >> 4) & 0x0F;
1958 if (dv)
1959 {
1960 int vol = pChn->nVolume;
1961 if (retrigTable1[dv])
1962 vol = (vol * retrigTable1[dv]) >> 4;
1963 else
1964 vol += ((int)retrigTable2[dv]) << 2;
1965 if (vol < 0) vol = 0;
1966 if (vol > 256) vol = 256;
1967 pChn->nVolume = vol;
1968 pChn->dwFlags |= CHN_FASTVOLRAMP;
1969 }
1970 UINT nNote = pChn->nNewNote;
1971 LONG nOldPeriod = pChn->nPeriod;
1972 if ((nNote) && (nNote <= 120) && (pChn->nLength)) CheckNNA(nChn, 0, nNote, TRUE);
1973 BOOL bResetEnv = FALSE;
1974 if (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))
1975 {
1976 if ((pChn->nRowInstr) && (param < 0x100)) { InstrumentChange(pChn, pChn->nRowInstr, FALSE, FALSE); bResetEnv = TRUE; }
1977 if (param < 0x100) bResetEnv = TRUE;
1978 }
1979 NoteChange(nChn, nNote, FALSE, bResetEnv);
1980 if ((m_nType & MOD_TYPE_IT) && (!pChn->nRowNote) && (nOldPeriod)) pChn->nPeriod = nOldPeriod;
1981 if (!(m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT))) nRetrigCount = 0;
1982 }
1983 pChn->nRetrigCount = (BYTE)nRetrigCount;
1984}
1985
1986
1987void CSoundFile::DoFreqSlide(MODCHANNEL *pChn, LONG nFreqSlide)
1988//-------------------------------------------------------------
1989{
1990 // IT Linear slides
1991 if (!pChn->nPeriod) return;
1992 if ((m_dwSongFlags & SONG_LINEARSLIDES) && (!(m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))))
1993 {
1994 if (nFreqSlide < 0)
1995 {
1996 UINT n = (- nFreqSlide) >> 2;
1997 if (n > 255) n = 255;
1998 pChn->nPeriod = _muldivr(pChn->nPeriod, LinearSlideDownTable[n], 65536);
1999 } else
2000 {
2001 UINT n = (nFreqSlide) >> 2;
2002
2003 if (n > 255) n = 255;
2004 pChn->nPeriod = _muldivr(pChn->nPeriod, LinearSlideUpTable[n], 65536);
2005 }
2006 } else
2007 {
2008 pChn->nPeriod += nFreqSlide;
2009 }
2010 if (pChn->nPeriod < 1)
2011 {
2012 pChn->nPeriod = 1;
2013 if (m_nType & MOD_TYPE_IT)
2014 {
2015 pChn->dwFlags |= CHN_NOTEFADE;
2016 pChn->nFadeOutVol = 0;
2017 }
2018 }
2019}
2020
2021
2022void CSoundFile::NoteCut(UINT nChn, UINT nTick)
2023//---------------------------------------------
2024{
2025 if (m_nTickCount == nTick)
2026 {
2027 MODCHANNEL *pChn = &Chn[nChn];
2028 // if (m_nInstruments) KeyOff(pChn); ?
2029 pChn->nVolume = 0;
2030 pChn->dwFlags |= CHN_FASTVOLRAMP;
2031 }
2032}
2033
2034
2035void CSoundFile::KeyOff(UINT nChn)
2036//--------------------------------
2037{
2038 MODCHANNEL *pChn = &Chn[nChn];
2039 BOOL bKeyOn = (pChn->dwFlags & CHN_KEYOFF) ? FALSE : TRUE;
2040 pChn->dwFlags |= CHN_KEYOFF;
2041 //if ((!pChn->pHeader) || (!(pChn->dwFlags & CHN_VOLENV)))
2042 if ((pChn->pHeader) && (!(pChn->dwFlags & CHN_VOLENV)))
2043 {
2044 pChn->dwFlags |= CHN_NOTEFADE;
2045 }
2046 if (!pChn->nLength) return;
2047 if ((pChn->dwFlags & CHN_SUSTAINLOOP) && (pChn->pInstrument) && (bKeyOn))
2048 {
2049 MODINSTRUMENT *psmp = pChn->pInstrument;
2050 if (psmp->uFlags & CHN_LOOP)
2051 {
2052 if (psmp->uFlags & CHN_PINGPONGLOOP)
2053 pChn->dwFlags |= CHN_PINGPONGLOOP;
2054 else
2055 pChn->dwFlags &= ~(CHN_PINGPONGLOOP|CHN_PINGPONGFLAG);
2056 pChn->dwFlags |= CHN_LOOP;
2057 pChn->nLength = psmp->nLength;
2058 pChn->nLoopStart = psmp->nLoopStart;
2059 pChn->nLoopEnd = psmp->nLoopEnd;
2060 if (pChn->nLength > pChn->nLoopEnd) pChn->nLength = pChn->nLoopEnd;
2061 } else
2062 {
2063 pChn->dwFlags &= ~(CHN_LOOP|CHN_PINGPONGLOOP|CHN_PINGPONGFLAG);
2064 pChn->nLength = psmp->nLength;
2065 }
2066 }
2067 if (pChn->pHeader)
2068 {
2069 INSTRUMENTHEADER *penv = pChn->pHeader;
2070 if (((penv->dwFlags & ENV_VOLLOOP) || (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))) && (penv->nFadeOut))
2071 pChn->dwFlags |= CHN_NOTEFADE;
2072 }
2073}
2074
2075
2076//////////////////////////////////////////////////////////
2077// CSoundFile: Global Effects
2078
2079
2080void CSoundFile::SetSpeed(UINT param)
2081//-----------------------------------
2082{
2083 UINT max = (m_nType == MOD_TYPE_IT) ? 256 : 128;
2084 // Modplug Tracker and Mod-Plugin don't do this check
2085#ifndef MODPLUG_TRACKER
2086#ifndef FASTSOUNDLIB
2087 // Big Hack!!!
2088 if ((!param) || (param >= 0x80) || ((m_nType & (MOD_TYPE_MOD|MOD_TYPE_XM|MOD_TYPE_MT2)) && (param >= 0x1E)))
2089 {
2090 if (IsSongFinished(m_nCurrentPattern, m_nRow+1))
2091 {
2092 GlobalFadeSong(1000);
2093 }
2094 }
2095#endif // FASTSOUNDLIB
2096#endif // MODPLUG_TRACKER
2097 if ((m_nType & MOD_TYPE_S3M) && (param > 0x80)) param -= 0x80;
2098 if ((param) && (param <= max)) m_nMusicSpeed = param;
2099}
2100
2101
2102void CSoundFile::SetTempo(UINT param)
2103//-----------------------------------
2104{
2105 if (param < 0x20)
2106 {
2107 // Tempo Slide
2108 if ((param & 0xF0) == 0x10)
2109 {
2110 m_nMusicTempo += (param & 0x0F) * 2;
2111 if (m_nMusicTempo > 255) m_nMusicTempo = 255;
2112 } else
2113 {
2114 m_nMusicTempo -= (param & 0x0F) * 2;
2115 if ((LONG)m_nMusicTempo < 32) m_nMusicTempo = 32;
2116 }
2117 } else
2118 {
2119 m_nMusicTempo = param;
2120 }
2121}
2122
2123
2124int CSoundFile::PatternLoop(MODCHANNEL *pChn, UINT param)
2125//-------------------------------------------------------
2126{
2127 if (param)
2128 {
2129 if (pChn->nPatternLoopCount)
2130 {
2131 pChn->nPatternLoopCount--;
2132 if (!pChn->nPatternLoopCount) return -1;
2133 } else
2134 {
2135 MODCHANNEL *p = Chn;
2136 for (UINT i=0; i<m_nChannels; i++, p++) if (p != pChn)
2137 {
2138 // Loop already done
2139 if (p->nPatternLoopCount) return -1;
2140 }
2141 pChn->nPatternLoopCount = param;
2142 }
2143 return pChn->nPatternLoop;
2144 } else
2145 {
2146 pChn->nPatternLoop = m_nRow;
2147 }
2148 return -1;
2149}
2150
2151
2152void CSoundFile::GlobalVolSlide(UINT param)
2153//-----------------------------------------
2154{
2155 LONG nGlbSlide = 0;
2156 if (param) m_nOldGlbVolSlide = param; else param = m_nOldGlbVolSlide;
2157 if (((param & 0x0F) == 0x0F) && (param & 0xF0))
2158 {
2159 if (m_dwSongFlags & SONG_FIRSTTICK) nGlbSlide = (param >> 4) * 2;
2160 } else
2161 if (((param & 0xF0) == 0xF0) && (param & 0x0F))
2162 {
2163 if (m_dwSongFlags & SONG_FIRSTTICK) nGlbSlide = - (int)((param & 0x0F) * 2);
2164 } else
2165 {
2166 if (!(m_dwSongFlags & SONG_FIRSTTICK))
2167 {
2168 if (param & 0xF0) nGlbSlide = (int)((param & 0xF0) >> 4) * 2;
2169 else nGlbSlide = -(int)((param & 0x0F) * 2);
2170 }
2171 }
2172 if (nGlbSlide)
2173 {
2174 if (m_nType != MOD_TYPE_IT) nGlbSlide *= 2;
2175 nGlbSlide += m_nGlobalVolume;
2176 if (nGlbSlide < 0) nGlbSlide = 0;
2177 if (nGlbSlide > 256) nGlbSlide = 256;
2178 m_nGlobalVolume = nGlbSlide;
2179 }
2180}
2181
2182
2183DWORD CSoundFile::IsSongFinished(UINT nStartOrder, UINT nStartRow) const
2184//----------------------------------------------------------------------
2185{
2186 UINT nOrd;
2187
2188 for (nOrd=nStartOrder; nOrd<MAX_ORDERS; nOrd++)
2189 {
2190 UINT nPat = Order[nOrd];
2191 if (nPat != 0xFE)
2192 {
2193 MODCOMMAND *p;
2194
2195 if (nPat >= MAX_PATTERNS) break;
2196 p = Patterns[nPat];
2197 if (p)
2198 {
2199 UINT len = PatternSize[nPat] * m_nChannels;
2200 UINT pos = (nOrd == nStartOrder) ? nStartRow : 0;
2201 pos *= m_nChannels;
2202 while (pos < len)
2203 {
2204 UINT cmd;
2205 if ((p[pos].note) || (p[pos].volcmd)) return 0;
2206 cmd = p[pos].command;
2207 if (cmd == CMD_MODCMDEX)
2208 {
2209 UINT cmdex = p[pos].param & 0xF0;
2210 if ((!cmdex) || (cmdex == 0x60) || (cmdex == 0xE0) || (cmdex == 0xF0)) cmd = 0;
2211 }
2212 if ((cmd) && (cmd != CMD_SPEED) && (cmd != CMD_TEMPO)) return 0;
2213 pos++;
2214 }
2215 }
2216 }
2217 }
2218 return (nOrd < MAX_ORDERS) ? nOrd : MAX_ORDERS-1;
2219}
2220
2221
2222BOOL CSoundFile::IsValidBackwardJump(UINT nStartOrder, UINT nStartRow, UINT nJumpOrder, UINT nJumpRow) const
2223//----------------------------------------------------------------------------------------------------------
2224{
2225 while ((nJumpOrder < MAX_PATTERNS) && (Order[nJumpOrder] == 0xFE)) nJumpOrder++;
2226 if ((nStartOrder >= MAX_PATTERNS) || (nJumpOrder >= MAX_PATTERNS)) return FALSE;
2227 // Treat only case with jumps in the same pattern
2228 if (nJumpOrder > nStartOrder) return TRUE;
2229 if ((nJumpOrder < nStartOrder) || (nJumpRow >= PatternSize[nStartOrder])
2230 || (!Patterns[nStartOrder]) || (nStartRow >= 256) || (nJumpRow >= 256)) return FALSE;
2231 // See if the pattern is being played backward
2232 BYTE row_hist[256];
2233 memset(row_hist, 0, sizeof(row_hist));
2234 UINT nRows = PatternSize[nStartOrder], row = nJumpRow;
2235 if (nRows > 256) nRows = 256;
2236 row_hist[nStartRow] = TRUE;
2237 while ((row < 256) && (!row_hist[row]))
2238 {
2239 if (row >= nRows) return TRUE;
2240 row_hist[row] = TRUE;
2241 MODCOMMAND *p = Patterns[nStartOrder] + row * m_nChannels;
2242 row++;
2243 int breakrow = -1, posjump = 0;
2244 for (UINT i=0; i<m_nChannels; i++, p++)
2245 {
2246 if (p->command == CMD_POSITIONJUMP)
2247 {
2248 if (p->param < nStartOrder) return FALSE;
2249 if (p->param > nStartOrder) return TRUE;
2250 posjump = TRUE;
2251 } else
2252 if (p->command == CMD_PATTERNBREAK)
2253 {
2254 breakrow = p->param;
2255 }
2256 }
2257 if (breakrow >= 0)
2258 {
2259 if (!posjump) return TRUE;
2260 row = breakrow;
2261 }
2262 if (row >= nRows) return TRUE;
2263 }
2264 return FALSE;
2265}
2266
2267
2268//////////////////////////////////////////////////////
2269// Note/Period/Frequency functions
2270
2271UINT CSoundFile::GetNoteFromPeriod(UINT period) const
2272//---------------------------------------------------
2273{
2274 if (!period) return 0;
2275 if (m_nType & (MOD_TYPE_MED|MOD_TYPE_MOD|MOD_TYPE_MTM|MOD_TYPE_669|MOD_TYPE_OKT|MOD_TYPE_AMF0))
2276 {
2277 period >>= 2;
2278 for (UINT i=0; i<6*12; i++)
2279 {
2280 if (period >= ProTrackerPeriodTable[i])
2281 {
2282 if ((period != ProTrackerPeriodTable[i]) && (i))
2283 {
2284 UINT p1 = ProTrackerPeriodTable[i-1];
2285 UINT p2 = ProTrackerPeriodTable[i];
2286 if (p1 - period < (period - p2)) return i+36;
2287 }
2288 return i+1+36;
2289 }
2290 }
2291 return 6*12+36;
2292 } else
2293 {
2294 for (UINT i=1; i<120; i++)
2295 {
2296 LONG n = GetPeriodFromNote(i, 0, 0);
2297 if ((n > 0) && (n <= (LONG)period)) return i;
2298 }
2299 return 120;
2300 }
2301}
2302
2303
2304
2305UINT CSoundFile::GetPeriodFromNote(UINT note, int nFineTune, UINT nC4Speed) const
2306//-------------------------------------------------------------------------------
2307{
2308 if ((!note) || (note > 0xF0)) return 0;
2309 if (m_nType & (MOD_TYPE_IT|MOD_TYPE_S3M|MOD_TYPE_STM|MOD_TYPE_MDL|MOD_TYPE_ULT|MOD_TYPE_WAV
2310 |MOD_TYPE_FAR|MOD_TYPE_DMF|MOD_TYPE_PTM|MOD_TYPE_AMS|MOD_TYPE_DBM|MOD_TYPE_AMF|MOD_TYPE_PSM))
2311 {
2312 note--;
2313 if (m_dwSongFlags & SONG_LINEARSLIDES)
2314 {
2315 return (FreqS3MTable[note % 12] << 5) >> (note / 12);
2316 } else
2317 {
2318 if (!nC4Speed) nC4Speed = 8363;
2319 return _muldiv(8363, (FreqS3MTable[note % 12] << 5), nC4Speed << (note / 12));
2320 }
2321 } else
2322 if (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))
2323 {
2324 if (note < 13) note = 13;
2325 note -= 13;
2326 if (m_dwSongFlags & SONG_LINEARSLIDES)
2327 {
2328 LONG l = ((120 - note) << 6) - (nFineTune / 2);
2329 if (l < 1) l = 1;
2330 return (UINT)l;
2331 } else
2332 {
2333 int finetune = nFineTune;
2334 UINT rnote = (note % 12) << 3;
2335 UINT roct = note / 12;
2336 int rfine = finetune / 16;
2337 int i = rnote + rfine + 8;
2338 if (i < 0) i = 0;
2339 if (i >= 104) i = 103;
2340 UINT per1 = XMPeriodTable[i];
2341 if ( finetune < 0 )
2342 {
2343 rfine--;
2344 finetune = -finetune;
2345 } else rfine++;
2346 i = rnote+rfine+8;
2347 if (i < 0) i = 0;
2348 if (i >= 104) i = 103;
2349 UINT per2 = XMPeriodTable[i];
2350 rfine = finetune & 0x0F;
2351 per1 *= 16-rfine;
2352 per2 *= rfine;
2353 return ((per1 + per2) << 1) >> roct;
2354 }
2355 } else
2356 {
2357 note--;
2358 nFineTune = XM2MODFineTune(nFineTune);
2359 if ((nFineTune) || (note < 36) || (note >= 36+6*12))
2360 return (ProTrackerTunedPeriods[nFineTune*12 + note % 12] << 5) >> (note / 12);
2361 else
2362 return (ProTrackerPeriodTable[note-36] << 2);
2363 }
2364}
2365
2366
2367UINT CSoundFile::GetFreqFromPeriod(UINT period, UINT nC4Speed, int nPeriodFrac) const
2368//-----------------------------------------------------------------------------------
2369{
2370 if (!period) return 0;
2371 if (m_nType & (MOD_TYPE_MED|MOD_TYPE_MOD|MOD_TYPE_MTM|MOD_TYPE_669|MOD_TYPE_OKT|MOD_TYPE_AMF0))
2372 {
2373 return (3546895L*4) / period;
2374 } else
2375 if (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))
2376 {
2377 if (m_dwSongFlags & SONG_LINEARSLIDES)
2378 return XMLinearTable[period % 768] >> (period / 768);
2379 else
2380 return 8363 * 1712L / period;
2381 } else
2382 {
2383 if (m_dwSongFlags & SONG_LINEARSLIDES)
2384 {
2385 if (!nC4Speed) nC4Speed = 8363;
2386 return _muldiv(nC4Speed, 1712L << 8, (period << 8)+nPeriodFrac);
2387 } else
2388 {
2389 return _muldiv(8363, 1712L << 8, (period << 8)+nPeriodFrac);
2390 }
2391 }
2392}
2393
2394
diff --git a/core/multimedia/opieplayer/modplug/sndfile.cpp b/core/multimedia/opieplayer/modplug/sndfile.cpp
new file mode 100644
index 0000000..1d0d610
--- a/dev/null
+++ b/core/multimedia/opieplayer/modplug/sndfile.cpp
@@ -0,0 +1,1875 @@
1/*
2 * This program is free software; you can redistribute it and modify it
3 * under the terms of the GNU General Public License as published by the
4 * Free Software Foundation; either version 2 of the license or (at your
5 * option) any later version.
6 *
7 * Authors: Olivier Lapicque <olivierl@jps.net>,
8 * Adam Goode <adam@evdebs.org> (endian and char fixes for PPC)
9*/
10
11#include <math.h> //for GCCFIX
12#include "stdafx.h"
13#include "sndfile.h"
14
15#define MMCMP_SUPPORT
16
17#ifdef MMCMP_SUPPORT
18extern BOOL MMCMP_Unpack(LPCBYTE *ppMemFile, LPDWORD pdwMemLength);
19#endif
20
21// External decompressors
22extern void AMSUnpack(const char *psrc, UINT inputlen, char *pdest, UINT dmax, char packcharacter);
23extern WORD MDLReadBits(DWORD &bitbuf, UINT &bitnum, LPBYTE &ibuf, CHAR n);
24extern int DMFUnpack(LPBYTE psample, LPBYTE ibuf, LPBYTE ibufmax, UINT maxlen);
25extern DWORD ITReadBits(DWORD &bitbuf, UINT &bitnum, LPBYTE &ibuf, CHAR n);
26extern void ITUnpack8Bit(signed char *pSample, DWORD dwLen, LPBYTE lpMemFile, DWORD dwMemLength, BOOL b215);
27extern void ITUnpack16Bit(signed char *pSample, DWORD dwLen, LPBYTE lpMemFile, DWORD dwMemLength, BOOL b215);
28
29
30 #define MAX_PACK_TABLES 3
31
32
33// Compression table
34static const signed char UnpackTable[MAX_PACK_TABLES][16] =
35//--------------------------------------------
36{
37 // CPU-generated dynamic table
38 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
39 // u-Law table
40 {0, 1, 2, 4, 8, 16, 32, 64,
41 -1, -2, -4, -8, -16, -32, -48, -64},
42 // Linear table
43 {0, 1, 2, 3, 5, 7, 12, 19,
44 -1, -2, -3, -5, -7, -12, -19, -31}
45};
46
47
48//////////////////////////////////////////////////////////
49// CSoundFile
50
51CSoundFile::CSoundFile()
52//----------------------
53{
54 m_nType = MOD_TYPE_NONE;
55 m_dwSongFlags = 0;
56 m_nChannels = 0;
57 m_nMixChannels = 0;
58 m_nSamples = 0;
59 m_nInstruments = 0;
60 m_nPatternNames = 0;
61 m_lpszPatternNames = NULL;
62 m_lpszSongComments = NULL;
63 m_nFreqFactor = m_nTempoFactor = 128;
64 m_nMasterVolume = 128;
65 m_nMinPeriod = 0x20;
66 m_nMaxPeriod = 0x7FFF;
67 m_nRepeatCount = 0;
68 memset(Chn, 0, sizeof(Chn));
69 memset(ChnMix, 0, sizeof(ChnMix));
70 memset(Ins, 0, sizeof(Ins));
71 memset(ChnSettings, 0, sizeof(ChnSettings));
72 memset(Headers, 0, sizeof(Headers));
73 memset(Order, 0xFF, sizeof(Order));
74 memset(Patterns, 0, sizeof(Patterns));
75 memset(m_szNames, 0, sizeof(m_szNames));
76 memset(m_MixPlugins, 0, sizeof(m_MixPlugins));
77}
78
79
80CSoundFile::~CSoundFile()
81//-----------------------
82 {
83 Destroy();
84}
85
86
87BOOL CSoundFile::Create(LPCBYTE lpStream, DWORD dwMemLength)
88//----------------------------------------------------------
89{
90 int i;
91
92 m_nType = MOD_TYPE_NONE;
93 m_dwSongFlags = 0;
94 m_nChannels = 0;
95 m_nMixChannels = 0;
96 m_nSamples = 0;
97 m_nInstruments = 0;
98 m_nFreqFactor = m_nTempoFactor = 128;
99 m_nMasterVolume = 128;
100 m_nDefaultGlobalVolume = 256;
101 m_nGlobalVolume = 256;
102 m_nOldGlbVolSlide = 0;
103 m_nDefaultSpeed = 6;
104 m_nDefaultTempo = 125;
105 m_nPatternDelay = 0;
106 m_nFrameDelay = 0;
107 m_nNextRow = 0;
108 m_nRow = 0;
109 m_nPattern = 0;
110 m_nCurrentPattern = 0;
111 m_nNextPattern = 0;
112 m_nRestartPos = 0;
113 m_nMinPeriod = 16;
114 m_nMaxPeriod = 32767;
115 m_nSongPreAmp = 0x30;
116 m_nPatternNames = 0;
117 m_nMaxOrderPosition = 0;
118 m_lpszPatternNames = NULL;
119 m_lpszSongComments = NULL;
120 memset(Ins, 0, sizeof(Ins));
121 memset(ChnMix, 0, sizeof(ChnMix));
122 memset(Chn, 0, sizeof(Chn));
123 memset(Headers, 0, sizeof(Headers));
124 memset(Order, 0xFF, sizeof(Order));
125 memset(Patterns, 0, sizeof(Patterns));
126 memset(m_szNames, 0, sizeof(m_szNames));
127 memset(m_MixPlugins, 0, sizeof(m_MixPlugins));
128 ResetMidiCfg();
129 for (UINT npt=0; npt<MAX_PATTERNS; npt++) PatternSize[npt] = 64;
130 for (UINT nch=0; nch<MAX_BASECHANNELS; nch++)
131 {
132 ChnSettings[nch].nPan = 128;
133 ChnSettings[nch].nVolume = 64;
134 ChnSettings[nch].dwFlags = 0;
135 ChnSettings[nch].szName[0] = 0;
136 }
137 if (lpStream)
138 {
139#ifdef MMCMP_SUPPORT
140 BOOL bMMCmp = MMCMP_Unpack(&lpStream, &dwMemLength);
141#endif
142 if ((!ReadXM(lpStream, dwMemLength))
143 && (!ReadIT(lpStream, dwMemLength))
144 && (!ReadS3M(lpStream, dwMemLength))
145 // && (!ReadWav(lpStream, dwMemLength))
146#ifndef MODPLUG_BASIC_SUPPORT
147 && (!ReadSTM(lpStream, dwMemLength))
148 && (!ReadMed(lpStream, dwMemLength))
149 && (!ReadMTM(lpStream, dwMemLength))
150 && (!ReadMDL(lpStream, dwMemLength))
151 && (!ReadDBM(lpStream, dwMemLength))
152 && (!Read669(lpStream, dwMemLength))
153 && (!ReadFAR(lpStream, dwMemLength))
154 && (!ReadAMS(lpStream, dwMemLength))
155 && (!ReadOKT(lpStream, dwMemLength))
156 && (!ReadPTM(lpStream, dwMemLength))
157 && (!ReadUlt(lpStream, dwMemLength))
158 && (!ReadDMF(lpStream, dwMemLength))
159 && (!ReadDSM(lpStream, dwMemLength))
160 && (!ReadUMX(lpStream, dwMemLength))
161 && (!ReadAMF(lpStream, dwMemLength))
162 && (!ReadPSM(lpStream, dwMemLength))
163 && (!ReadMT2(lpStream, dwMemLength))
164#endif // MODPLUG_BASIC_SUPPORT
165 && (!ReadMod(lpStream, dwMemLength))) m_nType = MOD_TYPE_NONE;
166#ifdef MMCMP_SUPPORT
167 if (bMMCmp)
168 {
169 GlobalFreePtr(lpStream);
170 lpStream = NULL;
171 }
172#endif
173 }
174 // Adjust song names
175 for (i=0; i<MAX_SAMPLES; i++)
176 {
177 LPSTR p = m_szNames[i];
178 int j = 31;
179 p[j] = 0;
180 while ((j>=0) && (p[j]<=' ')) p[j--] = 0;
181 while (j>=0)
182 {
183 if (((BYTE)p[j]) < ' ') p[j] = ' ';
184 j--;
185 }
186 }
187 // Adjust channels
188 for (i=0; i<MAX_BASECHANNELS; i++)
189 {
190 if (ChnSettings[i].nVolume > 64) ChnSettings[i].nVolume = 64;
191 if (ChnSettings[i].nPan > 256) ChnSettings[i].nPan = 128;
192 Chn[i].nPan = ChnSettings[i].nPan;
193 Chn[i].nGlobalVol = ChnSettings[i].nVolume;
194 Chn[i].dwFlags = ChnSettings[i].dwFlags;
195 Chn[i].nVolume = 256;
196 Chn[i].nCutOff = 0x7F;
197 }
198 // Checking instruments
199 MODINSTRUMENT *pins = Ins;
200
201 for (i=0; i<MAX_INSTRUMENTS; i++, pins++)
202 {
203 if (pins->pSample)
204 {
205 if (pins->nLoopEnd > pins->nLength) pins->nLoopEnd = pins->nLength;
206 if (pins->nLoopStart + 3 >= pins->nLoopEnd)
207 {
208 pins->nLoopStart = 0;
209 pins->nLoopEnd = 0;
210 }
211 if (pins->nSustainEnd > pins->nLength) pins->nSustainEnd = pins->nLength;
212 if (pins->nSustainStart + 3 >= pins->nSustainEnd)
213 {
214 pins->nSustainStart = 0;
215 pins->nSustainEnd = 0;
216 }
217 } else
218 {
219 pins->nLength = 0;
220 pins->nLoopStart = 0;
221 pins->nLoopEnd = 0;
222 pins->nSustainStart = 0;
223 pins->nSustainEnd = 0;
224 }
225 if (!pins->nLoopEnd) pins->uFlags &= ~CHN_LOOP;
226 if (!pins->nSustainEnd) pins->uFlags &= ~CHN_SUSTAINLOOP;
227 if (pins->nGlobalVol > 64) pins->nGlobalVol = 64;
228 }
229 // Check invalid instruments
230 while ((m_nInstruments > 0) && (!Headers[m_nInstruments])) m_nInstruments--;
231 // Set default values
232 if (m_nSongPreAmp < 0x20) m_nSongPreAmp = 0x20;
233 if (m_nDefaultTempo < 32) m_nDefaultTempo = 125;
234 if (!m_nDefaultSpeed) m_nDefaultSpeed = 6;
235 m_nMusicSpeed = m_nDefaultSpeed;
236 m_nMusicTempo = m_nDefaultTempo;
237 m_nGlobalVolume = m_nDefaultGlobalVolume;
238 m_nNextPattern = 0;
239 m_nCurrentPattern = 0;
240 m_nPattern = 0;
241 m_nBufferCount = 0;
242 m_nTickCount = m_nMusicSpeed;
243 m_nNextRow = 0;
244 m_nRow = 0;
245 if ((m_nRestartPos >= MAX_ORDERS) || (Order[m_nRestartPos] >= MAX_PATTERNS)) m_nRestartPos = 0;
246 // Load plugins
247 if (gpMixPluginCreateProc)
248 {
249 for (UINT iPlug=0; iPlug<MAX_MIXPLUGINS; iPlug++)
250 {
251 if ((m_MixPlugins[iPlug].Info.dwPluginId1)
252 || (m_MixPlugins[iPlug].Info.dwPluginId2))
253 {
254 gpMixPluginCreateProc(&m_MixPlugins[iPlug]);
255 if (m_MixPlugins[iPlug].pMixPlugin)
256 {
257 m_MixPlugins[iPlug].pMixPlugin->RestoreAllParameters();
258 }
259 }
260 }
261 }
262 if (m_nType)
263 {
264 UINT maxpreamp = 0x10+(m_nChannels*8);
265 if (maxpreamp > 100) maxpreamp = 100;
266 if (m_nSongPreAmp > maxpreamp) m_nSongPreAmp = maxpreamp;
267 return TRUE;
268 }
269 return FALSE;
270}
271
272
273BOOL CSoundFile::Destroy()
274
275//------------------------
276{
277 int i;
278 for (i=0; i<MAX_PATTERNS; i++) if (Patterns[i])
279 {
280 FreePattern(Patterns[i]);
281 Patterns[i] = NULL;
282 }
283 m_nPatternNames = 0;
284 if (m_lpszPatternNames)
285 {
286 delete m_lpszPatternNames;
287 m_lpszPatternNames = NULL;
288 }
289 if (m_lpszSongComments)
290 {
291 delete m_lpszSongComments;
292 m_lpszSongComments = NULL;
293 }
294 for (i=1; i<MAX_SAMPLES; i++)
295 {
296 MODINSTRUMENT *pins = &Ins[i];
297 if (pins->pSample)
298 {
299 FreeSample(pins->pSample);
300 pins->pSample = NULL;
301 }
302 }
303 for (i=0; i<MAX_INSTRUMENTS; i++)
304 {
305 if (Headers[i])
306 {
307 delete Headers[i];
308 Headers[i] = NULL;
309 }
310 }
311 for (i=0; i<MAX_MIXPLUGINS; i++)
312 {
313 if ((m_MixPlugins[i].nPluginDataSize) && (m_MixPlugins[i].pPluginData))
314 {
315 m_MixPlugins[i].nPluginDataSize = 0;
316 delete [] (signed char*)m_MixPlugins[i].pPluginData;
317 m_MixPlugins[i].pPluginData = NULL;
318 }
319 m_MixPlugins[i].pMixState = NULL;
320 if (m_MixPlugins[i].pMixPlugin)
321 {
322 m_MixPlugins[i].pMixPlugin->Release();
323 m_MixPlugins[i].pMixPlugin = NULL;
324 }
325 }
326 m_nType = MOD_TYPE_NONE;
327 m_nChannels = m_nSamples = m_nInstruments = 0;
328 return TRUE;
329}
330
331
332//////////////////////////////////////////////////////////////////////////
333// Memory Allocation
334
335MODCOMMAND *CSoundFile::AllocatePattern(UINT rows, UINT nchns)
336//------------------------------------------------------------
337{
338 MODCOMMAND *p = new MODCOMMAND[rows*nchns];
339 if (p) memset(p, 0, rows*nchns*sizeof(MODCOMMAND));
340 return p;
341}
342
343
344void CSoundFile::FreePattern(LPVOID pat)
345//--------------------------------------
346{
347 if (pat) delete [] (signed char*)pat;
348}
349
350
351signed char* CSoundFile::AllocateSample(UINT nbytes)
352//-------------------------------------------
353{
354 signed char * p = (signed char *)GlobalAllocPtr(GHND, (nbytes+39) & ~7);
355 if (p) p += 16;
356 return p;
357}
358
359
360void CSoundFile::FreeSample(LPVOID p)
361//-----------------------------------
362{
363 if (p)
364 {
365 GlobalFreePtr(((LPSTR)p)-16);
366 }
367}
368
369
370//////////////////////////////////////////////////////////////////////////
371// Misc functions
372
373void CSoundFile::ResetMidiCfg()
374//-----------------------------
375{
376 memset(&m_MidiCfg, 0, sizeof(m_MidiCfg));
377 lstrcpy(&m_MidiCfg.szMidiGlb[MIDIOUT_START*32], "FF");
378 lstrcpy(&m_MidiCfg.szMidiGlb[MIDIOUT_STOP*32], "FC");
379 lstrcpy(&m_MidiCfg.szMidiGlb[MIDIOUT_NOTEON*32], "9c n v");
380 lstrcpy(&m_MidiCfg.szMidiGlb[MIDIOUT_NOTEOFF*32], "9c n 0");
381 lstrcpy(&m_MidiCfg.szMidiGlb[MIDIOUT_PROGRAM*32], "Cc p");
382 lstrcpy(&m_MidiCfg.szMidiSFXExt[0], "F0F000z");
383 for (int iz=0; iz<16; iz++) wsprintf(&m_MidiCfg.szMidiZXXExt[iz*32], "F0F001%02X", iz*8);
384}
385
386
387UINT CSoundFile::GetNumChannels() const
388//-------------------------------------
389{
390 UINT n = 0;
391 for (UINT i=0; i<m_nChannels; i++) if (ChnSettings[i].nVolume) n++;
392 return n;
393}
394
395
396UINT CSoundFile::GetSongComments(LPSTR s, UINT len, UINT linesize)
397//----------------------------------------------------------------
398{
399 LPCSTR p = m_lpszSongComments;
400 if (!p) return 0;
401 UINT i = 2, ln=0;
402 if ((len) && (s)) s[0] = '\x0D';
403 if ((len > 1) && (s)) s[1] = '\x0A';
404 while ((*p)&& (i+2 < len))
405 {
406 BYTE c = (BYTE)*p++;
407 if ((c == 0x0D) || ((c == ' ') && (ln >= linesize)))
408 { if (s) { s[i++] = '\x0D'; s[i++] = '\x0A'; } else i+= 2; ln=0; }
409 else
410 if (c >= 0x20) { if (s) s[i++] = c; else i++; ln++; }
411 }
412 if (s) s[i] = 0;
413 return i;
414}
415
416
417UINT CSoundFile::GetRawSongComments(LPSTR s, UINT len, UINT linesize)
418//-------------------------------------------------------------------
419{
420 LPCSTR p = m_lpszSongComments;
421 if (!p) return 0;
422 UINT i = 0, ln=0;
423 while ((*p)&& (i < len-1))
424 {
425 BYTE c = (BYTE)*p++;
426 if ((c == 0x0D)|| (c == 0x0A))
427 {
428 if (ln)
429 {
430 while (ln < linesize) { if (s) s[i] = ' '; i++; ln++; }
431 ln = 0;
432 }
433 } else
434 if ((c == ' ') && (!ln))
435 {
436 UINT k=0;
437 while ((p[k]) && (p[k] >= ' '))k++;
438 if (k <= linesize)
439 {
440 if (s) s[i] = ' ';
441 i++;
442 ln++;
443 }
444 } else
445 {
446 if (s) s[i] = c;
447 i++;
448 ln++;
449 if (ln == linesize) ln = 0;
450 }
451 }
452 if (ln)
453 {
454 while ((ln < linesize) && (i < len))
455 {
456 if (s) s[i] = ' ';
457 i++;
458 ln++;
459 }
460 }
461 if (s) s[i] = 0;
462 return i;
463}
464
465
466BOOL CSoundFile::SetWaveConfig(UINT nRate,UINT nBits,UINT nChannels,BOOL bMMX)
467//----------------------------------------------------------------------------
468{
469 BOOL bReset = FALSE;
470 DWORD d = gdwSoundSetup & ~SNDMIX_ENABLEMMX;
471 if (bMMX) d |= SNDMIX_ENABLEMMX;
472 if ((gdwMixingFreq != nRate) || (gnBitsPerSample != nBits) || (gnChannels != nChannels) || (d != gdwSoundSetup)) bReset = TRUE;
473 gnChannels = nChannels;
474 gdwSoundSetup = d;
475 gdwMixingFreq = nRate;
476 gnBitsPerSample = nBits;
477 InitPlayer(bReset);
478 return TRUE;
479}
480
481
482BOOL CSoundFile::SetResamplingMode(UINT nMode)
483//--------------------------------------------
484{
485 DWORD d = gdwSoundSetup & ~(SNDMIX_NORESAMPLING|SNDMIX_HQRESAMPLER|SNDMIX_ULTRAHQSRCMODE);
486 switch(nMode)
487 {
488 case SRCMODE_NEAREST:d |= SNDMIX_NORESAMPLING; break;
489 case SRCMODE_LINEAR:break;
490 case SRCMODE_SPLINE:d |= SNDMIX_HQRESAMPLER; break;
491 case SRCMODE_POLYPHASE:d |= (SNDMIX_HQRESAMPLER|SNDMIX_ULTRAHQSRCMODE); break;
492 default:
493 return FALSE;
494 }
495 gdwSoundSetup = d;
496 return TRUE;
497}
498
499
500BOOL CSoundFile::SetMasterVolume(UINT nVol, BOOL bAdjustAGC)
501//----------------------------------------------------------
502{
503 if (nVol < 1) nVol = 1;
504 if (nVol > 0x200) nVol = 0x200;// x4 maximum
505 if ((nVol < m_nMasterVolume) && (nVol) && (gdwSoundSetup & SNDMIX_AGC) && (bAdjustAGC))
506 {
507 gnAGC = gnAGC * m_nMasterVolume / nVol;
508 if (gnAGC > AGC_UNITY) gnAGC = AGC_UNITY;
509 }
510 m_nMasterVolume = nVol;
511 return TRUE;
512}
513
514
515void CSoundFile::SetAGC(BOOL b)
516//-----------------------------
517{
518 if (b)
519 {
520 if (!(gdwSoundSetup & SNDMIX_AGC))
521 {
522 gdwSoundSetup |= SNDMIX_AGC;
523 gnAGC = AGC_UNITY;
524 }
525 } else gdwSoundSetup &= ~SNDMIX_AGC;
526}
527
528
529UINT CSoundFile::GetNumPatterns() const
530//-------------------------------------
531{
532 UINT i = 0;
533 while ((i < MAX_ORDERS) && (Order[i] < 0xFF)) i++;
534 return i;
535}
536
537
538UINT CSoundFile::GetNumInstruments() const
539//----------------------------------------
540{
541 UINT n=0;
542 for (UINT i=0; i<MAX_INSTRUMENTS; i++) if (Ins[i].pSample) n++;
543 return n;
544}
545
546
547UINT CSoundFile::GetMaxPosition() const
548//-------------------------------------
549{
550 UINT max = 0;
551 UINT i = 0;
552
553 while ((i < MAX_ORDERS) && (Order[i] != 0xFF))
554 {
555 if (Order[i] < MAX_PATTERNS) max += PatternSize[Order[i]];
556 i++;
557 }
558 return max;
559}
560
561
562UINT CSoundFile::GetCurrentPos() const
563//------------------------------------
564{
565 UINT pos = 0;
566
567 for (UINT i=0; i<m_nCurrentPattern; i++) if (Order[i] < MAX_PATTERNS)
568 pos += PatternSize[Order[i]];
569 return pos + m_nRow;
570}
571
572
573void CSoundFile::SetCurrentPos(UINT nPos)
574//---------------------------------------
575{
576 UINT i, nPattern;
577
578 for (i=0; i<MAX_CHANNELS; i++)
579 {
580 Chn[i].nNote = Chn[i].nNewNote = Chn[i].nNewIns = 0;
581 Chn[i].pInstrument = NULL;
582 Chn[i].pHeader = NULL;
583 Chn[i].nPortamentoDest = 0;
584 Chn[i].nCommand = 0;
585 Chn[i].nPatternLoopCount = 0;
586 Chn[i].nPatternLoop = 0;
587 Chn[i].nFadeOutVol = 0;
588 Chn[i].dwFlags |= CHN_KEYOFF|CHN_NOTEFADE;
589 Chn[i].nTremorCount = 0;
590 }
591 if (!nPos)
592 {
593 for (i=0; i<MAX_CHANNELS; i++)
594 {
595 Chn[i].nPeriod = 0;
596 Chn[i].nPos = Chn[i].nLength = 0;
597 Chn[i].nLoopStart = 0;
598 Chn[i].nLoopEnd = 0;
599 Chn[i].nROfs = Chn[i].nLOfs = 0;
600 Chn[i].pSample = NULL;
601 Chn[i].pInstrument = NULL;
602 Chn[i].pHeader = NULL;
603 Chn[i].nCutOff = 0x7F;
604 Chn[i].nResonance = 0;
605 Chn[i].nLeftVol = Chn[i].nRightVol = 0;
606 Chn[i].nNewLeftVol = Chn[i].nNewRightVol = 0;
607 Chn[i].nLeftRamp = Chn[i].nRightRamp = 0;
608 Chn[i].nVolume = 256;
609 if (i < MAX_BASECHANNELS)
610 {
611 Chn[i].dwFlags = ChnSettings[i].dwFlags;
612 Chn[i].nPan = ChnSettings[i].nPan;
613 Chn[i].nGlobalVol = ChnSettings[i].nVolume;
614 } else
615 {
616 Chn[i].dwFlags = 0;
617 Chn[i].nPan = 128;
618 Chn[i].nGlobalVol = 64;
619 }
620 }
621 m_nGlobalVolume = m_nDefaultGlobalVolume;
622 m_nMusicSpeed = m_nDefaultSpeed;
623 m_nMusicTempo = m_nDefaultTempo;
624 }
625 m_dwSongFlags &= ~(SONG_PATTERNLOOP|SONG_CPUVERYHIGH|SONG_FADINGSONG|SONG_ENDREACHED|SONG_GLOBALFADE);
626 for (nPattern = 0; nPattern < MAX_ORDERS; nPattern++)
627 {
628 UINT ord = Order[nPattern];
629 if (ord == 0xFE) continue;
630 if (ord == 0xFF) break;
631 if (ord < MAX_PATTERNS)
632 {
633 if (nPos < (UINT)PatternSize[ord]) break;
634 nPos -= PatternSize[ord];
635 }
636 }
637 // Buggy position ?
638 if ((nPattern >= MAX_ORDERS)
639 || (Order[nPattern] >= MAX_PATTERNS)
640 || (nPos >= PatternSize[Order[nPattern]]))
641 {
642 nPos = 0;
643 nPattern = 0;
644 }
645 UINT nRow = nPos;
646 if ((nRow) && (Order[nPattern] < MAX_PATTERNS))
647 {
648 MODCOMMAND *p = Patterns[Order[nPattern]];
649 if ((p) && (nRow < PatternSize[Order[nPattern]]))
650 {
651 BOOL bOk = FALSE;
652 while ((!bOk) && (nRow > 0))
653 {
654 UINT n = nRow * m_nChannels;
655 for (UINT k=0; k<m_nChannels; k++, n++)
656 {
657 if (p[n].note)
658 {
659 bOk = TRUE;
660 break;
661 }
662 }
663 if (!bOk) nRow--;
664 }
665 }
666 }
667 m_nNextPattern = nPattern;
668 m_nNextRow = nRow;
669 m_nTickCount = m_nMusicSpeed;
670 m_nBufferCount = 0;
671 m_nPatternDelay = 0;
672 m_nFrameDelay = 0;
673}
674
675
676void CSoundFile::SetCurrentOrder(UINT nPos)
677//-----------------------------------------
678{
679 while ((nPos < MAX_ORDERS) && (Order[nPos] == 0xFE)) nPos++;
680 if ((nPos >= MAX_ORDERS) || (Order[nPos] >= MAX_PATTERNS)) return;
681 for (UINT j=0; j<MAX_CHANNELS; j++)
682 {
683 Chn[j].nPeriod = 0;
684 Chn[j].nNote = 0;
685 Chn[j].nPortamentoDest = 0;
686 Chn[j].nCommand = 0;
687 Chn[j].nPatternLoopCount = 0;
688 Chn[j].nPatternLoop = 0;
689 Chn[j].nTremorCount = 0;
690 }
691 if (!nPos)
692 {
693 SetCurrentPos(0);
694 } else
695 {
696 m_nNextPattern = nPos;
697 m_nRow = m_nNextRow = 0;
698 m_nPattern = 0;
699 m_nTickCount = m_nMusicSpeed;
700 m_nBufferCount = 0;
701 m_nTotalCount = 0;
702 m_nPatternDelay = 0;
703 m_nFrameDelay = 0;
704 }
705 m_dwSongFlags &= ~(SONG_PATTERNLOOP|SONG_CPUVERYHIGH|SONG_FADINGSONG|SONG_ENDREACHED|SONG_GLOBALFADE);
706}
707
708
709void CSoundFile::ResetChannels()
710//------------------------------
711{
712 m_dwSongFlags &= ~(SONG_CPUVERYHIGH|SONG_FADINGSONG|SONG_ENDREACHED|SONG_GLOBALFADE);
713 m_nBufferCount = 0;
714 for (UINT i=0; i<MAX_CHANNELS; i++)
715 {
716 Chn[i].nROfs = Chn[i].nLOfs = 0;
717 }
718}
719
720
721void CSoundFile::LoopPattern(int nPat, int nRow)
722//----------------------------------------------
723{
724 if ((nPat < 0) || (nPat >= MAX_PATTERNS) || (!Patterns[nPat]))
725 {
726 m_dwSongFlags &= ~SONG_PATTERNLOOP;
727 } else
728 {
729 if ((nRow < 0) || (nRow >= PatternSize[nPat])) nRow = 0;
730 m_nPattern = nPat;
731 m_nRow = m_nNextRow = nRow;
732 m_nTickCount = m_nMusicSpeed;
733 m_nPatternDelay = 0;
734 m_nFrameDelay = 0;
735 m_nBufferCount = 0;
736 m_dwSongFlags |= SONG_PATTERNLOOP;
737 }
738}
739
740
741UINT CSoundFile::GetBestSaveFormat() const
742//----------------------------------------
743{
744 if ((!m_nSamples) || (!m_nChannels)) return MOD_TYPE_NONE;
745 if (!m_nType) return MOD_TYPE_NONE;
746 if (m_nType & (MOD_TYPE_MOD|MOD_TYPE_OKT))
747 return MOD_TYPE_MOD;
748 if (m_nType & (MOD_TYPE_S3M|MOD_TYPE_STM|MOD_TYPE_ULT|MOD_TYPE_FAR|MOD_TYPE_PTM))
749 return MOD_TYPE_S3M;
750 if (m_nType & (MOD_TYPE_XM|MOD_TYPE_MED|MOD_TYPE_MTM|MOD_TYPE_MT2))
751 return MOD_TYPE_XM;
752 return MOD_TYPE_IT;
753}
754
755
756UINT CSoundFile::GetSaveFormats() const
757//-------------------------------------
758{
759 UINT n = 0;
760 if ((!m_nSamples) || (!m_nChannels) || (m_nType == MOD_TYPE_NONE)) return 0;
761 switch(m_nType)
762 {
763 case MOD_TYPE_MOD:n = MOD_TYPE_MOD;
764 case MOD_TYPE_S3M:n = MOD_TYPE_S3M;
765 }
766 n |= MOD_TYPE_XM | MOD_TYPE_IT;
767 if (!m_nInstruments)
768 {
769 if (m_nSamples < 32) n |= MOD_TYPE_MOD;
770 n |= MOD_TYPE_S3M;
771 }
772 return n;
773}
774
775
776UINT CSoundFile::GetSampleName(UINT nSample,LPSTR s) const
777//--------------------------------------------------------
778{
779 char sztmp[40] = ""; // changed from CHAR
780 memcpy(sztmp, m_szNames[nSample],32);
781 sztmp[31] = 0;
782 if (s) strcpy(s, sztmp);
783 return strlen(sztmp);
784}
785
786
787UINT CSoundFile::GetInstrumentName(UINT nInstr,LPSTR s) const
788//-----------------------------------------------------------
789{
790 char sztmp[40] = ""; // changed from CHAR
791 if ((nInstr >= MAX_INSTRUMENTS) || (!Headers[nInstr]))
792 {
793 if (s) *s = 0;
794 return 0;
795 }
796 INSTRUMENTHEADER *penv = Headers[nInstr];
797 memcpy(sztmp, penv->name, 32);
798 sztmp[31] = 0;
799 if (s) strcpy(s, sztmp);
800 return strlen(sztmp);
801}
802
803
804#ifndef NO_PACKING
805UINT CSoundFile::PackSample(int &sample, int next)
806//------------------------------------------------
807{
808 UINT i = 0;
809 int delta = next - sample;
810 if (delta >= 0)
811 {
812 for (i=0; i<7; i++) if (delta <= (int)CompressionTable[i+1]) break;
813 } else
814 {
815 for (i=8; i<15; i++) if (delta >= (int)CompressionTable[i+1]) break;
816 }
817 sample += (int)CompressionTable[i];
818 return i;
819}
820
821
822BOOL CSoundFile::CanPackSample(LPSTR pSample, UINT nLen, UINT nPacking, BYTE *result)
823//-----------------------------------------------------------------------------------
824{
825 int pos, old, oldpos, besttable = 0;
826 DWORD dwErr, dwTotal, dwResult;
827 int i,j;
828
829 if (result) *result = 0;
830 if ((!pSample) || (nLen < 1024)) return FALSE;
831 // Try packing with different tables
832 dwResult = 0;
833 for (j=1; j<MAX_PACK_TABLES; j++)
834 {
835 memcpy(CompressionTable, UnpackTable[j], 16);
836 dwErr = 0;
837 dwTotal = 1;
838 old = pos = oldpos = 0;
839 for (i=0; i<(int)nLen; i++)
840 {
841 int s = (int)pSample[i];
842 PackSample(pos, s);
843 dwErr += abs(pos - oldpos);
844 dwTotal += abs(s - old);
845 old = s;
846 oldpos = pos;
847 }
848 dwErr = _muldiv(dwErr, 100, dwTotal);
849 if (dwErr >= dwResult)
850 {
851 dwResult = dwErr;
852 besttable = j;
853 }
854 }
855 memcpy(CompressionTable, UnpackTable[besttable], 16);
856 if (result)
857 {
858 if (dwResult > 100) *result= 100; else *result = (BYTE)dwResult;
859 }
860 return (dwResult >= nPacking) ? TRUE : FALSE;
861}
862#endif // NO_PACKING
863
864#ifndef MODPLUG_NO_FILESAVE
865
866UINT CSoundFile::WriteSample(FILE *f, MODINSTRUMENT *pins, UINT nFlags, UINT nMaxLen)
867//-----------------------------------------------------------------------------------
868{
869 UINT len = 0, bufcount;
870 signed char buffer[4096];
871 signed char *pSample = (signed char *)pins->pSample;
872 UINT nLen = pins->nLength;
873
874 if ((nMaxLen) && (nLen > nMaxLen)) nLen = nMaxLen;
875 if ((!pSample) || (f == NULL) || (!nLen)) return 0;
876 switch(nFlags)
877 {
878#ifndef NO_PACKING
879 // 3: 4-bit ADPCM data
880 case RS_ADPCM4:
881 {
882 int pos;
883 len = (nLen + 1) / 2;
884 fwrite(CompressionTable, 16, 1, f);
885 bufcount = 0;
886 pos = 0;
887 for (UINT j=0; j<len; j++)
888 {
889 BYTE b;
890 // Sample #1
891 b = PackSample(pos, (int)pSample[j*2]);
892 // Sample #2
893 b |= PackSample(pos, (int)pSample[j*2+1]) << 4;
894 buffer[bufcount++] = (signed char)b;
895 if (bufcount >= sizeof(buffer))
896 {
897 fwrite(buffer, 1, bufcount, f);
898 bufcount = 0;
899 }
900 }
901 if (bufcount) fwrite(buffer, 1, bufcount, f);
902 len += 16;
903 }
904 break;
905#endif // NO_PACKING
906
907 // 16-bit samples
908 case RS_PCM16U:
909 case RS_PCM16D:
910 case RS_PCM16S:
911 {
912 short int *p = (short int *)pSample;
913 int s_old = 0, s_ofs;
914 len = nLen * 2;
915 bufcount = 0;
916 s_ofs = (nFlags == RS_PCM16U) ? 0x8000 : 0;
917 for (UINT j=0; j<nLen; j++)
918 {
919 int s_new = *p;
920 p++;
921 if (pins->uFlags & CHN_STEREO)
922 {
923 s_new = (s_new + (*p) + 1) >> 1;
924 p++;
925 }
926 if (nFlags == RS_PCM16D)
927 {
928 *((short *)(&buffer[bufcount])) = (short)(s_new - s_old);
929 s_old = s_new;
930 } else
931 {
932 *((short *)(&buffer[bufcount])) = (short)(s_new + s_ofs);
933 }
934 bufcount += 2;
935 if (bufcount >= sizeof(buffer) - 1)
936 {
937 fwrite(buffer, 1, bufcount, f);
938 bufcount = 0;
939 }
940 }
941 if (bufcount) fwrite(buffer, 1, bufcount, f);
942 }
943 break;
944
945
946 // 8-bit Stereo samples (not interleaved)
947 case RS_STPCM8S:
948 case RS_STPCM8U:
949 case RS_STPCM8D:
950 {
951 int s_ofs = (nFlags == RS_STPCM8U) ? 0x80 : 0;
952 for (UINT iCh=0; iCh<2; iCh++)
953 {
954 signed char *p = pSample + iCh;
955 int s_old = 0;
956
957 bufcount = 0;
958 for (UINT j=0; j<nLen; j++)
959 {
960 int s_new = *p;
961 p += 2;
962 if (nFlags == RS_STPCM8D)
963 {
964 buffer[bufcount++] = (signed char)(s_new - s_old);
965 s_old = s_new;
966 } else
967 {
968 buffer[bufcount++] = (signed char)(s_new + s_ofs);
969 }
970 if (bufcount >= sizeof(buffer))
971 {
972 fwrite(buffer, 1, bufcount, f);
973 bufcount = 0;
974 }
975 }
976 if (bufcount) fwrite(buffer, 1, bufcount, f);
977 }
978 }
979 len = nLen * 2;
980 break;
981
982 // 16-bit Stereo samples (not interleaved)
983 case RS_STPCM16S:
984 case RS_STPCM16U:
985 case RS_STPCM16D:
986 {
987 int s_ofs = (nFlags == RS_STPCM16U) ? 0x8000 : 0;
988 for (UINT iCh=0; iCh<2; iCh++)
989 {
990 signed short *p = ((signed short *)pSample) + iCh;
991 int s_old = 0;
992
993 bufcount = 0;
994 for (UINT j=0; j<nLen; j++)
995 {
996 int s_new = *p;
997 p += 2;
998 if (nFlags == RS_STPCM16D)
999 {
1000 *((short *)(&buffer[bufcount])) = (short)(s_new - s_old);
1001 s_old = s_new;
1002 } else
1003 {
1004 *((short *)(&buffer[bufcount])) = (short)(s_new + s_ofs);
1005 }
1006 bufcount += 2;
1007 if (bufcount >= sizeof(buffer))
1008 {
1009 fwrite(buffer, 1, bufcount, f);
1010 bufcount = 0;
1011 }
1012 }
1013 if (bufcount) fwrite(buffer, 1, bufcount, f);
1014 }
1015 }
1016 len = nLen*4;
1017 break;
1018
1019 //Stereo signed interleaved
1020 case RS_STIPCM8S:
1021 case RS_STIPCM16S:
1022 len = nLen * 2;
1023 if (nFlags == RS_STIPCM16S) len *= 2;
1024 fwrite(pSample, 1, len, f);
1025 break;
1026
1027 // Default: assume 8-bit PCM data
1028 default:
1029 len = nLen;
1030 bufcount = 0;
1031 {
1032 signed char *p = pSample;
1033 int sinc = (pins->uFlags & CHN_16BIT) ? 2 : 1;
1034 int s_old = 0, s_ofs = (nFlags == RS_PCM8U) ? 0x80 : 0;
1035 if (pins->uFlags & CHN_16BIT) p++;
1036 for (UINT j=0; j<len; j++)
1037 {
1038 int s_new = (signed char)(*p);
1039 p += sinc;
1040 if (pins->uFlags & CHN_STEREO)
1041 {
1042 s_new = (s_new + ((int)*p) + 1) >> 1;
1043 p += sinc;
1044 }
1045 if (nFlags == RS_PCM8D)
1046 {
1047 buffer[bufcount++] = (signed char)(s_new - s_old);
1048 s_old = s_new;
1049 } else
1050 {
1051 buffer[bufcount++] = (signed char)(s_new + s_ofs);
1052 }
1053 if (bufcount >= sizeof(buffer))
1054 {
1055 fwrite(buffer, 1, bufcount, f);
1056 bufcount = 0;
1057 }
1058 }
1059 if (bufcount) fwrite(buffer, 1, bufcount, f);
1060 }
1061 }
1062 return len;
1063}
1064
1065#endif // MODPLUG_NO_FILESAVE
1066
1067
1068// Flags:
1069 //0 = signed 8-bit PCM data (default)
1070 //1 = unsigned 8-bit PCM data
1071 //2 = 8-bit ADPCM data with linear table
1072 //3 = 4-bit ADPCM data
1073 //4 = 16-bit ADPCM data with linear table
1074 //5 = signed 16-bit PCM data
1075 //6 = unsigned 16-bit PCM data
1076
1077
1078UINT CSoundFile::ReadSample(MODINSTRUMENT *pIns, UINT nFlags, LPCSTR lpMemFile, DWORD dwMemLength)
1079//------------------------------------------------------------------------------------------------
1080{
1081 UINT len = 0, mem = pIns->nLength+6;
1082
1083 if ((!pIns) || (pIns->nLength < 4) || (!lpMemFile)) return 0;
1084 if (pIns->nLength > MAX_SAMPLE_LENGTH) pIns->nLength = MAX_SAMPLE_LENGTH;
1085 pIns->uFlags &= ~(CHN_16BIT|CHN_STEREO);
1086 if (nFlags & RSF_16BIT)
1087 {
1088 mem *= 2;
1089 pIns->uFlags |= CHN_16BIT;
1090 }
1091 if (nFlags & RSF_STEREO)
1092 {
1093 mem *= 2;
1094 pIns->uFlags |= CHN_STEREO;
1095 }
1096 if ((pIns->pSample = AllocateSample(mem)) == NULL)
1097 {
1098 pIns->nLength = 0;
1099 return 0;
1100 }
1101 switch(nFlags)
1102 {
1103 // 1: 8-bit unsigned PCM data
1104 case RS_PCM8U:
1105 {
1106 len = pIns->nLength;
1107 if (len > dwMemLength) len = pIns->nLength = dwMemLength;
1108 signed char *pSample = pIns->pSample;
1109 for (UINT j=0; j<len; j++) pSample[j] = (signed char)(lpMemFile[j] - 0x80);
1110 }
1111 break;
1112
1113 // 2: 8-bit ADPCM data with linear table
1114 case RS_PCM8D:
1115 {
1116 len = pIns->nLength;
1117 if (len > dwMemLength) break;
1118 signed char *pSample = pIns->pSample;
1119 const signed char *p = (const signed char *)lpMemFile;
1120 int delta = 0;
1121
1122 for (UINT j=0; j<len; j++)
1123 {
1124 delta += p[j];
1125 *pSample++ = (signed char)delta;
1126 }
1127 }
1128 break;
1129
1130 // 3: 4-bit ADPCM data
1131 case RS_ADPCM4:
1132 {
1133 len = (pIns->nLength + 1) / 2;
1134 if (len > dwMemLength - 16) break;
1135 memcpy(CompressionTable, lpMemFile, 16);
1136 lpMemFile += 16;
1137 signed char *pSample = pIns->pSample;
1138 signed char delta = 0;
1139 for (UINT j=0; j<len; j++)
1140 {
1141 BYTE b0 = (BYTE)lpMemFile[j];
1142 BYTE b1 = (BYTE)(lpMemFile[j] >> 4);
1143 delta = (signed char)GetDeltaValue((int)delta, b0);
1144 pSample[0] = delta;
1145 delta = (signed char)GetDeltaValue((int)delta, b1);
1146 pSample[1] = delta;
1147 pSample += 2;
1148 }
1149 len += 16;
1150 }
1151 break;
1152
1153 // 4: 16-bit ADPCM data with linear table
1154 case RS_PCM16D:
1155 {
1156 len = pIns->nLength * 2;
1157 if (len > dwMemLength) break;
1158 short int *pSample = (short int *)pIns->pSample;
1159 short int *p = (short int *)lpMemFile;
1160 int delta16 = 0;
1161 for (UINT j=0; j<len; j+=2)
1162 {
1163 delta16 += bswapLE16(*p++);
1164 *pSample++ = (short int)delta16;
1165 }
1166 }
1167 break;
1168
1169 // 5: 16-bit signed PCM data
1170 case RS_PCM16S:
1171 {
1172 len = pIns->nLength * 2;
1173 if (len <= dwMemLength) memcpy(pIns->pSample, lpMemFile, len);
1174 short int *pSample = (short int *)pIns->pSample;
1175 for (UINT j=0; j<len; j+=2)
1176 {
1177 *pSample++ = bswapLE16(*pSample);
1178 }
1179 }
1180 break;
1181
1182 // 16-bit signed mono PCM motorola byte order
1183 case RS_PCM16M:
1184 len = pIns->nLength * 2;
1185 if (len > dwMemLength) len = dwMemLength & ~1;
1186 if (len > 1)
1187 {
1188 signed char *pSample = (signed char *)pIns->pSample;
1189 signed char *pSrc = (signed char *)lpMemFile;
1190 for (UINT j=0; j<len; j+=2)
1191 {
1192 // pSample[j] = pSrc[j+1];
1193 // pSample[j+1] = pSrc[j];
1194 *((unsigned short *)(pSample+j)) = bswapBE16(*((unsigned short *)(pSrc+j)));
1195 }
1196 }
1197 break;
1198
1199 // 6: 16-bit unsigned PCM data
1200 case RS_PCM16U:
1201 {
1202 len = pIns->nLength * 2;
1203 if (len > dwMemLength) break;
1204 short int *pSample = (short int *)pIns->pSample;
1205 short int *pSrc = (short int *)lpMemFile;
1206 for (UINT j=0; j<len; j+=2) *pSample++ = bswapLE16(*(pSrc++)) - 0x8000;
1207 }
1208 break;
1209
1210 // 16-bit signed stereo big endian
1211 case RS_STPCM16M:
1212 len = pIns->nLength * 2;
1213 if (len*2 <= dwMemLength)
1214 {
1215 signed char *pSample = (signed char *)pIns->pSample;
1216 signed char *pSrc = (signed char *)lpMemFile;
1217 for (UINT j=0; j<len; j+=2)
1218 {
1219 // pSample[j*2] = pSrc[j+1];
1220 // pSample[j*2+1] = pSrc[j];
1221 // pSample[j*2+2] = pSrc[j+1+len];
1222 // pSample[j*2+3] = pSrc[j+len];
1223 *((unsigned short *)(pSample+j*2)) = bswapBE16(*((unsigned short *)(pSrc+j)));
1224 *((unsigned short *)(pSample+j*2+2)) = bswapBE16(*((unsigned short *)(pSrc+j+len)));
1225 }
1226 len *= 2;
1227 }
1228 break;
1229
1230 // 8-bit stereo samples
1231 case RS_STPCM8S:
1232 case RS_STPCM8U:
1233 case RS_STPCM8D:
1234 {
1235 int iadd_l = 0, iadd_r = 0;
1236 if (nFlags == RS_STPCM8U) { iadd_l = iadd_r = -128; }
1237 len = pIns->nLength;
1238 signed char *psrc = (signed char *)lpMemFile;
1239 signed char *pSample = (signed char *)pIns->pSample;
1240 if (len*2 > dwMemLength) break;
1241 for (UINT j=0; j<len; j++)
1242 {
1243 pSample[j*2] = (signed char)(psrc[0] + iadd_l);
1244 pSample[j*2+1] = (signed char)(psrc[len] + iadd_r);
1245 psrc++;
1246 if (nFlags == RS_STPCM8D)
1247 {
1248 iadd_l = pSample[j*2];
1249 iadd_r = pSample[j*2+1];
1250 }
1251 }
1252 len *= 2;
1253 }
1254 break;
1255
1256 // 16-bit stereo samples
1257 case RS_STPCM16S:
1258 case RS_STPCM16U:
1259 case RS_STPCM16D:
1260 {
1261 int iadd_l = 0, iadd_r = 0;
1262 if (nFlags == RS_STPCM16U) { iadd_l = iadd_r = -0x8000; }
1263 len = pIns->nLength;
1264 short int *psrc = (short int *)lpMemFile;
1265 short int *pSample = (short int *)pIns->pSample;
1266 if (len*4 > dwMemLength) break;
1267 for (UINT j=0; j<len; j++)
1268 {
1269 pSample[j*2] = (short int) (bswapLE16(psrc[0]) + iadd_l);
1270 pSample[j*2+1] = (short int) (bswapLE16(psrc[len]) + iadd_r);
1271 psrc++;
1272 if (nFlags == RS_STPCM16D)
1273 {
1274 iadd_l = pSample[j*2];
1275 iadd_r = pSample[j*2+1];
1276 }
1277 }
1278 len *= 4;
1279 }
1280 break;
1281
1282 // IT 2.14 compressed samples
1283 case RS_IT2148:
1284 case RS_IT21416:
1285 case RS_IT2158:
1286 case RS_IT21516:
1287 len = dwMemLength;
1288 if (len < 4) break;
1289 if ((nFlags == RS_IT2148) || (nFlags == RS_IT2158))
1290 ITUnpack8Bit(pIns->pSample, pIns->nLength, (LPBYTE)lpMemFile, dwMemLength, (nFlags == RS_IT2158));
1291 else
1292 ITUnpack16Bit(pIns->pSample, pIns->nLength, (LPBYTE)lpMemFile, dwMemLength, (nFlags == RS_IT21516));
1293 break;
1294
1295#ifndef MODPLUG_BASIC_SUPPORT
1296#ifndef FASTSOUNDLIB
1297 // 8-bit interleaved stereo samples
1298 case RS_STIPCM8S:
1299 case RS_STIPCM8U:
1300 {
1301 int iadd = 0;
1302 if (nFlags == RS_STIPCM8U) { iadd = -0x80; }
1303 len = pIns->nLength;
1304 if (len*2 > dwMemLength) len = dwMemLength >> 1;
1305 LPBYTE psrc = (LPBYTE)lpMemFile;
1306 LPBYTE pSample = (LPBYTE)pIns->pSample;
1307 for (UINT j=0; j<len; j++)
1308 {
1309 pSample[j*2] = (signed char)(psrc[0] + iadd);
1310 pSample[j*2+1] = (signed char)(psrc[1] + iadd);
1311 psrc+=2;
1312 }
1313 len *= 2;
1314 }
1315 break;
1316
1317 // 16-bit interleaved stereo samples
1318 case RS_STIPCM16S:
1319 case RS_STIPCM16U:
1320 {
1321 int iadd = 0;
1322 if (nFlags == RS_STIPCM16U) iadd = -32768;
1323 len = pIns->nLength;
1324 if (len*4 > dwMemLength) len = dwMemLength >> 2;
1325 short int *psrc = (short int *)lpMemFile;
1326 short int *pSample = (short int *)pIns->pSample;
1327 for (UINT j=0; j<len; j++)
1328 {
1329 pSample[j*2] = (short int)(bswapLE16(psrc[0]) + iadd);
1330 pSample[j*2+1] = (short int)(bswapLE16(psrc[1]) + iadd);
1331 psrc += 2;
1332 }
1333 len *= 4;
1334 }
1335 break;
1336
1337 // AMS compressed samples
1338 case RS_AMS8:
1339 case RS_AMS16:
1340 len = 9;
1341 if (dwMemLength > 9)
1342 {
1343 const char *psrc = lpMemFile;
1344 char packcharacter = lpMemFile[8], *pdest = (char *)pIns->pSample;
1345 len += bswapLE32(*((LPDWORD)(lpMemFile+4)));
1346 if (len > dwMemLength) len = dwMemLength;
1347 UINT dmax = pIns->nLength;
1348 if (pIns->uFlags & CHN_16BIT) dmax <<= 1;
1349 AMSUnpack(psrc+9, len-9, pdest, dmax, packcharacter);
1350 }
1351 break;
1352
1353 // PTM 8bit delta to 16-bit sample
1354 case RS_PTM8DTO16:
1355 {
1356 len = pIns->nLength * 2;
1357 if (len > dwMemLength) break;
1358 signed char *pSample = (signed char *)pIns->pSample;
1359 signed char delta8 = 0;
1360 for (UINT j=0; j<len; j++)
1361 {
1362 delta8 += lpMemFile[j];
1363 *pSample++ = delta8;
1364 }
1365 WORD *pSampleW = (WORD *)pIns->pSample;
1366 for (UINT j=0; j<len; j+=2) // swaparoni!
1367 {
1368 *pSampleW++ = bswapLE16(*pSampleW);
1369 }
1370 }
1371 break;
1372
1373 // Huffman MDL compressed samples
1374 case RS_MDL8:
1375 case RS_MDL16:
1376 len = dwMemLength;
1377 if (len >= 4)
1378 {
1379 LPBYTE pSample = (LPBYTE)pIns->pSample;
1380 LPBYTE ibuf = (LPBYTE)lpMemFile;
1381 DWORD bitbuf = bswapLE32(*((DWORD *)ibuf));
1382 UINT bitnum = 32;
1383 BYTE dlt = 0, lowbyte = 0;
1384 ibuf += 4;
1385 for (UINT j=0; j<pIns->nLength; j++)
1386 {
1387 BYTE hibyte;
1388 BYTE sign;
1389 if (nFlags == RS_MDL16) lowbyte = (BYTE)MDLReadBits(bitbuf, bitnum, ibuf, 8);
1390 sign = (BYTE)MDLReadBits(bitbuf, bitnum, ibuf, 1);
1391 if (MDLReadBits(bitbuf, bitnum, ibuf, 1))
1392 {
1393 hibyte = (BYTE)MDLReadBits(bitbuf, bitnum, ibuf, 3);
1394 } else
1395 {
1396 hibyte = 8;
1397 while (!MDLReadBits(bitbuf, bitnum, ibuf, 1)) hibyte += 0x10;
1398 hibyte += MDLReadBits(bitbuf, bitnum, ibuf, 4);
1399 }
1400 if (sign) hibyte = ~hibyte;
1401 dlt += hibyte;
1402 if (nFlags != RS_MDL16)
1403 pSample[j] = dlt;
1404 else
1405 {
1406 pSample[j<<1] = lowbyte;
1407 pSample[(j<<1)+1] = dlt;
1408 }
1409 }
1410 }
1411 break;
1412
1413 case RS_DMF8:
1414 case RS_DMF16:
1415 len = dwMemLength;
1416 if (len >= 4)
1417 {
1418 UINT maxlen = pIns->nLength;
1419 if (pIns->uFlags & CHN_16BIT) maxlen <<= 1;
1420 LPBYTE ibuf = (LPBYTE)lpMemFile, ibufmax = (LPBYTE)(lpMemFile+dwMemLength);
1421 len = DMFUnpack((LPBYTE)pIns->pSample, ibuf, ibufmax, maxlen);
1422 }
1423 break;
1424
1425#ifdef MODPLUG_TRACKER
1426 // PCM 24-bit signed -> load sample, and normalize it to 16-bit
1427 case RS_PCM24S:
1428 case RS_PCM32S:
1429 len = pIns->nLength * 3;
1430 if (nFlags == RS_PCM32S) len += pIns->nLength;
1431 if (len > dwMemLength) break;
1432 if (len > 4*8)
1433 {
1434 UINT slsize = (nFlags == RS_PCM32S) ? 4 : 3;
1435 LPBYTE pSrc = (LPBYTE)lpMemFile;
1436 LONG max = 255;
1437 if (nFlags == RS_PCM32S) pSrc++;
1438 for (UINT j=0; j<len; j+=slsize)
1439 {
1440 LONG l = ((((pSrc[j+2] << 8) + pSrc[j+1]) << 8) + pSrc[j]) << 8;
1441 l /= 256;
1442 if (l > max) max = l;
1443 if (-l > max) max = -l;
1444 }
1445 max = (max / 128) + 1;
1446 signed short *pDest = (signed short *)pIns->pSample;
1447 for (UINT k=0; k<len; k+=slsize)
1448 {
1449 LONG l = ((((pSrc[k+2] << 8) + pSrc[k+1]) << 8) + pSrc[k]) << 8;
1450 *pDest++ = (signed short)(l / max);
1451 }
1452 }
1453 break;
1454
1455 // Stereo PCM 24-bit signed -> load sample, and normalize it to 16-bit
1456 case RS_STIPCM24S:
1457 case RS_STIPCM32S:
1458 len = pIns->nLength * 6;
1459 if (nFlags == RS_STIPCM32S) len += pIns->nLength * 2;
1460 if (len > dwMemLength) break;
1461 if (len > 8*8)
1462 {
1463 UINT slsize = (nFlags == RS_STIPCM32S) ? 4 : 3;
1464 LPBYTE pSrc = (LPBYTE)lpMemFile;
1465 LONG max = 255;
1466 if (nFlags == RS_STIPCM32S) pSrc++;
1467 for (UINT j=0; j<len; j+=slsize)
1468 {
1469 LONG l = ((((pSrc[j+2] << 8) + pSrc[j+1]) << 8) + pSrc[j]) << 8;
1470 l /= 256;
1471 if (l > max) max = l;
1472 if (-l > max) max = -l;
1473 }
1474 max = (max / 128) + 1;
1475 signed short *pDest = (signed short *)pIns->pSample;
1476 for (UINT k=0; k<len; k+=slsize)
1477 {
1478 LONG lr = ((((pSrc[k+2] << 8) + pSrc[k+1]) << 8) + pSrc[k]) << 8;
1479 k += slsize;
1480 LONG ll = ((((pSrc[k+2] << 8) + pSrc[k+1]) << 8) + pSrc[k]) << 8;
1481 pDest[0] = (signed short)ll;
1482 pDest[1] = (signed short)lr;
1483 pDest += 2;
1484 }
1485 }
1486 break;
1487
1488 // 16-bit signed big endian interleaved stereo
1489 case RS_STIPCM16M:
1490 {
1491 len = pIns->nLength;
1492 if (len*4 > dwMemLength) len = dwMemLength >> 2;
1493 LPCBYTE psrc = (LPCBYTE)lpMemFile;
1494 short int *pSample = (short int *)pIns->pSample;
1495 for (UINT j=0; j<len; j++)
1496 {
1497 pSample[j*2] = (signed short)(((UINT)psrc[0] << 8) | (psrc[1]));
1498 pSample[j*2+1] = (signed short)(((UINT)psrc[2] << 8) | (psrc[3]));
1499 psrc += 4;
1500 }
1501 len *= 4;
1502 }
1503 break;
1504
1505#endif // MODPLUG_TRACKER
1506#endif // !FASTSOUNDLIB
1507#endif // !MODPLUG_BASIC_SUPPORT
1508
1509 // Default: 8-bit signed PCM data
1510 default:
1511 len = pIns->nLength;
1512 if (len > dwMemLength) len = pIns->nLength = dwMemLength;
1513 memcpy(pIns->pSample, lpMemFile, len);
1514 }
1515 if (len > dwMemLength)
1516 {
1517 if (pIns->pSample)
1518 {
1519 pIns->nLength = 0;
1520 FreeSample(pIns->pSample);
1521 pIns->pSample = NULL;
1522 }
1523 return 0;
1524 }
1525 AdjustSampleLoop(pIns);
1526 return len;
1527}
1528
1529
1530void CSoundFile::AdjustSampleLoop(MODINSTRUMENT *pIns)
1531//----------------------------------------------------
1532{
1533 if (!pIns->pSample) return;
1534 if (pIns->nLoopEnd > pIns->nLength) pIns->nLoopEnd = pIns->nLength;
1535 if (pIns->nLoopStart+2 >= pIns->nLoopEnd)
1536 {
1537 pIns->nLoopStart = pIns->nLoopEnd = 0;
1538 pIns->uFlags &= ~CHN_LOOP;
1539 }
1540 UINT len = pIns->nLength;
1541 if (pIns->uFlags & CHN_16BIT)
1542 {
1543 short int *pSample = (short int *)pIns->pSample;
1544 // Adjust end of sample
1545 if (pIns->uFlags & CHN_STEREO)
1546 {
1547 pSample[len*2+6] = pSample[len*2+4] = pSample[len*2+2] = pSample[len*2] = pSample[len*2-2];
1548 pSample[len*2+7] = pSample[len*2+5] = pSample[len*2+3] = pSample[len*2+1] = pSample[len*2-1];
1549 } else
1550 {
1551 pSample[len+4] = pSample[len+3] = pSample[len+2] = pSample[len+1] = pSample[len] = pSample[len-1];
1552 }
1553 if ((pIns->uFlags & (CHN_LOOP|CHN_PINGPONGLOOP|CHN_STEREO)) == CHN_LOOP)
1554 {
1555 // Fix bad loops
1556 if ((pIns->nLoopEnd+3 >= pIns->nLength) || (m_nType & MOD_TYPE_S3M))
1557 {
1558 pSample[pIns->nLoopEnd] = pSample[pIns->nLoopStart];
1559 pSample[pIns->nLoopEnd+1] = pSample[pIns->nLoopStart+1];
1560 pSample[pIns->nLoopEnd+2] = pSample[pIns->nLoopStart+2];
1561 pSample[pIns->nLoopEnd+3] = pSample[pIns->nLoopStart+3];
1562 pSample[pIns->nLoopEnd+4] = pSample[pIns->nLoopStart+4];
1563 }
1564 }
1565 } else
1566 {
1567 signed char *pSample = pIns->pSample;
1568#ifndef FASTSOUNDLIB
1569 // Crappy samples (except chiptunes) ?
1570 if ((pIns->nLength > 0x100) && (m_nType & (MOD_TYPE_MOD|MOD_TYPE_S3M))
1571 && (!(pIns->uFlags & CHN_STEREO)))
1572 {
1573 int smpend = pSample[pIns->nLength-1], smpfix = 0, kscan;
1574 for (kscan=pIns->nLength-1; kscan>0; kscan--)
1575 {
1576 smpfix = pSample[kscan-1];
1577 if (smpfix != smpend) break;
1578 }
1579 int delta = smpfix - smpend;
1580 if (((!(pIns->uFlags & CHN_LOOP)) || (kscan > (int)pIns->nLoopEnd))
1581 && ((delta < -8) || (delta > 8)))
1582 {
1583 while (kscan<(int)pIns->nLength)
1584 {
1585 if (!(kscan & 7))
1586 {
1587 if (smpfix > 0) smpfix--;
1588 if (smpfix < 0) smpfix++;
1589 }
1590 pSample[kscan] = (signed char)smpfix;
1591 kscan++;
1592 }
1593 }
1594 }
1595#endif
1596 // Adjust end of sample
1597 if (pIns->uFlags & CHN_STEREO)
1598 {
1599 pSample[len*2+6] = pSample[len*2+4] = pSample[len*2+2] = pSample[len*2] = pSample[len*2-2];
1600 pSample[len*2+7] = pSample[len*2+5] = pSample[len*2+3] = pSample[len*2+1] = pSample[len*2-1];
1601 } else
1602 {
1603 pSample[len+4] = pSample[len+3] = pSample[len+2] = pSample[len+1] = pSample[len] = pSample[len-1];
1604 }
1605 if ((pIns->uFlags & (CHN_LOOP|CHN_PINGPONGLOOP|CHN_STEREO)) == CHN_LOOP)
1606 {
1607 if ((pIns->nLoopEnd+3 >= pIns->nLength) || (m_nType & (MOD_TYPE_MOD|MOD_TYPE_S3M)))
1608 {
1609 pSample[pIns->nLoopEnd] = pSample[pIns->nLoopStart];
1610 pSample[pIns->nLoopEnd+1] = pSample[pIns->nLoopStart+1];
1611 pSample[pIns->nLoopEnd+2] = pSample[pIns->nLoopStart+2];
1612 pSample[pIns->nLoopEnd+3] = pSample[pIns->nLoopStart+3];
1613 pSample[pIns->nLoopEnd+4] = pSample[pIns->nLoopStart+4];
1614 }
1615 }
1616 }
1617}
1618
1619
1620/////////////////////////////////////////////////////////////
1621// Transpose <-> Frequency conversions
1622
1623// returns 8363*2^((transp*128+ftune)/(12*128))
1624DWORD CSoundFile::TransposeToFrequency(int transp, int ftune)
1625//-----------------------------------------------------------
1626{
1627 //---GCCFIX: Removed assembly.
1628 return (DWORD)(8363*pow(2, (transp*128+ftune)/(1536)));
1629
1630#ifdef WIN32
1631 const float _fbase = 8363;
1632 const float _factor = 1.0f/(12.0f*128.0f);
1633 int result;
1634 DWORD freq;
1635
1636 transp = (transp << 7) + ftune;
1637 _asm {
1638 fild transp
1639 fld _factor
1640 fmulp st(1), st(0)
1641 fist result
1642 fisub result
1643 f2xm1
1644 fild result
1645 fld _fbase
1646 fscale
1647 fstp st(1)
1648 fmul st(1), st(0)
1649 faddp st(1), st(0)
1650 fistp freq
1651 }
1652 UINT derr = freq % 11025;
1653 if (derr <= 8) freq -= derr;
1654 if (derr >= 11015) freq += 11025-derr;
1655 derr = freq % 1000;
1656 if (derr <= 5) freq -= derr;
1657 if (derr >= 995) freq += 1000-derr;
1658 return freq;
1659#endif
1660}
1661
1662
1663// returns 12*128*log2(freq/8363)
1664int CSoundFile::FrequencyToTranspose(DWORD freq)
1665//----------------------------------------------
1666{
1667 //---GCCFIX: Removed assembly.
1668 return int(1536*(log(freq/8363)/log(2)));
1669
1670#ifdef WIN32
1671 const float _f1_8363 = 1.0f / 8363.0f;
1672 const float _factor = 128 * 12;
1673 LONG result;
1674
1675 if (!freq) return 0;
1676 _asm {
1677 fld _factor
1678 fild freq
1679 fld _f1_8363
1680 fmulp st(1), st(0)
1681 fyl2x
1682 fistp result
1683 }
1684 return result;
1685#endif
1686}
1687
1688
1689void CSoundFile::FrequencyToTranspose(MODINSTRUMENT *psmp)
1690//--------------------------------------------------------
1691{
1692 int f2t = FrequencyToTranspose(psmp->nC4Speed);
1693 int transp = f2t >> 7;
1694 int ftune = f2t & 0x7F;
1695 if (ftune > 80)
1696 {
1697 transp++;
1698 ftune -= 128;
1699 }
1700 if (transp > 127) transp = 127;
1701 if (transp < -127) transp = -127;
1702 psmp->RelativeTone = transp;
1703 psmp->nFineTune = ftune;
1704}
1705
1706
1707void CSoundFile::CheckCPUUsage(UINT nCPU)
1708//---------------------------------------
1709{
1710 if (nCPU > 100) nCPU = 100;
1711 gnCPUUsage = nCPU;
1712 if (nCPU < 90)
1713 {
1714 m_dwSongFlags &= ~SONG_CPUVERYHIGH;
1715 } else
1716 if ((m_dwSongFlags & SONG_CPUVERYHIGH) && (nCPU >= 94))
1717 {
1718 UINT i=MAX_CHANNELS;
1719 while (i >= 8)
1720 {
1721 i--;
1722 if (Chn[i].nLength)
1723 {
1724 Chn[i].nLength = Chn[i].nPos = 0;
1725 nCPU -= 2;
1726 if (nCPU < 94) break;
1727 }
1728 }
1729 } else
1730 if (nCPU > 90)
1731 {
1732 m_dwSongFlags |= SONG_CPUVERYHIGH;
1733 }
1734}
1735
1736
1737BOOL CSoundFile::SetPatternName(UINT nPat, LPCSTR lpszName)
1738//---------------------------------------------------------
1739{
1740 char szName[MAX_PATTERNNAME] = ""; // changed from CHAR
1741 if (nPat >= MAX_PATTERNS) return FALSE;
1742 if (lpszName) lstrcpyn(szName, lpszName, MAX_PATTERNNAME);
1743 szName[MAX_PATTERNNAME-1] = 0;
1744 if (!m_lpszPatternNames) m_nPatternNames = 0;
1745 if (nPat >= m_nPatternNames)
1746 {
1747 if (!lpszName[0]) return TRUE;
1748 UINT len = (nPat+1)*MAX_PATTERNNAME;
1749 char *p = new char[len]; // changed from CHAR
1750 if (!p) return FALSE;
1751 memset(p, 0, len);
1752 if (m_lpszPatternNames)
1753 {
1754 memcpy(p, m_lpszPatternNames, m_nPatternNames * MAX_PATTERNNAME);
1755 delete m_lpszPatternNames;
1756 m_lpszPatternNames = NULL;
1757 }
1758 m_lpszPatternNames = p;
1759 m_nPatternNames = nPat + 1;
1760 }
1761 memcpy(m_lpszPatternNames + nPat * MAX_PATTERNNAME, szName, MAX_PATTERNNAME);
1762 return TRUE;
1763}
1764
1765
1766BOOL CSoundFile::GetPatternName(UINT nPat, LPSTR lpszName, UINT cbSize) const
1767//---------------------------------------------------------------------------
1768{
1769 if ((!lpszName) || (!cbSize)) return FALSE;
1770 lpszName[0] = 0;
1771 if (cbSize > MAX_PATTERNNAME) cbSize = MAX_PATTERNNAME;
1772 if ((m_lpszPatternNames) && (nPat < m_nPatternNames))
1773 {
1774 memcpy(lpszName, m_lpszPatternNames + nPat * MAX_PATTERNNAME, cbSize);
1775 lpszName[cbSize-1] = 0;
1776 return TRUE;
1777 }
1778 return FALSE;
1779}
1780
1781
1782#ifndef FASTSOUNDLIB
1783
1784UINT CSoundFile::DetectUnusedSamples(BOOL *pbIns)
1785//-----------------------------------------------
1786{
1787 UINT nExt = 0;
1788
1789 if (!pbIns) return 0;
1790 if (m_nInstruments)
1791 {
1792 memset(pbIns, 0, MAX_SAMPLES * sizeof(BOOL));
1793 for (UINT ipat=0; ipat<MAX_PATTERNS; ipat++)
1794 {
1795 MODCOMMAND *p = Patterns[ipat];
1796 if (p)
1797 {
1798 UINT jmax = PatternSize[ipat] * m_nChannels;
1799 for (UINT j=0; j<jmax; j++, p++)
1800 {
1801 if ((p->note) && (p->note <= 120))
1802 {
1803 if ((p->instr) && (p->instr < MAX_INSTRUMENTS))
1804 {
1805 INSTRUMENTHEADER *penv = Headers[p->instr];
1806 if (penv)
1807 {
1808 UINT n = penv->Keyboard[p->note-1];
1809 if (n < MAX_SAMPLES) pbIns[n] = TRUE;
1810 }
1811 } else
1812 {
1813 for (UINT k=1; k<=m_nInstruments; k++)
1814 {
1815 INSTRUMENTHEADER *penv = Headers[k];
1816 if (penv)
1817 {
1818 UINT n = penv->Keyboard[p->note-1];
1819 if (n < MAX_SAMPLES) pbIns[n] = TRUE;
1820 }
1821 }
1822 }
1823 }
1824 }
1825 }
1826 }
1827 for (UINT ichk=1; ichk<=m_nSamples; ichk++)
1828 {
1829 if ((!pbIns[ichk]) && (Ins[ichk].pSample)) nExt++;
1830 }
1831 }
1832 return nExt;
1833}
1834
1835
1836BOOL CSoundFile::RemoveSelectedSamples(BOOL *pbIns)
1837//-------------------------------------------------
1838{
1839 if (!pbIns) return FALSE;
1840 for (UINT j=1; j<MAX_SAMPLES; j++)
1841 {
1842 if ((!pbIns[j]) && (Ins[j].pSample))
1843 {
1844 DestroySample(j);
1845 if ((j == m_nSamples) && (j > 1)) m_nSamples--;
1846 }
1847 }
1848 return TRUE;
1849}
1850
1851
1852BOOL CSoundFile::DestroySample(UINT nSample)
1853//------------------------------------------
1854{
1855 if ((!nSample) || (nSample >= MAX_SAMPLES)) return FALSE;
1856 if (!Ins[nSample].pSample) return TRUE;
1857 MODINSTRUMENT *pins = &Ins[nSample];
1858 signed char *pSample = pins->pSample;
1859 pins->pSample = NULL;
1860 pins->nLength = 0;
1861 pins->uFlags &= ~(CHN_16BIT);
1862 for (UINT i=0; i<MAX_CHANNELS; i++)
1863 {
1864 if (Chn[i].pSample == pSample)
1865 {
1866 Chn[i].nPos = Chn[i].nLength = 0;
1867 Chn[i].pSample = Chn[i].pCurrentSample = NULL;
1868 }
1869 }
1870 FreeSample(pSample);
1871 return TRUE;
1872}
1873
1874#endif // FASTSOUNDLIB
1875
diff --git a/core/multimedia/opieplayer/modplug/sndfile.h b/core/multimedia/opieplayer/modplug/sndfile.h
new file mode 100644
index 0000000..8017116
--- a/dev/null
+++ b/core/multimedia/opieplayer/modplug/sndfile.h
@@ -0,0 +1,984 @@
1/*
2 * This program is free software; you can redistribute it and modify it
3 * under the terms of the GNU General Public License as published by the
4 * Free Software Foundation; either version 2 of the license or (at your
5 * option) any later version.
6 *
7 * Authors: Olivier Lapicque <olivierl@jps.net>,
8 * Adam Goode <adam@evdebs.org> (endian and char fixes for PPC)
9*/
10
11#ifdef HAVE_CONFIG_H
12#include "config.h"
13#endif
14
15#ifndef __SNDFILE_H
16#define __SNDFILE_H
17
18#ifndef LPCBYTE
19typedef const BYTE * LPCBYTE;
20#endif
21
22 #define MOD_AMIGAC2 0x1AB
23 #define MAX_SAMPLE_LENGTH16000000
24 #define MAX_SAMPLE_RATE 50000
25 #define MAX_ORDERS 256
26 #define MAX_PATTERNS 240
27 #define MAX_SAMPLES 240
28 #define MAX_INSTRUMENTS MAX_SAMPLES
29#ifdef FASTSOUNDLIB
30 #define MAX_CHANNELS 80
31#else
32 #define MAX_CHANNELS 128
33#endif
34 #define MAX_BASECHANNELS64
35 #define MAX_ENVPOINTS 32
36 #define MIN_PERIOD 0x0020
37 #define MAX_PERIOD 0xFFFF
38 #define MAX_PATTERNNAME 32
39 #define MAX_CHANNELNAME 20
40 #define MAX_INFONAME 80
41 #define MAX_EQ_BANDS 6
42 #define MAX_MIXPLUGINS 8
43
44
45 #define MOD_TYPE_NONE 0x00
46 #define MOD_TYPE_MOD 0x01
47 #define MOD_TYPE_S3M 0x02
48 #define MOD_TYPE_XM 0x04
49 #define MOD_TYPE_MED 0x08
50 #define MOD_TYPE_MTM 0x10
51 #define MOD_TYPE_IT 0x20
52 #define MOD_TYPE_669 0x40
53 #define MOD_TYPE_ULT 0x80
54 #define MOD_TYPE_STM 0x100
55 #define MOD_TYPE_FAR 0x200
56 #define MOD_TYPE_WAV 0x400
57 #define MOD_TYPE_AMF 0x800
58 #define MOD_TYPE_AMS 0x1000
59 #define MOD_TYPE_DSM 0x2000
60 #define MOD_TYPE_MDL 0x4000
61 #define MOD_TYPE_OKT 0x8000
62 #define MOD_TYPE_MID 0x10000
63 #define MOD_TYPE_DMF 0x20000
64 #define MOD_TYPE_PTM 0x40000
65 #define MOD_TYPE_DBM 0x80000
66 #define MOD_TYPE_MT2 0x100000
67 #define MOD_TYPE_AMF0 0x200000
68 #define MOD_TYPE_PSM 0x400000
69 #define MOD_TYPE_J2B 0x800000
70 #define MOD_TYPE_UMX 0x80000000 // Fake type
71 #define MAX_MODTYPE 23
72
73
74
75// Channel flags:
76 // Bits 0-7:Sample Flags
77 #define CHN_16BIT 0x01
78 #define CHN_LOOP 0x02
79 #define CHN_PINGPONGLOOP0x04
80 #define CHN_SUSTAINLOOP 0x08
81 #define CHN_PINGPONGSUSTAIN0x10
82 #define CHN_PANNING 0x20
83 #define CHN_STEREO 0x40
84 #define CHN_PINGPONGFLAG0x80
85 // Bits 8-31:Channel Flags
86 #define CHN_MUTE 0x100
87 #define CHN_KEYOFF 0x200
88 #define CHN_NOTEFADE 0x400
89 #define CHN_SURROUND 0x800
90 #define CHN_NOIDO 0x1000
91 #define CHN_HQSRC 0x2000
92 #define CHN_FILTER 0x4000
93 #define CHN_VOLUMERAMP 0x8000
94 #define CHN_VIBRATO 0x10000
95 #define CHN_TREMOLO 0x20000
96 #define CHN_PANBRELLO 0x40000
97 #define CHN_PORTAMENTO 0x80000
98 #define CHN_GLISSANDO 0x100000
99 #define CHN_VOLENV 0x200000
100 #define CHN_PANENV 0x400000
101 #define CHN_PITCHENV 0x800000
102 #define CHN_FASTVOLRAMP 0x1000000
103 #define CHN_EXTRALOUD 0x2000000
104 #define CHN_REVERB 0x4000000
105 #define CHN_NOREVERB 0x8000000
106
107
108 #define ENV_VOLUME 0x0001
109 #define ENV_VOLSUSTAIN 0x0002
110 #define ENV_VOLLOOP 0x0004
111 #define ENV_PANNING 0x0008
112 #define ENV_PANSUSTAIN 0x0010
113 #define ENV_PANLOOP 0x0020
114 #define ENV_PITCH 0x0040
115 #define ENV_PITCHSUSTAIN0x0080
116 #define ENV_PITCHLOOP 0x0100
117 #define ENV_SETPANNING 0x0200
118 #define ENV_FILTER 0x0400
119 #define ENV_VOLCARRY 0x0800
120 #define ENV_PANCARRY 0x1000
121 #define ENV_PITCHCARRY 0x2000
122
123 #define CMD_NONE 0
124 #define CMD_ARPEGGIO 1
125 #define CMD_PORTAMENTOUP 2
126 #define CMD_PORTAMENTODOWN 3
127 #define CMD_TONEPORTAMENTO 4
128 #define CMD_VIBRATO 5
129 #define CMD_TONEPORTAVOL 6
130 #define CMD_VIBRATOVOL 7
131 #define CMD_TREMOLO 8
132 #define CMD_PANNING8 9
133 #define CMD_OFFSET 10
134 #define CMD_VOLUMESLIDE 11
135 #define CMD_POSITIONJUMP 12
136 #define CMD_VOLUME 13
137 #define CMD_PATTERNBREAK 14
138 #define CMD_RETRIG 15
139 #define CMD_SPEED 16
140 #define CMD_TEMPO 17
141 #define CMD_TREMOR 18
142 #define CMD_MODCMDEX 19
143 #define CMD_S3MCMDEX 20
144 #define CMD_CHANNELVOLUME 21
145 #define CMD_CHANNELVOLSLIDE 22
146 #define CMD_GLOBALVOLUME 23
147 #define CMD_GLOBALVOLSLIDE 24
148 #define CMD_KEYOFF 25
149 #define CMD_FINEVIBRATO 26
150 #define CMD_PANBRELLO 27
151 #define CMD_XFINEPORTAUPDOWN28
152 #define CMD_PANNINGSLIDE 29
153 #define CMD_SETENVPOSITION 30
154 #define CMD_MIDI 31
155
156
157// Volume Column commands
158 #define VOLCMD_VOLUME 1
159 #define VOLCMD_PANNING 2
160 #define VOLCMD_VOLSLIDEUP 3
161 #define VOLCMD_VOLSLIDEDOWN 4
162 #define VOLCMD_FINEVOLUP 5
163 #define VOLCMD_FINEVOLDOWN 6
164 #define VOLCMD_VIBRATOSPEED 7
165 #define VOLCMD_VIBRATO 8
166 #define VOLCMD_PANSLIDELEFT 9
167 #define VOLCMD_PANSLIDERIGHT10
168 #define VOLCMD_TONEPORTAMENTO11
169 #define VOLCMD_PORTAUP 12
170 #define VOLCMD_PORTADOWN 13
171
172 #define RSF_16BIT 0x04
173 #define RSF_STEREO 0x08
174
175 #define RS_PCM8S 0// 8-bit signed
176 #define RS_PCM8U 1// 8-bit unsigned
177 #define RS_PCM8D 2// 8-bit delta values
178 #define RS_ADPCM4 3// 4-bit ADPCM-packed
179 #define RS_PCM16D 4// 16-bit delta values
180 #define RS_PCM16S 5// 16-bit signed
181 #define RS_PCM16U 6// 16-bit unsigned
182 #define RS_PCM16M 7// 16-bit motorola order
183 #define RS_STPCM8S (RS_PCM8S|RSF_STEREO)// stereo 8-bit signed
184 #define RS_STPCM8U (RS_PCM8U|RSF_STEREO)// stereo 8-bit unsigned
185 #define RS_STPCM8D (RS_PCM8D|RSF_STEREO)// stereo 8-bit delta values
186 #define RS_STPCM16S (RS_PCM16S|RSF_STEREO)// stereo 16-bit signed
187 #define RS_STPCM16U (RS_PCM16U|RSF_STEREO)// stereo 16-bit unsigned
188 #define RS_STPCM16D (RS_PCM16D|RSF_STEREO)// stereo 16-bit delta values
189 #define RS_STPCM16M (RS_PCM16M|RSF_STEREO)// stereo 16-bit signed big endian
190// IT 2.14 compressed samples
191 #define RS_IT2148 0x10
192 #define RS_IT21416 0x14
193 #define RS_IT2158 0x12
194 #define RS_IT21516 0x16
195// AMS Packed Samples
196 #define RS_AMS8 0x11
197 #define RS_AMS16 0x15
198// DMF Huffman compression
199 #define RS_DMF8 0x13
200 #define RS_DMF16 0x17
201// MDL Huffman compression
202 #define RS_MDL8 0x20
203 #define RS_MDL16 0x24
204 #define RS_PTM8DTO160x25
205// Stereo Interleaved Samples
206 #define RS_STIPCM8S (RS_PCM8S|0x40|RSF_STEREO)// stereo 8-bit signed
207 #define RS_STIPCM8U (RS_PCM8U|0x40|RSF_STEREO)// stereo 8-bit unsigned
208 #define RS_STIPCM16S (RS_PCM16S|0x40|RSF_STEREO)// stereo 16-bit signed
209 #define RS_STIPCM16U (RS_PCM16U|0x40|RSF_STEREO)// stereo 16-bit unsigned
210 #define RS_STIPCM16M (RS_PCM16M|0x40|RSF_STEREO)// stereo 16-bit signed big endian
211// 24-bit signed
212 #define RS_PCM24S (RS_PCM16S|0x80) // mono 24-bit signed
213 #define RS_STIPCM24S (RS_PCM16S|0x80|RSF_STEREO)// stereo 24-bit signed
214 #define RS_PCM32S (RS_PCM16S|0xC0) // mono 24-bit signed
215 #define RS_STIPCM32S (RS_PCM16S|0xC0|RSF_STEREO)// stereo 24-bit signed
216
217// NNA types
218 #define NNA_NOTECUT 0
219 #define NNA_CONTINUE1
220 #define NNA_NOTEOFF 2
221 #define NNA_NOTEFADE3
222
223// DCT types
224 #define DCT_NONE 0
225 #define DCT_NOTE 1
226 #define DCT_SAMPLE 2
227 #define DCT_INSTRUMENT3
228
229// DNA types
230 #define DNA_NOTECUT 0
231 #define DNA_NOTEOFF 1
232 #define DNA_NOTEFADE2
233
234// Mixer Hardware-Dependent features
235 #define SYSMIX_ENABLEMMX0x01
236 #define SYSMIX_WINDOWSNT0x02
237 #define SYSMIX_SLOWCPU 0x04
238 #define SYSMIX_FASTCPU 0x08
239
240// Module flags
241 #define SONG_EMBEDMIDICFG0x0001
242 #define SONG_FASTVOLSLIDES0x0002
243 #define SONG_ITOLDEFFECTS0x0004
244 #define SONG_ITCOMPATMODE0x0008
245 #define SONG_LINEARSLIDES0x0010
246 #define SONG_PATTERNLOOP0x0020
247 #define SONG_STEP 0x0040
248 #define SONG_PAUSED 0x0080
249 #define SONG_FADINGSONG 0x0100
250 #define SONG_ENDREACHED 0x0200
251 #define SONG_GLOBALFADE 0x0400
252 #define SONG_CPUVERYHIGH0x0800
253 #define SONG_FIRSTTICK 0x1000
254 #define SONG_MPTFILTERMODE0x2000
255 #define SONG_SURROUNDPAN0x4000
256 #define SONG_EXFILTERRANGE0x8000
257 #define SONG_AMIGALIMITS0x10000
258
259// Global Options (Renderer)
260 #define SNDMIX_REVERSESTEREO0x0001
261 #define SNDMIX_NOISEREDUCTION0x0002
262 #define SNDMIX_AGC 0x0004
263 #define SNDMIX_NORESAMPLING 0x0008
264 #define SNDMIX_HQRESAMPLER 0x0010
265 #define SNDMIX_MEGABASS 0x0020
266 #define SNDMIX_SURROUND 0x0040
267 #define SNDMIX_REVERB 0x0080
268 #define SNDMIX_EQ 0x0100
269 #define SNDMIX_SOFTPANNING 0x0200
270 #define SNDMIX_ULTRAHQSRCMODE0x0400
271// Misc Flags (can safely be turned on or off)
272 #define SNDMIX_DIRECTTODISK 0x10000
273 #define SNDMIX_ENABLEMMX 0x20000
274 #define SNDMIX_NOBACKWARDJUMPS0x40000
275 #define SNDMIX_MAXDEFAULTPAN 0x80000// Used by the MOD loader
276
277
278// Reverb Types (GM2 Presets)
279enum {
280 REVERBTYPE_SMALLROOM,
281 REVERBTYPE_MEDIUMROOM,
282 REVERBTYPE_LARGEROOM,
283 REVERBTYPE_SMALLHALL,
284 REVERBTYPE_MEDIUMHALL,
285 REVERBTYPE_LARGEHALL,
286 NUM_REVERBTYPES
287};
288
289
290enum {
291 SRCMODE_NEAREST,
292 SRCMODE_LINEAR,
293 SRCMODE_SPLINE,
294 SRCMODE_POLYPHASE,
295 NUM_SRC_MODES
296};
297
298
299// Sample Struct
300typedef struct _MODINSTRUMENT
301{
302 UINT nLength,nLoopStart,nLoopEnd;
303 UINT nSustainStart, nSustainEnd;
304 signed char *pSample;
305 UINT nC4Speed;
306 WORD nPan;
307 WORD nVolume;
308 WORD nGlobalVol;
309 WORD uFlags;
310 signed char RelativeTone;
311 signed char nFineTune;
312 BYTE nVibType;
313 BYTE nVibSweep;
314 BYTE nVibDepth;
315 BYTE nVibRate;
316 CHAR name[22];
317} MODINSTRUMENT;
318
319
320// Instrument Struct
321typedef struct _INSTRUMENTHEADER
322{
323 UINT nFadeOut;
324 DWORD dwFlags;
325 WORD nGlobalVol;
326 WORD nPan;
327 WORD VolPoints[MAX_ENVPOINTS];
328 WORD PanPoints[MAX_ENVPOINTS];
329 WORD PitchPoints[MAX_ENVPOINTS];
330 BYTE VolEnv[MAX_ENVPOINTS];
331 BYTE PanEnv[MAX_ENVPOINTS];
332 BYTE PitchEnv[MAX_ENVPOINTS];
333 BYTE Keyboard[128];
334 BYTE NoteMap[128];
335
336 BYTE nVolEnv;
337 BYTE nPanEnv;
338 BYTE nPitchEnv;
339 BYTE nVolLoopStart;
340 BYTE nVolLoopEnd;
341 BYTE nVolSustainBegin;
342 BYTE nVolSustainEnd;
343 BYTE nPanLoopStart;
344 BYTE nPanLoopEnd;
345 BYTE nPanSustainBegin;
346 BYTE nPanSustainEnd;
347 BYTE nPitchLoopStart;
348 BYTE nPitchLoopEnd;
349 BYTE nPitchSustainBegin;
350 BYTE nPitchSustainEnd;
351 BYTE nNNA;
352 BYTE nDCT;
353 BYTE nDNA;
354 BYTE nPanSwing;
355 BYTE nVolSwing;
356 BYTE nIFC;
357 BYTE nIFR;
358 WORD wMidiBank;
359 BYTE nMidiProgram;
360 BYTE nMidiChannel;
361 BYTE nMidiDrumKey;
362 signed char nPPS;
363 unsigned char nPPC;
364 CHAR name[32];
365 CHAR filename[12];
366} INSTRUMENTHEADER;
367
368
369// Channel Struct
370typedef struct _MODCHANNEL
371{
372 // First 32-bytes: Most used mixing information: don't change it
373 signed char * pCurrentSample;
374 DWORD nPos;
375 DWORD nPosLo;// actually 16-bit
376 LONG nInc; // 16.16
377 LONG nRightVol;
378 LONG nLeftVol;
379 LONG nRightRamp;
380 LONG nLeftRamp;
381 // 2nd cache line
382 DWORD nLength;
383 DWORD dwFlags;
384 DWORD nLoopStart;
385 DWORD nLoopEnd;
386 LONG nRampRightVol;
387 LONG nRampLeftVol;
388 LONG nFilter_Y1, nFilter_Y2, nFilter_Y3, nFilter_Y4;
389 LONG nFilter_A0, nFilter_B0, nFilter_B1;
390 LONG nROfs, nLOfs;
391 LONG nRampLength;
392 // Information not used in the mixer
393 signed char * pSample;
394 LONG nNewRightVol, nNewLeftVol;
395 LONG nRealVolume, nRealPan;
396 LONG nVolume, nPan, nFadeOutVol;
397 LONG nPeriod, nC4Speed, nPortamentoDest;
398 INSTRUMENTHEADER *pHeader;
399 MODINSTRUMENT *pInstrument;
400 DWORD nVolEnvPosition, nPanEnvPosition, nPitchEnvPosition;
401 DWORD nMasterChn, nVUMeter;
402 LONG nGlobalVol, nInsVol;
403 LONG nFineTune, nTranspose;
404 LONG nPortamentoSlide, nAutoVibDepth;
405 UINT nAutoVibPos, nVibratoPos, nTremoloPos, nPanbrelloPos;
406 // 16-bit members
407 signed short nVolSwing, nPanSwing;
408 // 8-bit members
409 BYTE nNote, nNNA;
410 BYTE nNewNote, nNewIns, nCommand, nArpeggio;
411 BYTE nOldVolumeSlide, nOldFineVolUpDown;
412 BYTE nOldPortaUpDown, nOldFinePortaUpDown;
413 BYTE nOldPanSlide, nOldChnVolSlide;
414 BYTE nVibratoType, nVibratoSpeed, nVibratoDepth;
415 BYTE nTremoloType, nTremoloSpeed, nTremoloDepth;
416 BYTE nPanbrelloType, nPanbrelloSpeed, nPanbrelloDepth;
417 BYTE nOldCmdEx, nOldVolParam, nOldTempo;
418 BYTE nOldOffset, nOldHiOffset;
419 BYTE nCutOff, nResonance;
420 BYTE nRetrigCount, nRetrigParam;
421 BYTE nTremorCount, nTremorParam;
422 BYTE nPatternLoop, nPatternLoopCount;
423 BYTE nRowNote, nRowInstr;
424 BYTE nRowVolCmd, nRowVolume;
425 BYTE nRowCommand, nRowParam;
426 BYTE nLeftVU, nRightVU;
427 BYTE nActiveMacro, nPadding;
428} MODCHANNEL;
429
430
431typedef struct _MODCHANNELSETTINGS
432{
433 UINT nPan;
434 UINT nVolume;
435 DWORD dwFlags;
436 UINT nMixPlugin;
437 char szName[MAX_CHANNELNAME]; // changed from CHAR
438} MODCHANNELSETTINGS;
439
440
441typedef struct _MODCOMMAND
442{
443 BYTE note;
444 BYTE instr;
445 BYTE volcmd;
446 BYTE command;
447 BYTE vol;
448 BYTE param;
449} MODCOMMAND, *LPMODCOMMAND;
450
451////////////////////////////////////////////////////////////////////
452// Mix Plugins
453 #define MIXPLUG_MIXREADY 0x01// Set when cleared
454
455class IMixPlugin
456{
457public:
458 virtual int AddRef() = 0;
459 virtual int Release() = 0;
460 virtual void SaveAllParameters() = 0;
461 virtual void RestoreAllParameters() = 0;
462 virtual void Process(float *pOutL, float *pOutR, unsigned long nSamples) = 0;
463 virtual void Init(unsigned long nFreq, int bReset) = 0;
464 virtual void MidiSend(DWORD dwMidiCode) = 0;
465 virtual void MidiCommand(UINT nMidiCh, UINT nMidiProg, UINT note, UINT vol) = 0;
466};
467
468
469 #define MIXPLUG_INPUTF_MASTEREFFECT 0x01// Apply to master mix
470 #define MIXPLUG_INPUTF_BYPASS 0x02// Bypass effect
471 #define MIXPLUG_INPUTF_WETMIX 0x04// Wet Mix (dry added)
472
473typedef struct _SNDMIXPLUGINSTATE
474{
475 DWORD dwFlags; // MIXPLUG_XXXX
476 LONG nVolDecayL, nVolDecayR;// Buffer click removal
477 int *pMixBuffer; // Stereo effect send buffer
478 float *pOutBufferL; // Temp storage for int -> float conversion
479 float *pOutBufferR;
480} SNDMIXPLUGINSTATE, *PSNDMIXPLUGINSTATE;
481
482typedef struct _SNDMIXPLUGININFO
483{
484 DWORD dwPluginId1;
485 DWORD dwPluginId2;
486 DWORD dwInputRouting;// MIXPLUG_INPUTF_XXXX
487 DWORD dwOutputRouting;// 0=mix 0x80+=fx
488 DWORD dwReserved[4];// Reserved for routing info
489 CHAR szName[32];
490 CHAR szLibraryName[64];// original DLL name
491} SNDMIXPLUGININFO, *PSNDMIXPLUGININFO; // Size should be 128
492
493typedef struct _SNDMIXPLUGIN
494{
495 IMixPlugin *pMixPlugin;
496 PSNDMIXPLUGINSTATE pMixState;
497 ULONG nPluginDataSize;
498 PVOID pPluginData;
499 SNDMIXPLUGININFO Info;
500} SNDMIXPLUGIN, *PSNDMIXPLUGIN;
501
502 typedefBOOL (__cdecl *PMIXPLUGINCREATEPROC)(PSNDMIXPLUGIN);
503
504////////////////////////////////////////////////////////////////////
505
506enum {
507 MIDIOUT_START=0,
508 MIDIOUT_STOP,
509 MIDIOUT_TICK,
510 MIDIOUT_NOTEON,
511 MIDIOUT_NOTEOFF,
512 MIDIOUT_VOLUME,
513 MIDIOUT_PAN,
514 MIDIOUT_BANKSEL,
515 MIDIOUT_PROGRAM,
516};
517
518
519typedef struct MODMIDICFG
520{
521 char szMidiGlb[9*32]; // changed from CHAR
522 char szMidiSFXExt[16*32]; // changed from CHAR
523 char szMidiZXXExt[128*32]; // changed from CHAR
524} MODMIDICFG, *LPMODMIDICFG;
525
526
527typedef VOID (__cdecl * LPSNDMIXHOOKPROC)(int *, unsigned long, unsigned long); // buffer, samples, channels
528
529
530
531//==============
532class CSoundFile
533//==============
534{
535 public:// Static Members
536 static UINT m_nXBassDepth, m_nXBassRange;
537 static UINT m_nReverbDepth, m_nReverbDelay, gnReverbType;
538 static UINT m_nProLogicDepth, m_nProLogicDelay;
539 static UINT m_nStereoSeparation;
540 static UINT m_nMaxMixChannels;
541 static LONG m_nStreamVolume;
542 static DWORD gdwSysInfo, gdwSoundSetup, gdwMixingFreq, gnBitsPerSample, gnChannels;
543 static UINT gnAGC, gnVolumeRampSamples, gnVUMeter, gnCPUUsage;
544 static LPSNDMIXHOOKPROC gpSndMixHook;
545 static PMIXPLUGINCREATEPROC gpMixPluginCreateProc;
546
547 public:// for Editing
548 MODCHANNEL Chn[MAX_CHANNELS]; // Channels
549 UINT ChnMix[MAX_CHANNELS]; // Channels to be mixed
550 MODINSTRUMENT Ins[MAX_SAMPLES]; // Instruments
551 INSTRUMENTHEADER *Headers[MAX_INSTRUMENTS]; // Instrument Headers
552 MODCHANNELSETTINGS ChnSettings[MAX_BASECHANNELS]; // Channels settings
553 MODCOMMAND *Patterns[MAX_PATTERNS]; // Patterns
554 WORD PatternSize[MAX_PATTERNS]; // Patterns Lengths
555 BYTE Order[MAX_ORDERS]; // Pattern Orders
556 MODMIDICFG m_MidiCfg; // Midi macro config table
557 SNDMIXPLUGIN m_MixPlugins[MAX_MIXPLUGINS]; // Mix plugins
558 UINT m_nDefaultSpeed, m_nDefaultTempo, m_nDefaultGlobalVolume;
559 DWORD m_dwSongFlags; // Song flags SONG_XXXX
560 UINT m_nChannels, m_nMixChannels, m_nMixStat, m_nBufferCount;
561 UINT m_nType, m_nSamples, m_nInstruments;
562 UINT m_nTickCount, m_nTotalCount, m_nPatternDelay, m_nFrameDelay;
563 UINT m_nMusicSpeed, m_nMusicTempo;
564 UINT m_nNextRow, m_nRow;
565 UINT m_nPattern,m_nCurrentPattern,m_nNextPattern,m_nRestartPos;
566 UINT m_nMasterVolume, m_nGlobalVolume, m_nSongPreAmp;
567 UINT m_nFreqFactor, m_nTempoFactor, m_nOldGlbVolSlide;
568 LONG m_nMinPeriod, m_nMaxPeriod, m_nRepeatCount, m_nInitialRepeatCount;
569 DWORD m_nGlobalFadeSamples, m_nGlobalFadeMaxSamples;
570 UINT m_nMaxOrderPosition;
571 UINT m_nPatternNames;
572 LPSTR m_lpszSongComments, m_lpszPatternNames;
573 char m_szNames[MAX_INSTRUMENTS][32]; // changed from CHAR
574 CHAR CompressionTable[16];
575
576public:
577 CSoundFile();
578 ~CSoundFile();
579
580public:
581 BOOL Create(LPCBYTE lpStream, DWORD dwMemLength=0);
582 BOOL Destroy();
583 UINT GetType() const { return m_nType; }
584 UINT GetNumChannels() const;
585 UINT GetLogicalChannels() const { return m_nChannels; }
586 BOOL SetMasterVolume(UINT vol, BOOL bAdjustAGC=FALSE);
587 UINT GetMasterVolume() const { return m_nMasterVolume; }
588 UINT GetNumPatterns() const;
589 UINT GetNumInstruments() const;
590 UINT GetNumSamples() const { return m_nSamples; }
591 UINT GetCurrentPos() const;
592 UINT GetCurrentPattern() const { return m_nPattern; }
593 UINT GetCurrentOrder() const { return m_nCurrentPattern; }
594 UINT GetSongComments(LPSTR s, UINT cbsize, UINT linesize=32);
595 UINT GetRawSongComments(LPSTR s, UINT cbsize, UINT linesize=32);
596 UINT GetMaxPosition() const;
597 void SetCurrentPos(UINT nPos);
598 void SetCurrentOrder(UINT nOrder);
599 void GetTitle(LPSTR s) const { lstrcpyn(s,m_szNames[0],32); }
600 LPCSTR GetTitle() const { return m_szNames[0]; }
601 UINT GetSampleName(UINT nSample,LPSTR s=NULL) const;
602 UINT GetInstrumentName(UINT nInstr,LPSTR s=NULL) const;
603 UINT GetMusicSpeed() const { return m_nMusicSpeed; }
604 UINT GetMusicTempo() const { return m_nMusicTempo; }
605 DWORD GetLength(BOOL bAdjust, BOOL bTotal=FALSE);
606 DWORD GetSongTime() { return GetLength(FALSE, TRUE); }
607 void SetRepeatCount(int n) { m_nRepeatCount = n; m_nInitialRepeatCount = n; }
608 int GetRepeatCount() const { return m_nRepeatCount; }
609 BOOL IsPaused() const {return (m_dwSongFlags & SONG_PAUSED) ? TRUE : FALSE; }
610 void LoopPattern(int nPat, int nRow=0);
611 void CheckCPUUsage(UINT nCPU);
612 BOOL SetPatternName(UINT nPat, LPCSTR lpszName);
613 BOOL GetPatternName(UINT nPat, LPSTR lpszName, UINT cbSize=MAX_PATTERNNAME) const;
614 // Module Loaders
615 BOOL ReadXM(LPCBYTE lpStream, DWORD dwMemLength);
616 BOOL ReadS3M(LPCBYTE lpStream, DWORD dwMemLength);
617 BOOL ReadMod(LPCBYTE lpStream, DWORD dwMemLength);
618 BOOL ReadMed(LPCBYTE lpStream, DWORD dwMemLength);
619 BOOL ReadMTM(LPCBYTE lpStream, DWORD dwMemLength);
620 BOOL ReadSTM(LPCBYTE lpStream, DWORD dwMemLength);
621 BOOL ReadIT(LPCBYTE lpStream, DWORD dwMemLength);
622 BOOL Read669(LPCBYTE lpStream, DWORD dwMemLength);
623 BOOL ReadUlt(LPCBYTE lpStream, DWORD dwMemLength);
624 //BOOL ReadWav(LPCBYTE lpStream, DWORD dwMemLength);
625 BOOL ReadDSM(LPCBYTE lpStream, DWORD dwMemLength);
626 BOOL ReadFAR(LPCBYTE lpStream, DWORD dwMemLength);
627 BOOL ReadAMS(LPCBYTE lpStream, DWORD dwMemLength);
628 BOOL ReadAMS2(LPCBYTE lpStream, DWORD dwMemLength);
629 BOOL ReadMDL(LPCBYTE lpStream, DWORD dwMemLength);
630 BOOL ReadOKT(LPCBYTE lpStream, DWORD dwMemLength);
631 BOOL ReadDMF(LPCBYTE lpStream, DWORD dwMemLength);
632 BOOL ReadPTM(LPCBYTE lpStream, DWORD dwMemLength);
633 BOOL ReadDBM(LPCBYTE lpStream, DWORD dwMemLength);
634 BOOL ReadAMF(LPCBYTE lpStream, DWORD dwMemLength);
635 BOOL ReadMT2(LPCBYTE lpStream, DWORD dwMemLength);
636 BOOL ReadPSM(LPCBYTE lpStream, DWORD dwMemLength);
637 BOOL ReadJ2B(LPCBYTE lpStream, DWORD dwMemLength);
638 BOOL ReadUMX(LPCBYTE lpStream, DWORD dwMemLength);
639 // Save Functions
640#ifndef MODPLUG_NO_FILESAVE
641 UINT WriteSample(FILE *f, MODINSTRUMENT *pins, UINT nFlags, UINT nMaxLen=0);
642 BOOL SaveXM(LPCSTR lpszFileName, UINT nPacking=0);
643 BOOL SaveS3M(LPCSTR lpszFileName, UINT nPacking=0);
644 BOOL SaveMod(LPCSTR lpszFileName, UINT nPacking=0);
645 BOOL SaveIT(LPCSTR lpszFileName, UINT nPacking=0);
646#endif // MODPLUG_NO_FILESAVE
647 // MOD Convert function
648 UINT GetBestSaveFormat() const;
649 UINT GetSaveFormats() const;
650 void ConvertModCommand(MODCOMMAND *) const;
651 void S3MConvert(MODCOMMAND *m, BOOL bIT) const;
652 void S3MSaveConvert(UINT *pcmd, UINT *pprm, BOOL bIT) const;
653 WORD ModSaveCommand(const MODCOMMAND *m, BOOL bXM) const;
654
655public:
656 // Real-time sound functions
657 VOID ResetChannels();
658
659 UINT Read(LPVOID lpBuffer, UINT cbBuffer);
660 UINT CreateStereoMix(int count);
661 BOOL FadeSong(UINT msec);
662 BOOL GlobalFadeSong(UINT msec);
663 UINT GetTotalTickCount() const { return m_nTotalCount; }
664 VOID ResetTotalTickCount() { m_nTotalCount = 0; }
665
666public:
667 // Mixer Config
668 static BOOL InitPlayer(BOOL bReset=FALSE);
669 static BOOL SetWaveConfig(UINT nRate,UINT nBits,UINT nChannels,BOOL bMMX=FALSE);
670 static BOOL SetResamplingMode(UINT nMode); // SRCMODE_XXXX
671 static BOOL IsStereo() { return (gnChannels > 1) ? TRUE : FALSE; }
672 static DWORD GetSampleRate() { return gdwMixingFreq; }
673 static DWORD GetBitsPerSample() { return gnBitsPerSample; }
674 static DWORD InitSysInfo();
675 static DWORD GetSysInfo() { return gdwSysInfo; }
676 // AGC
677 static BOOL GetAGC() { return (gdwSoundSetup & SNDMIX_AGC) ? TRUE : FALSE; }
678 static void SetAGC(BOOL b);
679 static void ResetAGC();
680 static void ProcessAGC(int count);
681
682 //GCCFIX -- added these functions back in!
683 static BOOL SetWaveConfigEx(BOOL bSurround,BOOL bNoOverSampling,BOOL bReverb,BOOL hqido,BOOL bMegaBass,BOOL bNR,BOOL bEQ);
684 // DSP Effects
685 static void InitializeDSP(BOOL bReset);
686 static void ProcessStereoDSP(int count);
687 static void ProcessMonoDSP(int count);
688 // [Reverb level 0(quiet)-100(loud)], [delay in ms, usually 40-200ms]
689 static BOOL SetReverbParameters(UINT nDepth, UINT nDelay);
690 // [XBass level 0(quiet)-100(loud)], [cutoff in Hz 10-100]
691 static BOOL SetXBassParameters(UINT nDepth, UINT nRange);
692 // [Surround level 0(quiet)-100(heavy)] [delay in ms, usually 5-40ms]
693 static BOOL SetSurroundParameters(UINT nDepth, UINT nDelay);
694public:
695 BOOL ReadNote();
696 BOOL ProcessRow();
697 BOOL ProcessEffects();
698 UINT GetNNAChannel(UINT nChn) const;
699 void CheckNNA(UINT nChn, UINT instr, int note, BOOL bForceCut);
700 void NoteChange(UINT nChn, int note, BOOL bPorta=FALSE, BOOL bResetEnv=TRUE);
701 void InstrumentChange(MODCHANNEL *pChn, UINT instr, BOOL bPorta=FALSE,BOOL bUpdVol=TRUE,BOOL bResetEnv=TRUE);
702 // Channel Effects
703 void PortamentoUp(MODCHANNEL *pChn, UINT param);
704 void PortamentoDown(MODCHANNEL *pChn, UINT param);
705 void FinePortamentoUp(MODCHANNEL *pChn, UINT param);
706 void FinePortamentoDown(MODCHANNEL *pChn, UINT param);
707 void ExtraFinePortamentoUp(MODCHANNEL *pChn, UINT param);
708 void ExtraFinePortamentoDown(MODCHANNEL *pChn, UINT param);
709 void TonePortamento(MODCHANNEL *pChn, UINT param);
710 void Vibrato(MODCHANNEL *pChn, UINT param);
711 void FineVibrato(MODCHANNEL *pChn, UINT param);
712 void VolumeSlide(MODCHANNEL *pChn, UINT param);
713 void PanningSlide(MODCHANNEL *pChn, UINT param);
714 void ChannelVolSlide(MODCHANNEL *pChn, UINT param);
715 void FineVolumeUp(MODCHANNEL *pChn, UINT param);
716 void FineVolumeDown(MODCHANNEL *pChn, UINT param);
717 void Tremolo(MODCHANNEL *pChn, UINT param);
718 void Panbrello(MODCHANNEL *pChn, UINT param);
719 void RetrigNote(UINT nChn, UINT param);
720 void NoteCut(UINT nChn, UINT nTick);
721 void KeyOff(UINT nChn);
722 int PatternLoop(MODCHANNEL *, UINT param);
723 void ExtendedMODCommands(UINT nChn, UINT param);
724 void ExtendedS3MCommands(UINT nChn, UINT param);
725 void ExtendedChannelEffect(MODCHANNEL *, UINT param);
726 void ProcessMidiMacro(UINT nChn, LPCSTR pszMidiMacro, UINT param=0);
727 void SetupChannelFilter(MODCHANNEL *pChn, BOOL bReset, int flt_modifier=256) const;
728 // Low-Level effect processing
729 void DoFreqSlide(MODCHANNEL *pChn, LONG nFreqSlide);
730 // Global Effects
731 void SetTempo(UINT param);
732 void SetSpeed(UINT param);
733 void GlobalVolSlide(UINT param);
734 DWORD IsSongFinished(UINT nOrder, UINT nRow) const;
735 BOOL IsValidBackwardJump(UINT nStartOrder, UINT nStartRow, UINT nJumpOrder, UINT nJumpRow) const;
736 // Read/Write sample functions
737 signed char GetDeltaValue(signed char prev, UINT n) const { return (signed char)(prev + CompressionTable[n & 0x0F]); }
738 UINT PackSample(int &sample, int next);
739 BOOL CanPackSample(LPSTR pSample, UINT nLen, UINT nPacking, BYTE *result=NULL);
740 UINT ReadSample(MODINSTRUMENT *pIns, UINT nFlags, LPCSTR pMemFile, DWORD dwMemLength);
741 BOOL DestroySample(UINT nSample);
742 BOOL DestroyInstrument(UINT nInstr);
743 BOOL IsSampleUsed(UINT nSample);
744 BOOL IsInstrumentUsed(UINT nInstr);
745 BOOL RemoveInstrumentSamples(UINT nInstr);
746 UINT DetectUnusedSamples(BOOL *);
747 BOOL RemoveSelectedSamples(BOOL *);
748 void AdjustSampleLoop(MODINSTRUMENT *pIns);
749 // I/O from another sound file
750 BOOL ReadInstrumentFromSong(UINT nInstr, CSoundFile *, UINT nSrcInstrument);
751 BOOL ReadSampleFromSong(UINT nSample, CSoundFile *, UINT nSrcSample);
752 // Period/Note functions
753 UINT GetNoteFromPeriod(UINT period) const;
754 UINT GetPeriodFromNote(UINT note, int nFineTune, UINT nC4Speed) const;
755 UINT GetFreqFromPeriod(UINT period, UINT nC4Speed, int nPeriodFrac=0) const;
756 // Misc functions
757 MODINSTRUMENT *GetSample(UINT n) { return Ins+n; }
758 void ResetMidiCfg();
759 UINT MapMidiInstrument(DWORD dwProgram, UINT nChannel, UINT nNote);
760 BOOL ITInstrToMPT(const void *p, INSTRUMENTHEADER *penv, UINT trkvers);
761 UINT SaveMixPlugins(FILE *f=NULL, BOOL bUpdate=TRUE);
762 UINT LoadMixPlugins(const void *pData, UINT nLen);
763#ifndef NO_FILTER
764 DWORD CutOffToFrequency(UINT nCutOff, int flt_modifier=256) const; // [0-255] => [1-10KHz]
765#endif
766
767 // Static helper functions
768public:
769 static DWORD TransposeToFrequency(int transp, int ftune=0);
770 static int FrequencyToTranspose(DWORD freq);
771 static void FrequencyToTranspose(MODINSTRUMENT *psmp);
772
773 // System-Dependant functions
774public:
775 static MODCOMMAND *AllocatePattern(UINT rows, UINT nchns);
776 static signed char* AllocateSample(UINT nbytes);
777 static void FreePattern(LPVOID pat);
778 static void FreeSample(LPVOID p);
779 static UINT Normalize24BitBuffer(LPBYTE pbuffer, UINT cbsizebytes, DWORD lmax24, DWORD dwByteInc);
780};
781
782
783// inline DWORD BigEndian(DWORD x) { return ((x & 0xFF) << 24) | ((x & 0xFF00) << 8) | ((x & 0xFF0000) >> 8) | ((x & 0xFF000000) >> 24); }
784// inline WORD BigEndianW(WORD x) { return (WORD)(((x >> 8) & 0xFF) | ((x << 8) & 0xFF00)); }
785
786
787//////////////////////////////////////////////////////////
788// WAVE format information
789
790#pragma pack(1)
791
792// Standard IFF chunks IDs
793 #define IFFID_FORM 0x4d524f46
794 #define IFFID_RIFF 0x46464952
795 #define IFFID_WAVE 0x45564157
796 #define IFFID_LIST 0x5453494C
797 #define IFFID_INFO 0x4F464E49
798
799// IFF Info fields
800 #define IFFID_ICOP 0x504F4349
801 #define IFFID_IART 0x54524149
802 #define IFFID_IPRD 0x44525049
803 #define IFFID_INAM 0x4D414E49
804 #define IFFID_ICMT 0x544D4349
805 #define IFFID_IENG 0x474E4549
806 #define IFFID_ISFT 0x54465349
807 #define IFFID_ISBJ 0x4A425349
808 #define IFFID_IGNR 0x524E4749
809 #define IFFID_ICRD 0x44524349
810
811// Wave IFF chunks IDs
812 #define IFFID_wave 0x65766177
813 #define IFFID_fmt 0x20746D66
814 #define IFFID_wsmp 0x706D7377
815 #define IFFID_pcm 0x206d6370
816 #define IFFID_data 0x61746164
817 #define IFFID_smpl 0x6C706D73
818 #define IFFID_xtra 0x61727478
819
820typedef struct WAVEFILEHEADER
821{
822 DWORD id_RIFF; // "RIFF"
823 DWORD filesize; // file length-8
824 DWORD id_WAVE;
825} WAVEFILEHEADER;
826
827
828typedef struct WAVEFORMATHEADER
829{
830 DWORD id_fmt; // "fmt "
831 DWORD hdrlen; // 16
832 WORD format; // 1
833 WORD channels; // 1:mono, 2:stereo
834 DWORD freqHz; // sampling freq
835 DWORD bytessec; // bytes/sec=freqHz*samplesize
836 WORD samplesize;// sizeof(sample)
837 WORD bitspersample;// bits per sample (8/16)
838} WAVEFORMATHEADER;
839
840
841typedef struct WAVEDATAHEADER
842{
843 DWORD id_data; // "data"
844 DWORD length; // length of data
845} WAVEDATAHEADER;
846
847
848typedef struct WAVESMPLHEADER
849{
850 // SMPL
851 DWORD smpl_id; // "smpl"-> 0x6C706D73
852 DWORD smpl_len; // length of smpl: 3Ch(54h with sustain loop)
853 DWORD dwManufacturer;
854 DWORD dwProduct;
855 DWORD dwSamplePeriod;// 1000000000/freqHz
856 DWORD dwBaseNote;// 3Ch = C-4 -> 60 + RelativeTone
857 DWORD dwPitchFraction;
858 DWORD dwSMPTEFormat;
859 DWORD dwSMPTEOffset;
860 DWORD dwSampleLoops;// number of loops
861 DWORD cbSamplerData;
862} WAVESMPLHEADER;
863
864
865typedef struct SAMPLELOOPSTRUCT
866{
867 DWORD dwIdentifier;
868 DWORD dwLoopType; // 0=normal, 1=bidi
869 DWORD dwLoopStart;
870 DWORD dwLoopEnd; // Byte offset ?
871 DWORD dwFraction;
872 DWORD dwPlayCount; // Loop Count, 0=infinite
873} SAMPLELOOPSTRUCT;
874
875
876typedef struct WAVESAMPLERINFO
877{
878 WAVESMPLHEADER wsiHdr;
879 SAMPLELOOPSTRUCT wsiLoops[2];
880} WAVESAMPLERINFO;
881
882
883typedef struct WAVELISTHEADER
884{
885 DWORD list_id;// "LIST" -> 0x5453494C
886 DWORD list_len;
887 DWORD info; // "INFO"
888} WAVELISTHEADER;
889
890
891typedef struct WAVEEXTRAHEADER
892{
893 DWORD xtra_id; // "xtra"-> 0x61727478
894 DWORD xtra_len;
895 DWORD dwFlags;
896 WORD wPan;
897 WORD wVolume;
898 WORD wGlobalVol;
899 WORD wReserved;
900 BYTE nVibType;
901 BYTE nVibSweep;
902 BYTE nVibDepth;
903 BYTE nVibRate;
904} WAVEEXTRAHEADER;
905
906#pragma pack()
907
908///////////////////////////////////////////////////////////
909// Low-level Mixing functions
910
911 #define MIXBUFFERSIZE 512
912 #define MIXING_ATTENUATION4
913 #define MIXING_CLIPMIN (-0x08000000)
914 #define MIXING_CLIPMAX (0x07FFFFFF)
915 #define VOLUMERAMPPRECISION12
916 #define FADESONGDELAY 100
917 #define EQ_BUFFERSIZE (MIXBUFFERSIZE)
918 #define AGC_PRECISION 9
919 #define AGC_UNITY (1 << AGC_PRECISION)
920
921// Calling conventions
922#ifdef WIN32
923 #define MPPASMCALL__cdecl
924 #define MPPFASTCALL__fastcall
925#else
926#define MPPASMCALL
927#define MPPFASTCALL
928#endif
929
930 #define MOD2XMFineTune(k)((int)( (signed char)((k)<<4) ))
931 #define XM2MODFineTune(k)((int)( (k>>4)&0x0f ))
932
933int _muldiv(long a, long b, long c);
934int _muldivr(long a, long b, long c);
935
936
937// Byte swapping functions from the GNU C Library and libsdl
938
939/* Swap bytes in 16 bit value. */
940#ifdef __GNUC__
941# define bswap_16(x) \
942 (__extension__ \
943 ({ unsigned short int __bsx = (x); \
944 ((((__bsx) >> 8) & 0xff) | (((__bsx) & 0xff) << 8)); }))
945#else
946static __inline unsigned short int
947bswap_16 (unsigned short int __bsx)
948{
949 return ((((__bsx) >> 8) & 0xff) | (((__bsx) & 0xff) << 8));
950}
951#endif
952
953/* Swap bytes in 32 bit value. */
954#ifdef __GNUC__
955# define bswap_32(x) \
956 (__extension__ \
957 ({ unsigned int __bsx = (x); \
958 ((((__bsx) & 0xff000000) >> 24) | (((__bsx) & 0x00ff0000) >> 8) | \
959 (((__bsx) & 0x0000ff00) << 8) | (((__bsx) & 0x000000ff) << 24)); }))
960#else
961static __inline unsigned int
962bswap_32 (unsigned int __bsx)
963{
964 return ((((__bsx) & 0xff000000) >> 24) | (((__bsx) & 0x00ff0000) >> 8) |
965 (((__bsx) & 0x0000ff00) << 8) | (((__bsx) & 0x000000ff) << 24));
966}
967#endif
968
969
970// From libsdl
971#ifdef WORDS_BIGENDIAN
972#define bswapLE16(X) bswap_16(X)
973#define bswapLE32(X) bswap_32(X)
974#define bswapBE16(X) (X)
975#define bswapBE32(X) (X)
976#else
977#define bswapLE16(X) (X)
978#define bswapLE32(X) (X)
979#define bswapBE16(X) bswap_16(X)
980#define bswapBE32(X) bswap_32(X)
981#endif
982
983
984#endif
diff --git a/core/multimedia/opieplayer/modplug/sndmix.cpp b/core/multimedia/opieplayer/modplug/sndmix.cpp
new file mode 100644
index 0000000..bfc5f4a
--- a/dev/null
+++ b/core/multimedia/opieplayer/modplug/sndmix.cpp
@@ -0,0 +1,1248 @@
1/*
2 * This program is free software; you can redistribute it and modify it
3 * under the terms of the GNU General Public License as published by the
4 * Free Software Foundation; either version 2 of the license or (at your
5 * option) any later version.
6 *
7 * Authors: Olivier Lapicque <olivierl@jps.net>
8*/
9
10#include "stdafx.h"
11#include "sndfile.h"
12
13#ifdef MODPLUG_TRACKER
14#define ENABLE_STEREOVU
15#endif
16
17// Volume ramp length, in 1/10 ms
18 #define VOLUMERAMPLEN 146// 1.46ms = 64 samples at 44.1kHz
19
20// VU-Meter
21 #define VUMETER_DECAY 4
22
23// SNDMIX: These are global flags for playback control
24UINT CSoundFile::m_nStereoSeparation = 128;
25LONG CSoundFile::m_nStreamVolume = 0x8000;
26UINT CSoundFile::m_nMaxMixChannels = 32;
27// Mixing Configuration (SetWaveConfig)
28DWORD CSoundFile::gdwSysInfo = 0;
29DWORD CSoundFile::gnChannels = 1;
30DWORD CSoundFile::gdwSoundSetup = 0;
31DWORD CSoundFile::gdwMixingFreq = 44100;
32DWORD CSoundFile::gnBitsPerSample = 16;
33// Mixing data initialized in
34UINT CSoundFile::gnAGC = AGC_UNITY;
35UINT CSoundFile::gnVolumeRampSamples = 64;
36UINT CSoundFile::gnVUMeter = 0;
37UINT CSoundFile::gnCPUUsage = 0;
38LPSNDMIXHOOKPROC CSoundFile::gpSndMixHook = NULL;
39PMIXPLUGINCREATEPROC CSoundFile::gpMixPluginCreateProc = NULL;
40LONG gnDryROfsVol = 0;
41LONG gnDryLOfsVol = 0;
42LONG gnRvbROfsVol = 0;
43LONG gnRvbLOfsVol = 0;
44int gbInitPlugins = 0;
45
46typedef DWORD (MPPASMCALL * LPCONVERTPROC)(LPVOID, int *, DWORD, LPLONG, LPLONG);
47
48extern DWORD MPPASMCALL X86_Convert32To8(LPVOID lpBuffer, int *, DWORD nSamples, LPLONG, LPLONG);
49extern DWORD MPPASMCALL X86_Convert32To16(LPVOID lpBuffer, int *, DWORD nSamples, LPLONG, LPLONG);
50extern DWORD MPPASMCALL X86_Convert32To24(LPVOID lpBuffer, int *, DWORD nSamples, LPLONG, LPLONG);
51extern DWORD MPPASMCALL X86_Convert32To32(LPVOID lpBuffer, int *, DWORD nSamples, LPLONG, LPLONG);
52extern UINT MPPASMCALL X86_AGC(int *pBuffer, UINT nSamples, UINT nAGC);
53extern VOID MPPASMCALL X86_Dither(int *pBuffer, UINT nSamples, UINT nBits);
54extern VOID MPPASMCALL X86_InterleaveFrontRear(int *pFrontBuf, int *pRearBuf, DWORD nSamples);
55extern VOID MPPASMCALL X86_StereoFill(int *pBuffer, UINT nSamples, LPLONG lpROfs, LPLONG lpLOfs);
56extern VOID MPPASMCALL X86_MonoFromStereo(int *pMixBuf, UINT nSamples);
57
58extern const short int ModSinusTable[64];
59extern const short int ModRampDownTable[64];
60extern const short int ModSquareTable[64];
61extern const short int ModRandomTable[64];
62extern const DWORD LinearSlideUpTable[256];
63extern const DWORD LinearSlideDownTable[256];
64extern const DWORD FineLinearSlideUpTable[16];
65extern const DWORD FineLinearSlideDownTable[16];
66 extern const signed char ft2VibratoTable[256];// -64 .. +64
67extern int MixSoundBuffer[MIXBUFFERSIZE*4];
68extern int MixRearBuffer[MIXBUFFERSIZE*2];
69UINT gnReverbSend;
70
71
72// Log tables for pre-amp
73// We don't want the tracker to get too loud
74const UINT PreAmpTable[16] =
75{
76 0x60, 0x60, 0x60, 0x70,// 0-7
77 0x80, 0x88, 0x90, 0x98,// 8-15
78 0xA0, 0xA4, 0xA8, 0xB0,// 16-23
79 0xB4, 0xB8, 0xBC, 0xC0,// 24-31
80};
81
82const UINT PreAmpAGCTable[16] =
83{
84 0x60, 0x60, 0x60, 0x60,
85 0x68, 0x70, 0x78, 0x80,
86 0x84, 0x88, 0x8C, 0x90,
87 0x94, 0x98, 0x9C, 0xA0,
88};
89
90
91// Return (a*b)/c - no divide error
92int _muldiv(long a, long b, long c)
93{
94#ifdef WIN32
95 int sign, result;
96 _asm {
97 mov eax, a
98 mov ebx, b
99 or eax, eax
100 mov edx, eax
101 jge aneg
102 neg eax
103aneg:
104 xor edx, ebx
105 or ebx, ebx
106 mov ecx, c
107 jge bneg
108 neg ebx
109bneg:
110 xor edx, ecx
111 or ecx, ecx
112 mov sign, edx
113 jge cneg
114 neg ecx
115cneg:
116 mul ebx
117 cmp edx, ecx
118 jae diverr
119 div ecx
120 jmp ok
121diverr:
122 mov eax, 0x7fffffff
123ok:
124 mov edx, sign
125 or edx, edx
126 jge rneg
127 neg eax
128rneg:
129 mov result, eax
130 }
131 return result;
132#else
133 return ((unsigned long long) a * (unsigned long long) b ) / c;
134#endif
135}
136
137
138// Return (a*b+c/2)/c - no divide error
139int _muldivr(long a, long b, long c)
140{
141#ifdef WIN32
142 int sign, result;
143 _asm {
144 mov eax, a
145 mov ebx, b
146 or eax, eax
147 mov edx, eax
148 jge aneg
149 neg eax
150aneg:
151 xor edx, ebx
152 or ebx, ebx
153 mov ecx, c
154 jge bneg
155 neg ebx
156bneg:
157 xor edx, ecx
158 or ecx, ecx
159 mov sign, edx
160 jge cneg
161 neg ecx
162cneg:
163 mul ebx
164 mov ebx, ecx
165 shr ebx, 1
166 add eax, ebx
167 adc edx, 0
168 cmp edx, ecx
169 jae diverr
170 div ecx
171 jmp ok
172diverr:
173 mov eax, 0x7fffffff
174ok:
175 mov edx, sign
176 or edx, edx
177 jge rneg
178 neg eax
179rneg:
180 mov result, eax
181 }
182 return result;
183#else
184 return ((unsigned long long) a * (unsigned long long) b + (c >> 1)) / c;
185#endif
186}
187
188
189BOOL CSoundFile::InitPlayer(BOOL bReset)
190//--------------------------------------
191{
192 if (m_nMaxMixChannels > MAX_CHANNELS) m_nMaxMixChannels = MAX_CHANNELS;
193 if (gdwMixingFreq < 4000) gdwMixingFreq = 4000;
194 if (gdwMixingFreq > MAX_SAMPLE_RATE) gdwMixingFreq = MAX_SAMPLE_RATE;
195 gnVolumeRampSamples = (gdwMixingFreq * VOLUMERAMPLEN) / 100000;
196 if (gnVolumeRampSamples < 8) gnVolumeRampSamples = 8;
197 gnDryROfsVol = gnDryLOfsVol = 0;
198 gnRvbROfsVol = gnRvbLOfsVol = 0;
199 if (bReset)
200 {
201 gnVUMeter = 0;
202 gnCPUUsage = 0;
203 }
204 gbInitPlugins = (bReset) ? 3 : 1;
205 InitializeDSP(bReset);
206 return TRUE;
207}
208
209
210BOOL CSoundFile::FadeSong(UINT msec)
211//----------------------------------
212{
213 LONG nsamples = _muldiv(msec, gdwMixingFreq, 1000);
214 if (nsamples <= 0) return FALSE;
215 if (nsamples > 0x100000) nsamples = 0x100000;
216 m_nBufferCount = nsamples;
217 LONG nRampLength = m_nBufferCount;
218 // Ramp everything down
219 for (UINT noff=0; noff < m_nMixChannels; noff++)
220 {
221 MODCHANNEL *pramp = &Chn[ChnMix[noff]];
222 if (!pramp) continue;
223 pramp->nNewLeftVol = pramp->nNewRightVol = 0;
224 pramp->nRightRamp = (-pramp->nRightVol << VOLUMERAMPPRECISION) / nRampLength;
225 pramp->nLeftRamp = (-pramp->nLeftVol << VOLUMERAMPPRECISION) / nRampLength;
226 pramp->nRampRightVol = pramp->nRightVol << VOLUMERAMPPRECISION;
227 pramp->nRampLeftVol = pramp->nLeftVol << VOLUMERAMPPRECISION;
228 pramp->nRampLength = nRampLength;
229 pramp->dwFlags |= CHN_VOLUMERAMP;
230 }
231 m_dwSongFlags |= SONG_FADINGSONG;
232 return TRUE;
233}
234
235
236BOOL CSoundFile::GlobalFadeSong(UINT msec)
237//----------------------------------------
238{
239 if (m_dwSongFlags & SONG_GLOBALFADE) return FALSE;
240 m_nGlobalFadeMaxSamples = _muldiv(msec, gdwMixingFreq, 1000);
241 m_nGlobalFadeSamples = m_nGlobalFadeMaxSamples;
242 m_dwSongFlags |= SONG_GLOBALFADE;
243 return TRUE;
244}
245
246
247UINT CSoundFile::Read(LPVOID lpDestBuffer, UINT cbBuffer)
248//-------------------------------------------------------
249{
250 LPBYTE lpBuffer = (LPBYTE)lpDestBuffer;
251 LPCONVERTPROC pCvt = X86_Convert32To8;
252 UINT lRead, lMax, lSampleSize, lCount, lSampleCount, nStat=0;
253 LONG nVUMeterMin = 0x7FFFFFFF, nVUMeterMax = -0x7FFFFFFF;
254 UINT nMaxPlugins;
255
256 {
257 nMaxPlugins = MAX_MIXPLUGINS;
258 while ((nMaxPlugins > 0) && (!m_MixPlugins[nMaxPlugins-1].pMixPlugin)) nMaxPlugins--;
259 }
260 m_nMixStat = 0;
261 lSampleSize = gnChannels;
262 if (gnBitsPerSample == 16) { lSampleSize *= 2; pCvt = X86_Convert32To16; }
263#ifndef FASTSOUNDLIB
264 else if (gnBitsPerSample == 24) { lSampleSize *= 3; pCvt = X86_Convert32To24; }
265 else if (gnBitsPerSample == 32) { lSampleSize *= 4; pCvt = X86_Convert32To32; }
266#endif
267 lMax = cbBuffer / lSampleSize;
268 if ((!lMax) || (!lpBuffer) || (!m_nChannels)) return 0;
269 lRead = lMax;
270 if (m_dwSongFlags & SONG_ENDREACHED) goto MixDone;
271 while (lRead > 0)
272 {
273 // Update Channel Data
274 if (!m_nBufferCount)
275 {
276#ifndef FASTSOUNDLIB
277 if (m_dwSongFlags & SONG_FADINGSONG)
278 {
279 m_dwSongFlags |= SONG_ENDREACHED;
280 m_nBufferCount = lRead;
281 } else
282#endif
283 if (!ReadNote())
284 {
285#ifndef FASTSOUNDLIB
286 if (!FadeSong(FADESONGDELAY))
287#endif
288 {
289 m_dwSongFlags |= SONG_ENDREACHED;
290 if (lRead == lMax) goto MixDone;
291 m_nBufferCount = lRead;
292 }
293 }
294 }
295 lCount = m_nBufferCount;
296 if (lCount > MIXBUFFERSIZE) lCount = MIXBUFFERSIZE;
297 if (lCount > lRead) lCount = lRead;
298 if (!lCount) break;
299 lSampleCount = lCount;
300#ifndef NO_REVERB
301 gnReverbSend = 0;
302#endif
303 // Resetting sound buffer
304 X86_StereoFill(MixSoundBuffer, lSampleCount, &gnDryROfsVol, &gnDryLOfsVol);
305 if (gnChannels >= 2)
306 {
307 lSampleCount *= 2;
308 m_nMixStat += CreateStereoMix(lCount);
309 ProcessStereoDSP(lCount);
310 } else
311 {
312 m_nMixStat += CreateStereoMix(lCount);
313 if (nMaxPlugins) ProcessPlugins(lCount);
314 ProcessStereoDSP(lCount);
315 X86_MonoFromStereo(MixSoundBuffer, lCount);
316 }
317 nStat++;
318#ifndef NO_AGC
319 // Automatic Gain Control
320 if (gdwSoundSetup & SNDMIX_AGC) ProcessAGC(lSampleCount);
321#endif
322 UINT lTotalSampleCount = lSampleCount;
323#ifndef FASTSOUNDLIB
324 // Multichannel
325 if (gnChannels > 2)
326 {
327 X86_InterleaveFrontRear(MixSoundBuffer, MixRearBuffer, lSampleCount);
328 lTotalSampleCount *= 2;
329 }
330 // Hook Function
331 if (gpSndMixHook)
332 {
333 gpSndMixHook(MixSoundBuffer, lTotalSampleCount, gnChannels);
334 }
335#endif
336 // Perform clipping + VU-Meter
337 lpBuffer += pCvt(lpBuffer, MixSoundBuffer, lTotalSampleCount, &nVUMeterMin, &nVUMeterMax);
338 // Buffer ready
339 lRead -= lCount;
340 m_nBufferCount -= lCount;
341 }
342MixDone:
343 if (lRead) memset(lpBuffer, (gnBitsPerSample == 8) ? 0x80 : 0, lRead * lSampleSize);
344 // VU-Meter
345 nVUMeterMin >>= (24-MIXING_ATTENUATION);
346 nVUMeterMax >>= (24-MIXING_ATTENUATION);
347 if (nVUMeterMax < nVUMeterMin) nVUMeterMax = nVUMeterMin;
348 if ((gnVUMeter = (UINT)(nVUMeterMax - nVUMeterMin)) > 0xFF) gnVUMeter = 0xFF;
349 if (nStat) { m_nMixStat += nStat-1; m_nMixStat /= nStat; }
350 return lMax - lRead;
351}
352
353
354
355/////////////////////////////////////////////////////////////////////////////
356// Handles navigation/effects
357
358BOOL CSoundFile::ProcessRow()
359//---------------------------
360{
361 if (++m_nTickCount >= m_nMusicSpeed * (m_nPatternDelay+1) + m_nFrameDelay)
362 {
363 m_nPatternDelay = 0;
364 m_nFrameDelay = 0;
365 m_nTickCount = 0;
366 m_nRow = m_nNextRow;
367 // Reset Pattern Loop Effect
368 if (m_nCurrentPattern != m_nNextPattern) m_nCurrentPattern = m_nNextPattern;
369 // Check if pattern is valid
370 if (!(m_dwSongFlags & SONG_PATTERNLOOP))
371 {
372 m_nPattern = (m_nCurrentPattern < MAX_ORDERS) ? Order[m_nCurrentPattern] : 0xFF;
373 if ((m_nPattern < MAX_PATTERNS) && (!Patterns[m_nPattern])) m_nPattern = 0xFE;
374 while (m_nPattern >= MAX_PATTERNS)
375 {
376 // End of song ?
377 if ((m_nPattern == 0xFF) || (m_nCurrentPattern >= MAX_ORDERS))
378 {
379 //if (!m_nRepeatCount)
380 return FALSE; //never repeat entire song
381 if (!m_nRestartPos)
382 {
383 m_nMusicSpeed = m_nDefaultSpeed;
384 m_nMusicTempo = m_nDefaultTempo;
385 m_nGlobalVolume = m_nDefaultGlobalVolume;
386 for (UINT i=0; i<MAX_CHANNELS; i++)
387 {
388 Chn[i].dwFlags |= CHN_NOTEFADE | CHN_KEYOFF;
389 Chn[i].nFadeOutVol = 0;
390 if (i < m_nChannels)
391 {
392 Chn[i].nGlobalVol = ChnSettings[i].nVolume;
393 Chn[i].nVolume = ChnSettings[i].nVolume;
394 Chn[i].nPan = ChnSettings[i].nPan;
395 Chn[i].nPanSwing = Chn[i].nVolSwing = 0;
396 Chn[i].nOldVolParam = 0;
397 Chn[i].nOldOffset = 0;
398 Chn[i].nOldHiOffset = 0;
399 Chn[i].nPortamentoDest = 0;
400 if (!Chn[i].nLength)
401 {
402 Chn[i].dwFlags = ChnSettings[i].dwFlags;
403 Chn[i].nLoopStart = 0;
404 Chn[i].nLoopEnd = 0;
405 Chn[i].pHeader = NULL;
406 Chn[i].pSample = NULL;
407 Chn[i].pInstrument = NULL;
408 }
409 }
410 }
411 }
412 // if (m_nRepeatCount > 0) m_nRepeatCount--;
413 m_nCurrentPattern = m_nRestartPos;
414 m_nRow = 0;
415 if ((Order[m_nCurrentPattern] >= MAX_PATTERNS) || (!Patterns[Order[m_nCurrentPattern]])) return FALSE;
416 } else
417 {
418 m_nCurrentPattern++;
419 }
420 m_nPattern = (m_nCurrentPattern < MAX_ORDERS) ? Order[m_nCurrentPattern] : 0xFF;
421 if ((m_nPattern < MAX_PATTERNS) && (!Patterns[m_nPattern])) m_nPattern = 0xFE;
422 }
423 m_nNextPattern = m_nCurrentPattern;
424 }
425 // Weird stuff?
426 if ((m_nPattern >= MAX_PATTERNS) || (!Patterns[m_nPattern])) return FALSE;
427 // Should never happen
428 if (m_nRow >= PatternSize[m_nPattern]) m_nRow = 0;
429 m_nNextRow = m_nRow + 1;
430 if (m_nNextRow >= PatternSize[m_nPattern])
431 {
432 if (!(m_dwSongFlags & SONG_PATTERNLOOP)) m_nNextPattern = m_nCurrentPattern + 1;
433 m_nNextRow = 0;
434 }
435 // Reset channel values
436 MODCHANNEL *pChn = Chn;
437 MODCOMMAND *m = Patterns[m_nPattern] + m_nRow * m_nChannels;
438 for (UINT nChn=0; nChn<m_nChannels; pChn++, nChn++, m++)
439 {
440 pChn->nRowNote = m->note;
441 pChn->nRowInstr = m->instr;
442 pChn->nRowVolCmd = m->volcmd;
443 pChn->nRowVolume = m->vol;
444 pChn->nRowCommand = m->command;
445 pChn->nRowParam = m->param;
446
447 pChn->nLeftVol = pChn->nNewLeftVol;
448 pChn->nRightVol = pChn->nNewRightVol;
449 pChn->dwFlags &= ~(CHN_PORTAMENTO | CHN_VIBRATO | CHN_TREMOLO | CHN_PANBRELLO);
450 pChn->nCommand = 0;
451 }
452 }
453 // Should we process tick0 effects?
454 if (!m_nMusicSpeed) m_nMusicSpeed = 1;
455 m_dwSongFlags |= SONG_FIRSTTICK;
456 if (m_nTickCount)
457 {
458 m_dwSongFlags &= ~SONG_FIRSTTICK;
459 if ((!(m_nType & MOD_TYPE_XM)) && (m_nTickCount < m_nMusicSpeed * (1 + m_nPatternDelay)))
460 {
461 if (!(m_nTickCount % m_nMusicSpeed)) m_dwSongFlags |= SONG_FIRSTTICK;
462 }
463
464 }
465 // Update Effects
466 return ProcessEffects();
467}
468
469
470////////////////////////////////////////////////////////////////////////////////////////////
471// Handles envelopes & mixer setup
472
473BOOL CSoundFile::ReadNote()
474//-------------------------
475{
476 if (!ProcessRow()) return FALSE;
477 ////////////////////////////////////////////////////////////////////////////////////
478 m_nTotalCount++;
479 if (!m_nMusicTempo) return FALSE;
480 m_nBufferCount = (gdwMixingFreq * 5 * m_nTempoFactor) / (m_nMusicTempo << 8);
481 // Master Volume + Pre-Amplification / Attenuation setup
482 DWORD nMasterVol;
483 {
484 int nchn32 = (m_nChannels < 32) ? m_nChannels : 31;
485 if ((m_nType & MOD_TYPE_IT) && (m_nInstruments) && (nchn32 < 6)) nchn32 = 6;
486 int realmastervol = m_nMasterVolume;
487 if (realmastervol > 0x80)
488 {
489 realmastervol = 0x80 + ((realmastervol - 0x80) * (nchn32+4)) / 16;
490 }
491 UINT attenuation = (gdwSoundSetup & SNDMIX_AGC) ? PreAmpAGCTable[nchn32>>1] : PreAmpTable[nchn32>>1];
492 DWORD mastervol = (realmastervol * (m_nSongPreAmp + 0x10)) >> 6;
493 if (mastervol > 0x200) mastervol = 0x200;
494 if ((m_dwSongFlags & SONG_GLOBALFADE) && (m_nGlobalFadeMaxSamples))
495 {
496 mastervol = _muldiv(mastervol, m_nGlobalFadeSamples, m_nGlobalFadeMaxSamples);
497 }
498 nMasterVol = (mastervol << 7) / attenuation;
499 if (nMasterVol > 0x180) nMasterVol = 0x180;
500 }
501 ////////////////////////////////////////////////////////////////////////////////////
502 // Update channels data
503 m_nMixChannels = 0;
504 MODCHANNEL *pChn = Chn;
505 for (UINT nChn=0; nChn<MAX_CHANNELS; nChn++,pChn++)
506 {
507 if ((pChn->dwFlags & CHN_NOTEFADE) && (!(pChn->nFadeOutVol|pChn->nRightVol|pChn->nLeftVol)))
508 {
509 pChn->nLength = 0;
510 pChn->nROfs = pChn->nLOfs = 0;
511 }
512 // Check for unused channel
513 if ((pChn->dwFlags & CHN_MUTE) || ((nChn >= m_nChannels) && (!pChn->nLength)))
514 {
515 pChn->nVUMeter = 0;
516#ifdef ENABLE_STEREOVU
517 pChn->nLeftVU = pChn->nRightVU = 0;
518#endif
519 continue;
520 }
521 // Reset channel data
522 pChn->nInc = 0;
523 pChn->nRealVolume = 0;
524 pChn->nRealPan = pChn->nPan + pChn->nPanSwing;
525 if (pChn->nRealPan < 0) pChn->nRealPan = 0;
526 if (pChn->nRealPan > 256) pChn->nRealPan = 256;
527 pChn->nRampLength = 0;
528 // Calc Frequency
529 if ((pChn->nPeriod)&& (pChn->nLength))
530 {
531 int vol = pChn->nVolume + pChn->nVolSwing;
532
533 if (vol < 0) vol = 0;
534 if (vol > 256) vol = 256;
535 // Tremolo
536 if (pChn->dwFlags & CHN_TREMOLO)
537 {
538 UINT trempos = pChn->nTremoloPos & 0x3F;
539 if (vol > 0)
540 {
541 int tremattn = (m_nType & MOD_TYPE_XM) ? 5 : 6;
542 switch (pChn->nTremoloType & 0x03)
543 {
544 case 1:
545 vol += (ModRampDownTable[trempos] * (int)pChn->nTremoloDepth) >> tremattn;
546 break;
547 case 2:
548 vol += (ModSquareTable[trempos] * (int)pChn->nTremoloDepth) >> tremattn;
549 break;
550 case 3:
551 vol += (ModRandomTable[trempos] * (int)pChn->nTremoloDepth) >> tremattn;
552 break;
553 default:
554 vol += (ModSinusTable[trempos] * (int)pChn->nTremoloDepth) >> tremattn;
555 }
556 }
557 if ((m_nTickCount) || ((m_nType & (MOD_TYPE_STM|MOD_TYPE_S3M|MOD_TYPE_IT)) && (!(m_dwSongFlags & SONG_ITOLDEFFECTS))))
558 {
559 pChn->nTremoloPos = (trempos + pChn->nTremoloSpeed) & 0x3F;
560 }
561 }
562 // Tremor
563 if (pChn->nCommand == CMD_TREMOR)
564 {
565 UINT n = (pChn->nTremorParam >> 4) + (pChn->nTremorParam & 0x0F);
566 UINT ontime = pChn->nTremorParam >> 4;
567 if ((!(m_nType & MOD_TYPE_IT)) || (m_dwSongFlags & SONG_ITOLDEFFECTS)) { n += 2; ontime++; }
568 UINT tremcount = (UINT)pChn->nTremorCount;
569 if (tremcount >= n) tremcount = 0;
570 if ((m_nTickCount) || (m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT)))
571 {
572 if (tremcount >= ontime) vol = 0;
573 pChn->nTremorCount = (BYTE)(tremcount + 1);
574 }
575 pChn->dwFlags |= CHN_FASTVOLRAMP;
576 }
577 // Clip volume
578 if (vol < 0) vol = 0;
579 if (vol > 0x100) vol = 0x100;
580 vol <<= 6;
581 // Process Envelopes
582 if (pChn->pHeader)
583 {
584 INSTRUMENTHEADER *penv = pChn->pHeader;
585 // Volume Envelope
586 if ((pChn->dwFlags & CHN_VOLENV) && (penv->nVolEnv))
587 {
588 int envpos = pChn->nVolEnvPosition;
589 UINT pt = penv->nVolEnv - 1;
590 for (UINT i=0; i<(UINT)(penv->nVolEnv-1); i++)
591 {
592 if (envpos <= penv->VolPoints[i])
593 {
594 pt = i;
595 break;
596 }
597 }
598 int x2 = penv->VolPoints[pt];
599 int x1, envvol;
600 if (envpos >= x2)
601 {
602 envvol = penv->VolEnv[pt] << 2;
603 x1 = x2;
604 } else
605 if (pt)
606 {
607 envvol = penv->VolEnv[pt-1] << 2;
608 x1 = penv->VolPoints[pt-1];
609 } else
610 {
611 envvol = 0;
612 x1 = 0;
613 }
614 if (envpos > x2) envpos = x2;
615 if ((x2 > x1) && (envpos > x1))
616 {
617 envvol += ((envpos - x1) * (((int)penv->VolEnv[pt]<<2) - envvol)) / (x2 - x1);
618 }
619 if (envvol < 0) envvol = 0;
620 if (envvol > 256) envvol = 256;
621 vol = (vol * envvol) >> 8;
622 }
623 // Panning Envelope
624 if ((pChn->dwFlags & CHN_PANENV) && (penv->nPanEnv))
625 {
626 int envpos = pChn->nPanEnvPosition;
627 UINT pt = penv->nPanEnv - 1;
628 for (UINT i=0; i<(UINT)(penv->nPanEnv-1); i++)
629 {
630 if (envpos <= penv->PanPoints[i])
631 {
632 pt = i;
633 break;
634 }
635 }
636 int x2 = penv->PanPoints[pt], y2 = penv->PanEnv[pt];
637 int x1, envpan;
638 if (envpos >= x2)
639 {
640 envpan = y2;
641 x1 = x2;
642 } else
643 if (pt)
644 {
645 envpan = penv->PanEnv[pt-1];
646 x1 = penv->PanPoints[pt-1];
647 } else
648 {
649 envpan = 128;
650 x1 = 0;
651 }
652 if ((x2 > x1) && (envpos > x1))
653 {
654 envpan += ((envpos - x1) * (y2 - envpan)) / (x2 - x1);
655 }
656 if (envpan < 0) envpan = 0;
657 if (envpan > 64) envpan = 64;
658 int pan = pChn->nPan;
659 if (pan >= 128)
660 {
661 pan += ((envpan - 32) * (256 - pan)) / 32;
662 } else
663 {
664 pan += ((envpan - 32) * (pan)) / 32;
665 }
666 if (pan < 0) pan = 0;
667 if (pan > 256) pan = 256;
668 pChn->nRealPan = pan;
669 }
670 // FadeOut volume
671 if (pChn->dwFlags & CHN_NOTEFADE)
672 {
673 UINT fadeout = penv->nFadeOut;
674 if (fadeout)
675 {
676 pChn->nFadeOutVol -= fadeout << 1;
677 if (pChn->nFadeOutVol <= 0) pChn->nFadeOutVol = 0;
678 vol = (vol * pChn->nFadeOutVol) >> 16;
679 } else
680 if (!pChn->nFadeOutVol)
681 {
682 vol = 0;
683 }
684 }
685 // Pitch/Pan separation
686 if ((penv->nPPS) && (pChn->nRealPan) && (pChn->nNote))
687 {
688 int pandelta = (int)pChn->nRealPan + (int)((int)(pChn->nNote - penv->nPPC - 1) * (int)penv->nPPS) / (int)8;
689 if (pandelta < 0) pandelta = 0;
690 if (pandelta > 256) pandelta = 256;
691 pChn->nRealPan = pandelta;
692 }
693 } else
694 {
695 // No Envelope: key off => note cut
696 if (pChn->dwFlags & CHN_NOTEFADE) // 1.41-: CHN_KEYOFF|CHN_NOTEFADE
697 {
698 pChn->nFadeOutVol = 0;
699 vol = 0;
700 }
701 }
702 // vol is 14-bits
703 if (vol)
704 {
705 // IMPORTANT: pChn->nRealVolume is 14 bits !!!
706 // -> _muldiv( 14+8, 6+6, 18); => RealVolume: 14-bit result (22+12-20)
707 pChn->nRealVolume = _muldiv(vol * m_nGlobalVolume, pChn->nGlobalVol * pChn->nInsVol, 1 << 20);
708 }
709 if (pChn->nPeriod < m_nMinPeriod) pChn->nPeriod = m_nMinPeriod;
710 int period = pChn->nPeriod;
711 if ((pChn->dwFlags & (CHN_GLISSANDO|CHN_PORTAMENTO)) ==(CHN_GLISSANDO|CHN_PORTAMENTO))
712 {
713 period = GetPeriodFromNote(GetNoteFromPeriod(period), pChn->nFineTune, pChn->nC4Speed);
714 }
715
716 // Arpeggio ?
717 if (pChn->nCommand == CMD_ARPEGGIO)
718 {
719 switch(m_nTickCount % 3)
720 {
721 case 1:period = GetPeriodFromNote(pChn->nNote + (pChn->nArpeggio >> 4), pChn->nFineTune, pChn->nC4Speed); break;
722 case 2:period = GetPeriodFromNote(pChn->nNote + (pChn->nArpeggio & 0x0F), pChn->nFineTune, pChn->nC4Speed); break;
723 }
724 }
725
726 if (m_dwSongFlags & SONG_AMIGALIMITS)
727 {
728 if (period < 113*4) period = 113*4;
729 if (period > 856*4) period = 856*4;
730 }
731
732 // Pitch/Filter Envelope
733 if ((pChn->pHeader) && (pChn->dwFlags & CHN_PITCHENV) && (pChn->pHeader->nPitchEnv))
734 {
735 INSTRUMENTHEADER *penv = pChn->pHeader;
736 int envpos = pChn->nPitchEnvPosition;
737 UINT pt = penv->nPitchEnv - 1;
738 for (UINT i=0; i<(UINT)(penv->nPitchEnv-1); i++)
739 {
740 if (envpos <= penv->PitchPoints[i])
741 {
742 pt = i;
743 break;
744 }
745 }
746 int x2 = penv->PitchPoints[pt];
747 int x1, envpitch;
748 if (envpos >= x2)
749 {
750 envpitch = (((int)penv->PitchEnv[pt]) - 32) * 8;
751 x1 = x2;
752 } else
753 if (pt)
754 {
755 envpitch = (((int)penv->PitchEnv[pt-1]) - 32) * 8;
756 x1 = penv->PitchPoints[pt-1];
757 } else
758 {
759 envpitch = 0;
760 x1 = 0;
761 }
762 if (envpos > x2) envpos = x2;
763 if ((x2 > x1) && (envpos > x1))
764 {
765 int envpitchdest = (((int)penv->PitchEnv[pt]) - 32) * 8;
766 envpitch += ((envpos - x1) * (envpitchdest - envpitch)) / (x2 - x1);
767 }
768 if (envpitch < -256) envpitch = -256;
769 if (envpitch > 256) envpitch = 256;
770 // Filter Envelope: controls cutoff frequency
771 if (penv->dwFlags & ENV_FILTER)
772 {
773#ifndef NO_FILTER
774 SetupChannelFilter(pChn, (pChn->dwFlags & CHN_FILTER) ? FALSE : TRUE, envpitch);
775#endif // NO_FILTER
776 } else
777 // Pitch Envelope
778 {
779 int l = envpitch;
780 if (l < 0)
781 {
782 l = -l;
783 if (l > 255) l = 255;
784 period = _muldiv(period, LinearSlideUpTable[l], 0x10000);
785 } else
786 {
787 if (l > 255) l = 255;
788 period = _muldiv(period, LinearSlideDownTable[l], 0x10000);
789 }
790 }
791 }
792
793 // Vibrato
794 if (pChn->dwFlags & CHN_VIBRATO)
795 {
796 UINT vibpos = pChn->nVibratoPos;
797 LONG vdelta;
798 switch (pChn->nVibratoType & 0x03)
799 {
800 case 1:
801 vdelta = ModRampDownTable[vibpos];
802 break;
803 case 2:
804 vdelta = ModSquareTable[vibpos];
805 break;
806 case 3:
807 vdelta = ModRandomTable[vibpos];
808 break;
809 default:
810 vdelta = ModSinusTable[vibpos];
811 }
812 UINT vdepth = ((m_nType != MOD_TYPE_IT) || (m_dwSongFlags & SONG_ITOLDEFFECTS)) ? 6 : 7;
813 vdelta = (vdelta * (int)pChn->nVibratoDepth) >> vdepth;
814 if ((m_dwSongFlags & SONG_LINEARSLIDES) && (m_nType & MOD_TYPE_IT))
815 {
816 LONG l = vdelta;
817 if (l < 0)
818 {
819 l = -l;
820 vdelta = _muldiv(period, LinearSlideDownTable[l >> 2], 0x10000) - period;
821 if (l & 0x03) vdelta += _muldiv(period, FineLinearSlideDownTable[l & 0x03], 0x10000) - period;
822
823 } else
824 {
825 vdelta = _muldiv(period, LinearSlideUpTable[l >> 2], 0x10000) - period;
826 if (l & 0x03) vdelta += _muldiv(period, FineLinearSlideUpTable[l & 0x03], 0x10000) - period;
827
828 }
829 }
830 period += vdelta;
831 if ((m_nTickCount) || ((m_nType & MOD_TYPE_IT) && (!(m_dwSongFlags & SONG_ITOLDEFFECTS))))
832 {
833 pChn->nVibratoPos = (vibpos + pChn->nVibratoSpeed) & 0x3F;
834 }
835 }
836 // Panbrello
837 if (pChn->dwFlags & CHN_PANBRELLO)
838 {
839 UINT panpos = ((pChn->nPanbrelloPos+0x10) >> 2) & 0x3F;
840 LONG pdelta;
841 switch (pChn->nPanbrelloType & 0x03)
842 {
843 case 1:
844 pdelta = ModRampDownTable[panpos];
845 break;
846 case 2:
847 pdelta = ModSquareTable[panpos];
848 break;
849 case 3:
850 pdelta = ModRandomTable[panpos];
851 break;
852 default:
853 pdelta = ModSinusTable[panpos];
854 }
855 pChn->nPanbrelloPos += pChn->nPanbrelloSpeed;
856 pdelta = ((pdelta * (int)pChn->nPanbrelloDepth) + 2) >> 3;
857 pdelta += pChn->nRealPan;
858 if (pdelta < 0) pdelta = 0;
859 if (pdelta > 256) pdelta = 256;
860 pChn->nRealPan = pdelta;
861 }
862 int nPeriodFrac = 0;
863 // Instrument Auto-Vibrato
864 if ((pChn->pInstrument) && (pChn->pInstrument->nVibDepth))
865 {
866 MODINSTRUMENT *pins = pChn->pInstrument;
867 if (pins->nVibSweep == 0)
868 {
869 pChn->nAutoVibDepth = pins->nVibDepth << 8;
870 } else
871 {
872 if (m_nType & MOD_TYPE_IT)
873 {
874 pChn->nAutoVibDepth += pins->nVibSweep << 3;
875 } else
876 if (!(pChn->dwFlags & CHN_KEYOFF))
877 {
878 pChn->nAutoVibDepth += (pins->nVibDepth << 8) /pins->nVibSweep;
879 }
880 if ((pChn->nAutoVibDepth >> 8) > pins->nVibDepth)
881 pChn->nAutoVibDepth = pins->nVibDepth << 8;
882 }
883 pChn->nAutoVibPos += pins->nVibRate;
884 int val;
885 switch(pins->nVibType)
886 {
887 case 4:// Random
888 val = ModRandomTable[pChn->nAutoVibPos & 0x3F];
889 pChn->nAutoVibPos++;
890 break;
891 case 3:// Ramp Down
892 val = ((0x40 - (pChn->nAutoVibPos >> 1)) & 0x7F) - 0x40;
893 break;
894 case 2:// Ramp Up
895 val = ((0x40 + (pChn->nAutoVibPos >> 1)) & 0x7f) - 0x40;
896 break;
897 case 1:// Square
898 val = (pChn->nAutoVibPos & 128) ? +64 : -64;
899 break;
900 default:// Sine
901 val = ft2VibratoTable[pChn->nAutoVibPos & 255];
902 }
903 int n =((val * pChn->nAutoVibDepth) >> 8);
904 if (m_nType & MOD_TYPE_IT)
905 {
906 int df1, df2;
907 if (n < 0)
908 {
909 n = -n;
910 UINT n1 = n >> 8;
911 df1 = LinearSlideUpTable[n1];
912 df2 = LinearSlideUpTable[n1+1];
913 } else
914 {
915 UINT n1 = n >> 8;
916 df1 = LinearSlideDownTable[n1];
917 df2 = LinearSlideDownTable[n1+1];
918 }
919 n >>= 2;
920 period = _muldiv(period, df1 + ((df2-df1)*(n&0x3F)>>6), 256);
921 nPeriodFrac = period & 0xFF;
922 period >>= 8;
923 } else
924 {
925 period += (n >> 6);
926 }
927 }
928 // Final Period
929 if (period <= m_nMinPeriod)
930 {
931 if (m_nType & MOD_TYPE_S3M) pChn->nLength = 0;
932 period = m_nMinPeriod;
933 }
934 if (period > m_nMaxPeriod)
935 {
936 if ((m_nType & MOD_TYPE_IT) || (period >= 0x100000))
937 {
938 pChn->nFadeOutVol = 0;
939 pChn->dwFlags |= CHN_NOTEFADE;
940 pChn->nRealVolume = 0;
941 }
942 period = m_nMaxPeriod;
943 nPeriodFrac = 0;
944 }
945 UINT freq = GetFreqFromPeriod(period, pChn->nC4Speed, nPeriodFrac);
946 if ((m_nType & MOD_TYPE_IT) && (freq < 256))
947 {
948 pChn->nFadeOutVol = 0;
949 pChn->dwFlags |= CHN_NOTEFADE;
950 pChn->nRealVolume = 0;
951 }
952 UINT ninc = _muldiv(freq, 0x10000, gdwMixingFreq);
953 if ((ninc >= 0xFFB0) && (ninc <= 0x10090)) ninc = 0x10000;
954 if (m_nFreqFactor != 128) ninc = (ninc * m_nFreqFactor) >> 7;
955 if (ninc > 0xFF0000) ninc = 0xFF0000;
956 pChn->nInc = (ninc+1) & ~3;
957 }
958
959 // Increment envelope position
960 if (pChn->pHeader)
961 {
962 INSTRUMENTHEADER *penv = pChn->pHeader;
963 // Volume Envelope
964 if (pChn->dwFlags & CHN_VOLENV)
965 {
966 // Increase position
967 pChn->nVolEnvPosition++;
968 // Volume Loop ?
969 if (penv->dwFlags & ENV_VOLLOOP)
970 {
971 UINT volloopend = penv->VolPoints[penv->nVolLoopEnd];
972 if (m_nType != MOD_TYPE_XM) volloopend++;
973 if (pChn->nVolEnvPosition == volloopend)
974 {
975 pChn->nVolEnvPosition = penv->VolPoints[penv->nVolLoopStart];
976 if ((penv->nVolLoopEnd == penv->nVolLoopStart) && (!penv->VolEnv[penv->nVolLoopStart])
977 && ((!(m_nType & MOD_TYPE_XM)) || (penv->nVolLoopEnd+1 == penv->nVolEnv)))
978 {
979 pChn->dwFlags |= CHN_NOTEFADE;
980 pChn->nFadeOutVol = 0;
981 }
982 }
983 }
984 // Volume Sustain ?
985 if ((penv->dwFlags & ENV_VOLSUSTAIN) && (!(pChn->dwFlags & CHN_KEYOFF)))
986 {
987 if (pChn->nVolEnvPosition == (UINT)penv->VolPoints[penv->nVolSustainEnd]+1)
988 pChn->nVolEnvPosition = penv->VolPoints[penv->nVolSustainBegin];
989 } else
990 // End of Envelope ?
991 if (pChn->nVolEnvPosition > penv->VolPoints[penv->nVolEnv - 1])
992 {
993 if ((m_nType & MOD_TYPE_IT) || (pChn->dwFlags & CHN_KEYOFF)) pChn->dwFlags |= CHN_NOTEFADE;
994 pChn->nVolEnvPosition = penv->VolPoints[penv->nVolEnv - 1];
995 if ((!penv->VolEnv[penv->nVolEnv-1]) && ((nChn >= m_nChannels) || (m_nType & MOD_TYPE_IT)))
996 {
997 pChn->dwFlags |= CHN_NOTEFADE;
998 pChn->nFadeOutVol = 0;
999
1000 pChn->nRealVolume = 0;
1001 }
1002 }
1003 }
1004 // Panning Envelope
1005 if (pChn->dwFlags & CHN_PANENV)
1006 {
1007 pChn->nPanEnvPosition++;
1008 if (penv->dwFlags & ENV_PANLOOP)
1009 {
1010 UINT panloopend = penv->PanPoints[penv->nPanLoopEnd];
1011 if (m_nType != MOD_TYPE_XM) panloopend++;
1012 if (pChn->nPanEnvPosition == panloopend)
1013 pChn->nPanEnvPosition = penv->PanPoints[penv->nPanLoopStart];
1014 }
1015 // Panning Sustain ?
1016 if ((penv->dwFlags & ENV_PANSUSTAIN) && (pChn->nPanEnvPosition == (UINT)penv->PanPoints[penv->nPanSustainEnd]+1)
1017 && (!(pChn->dwFlags & CHN_KEYOFF)))
1018 {
1019 // Panning sustained
1020 pChn->nPanEnvPosition = penv->PanPoints[penv->nPanSustainBegin];
1021 } else
1022 {
1023 if (pChn->nPanEnvPosition > penv->PanPoints[penv->nPanEnv - 1])
1024 pChn->nPanEnvPosition = penv->PanPoints[penv->nPanEnv - 1];
1025 }
1026 }
1027 // Pitch Envelope
1028 if (pChn->dwFlags & CHN_PITCHENV)
1029 {
1030 // Increase position
1031 pChn->nPitchEnvPosition++;
1032 // Pitch Loop ?
1033 if (penv->dwFlags & ENV_PITCHLOOP)
1034 {
1035 if (pChn->nPitchEnvPosition >= penv->PitchPoints[penv->nPitchLoopEnd])
1036 pChn->nPitchEnvPosition = penv->PitchPoints[penv->nPitchLoopStart];
1037 }
1038 // Pitch Sustain ?
1039 if ((penv->dwFlags & ENV_PITCHSUSTAIN) && (!(pChn->dwFlags & CHN_KEYOFF)))
1040 {
1041 if (pChn->nPitchEnvPosition == (UINT)penv->PitchPoints[penv->nPitchSustainEnd]+1)
1042 pChn->nPitchEnvPosition = penv->PitchPoints[penv->nPitchSustainBegin];
1043 } else
1044 {
1045 if (pChn->nPitchEnvPosition > penv->PitchPoints[penv->nPitchEnv - 1])
1046 pChn->nPitchEnvPosition = penv->PitchPoints[penv->nPitchEnv - 1];
1047 }
1048 }
1049 }
1050#ifdef MODPLUG_PLAYER
1051 // Limit CPU -> > 80% -> don't ramp
1052 if ((gnCPUUsage >= 80) && (!pChn->nRealVolume))
1053 {
1054 pChn->nLeftVol = pChn->nRightVol = 0;
1055 }
1056#endif // MODPLUG_PLAYER
1057 // Volume ramping
1058 pChn->dwFlags &= ~CHN_VOLUMERAMP;
1059 if ((pChn->nRealVolume) || (pChn->nLeftVol) || (pChn->nRightVol))
1060 pChn->dwFlags |= CHN_VOLUMERAMP;
1061#ifdef MODPLUG_PLAYER
1062 // Decrease VU-Meter
1063 if (pChn->nVUMeter > VUMETER_DECAY)pChn->nVUMeter -= VUMETER_DECAY; else pChn->nVUMeter = 0;
1064#endif // MODPLUG_PLAYER
1065#ifdef ENABLE_STEREOVU
1066 if (pChn->nLeftVU > VUMETER_DECAY) pChn->nLeftVU -= VUMETER_DECAY; else pChn->nLeftVU = 0;
1067 if (pChn->nRightVU > VUMETER_DECAY) pChn->nRightVU -= VUMETER_DECAY; else pChn->nRightVU = 0;
1068#endif
1069 // Check for too big nInc
1070 if (((pChn->nInc >> 16) + 1) >= (LONG)(pChn->nLoopEnd - pChn->nLoopStart)) pChn->dwFlags &= ~CHN_LOOP;
1071 pChn->nNewRightVol = pChn->nNewLeftVol = 0;
1072 pChn->pCurrentSample = ((pChn->pSample) && (pChn->nLength) && (pChn->nInc)) ? pChn->pSample : NULL;
1073 if (pChn->pCurrentSample)
1074 {
1075 // Update VU-Meter (nRealVolume is 14-bit)
1076#ifdef MODPLUG_PLAYER
1077 UINT vutmp = pChn->nRealVolume >> (14 - 8);
1078 if (vutmp > 0xFF) vutmp = 0xFF;
1079 if (pChn->nVUMeter >= 0x100) pChn->nVUMeter = vutmp;
1080 vutmp >>= 1;
1081 if (pChn->nVUMeter < vutmp)pChn->nVUMeter = vutmp;
1082#endif // MODPLUG_PLAYER
1083#ifdef ENABLE_STEREOVU
1084 UINT vul = (pChn->nRealVolume * pChn->nRealPan) >> 14;
1085 if (vul > 127) vul = 127;
1086 if (pChn->nLeftVU > 127) pChn->nLeftVU = (BYTE)vul;
1087 vul >>= 1;
1088 if (pChn->nLeftVU < vul) pChn->nLeftVU = (BYTE)vul;
1089 UINT vur = (pChn->nRealVolume * (256-pChn->nRealPan)) >> 14;
1090 if (vur > 127) vur = 127;
1091 if (pChn->nRightVU > 127) pChn->nRightVU = (BYTE)vur;
1092 vur >>= 1;
1093 if (pChn->nRightVU < vur) pChn->nRightVU = (BYTE)vur;
1094#endif
1095#ifdef MODPLUG_TRACKER
1096 UINT kChnMasterVol = (pChn->dwFlags & CHN_EXTRALOUD) ? 0x100 : nMasterVol;
1097#else
1098 #define kChnMasterVolnMasterVol
1099#endif // MODPLUG_TRACKER
1100 // Adjusting volumes
1101 if (gnChannels >= 2)
1102 {
1103 int pan = ((int)pChn->nRealPan) - 128;
1104 pan *= (int)m_nStereoSeparation;
1105 pan /= 128;
1106 pan += 128;
1107
1108 if (pan < 0) pan = 0;
1109 if (pan > 256) pan = 256;
1110#ifndef FASTSOUNDLIB
1111 if (gdwSoundSetup & SNDMIX_REVERSESTEREO) pan = 256 - pan;
1112#endif
1113 LONG realvol = (pChn->nRealVolume * kChnMasterVol) >> (8-1);
1114 if (gdwSoundSetup & SNDMIX_SOFTPANNING)
1115 {
1116 if (pan < 128)
1117 {
1118 pChn->nNewLeftVol = (realvol * pan) >> 8;
1119 pChn->nNewRightVol = (realvol * 128) >> 8;
1120 } else
1121 {
1122 pChn->nNewLeftVol = (realvol * 128) >> 8;
1123 pChn->nNewRightVol = (realvol * (256 - pan)) >> 8;
1124 }
1125 } else
1126 {
1127 pChn->nNewLeftVol = (realvol * pan) >> 8;
1128 pChn->nNewRightVol = (realvol * (256 - pan)) >> 8;
1129 }
1130 } else
1131 {
1132 pChn->nNewRightVol = (pChn->nRealVolume * kChnMasterVol) >> 8;
1133 pChn->nNewLeftVol = pChn->nNewRightVol;
1134 }
1135 // Clipping volumes
1136 if (pChn->nNewRightVol > 0xFFFF) pChn->nNewRightVol = 0xFFFF;
1137 if (pChn->nNewLeftVol > 0xFFFF) pChn->nNewLeftVol = 0xFFFF;
1138 // Check IDO
1139 if (gdwSoundSetup & SNDMIX_NORESAMPLING)
1140 {
1141 pChn->dwFlags |= CHN_NOIDO;
1142 } else
1143 {
1144 pChn->dwFlags &= ~(CHN_NOIDO|CHN_HQSRC);
1145 if( pChn->nInc == 0x10000 )
1146 {pChn->dwFlags |= CHN_NOIDO;
1147 }
1148 else
1149 {if( ((gdwSoundSetup & SNDMIX_HQRESAMPLER) == 0) && ((gdwSoundSetup & SNDMIX_ULTRAHQSRCMODE) == 0) )
1150 {if (pChn->nInc >= 0xFF00) pChn->dwFlags |= CHN_NOIDO;
1151 }
1152 }
1153 }
1154 pChn->nNewRightVol >>= MIXING_ATTENUATION;
1155 pChn->nNewLeftVol >>= MIXING_ATTENUATION;
1156 pChn->nRightRamp = pChn->nLeftRamp = 0;
1157 // Dolby Pro-Logic Surround
1158 if ((pChn->dwFlags & CHN_SURROUND) && (gnChannels <= 2)) pChn->nNewLeftVol = - pChn->nNewLeftVol;
1159 // Checking Ping-Pong Loops
1160 if (pChn->dwFlags & CHN_PINGPONGFLAG) pChn->nInc = -pChn->nInc;
1161 // Setting up volume ramp
1162 if ((pChn->dwFlags & CHN_VOLUMERAMP)
1163 && ((pChn->nRightVol != pChn->nNewRightVol)
1164 || (pChn->nLeftVol != pChn->nNewLeftVol)))
1165 {
1166 LONG nRampLength = gnVolumeRampSamples;
1167 LONG nRightDelta = ((pChn->nNewRightVol - pChn->nRightVol) << VOLUMERAMPPRECISION);
1168 LONG nLeftDelta = ((pChn->nNewLeftVol - pChn->nLeftVol) << VOLUMERAMPPRECISION);
1169#ifndef FASTSOUNDLIB
1170 if ((gdwSoundSetup & SNDMIX_DIRECTTODISK)
1171 || ((gdwSysInfo & (SYSMIX_ENABLEMMX|SYSMIX_FASTCPU))
1172 && (gdwSoundSetup & SNDMIX_HQRESAMPLER) && (gnCPUUsage <= 20)))
1173 {
1174 if ((pChn->nRightVol|pChn->nLeftVol) && (pChn->nNewRightVol|pChn->nNewLeftVol) && (!(pChn->dwFlags & CHN_FASTVOLRAMP)))
1175 {
1176 nRampLength = m_nBufferCount;
1177 if (nRampLength > (1 << (VOLUMERAMPPRECISION-1))) nRampLength = (1 << (VOLUMERAMPPRECISION-1));
1178 if (nRampLength < (LONG)gnVolumeRampSamples) nRampLength = gnVolumeRampSamples;
1179 }
1180 }
1181#endif
1182 pChn->nRightRamp = nRightDelta / nRampLength;
1183 pChn->nLeftRamp = nLeftDelta / nRampLength;
1184 pChn->nRightVol = pChn->nNewRightVol - ((pChn->nRightRamp * nRampLength) >> VOLUMERAMPPRECISION);
1185 pChn->nLeftVol = pChn->nNewLeftVol - ((pChn->nLeftRamp * nRampLength) >> VOLUMERAMPPRECISION);
1186 if (pChn->nRightRamp|pChn->nLeftRamp)
1187 {
1188 pChn->nRampLength = nRampLength;
1189 } else
1190 {
1191 pChn->dwFlags &= ~CHN_VOLUMERAMP;
1192 pChn->nRightVol = pChn->nNewRightVol;
1193 pChn->nLeftVol = pChn->nNewLeftVol;
1194 }
1195 } else
1196 {
1197 pChn->dwFlags &= ~CHN_VOLUMERAMP;
1198 pChn->nRightVol = pChn->nNewRightVol;
1199 pChn->nLeftVol = pChn->nNewLeftVol;
1200 }
1201 pChn->nRampRightVol = pChn->nRightVol << VOLUMERAMPPRECISION;
1202 pChn->nRampLeftVol = pChn->nLeftVol << VOLUMERAMPPRECISION;
1203 // Adding the channel in the channel list
1204 ChnMix[m_nMixChannels++] = nChn;
1205 if (m_nMixChannels >= MAX_CHANNELS) break;
1206 } else
1207 {
1208#ifdef ENABLE_STEREOVU
1209 // Note change but no sample
1210 if (pChn->nLeftVU > 128) pChn->nLeftVU = 0;
1211 if (pChn->nRightVU > 128) pChn->nRightVU = 0;
1212#endif
1213 if (pChn->nVUMeter > 0xFF) pChn->nVUMeter = 0;
1214 pChn->nLeftVol = pChn->nRightVol = 0;
1215 pChn->nLength = 0;
1216 }
1217 }
1218 // Checking Max Mix Channels reached: ordering by volume
1219 if ((m_nMixChannels >= m_nMaxMixChannels) && (!(gdwSoundSetup & SNDMIX_DIRECTTODISK)))
1220 {
1221 for (UINT i=0; i<m_nMixChannels; i++)
1222 {
1223 UINT j=i;
1224 while ((j+1<m_nMixChannels) && (Chn[ChnMix[j]].nRealVolume < Chn[ChnMix[j+1]].nRealVolume))
1225 {
1226 UINT n = ChnMix[j];
1227 ChnMix[j] = ChnMix[j+1];
1228 ChnMix[j+1] = n;
1229 j++;
1230 }
1231 }
1232 }
1233 if (m_dwSongFlags & SONG_GLOBALFADE)
1234 {
1235 if (!m_nGlobalFadeSamples)
1236 {
1237 m_dwSongFlags |= SONG_ENDREACHED;
1238 return FALSE;
1239 }
1240 if (m_nGlobalFadeSamples > m_nBufferCount)
1241 m_nGlobalFadeSamples -= m_nBufferCount;
1242 else
1243 m_nGlobalFadeSamples = 0;
1244 }
1245 return TRUE;
1246}
1247
1248
diff --git a/core/multimedia/opieplayer/modplug/stdafx.h b/core/multimedia/opieplayer/modplug/stdafx.h
new file mode 100644
index 0000000..774eefb
--- a/dev/null
+++ b/core/multimedia/opieplayer/modplug/stdafx.h
@@ -0,0 +1,107 @@
1/*
2 * This program is free software; you can redistribute it and modify it
3 * under the terms of the GNU General Public License as published by the
4 * Free Software Foundation; either version 2 of the license or (at your
5 * option) any later version.
6 *
7 * Authors: Rani Assaf <rani@magic.metawire.com>,
8 * Olivier Lapicque <olivierl@jps.net>,
9 * Adam Goode <adam@evdebs.org> (endian and char fixes for PPC)
10*/
11
12#ifndef _STDAFX_H_
13#define _STDAFX_H_
14
15#include <qglobal.h> // for Q_PACKED
16
17#ifdef WIN32
18
19#pragma warning (disable:4201)
20#pragma warning (disable:4514)
21#include <windows.h>
22#include <windowsx.h>
23#include <mmsystem.h>
24#include <stdio.h>
25
26inline void ProcessPlugins(int n) {}
27
28#else
29#include <stdlib.h>
30#include <stdio.h>
31#include <string.h>
32
33typedef signed char CHAR;
34typedef unsigned char UCHAR;
35typedef unsigned char* PUCHAR;
36typedef unsigned short USHORT;
37typedef unsigned long ULONG;
38typedef unsigned long UINT;
39typedef unsigned long DWORD;
40typedef long LONG;
41typedef unsigned short WORD;
42typedef unsigned char BYTE;
43typedef unsigned char * LPBYTE;
44typedef bool BOOL;
45typedef char * LPSTR;
46typedef void * LPVOID;
47typedef long * LPLONG;
48typedef unsigned long * LPDWORD;
49typedef unsigned short * LPWORD;
50typedef const char * LPCSTR;
51typedef long long LONGLONG;
52typedef void * PVOID;
53
54
55inline LONG MulDiv (long a, long b, long c)
56{
57 // if (!c) return 0;
58 return ((unsigned long long) a * (unsigned long long) b ) / c;
59}
60
61#ifdef __GNUG__
62#define __cdecl
63#define VOID void
64#define MODPLUG_NO_FILESAVE
65#define __declspec(BLAH)
66#define NO_AGC
67#define LPCTSTR LPCSTR
68#define lstrcpyn strncpy
69#define lstrcpy strcpy
70#define lstrcmp strcmp
71#define WAVE_FORMAT_PCM 1
72//#define ENABLE_EQ
73#endif
74
75#define GHND 0
76
77inline signed char * GlobalAllocPtr(unsigned int, size_t size)
78{
79 signed char * p = (signed char *) malloc(size);
80
81 if (p != NULL) memset(p, 0, size);
82 return p;
83}
84
85inline void ProcessPlugins(int ) {}
86
87#define GlobalFreePtr(p) free((void *)(p))
88
89#ifndef strnicmp
90 #define strnicmp(a,b,c) strncasecmp(a,b,c)
91#endif
92 #define wsprintf sprintf
93
94#ifndef FALSE
95 #define FALSEfalse
96#endif
97
98#ifndef TRUE
99 #define TRUEtrue
100#endif
101
102#endif // WIN32
103
104#endif
105
106
107
diff --git a/core/multimedia/opieplayer/modplug/tables.cpp b/core/multimedia/opieplayer/modplug/tables.cpp
new file mode 100644
index 0000000..e7198b2
--- a/dev/null
+++ b/core/multimedia/opieplayer/modplug/tables.cpp
@@ -0,0 +1,399 @@
1/*
2 * This program is free software; you can redistribute it and modify it
3 * under the terms of the GNU General Public License as published by the
4 * Free Software Foundation; either version 2 of the license or (at your
5 * option) any later version.
6 *
7 * Authors: Olivier Lapicque <olivierl@jps.net>
8*/
9
10#include "stdafx.h"
11#include "sndfile.h"
12
13#ifndef FASTSOUNDLIB
14//#pragma data_seg(".tables")
15#endif
16
17extern const BYTE ImpulseTrackerPortaVolCmd[16];
18const BYTE ImpulseTrackerPortaVolCmd[16] =
19{
20 0x00, 0x01, 0x04, 0x08, 0x10, 0x20, 0x40, 0x60,
21 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
22};
23
24// Period table for Protracker octaves 0-5:
25extern const WORD ProTrackerPeriodTable[6*12];
26const WORD ProTrackerPeriodTable[6*12] =
27{
28 1712,1616,1524,1440,1356,1280,1208,1140,1076,1016,960,907,
29 856,808,762,720,678,640,604,570,538,508,480,453,
30 428,404,381,360,339,320,302,285,269,254,240,226,
31 214,202,190,180,170,160,151,143,135,127,120,113,
32 107,101,95,90,85,80,75,71,67,63,60,56,
33 53,50,47,45,42,40,37,35,33,31,30,28
34};
35
36
37extern const WORD ProTrackerTunedPeriods[16*12];
38const WORD ProTrackerTunedPeriods[16*12] =
39{
40 1712,1616,1524,1440,1356,1280,1208,1140,1076,1016,960,907,
41 1700,1604,1514,1430,1348,1274,1202,1134,1070,1010,954,900,
42 1688,1592,1504,1418,1340,1264,1194,1126,1064,1004,948,894,
43 1676,1582,1492,1408,1330,1256,1184,1118,1056,996,940,888,
44 1664,1570,1482,1398,1320,1246,1176,1110,1048,990,934,882,
45 1652,1558,1472,1388,1310,1238,1168,1102,1040,982,926,874,
46 1640,1548,1460,1378,1302,1228,1160,1094,1032,974,920,868,
47 1628,1536,1450,1368,1292,1220,1150,1086,1026,968,914,862,
48 1814,1712,1616,1524,1440,1356,1280,1208,1140,1076,1016,960,
49 1800,1700,1604,1514,1430,1350,1272,1202,1134,1070,1010,954,
50 1788,1688,1592,1504,1418,1340,1264,1194,1126,1064,1004,948,
51 1774,1676,1582,1492,1408,1330,1256,1184,1118,1056,996,940,
52 1762,1664,1570,1482,1398,1320,1246,1176,1110,1048,988,934,
53 1750,1652,1558,1472,1388,1310,1238,1168,1102,1040,982,926,
54 1736,1640,1548,1460,1378,1302,1228,1160,1094,1032,974,920,
55 1724,1628,1536,1450,1368,1292,1220,1150,1086,1026,968,914
56};
57
58
59// S3M C-4 periods
60extern const WORD FreqS3MTable[16];
61const WORD FreqS3MTable[16] =
62{
63 1712,1616,1524,1440,1356,1280,
64 1208,1140,1076,1016,960,907,
65 0,0,0,0
66};
67
68
69// S3M FineTune frequencies
70extern const WORD S3MFineTuneTable[16];
71const WORD S3MFineTuneTable[16] =
72{
73 7895,7941,7985,8046,8107,8169,8232,8280,
74 8363,8413,8463,8529,8581,8651,8723,8757,// 8363*2^((i-8)/(12*8))
75};
76
77
78// Sinus table
79extern const short int ModSinusTable[64];
80const short int ModSinusTable[64] =
81{
82 0,12,25,37,49,60,71,81,90,98,106,112,117,122,125,126,
83 127,126,125,122,117,112,106,98,90,81,71,60,49,37,25,12,
84 0,-12,-25,-37,-49,-60,-71,-81,-90,-98,-106,-112,-117,-122,-125,-126,
85 -127,-126,-125,-122,-117,-112,-106,-98,-90,-81,-71,-60,-49,-37,-25,-12
86};
87
88// Triangle wave table (ramp down)
89extern const short int ModRampDownTable[64];
90const short int ModRampDownTable[64] =
91{
92 0,-4,-8,-12,-16,-20,-24,-28,-32,-36,-40,-44,-48,-52,-56,-60,
93 -64,-68,-72,-76,-80,-84,-88,-92,-96,-100,-104,-108,-112,-116,-120,-124,
94 127,123,119,115,111,107,103,99,95,91,87,83,79,75,71,67,
95 63,59,55,51,47,43,39,35,31,27,23,19,15,11,7,3
96};
97
98// Square wave table
99extern const short int ModSquareTable[64];
100const short int ModSquareTable[64] =
101{
102 127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,
103 127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,
104 -127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,
105 -127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127
106};
107
108// Random wave table
109extern const short int ModRandomTable[64];
110const short int ModRandomTable[64] =
111{
112 98,-127,-43,88,102,41,-65,-94,125,20,-71,-86,-70,-32,-16,-96,
113 17,72,107,-5,116,-69,-62,-40,10,-61,65,109,-18,-38,-13,-76,
114 -23,88,21,-94,8,106,21,-112,6,109,20,-88,-30,9,-127,118,
115 42,-34,89,-4,-51,-72,21,-29,112,123,84,-101,-92,98,-54,-95
116};
117
118
119// volume fade tables for Retrig Note:
120extern const signed char retrigTable1[16];
121const signed char retrigTable1[16] =
122{ 0, 0, 0, 0, 0, 0, 10, 8, 0, 0, 0, 0, 0, 0, 24, 32 };
123
124extern const signed char retrigTable2[16];
125const signed char retrigTable2[16] =
126{ 0, -1, -2, -4, -8, -16, 0, 0, 0, 1, 2, 4, 8, 16, 0, 0 };
127
128
129
130
131extern const WORD XMPeriodTable[104];
132const WORD XMPeriodTable[104] =
133{
134 907,900,894,887,881,875,868,862,856,850,844,838,832,826,820,814,
135 808,802,796,791,785,779,774,768,762,757,752,746,741,736,730,725,
136 720,715,709,704,699,694,689,684,678,675,670,665,660,655,651,646,
137 640,636,632,628,623,619,614,610,604,601,597,592,588,584,580,575,
138 570,567,563,559,555,551,547,543,538,535,532,528,524,520,516,513,
139 508,505,502,498,494,491,487,484,480,477,474,470,467,463,460,457,
140 453,450,447,443,440,437,434,431
141};
142
143
144extern const UINT XMLinearTable[768];
145const UINT XMLinearTable[768] =
146{
147 535232,534749,534266,533784,533303,532822,532341,531861,
148 531381,530902,530423,529944,529466,528988,528511,528034,
149 527558,527082,526607,526131,525657,525183,524709,524236,
150 523763,523290,522818,522346,521875,521404,520934,520464,
151 519994,519525,519057,518588,518121,517653,517186,516720,
152 516253,515788,515322,514858,514393,513929,513465,513002,
153 512539,512077,511615,511154,510692,510232,509771,509312,
154 508852,508393,507934,507476,507018,506561,506104,505647,
155 505191,504735,504280,503825,503371,502917,502463,502010,
156 501557,501104,500652,500201,499749,499298,498848,498398,
157 497948,497499,497050,496602,496154,495706,495259,494812,
158 494366,493920,493474,493029,492585,492140,491696,491253,
159 490809,490367,489924,489482,489041,488600,488159,487718,
160 487278,486839,486400,485961,485522,485084,484647,484210,
161 483773,483336,482900,482465,482029,481595,481160,480726,
162 480292,479859,479426,478994,478562,478130,477699,477268,
163 476837,476407,475977,475548,475119,474690,474262,473834,
164 473407,472979,472553,472126,471701,471275,470850,470425,
165 470001,469577,469153,468730,468307,467884,467462,467041,
166 466619,466198,465778,465358,464938,464518,464099,463681,
167 463262,462844,462427,462010,461593,461177,460760,460345,
168 459930,459515,459100,458686,458272,457859,457446,457033,
169 456621,456209,455797,455386,454975,454565,454155,453745,
170 453336,452927,452518,452110,451702,451294,450887,450481,
171 450074,449668,449262,448857,448452,448048,447644,447240,
172 446836,446433,446030,445628,445226,444824,444423,444022,
173 443622,443221,442821,442422,442023,441624,441226,440828,
174 440430,440033,439636,439239,438843,438447,438051,437656,
175 437261,436867,436473,436079,435686,435293,434900,434508,
176 434116,433724,433333,432942,432551,432161,431771,431382,
177 430992,430604,430215,429827,429439,429052,428665,428278,
178 427892,427506,427120,426735,426350,425965,425581,425197,
179 424813,424430,424047,423665,423283,422901,422519,422138,
180 421757,421377,420997,420617,420237,419858,419479,419101,
181 418723,418345,417968,417591,417214,416838,416462,416086,
182 415711,415336,414961,414586,414212,413839,413465,413092,
183 412720,412347,411975,411604,411232,410862,410491,410121,
184 409751,409381,409012,408643,408274,407906,407538,407170,
185 406803,406436,406069,405703,405337,404971,404606,404241,
186 403876,403512,403148,402784,402421,402058,401695,401333,
187 400970,400609,400247,399886,399525,399165,398805,398445,
188 398086,397727,397368,397009,396651,396293,395936,395579,
189 395222,394865,394509,394153,393798,393442,393087,392733,
190 392378,392024,391671,391317,390964,390612,390259,389907,
191 389556,389204,388853,388502,388152,387802,387452,387102,
192 386753,386404,386056,385707,385359,385012,384664,384317,
193 383971,383624,383278,382932,382587,382242,381897,381552,
194 381208,380864,380521,380177,379834,379492,379149,378807,
195
196 378466,378124,377783,377442,377102,376762,376422,376082,
197 375743,375404,375065,374727,374389,374051,373714,373377,
198 373040,372703,372367,372031,371695,371360,371025,370690,
199 370356,370022,369688,369355,369021,368688,368356,368023,
200 367691,367360,367028,366697,366366,366036,365706,365376,
201 365046,364717,364388,364059,363731,363403,363075,362747,
202 362420,362093,361766,361440,361114,360788,360463,360137,
203 359813,359488,359164,358840,358516,358193,357869,357547,
204 357224,356902,356580,356258,355937,355616,355295,354974,
205 354654,354334,354014,353695,353376,353057,352739,352420,
206 352103,351785,351468,351150,350834,350517,350201,349885,
207 349569,349254,348939,348624,348310,347995,347682,347368,
208 347055,346741,346429,346116,345804,345492,345180,344869,
209 344558,344247,343936,343626,343316,343006,342697,342388,
210 342079,341770,341462,341154,340846,340539,340231,339924,
211 339618,339311,339005,338700,338394,338089,337784,337479,
212 337175,336870,336566,336263,335959,335656,335354,335051,
213 334749,334447,334145,333844,333542,333242,332941,332641,
214 332341,332041,331741,331442,331143,330844,330546,330247,
215 329950,329652,329355,329057,328761,328464,328168,327872,
216 327576,327280,326985,326690,326395,326101,325807,325513,
217 325219,324926,324633,324340,324047,323755,323463,323171,
218 322879,322588,322297,322006,321716,321426,321136,320846,
219 320557,320267,319978,319690,319401,319113,318825,318538,
220 318250,317963,317676,317390,317103,316817,316532,316246,
221 315961,315676,315391,315106,314822,314538,314254,313971,
222 313688,313405,313122,312839,312557,312275,311994,311712,
223 311431,311150,310869,310589,310309,310029,309749,309470,
224 309190,308911,308633,308354,308076,307798,307521,307243,
225 306966,306689,306412,306136,305860,305584,305308,305033,
226 304758,304483,304208,303934,303659,303385,303112,302838,
227 302565,302292,302019,301747,301475,301203,300931,300660,
228 300388,300117,299847,299576,299306,299036,298766,298497,
229 298227,297958,297689,297421,297153,296884,296617,296349,
230 296082,295815,295548,295281,295015,294749,294483,294217,
231 293952,293686,293421,293157,292892,292628,292364,292100,
232 291837,291574,291311,291048,290785,290523,290261,289999,
233 289737,289476,289215,288954,288693,288433,288173,287913,
234 287653,287393,287134,286875,286616,286358,286099,285841,
235 285583,285326,285068,284811,284554,284298,284041,283785,
236 283529,283273,283017,282762,282507,282252,281998,281743,
237 281489,281235,280981,280728,280475,280222,279969,279716,
238 279464,279212,278960,278708,278457,278206,277955,277704,
239 277453,277203,276953,276703,276453,276204,275955,275706,
240 275457,275209,274960,274712,274465,274217,273970,273722,
241 273476,273229,272982,272736,272490,272244,271999,271753,
242 271508,271263,271018,270774,270530,270286,270042,269798,
243 269555,269312,269069,268826,268583,268341,268099,267857
244};
245
246
247extern const signed char ft2VibratoTable[256];
248const signed char ft2VibratoTable[256] =
249{
250 0,-2,-3,-5,-6,-8,-9,-11,-12,-14,-16,-17,-19,-20,-22,-23,
251 -24,-26,-27,-29,-30,-32,-33,-34,-36,-37,-38,-39,-41,-42,
252 -43,-44,-45,-46,-47,-48,-49,-50,-51,-52,-53,-54,-55,-56,
253 -56,-57,-58,-59,-59,-60,-60,-61,-61,-62,-62,-62,-63,-63,
254 -63,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-63,-63,
255 -63,-62,-62,-62,-61,-61,-60,-60,-59,-59,-58,-57,-56,-56,
256 -55,-54,-53,-52,-51,-50,-49,-48,-47,-46,-45,-44,-43,-42,
257 -41,-39,-38,-37,-36,-34,-33,-32,-30,-29,-27,-26,-24,-23,
258 -22,-20,-19,-17,-16,-14,-12,-11,-9,-8,-6,-5,-3,-2,0,
259 2,3,5,6,8,9,11,12,14,16,17,19,20,22,23,24,26,27,29,30,
260 32,33,34,36,37,38,39,41,42,43,44,45,46,47,48,49,50,51,
261 52,53,54,55,56,56,57,58,59,59,60,60,61,61,62,62,62,63,
262 63,63,64,64,64,64,64,64,64,64,64,64,64,63,63,63,62,62,
263 62,61,61,60,60,59,59,58,57,56,56,55,54,53,52,51,50,49,
264 48,47,46,45,44,43,42,41,39,38,37,36,34,33,32,30,29,27,
265 26,24,23,22,20,19,17,16,14,12,11,9,8,6,5,3,2
266};
267
268
269
270extern const DWORD FineLinearSlideUpTable[16];
271const DWORD FineLinearSlideUpTable[16] =
272{
273 65536, 65595, 65654, 65714,65773, 65832, 65892, 65951,
274 66011, 66071, 66130, 66190, 66250, 66309, 66369, 66429
275};
276
277
278extern const DWORD FineLinearSlideDownTable[16];
279const DWORD FineLinearSlideDownTable[16] =
280{
281 65535, 65477, 65418, 65359, 65300, 65241, 65182, 65123,
282 65065, 65006, 64947, 64888, 64830, 64772, 64713, 64645
283};
284
285
286extern const DWORD LinearSlideUpTable[256];
287const DWORD LinearSlideUpTable[256] =
288{
289 65536, 65773, 66010, 66249, 66489, 66729, 66971, 67213,
290 67456, 67700, 67945, 68190, 68437, 68685, 68933, 69182,
291 69432, 69684, 69936, 70189, 70442, 70697, 70953, 71209,
292 71467, 71725, 71985, 72245, 72507, 72769, 73032, 73296,
293 73561, 73827, 74094, 74362, 74631, 74901, 75172, 75444,
294 75717, 75991, 76265, 76541, 76818, 77096, 77375, 77655,
295 77935, 78217, 78500, 78784, 79069, 79355, 79642, 79930,
296 80219, 80509, 80800, 81093, 81386, 81680, 81976, 82272,
297 82570, 82868, 83168, 83469, 83771, 84074, 84378, 84683,
298 84989, 85297, 85605, 85915, 86225, 86537, 86850, 87164,
299 87480, 87796, 88113, 88432, 88752, 89073, 89395, 89718,
300 90043, 90369, 90695, 91023, 91353, 91683, 92015, 92347,
301 92681, 93017, 93353, 93691, 94029, 94370, 94711, 95053,
302 95397, 95742, 96088, 96436, 96785, 97135, 97486, 97839,
303 98193, 98548, 98904, 99262, 99621, 99981, 100343, 100706,
304 101070, 101435, 101802, 102170, 102540, 102911, 103283, 103657,
305 104031, 104408, 104785, 105164, 105545, 105926, 106309, 106694,
306 107080, 107467, 107856, 108246, 108637, 109030, 109425, 109820,
307 110217, 110616, 111016, 111418, 111821, 112225, 112631, 113038,
308 113447, 113857, 114269, 114682, 115097, 115514, 115931, 116351,
309 116771, 117194, 117618, 118043, 118470, 118898, 119328, 119760,
310 120193, 120628, 121064, 121502, 121941, 122382, 122825, 123269,
311 123715, 124162, 124611, 125062, 125514, 125968, 126424, 126881,
312 127340, 127801, 128263, 128727, 129192, 129660, 130129, 130599,
313 131072, 131546, 132021, 132499, 132978, 133459, 133942, 134426,
314 134912, 135400, 135890, 136381, 136875, 137370, 137866, 138365,
315 138865, 139368, 139872, 140378, 140885, 141395, 141906, 142419,
316 142935, 143451, 143970, 144491, 145014, 145538, 146064, 146593,
317 147123, 147655, 148189, 148725, 149263, 149803, 150344, 150888,
318 151434, 151982, 152531, 153083, 153637, 154192, 154750, 155310,
319 155871, 156435, 157001, 157569, 158138, 158710, 159284, 159860,
320 160439, 161019, 161601, 162186, 162772, 163361, 163952, 164545,
321};
322
323
324extern const DWORD LinearSlideDownTable[256];
325const DWORD LinearSlideDownTable[256] =
326{
327 65536, 65299, 65064, 64830, 64596, 64363, 64131, 63900,
328 63670, 63440, 63212, 62984, 62757, 62531, 62305, 62081,
329 61857, 61634, 61412, 61191, 60970, 60751, 60532, 60314,
330 60096, 59880, 59664, 59449, 59235, 59021, 58809, 58597,
331 58385, 58175, 57965, 57757, 57548, 57341, 57134, 56928,
332 56723, 56519, 56315, 56112, 55910, 55709, 55508, 55308,
333 55108, 54910, 54712, 54515, 54318, 54123, 53928, 53733,
334
335 53540, 53347, 53154, 52963, 52772, 52582, 52392, 52204,
336 52015, 51828, 51641, 51455, 51270, 51085, 50901, 50717,
337 50535, 50353, 50171, 49990, 49810, 49631, 49452, 49274,
338 49096, 48919, 48743, 48567, 48392, 48218, 48044, 47871,
339 47698, 47526, 47355, 47185, 47014, 46845, 46676, 46508,
340 46340, 46173, 46007, 45841, 45676, 45511, 45347, 45184,
341 45021, 44859, 44697, 44536, 44376, 44216, 44056, 43898,
342 43740, 43582, 43425, 43268, 43112, 42957, 42802, 42648,
343 42494, 42341, 42189, 42037, 41885, 41734, 41584, 41434,
344 41285, 41136, 40988, 40840, 40693, 40546, 40400, 40254,
345 40109, 39965, 39821, 39677, 39534, 39392, 39250, 39108,
346 38967, 38827, 38687, 38548, 38409, 38270, 38132, 37995,
347 37858, 37722, 37586, 37450, 37315, 37181, 37047, 36913,
348 36780, 36648, 36516, 36384, 36253, 36122, 35992, 35862,
349 35733, 35604, 35476, 35348, 35221, 35094, 34968, 34842,
350 34716, 34591, 34466, 34342, 34218, 34095, 33972, 33850,
351 33728, 33606, 33485, 33364, 33244, 33124, 33005, 32886,
352 32768, 32649, 32532, 32415, 32298, 32181, 32065, 31950,
353 31835, 31720, 31606, 31492, 31378, 31265, 31152, 31040,
354 30928, 30817, 30706, 30595, 30485, 30375, 30266, 30157,
355 30048, 29940, 29832, 29724, 29617, 29510, 29404, 29298,
356 29192, 29087, 28982, 28878, 28774, 28670, 28567, 28464,
357 28361, 28259, 28157, 28056, 27955, 27854, 27754, 27654,
358 27554, 27455, 27356, 27257, 27159, 27061, 26964, 26866,
359 26770, 26673, 26577, 26481, 26386, 26291, 26196, 26102,
360};
361
362
363extern const int SpectrumSinusTable[256*2];
364const int SpectrumSinusTable[256*2] =
365{
366 0, 1, 1, 2, 3, 3, 4, 5, 6, 7, 7, 8, 9, 10, 10, 11,
367 12, 13, 14, 14, 15, 16, 17, 17, 18, 19, 20, 20, 21, 22, 22, 23,
368 24, 25, 25, 26, 27, 28, 28, 29, 30, 30, 31, 32, 32, 33, 34, 34,
369 35, 36, 36, 37, 38, 38, 39, 39, 40, 41, 41, 42, 42, 43, 44, 44,
370 45, 45, 46, 46, 47, 47, 48, 48, 49, 49, 50, 50, 51, 51, 52, 52,
371 53, 53, 53, 54, 54, 55, 55, 55, 56, 56, 57, 57, 57, 58, 58, 58,
372 59, 59, 59, 59, 60, 60, 60, 60, 61, 61, 61, 61, 61, 62, 62, 62,
373 62, 62, 62, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
374 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 62, 62,
375 62, 62, 62, 62, 61, 61, 61, 61, 61, 60, 60, 60, 60, 59, 59, 59,
376 59, 58, 58, 58, 57, 57, 57, 56, 56, 55, 55, 55, 54, 54, 53, 53,
377 53, 52, 52, 51, 51, 50, 50, 49, 49, 48, 48, 47, 47, 46, 46, 45,
378 45, 44, 44, 43, 42, 42, 41, 41, 40, 39, 39, 38, 38, 37, 36, 36,
379 35, 34, 34, 33, 32, 32, 31, 30, 30, 29, 28, 28, 27, 26, 25, 25,
380 24, 23, 22, 22, 21, 20, 20, 19, 18, 17, 17, 16, 15, 14, 14, 13,
381 12, 11, 10, 10, 9, 8, 7, 7, 6, 5, 4, 3, 3, 2, 1, 0,
382 0, -1, -1, -2, -3, -3, -4, -5, -6, -7, -7, -8, -9, -10, -10, -11,
383 -12, -13, -14, -14, -15, -16, -17, -17, -18, -19, -20, -20, -21, -22, -22, -23,
384 -24, -25, -25, -26, -27, -28, -28, -29, -30, -30, -31, -32, -32, -33, -34, -34,
385 -35, -36, -36, -37, -38, -38, -39, -39, -40, -41, -41, -42, -42, -43, -44, -44,
386 -45, -45, -46, -46, -47, -47, -48, -48, -49, -49, -50, -50, -51, -51, -52, -52,
387 -53, -53, -53, -54, -54, -55, -55, -55, -56, -56, -57, -57, -57, -58, -58, -58,
388 -59, -59, -59, -59, -60, -60, -60, -60, -61, -61, -61, -61, -61, -62, -62, -62,
389 -62, -62, -62, -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, -63,
390 -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, -62, -62,
391 -62, -62, -62, -62, -61, -61, -61, -61, -61, -60, -60, -60, -60, -59, -59, -59,
392 -59, -58, -58, -58, -57, -57, -57, -56, -56, -55, -55, -55, -54, -54, -53, -53,
393 -53, -52, -52, -51, -51, -50, -50, -49, -49, -48, -48, -47, -47, -46, -46, -45,
394 -45, -44, -44, -43, -42, -42, -41, -41, -40, -39, -39, -38, -38, -37, -36, -36,
395 -35, -34, -34, -33, -32, -32, -31, -30, -30, -29, -28, -28, -27, -26, -25, -25,
396 -24, -23, -22, -22, -21, -20, -20, -19, -18, -17, -17, -16, -15, -14, -14, -13,
397 -12, -11, -10, -10, -9, -8, -7, -7, -6, -5, -4, -3, -3, -2, -1, 0,
398};
399