author | llornkcor <llornkcor> | 2002-07-20 22:07:31 (UTC) |
---|---|---|
committer | llornkcor <llornkcor> | 2002-07-20 22:07:31 (UTC) |
commit | 2342d48be31847e7ead9d1cc682452e8f0122351 (patch) (unidiff) | |
tree | 8329bb94e9d429c905a0ef6b881cf1c0f775bf14 | |
parent | 0f24c1fb86d3bb58d8696358b824c0e01752b10d (diff) | |
download | opie-2342d48be31847e7ead9d1cc682452e8f0122351.zip opie-2342d48be31847e7ead9d1cc682452e8f0122351.tar.gz opie-2342d48be31847e7ead9d1cc682452e8f0122351.tar.bz2 |
initial commit of modplugin
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 @@ | |||
1 | moc_* | ||
2 | Makefile | ||
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) | ||
20 | int MixSoundBuffer[MIXBUFFERSIZE*4]; | ||
21 | |||
22 | // Reverb Mix Buffer | ||
23 | #ifndef NO_REVERB | ||
24 | int MixReverbBuffer[MIXBUFFERSIZE*2]; | ||
25 | extern UINT gnReverbSend; | ||
26 | #endif | ||
27 | |||
28 | #ifndef FASTSOUNDLIB | ||
29 | int MixRearBuffer[MIXBUFFERSIZE*2]; | ||
30 | float MixFloatBuffer[MIXBUFFERSIZE*2]; | ||
31 | #endif | ||
32 | |||
33 | #ifdef WIN32 | ||
34 | #pragma bss_seg() | ||
35 | #endif | ||
36 | |||
37 | |||
38 | extern LONG gnDryROfsVol; | ||
39 | extern LONG gnDryLOfsVol; | ||
40 | extern LONG gnRvbROfsVol; | ||
41 | extern LONG gnRvbLOfsVol; | ||
42 | |||
43 | // 4x256 taps polyphase FIR resampling filter | ||
44 | extern short int gFastSinc[]; | ||
45 | extern 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 | |||
101 | class CzCUBICSPLINE | ||
102 | {public: | ||
103 | CzCUBICSPLINE( ); | ||
104 | ~CzCUBICSPLINE( ); | ||
105 | static signed short lut[4*(1L<<SPLINE_FRACBITS)]; | ||
106 | }; | ||
107 | |||
108 | signed short CzCUBICSPLINE::lut[4*(1L<<SPLINE_FRACBITS)]; | ||
109 | |||
110 | CzCUBICSPLINE::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 | |||
140 | CzCUBICSPLINE::~CzCUBICSPLINE( ) | ||
141 | {// nothing todo | ||
142 | } | ||
143 | |||
144 | CzCUBICSPLINE 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 | |||
192 | class 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 | |||
245 | signed short CzWINDOWEDFIR::lut[WFIR_LUTLEN*WFIR_WIDTH]; | ||
246 | |||
247 | CzWINDOWEDFIR::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 | |||
268 | CzWINDOWEDFIR::~CzWINDOWEDFIR() | ||
269 | {// nothing todo | ||
270 | } | ||
271 | |||
272 | CzWINDOWEDFIR 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 | |||
565 | typedef 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 | |||
659 | void MPPASMCALL X86_InitMixBuffer(int *pBuffer, UINT nSamples); | ||
660 | void MPPASMCALL X86_EndChannelOfs(MODCHANNEL *pChannel, int *pBuffer, UINT nSamples); | ||
661 | void MPPASMCALL X86_StereoFill(int *pBuffer, UINT nSamples, LPLONG lpROfs, LPLONG lpLOfs); | ||
662 | void X86_StereoMixToFloat(const int *, float *, float *, UINT nCount); | ||
663 | void X86_FloatToStereoMix(const float *pIn1, const float *pIn2, int *pOut, UINT nCount); | ||
664 | |||
665 | ///////////////////////////////////////////////////// | ||
666 | // Mono samples functions | ||
667 | |||
668 | BEGIN_MIX_INTERFACE(Mono8BitMix) | ||
669 | SNDMIX_BEGINSAMPLELOOP8 | ||
670 | SNDMIX_GETMONOVOL8NOIDO | ||
671 | SNDMIX_STOREMONOVOL | ||
672 | END_MIX_INTERFACE() | ||
673 | |||
674 | BEGIN_MIX_INTERFACE(Mono16BitMix) | ||
675 | SNDMIX_BEGINSAMPLELOOP16 | ||
676 | SNDMIX_GETMONOVOL16NOIDO | ||
677 | SNDMIX_STOREMONOVOL | ||
678 | END_MIX_INTERFACE() | ||
679 | |||
680 | BEGIN_MIX_INTERFACE(Mono8BitLinearMix) | ||
681 | SNDMIX_BEGINSAMPLELOOP8 | ||
682 | SNDMIX_GETMONOVOL8LINEAR | ||
683 | SNDMIX_STOREMONOVOL | ||
684 | END_MIX_INTERFACE() | ||
685 | |||
686 | BEGIN_MIX_INTERFACE(Mono16BitLinearMix) | ||
687 | SNDMIX_BEGINSAMPLELOOP16 | ||
688 | SNDMIX_GETMONOVOL16LINEAR | ||
689 | SNDMIX_STOREMONOVOL | ||
690 | END_MIX_INTERFACE() | ||
691 | |||
692 | BEGIN_MIX_INTERFACE(Mono8BitSplineMix) | ||
693 | SNDMIX_BEGINSAMPLELOOP8 | ||
694 | SNDMIX_GETMONOVOL8SPLINE | ||
695 | SNDMIX_STOREMONOVOL | ||
696 | END_MIX_INTERFACE() | ||
697 | |||
698 | BEGIN_MIX_INTERFACE(Mono16BitSplineMix) | ||
699 | SNDMIX_BEGINSAMPLELOOP16 | ||
700 | SNDMIX_GETMONOVOL16SPLINE | ||
701 | SNDMIX_STOREMONOVOL | ||
702 | END_MIX_INTERFACE() | ||
703 | |||
704 | BEGIN_MIX_INTERFACE(Mono8BitFirFilterMix) | ||
705 | SNDMIX_BEGINSAMPLELOOP8 | ||
706 | SNDMIX_GETMONOVOL8FIRFILTER | ||
707 | SNDMIX_STOREMONOVOL | ||
708 | END_MIX_INTERFACE() | ||
709 | |||
710 | BEGIN_MIX_INTERFACE(Mono16BitFirFilterMix) | ||
711 | SNDMIX_BEGINSAMPLELOOP16 | ||
712 | SNDMIX_GETMONOVOL16FIRFILTER | ||
713 | SNDMIX_STOREMONOVOL | ||
714 | END_MIX_INTERFACE() | ||
715 | |||
716 | |||
717 | // Volume Ramps | ||
718 | BEGIN_RAMPMIX_INTERFACE(Mono8BitRampMix) | ||
719 | SNDMIX_BEGINSAMPLELOOP8 | ||
720 | SNDMIX_GETMONOVOL8NOIDO | ||
721 | SNDMIX_RAMPMONOVOL | ||
722 | END_RAMPMIX_INTERFACE() | ||
723 | |||
724 | BEGIN_RAMPMIX_INTERFACE(Mono16BitRampMix) | ||
725 | SNDMIX_BEGINSAMPLELOOP16 | ||
726 | SNDMIX_GETMONOVOL16NOIDO | ||
727 | SNDMIX_RAMPMONOVOL | ||
728 | END_RAMPMIX_INTERFACE() | ||
729 | |||
730 | BEGIN_RAMPMIX_INTERFACE(Mono8BitLinearRampMix) | ||
731 | SNDMIX_BEGINSAMPLELOOP8 | ||
732 | SNDMIX_GETMONOVOL8LINEAR | ||
733 | SNDMIX_RAMPMONOVOL | ||
734 | END_RAMPMIX_INTERFACE() | ||
735 | |||
736 | BEGIN_RAMPMIX_INTERFACE(Mono16BitLinearRampMix) | ||
737 | SNDMIX_BEGINSAMPLELOOP16 | ||
738 | SNDMIX_GETMONOVOL16LINEAR | ||
739 | SNDMIX_RAMPMONOVOL | ||
740 | END_RAMPMIX_INTERFACE() | ||
741 | |||
742 | BEGIN_RAMPMIX_INTERFACE(Mono8BitSplineRampMix) | ||
743 | SNDMIX_BEGINSAMPLELOOP8 | ||
744 | SNDMIX_GETMONOVOL8SPLINE | ||
745 | SNDMIX_RAMPMONOVOL | ||
746 | END_RAMPMIX_INTERFACE() | ||
747 | |||
748 | BEGIN_RAMPMIX_INTERFACE(Mono16BitSplineRampMix) | ||
749 | SNDMIX_BEGINSAMPLELOOP16 | ||
750 | SNDMIX_GETMONOVOL16SPLINE | ||
751 | SNDMIX_RAMPMONOVOL | ||
752 | END_RAMPMIX_INTERFACE() | ||
753 | |||
754 | BEGIN_RAMPMIX_INTERFACE(Mono8BitFirFilterRampMix) | ||
755 | SNDMIX_BEGINSAMPLELOOP8 | ||
756 | SNDMIX_GETMONOVOL8FIRFILTER | ||
757 | SNDMIX_RAMPMONOVOL | ||
758 | END_RAMPMIX_INTERFACE() | ||
759 | |||
760 | BEGIN_RAMPMIX_INTERFACE(Mono16BitFirFilterRampMix) | ||
761 | SNDMIX_BEGINSAMPLELOOP16 | ||
762 | SNDMIX_GETMONOVOL16FIRFILTER | ||
763 | SNDMIX_RAMPMONOVOL | ||
764 | END_RAMPMIX_INTERFACE() | ||
765 | |||
766 | |||
767 | ////////////////////////////////////////////////////// | ||
768 | // Fast mono mix for leftvol=rightvol (1 less imul) | ||
769 | |||
770 | BEGIN_MIX_INTERFACE(FastMono8BitMix) | ||
771 | SNDMIX_BEGINSAMPLELOOP8 | ||
772 | SNDMIX_GETMONOVOL8NOIDO | ||
773 | SNDMIX_STOREFASTMONOVOL | ||
774 | END_MIX_INTERFACE() | ||
775 | |||
776 | BEGIN_MIX_INTERFACE(FastMono16BitMix) | ||
777 | SNDMIX_BEGINSAMPLELOOP16 | ||
778 | SNDMIX_GETMONOVOL16NOIDO | ||
779 | SNDMIX_STOREFASTMONOVOL | ||
780 | END_MIX_INTERFACE() | ||
781 | |||
782 | BEGIN_MIX_INTERFACE(FastMono8BitLinearMix) | ||
783 | SNDMIX_BEGINSAMPLELOOP8 | ||
784 | SNDMIX_GETMONOVOL8LINEAR | ||
785 | SNDMIX_STOREFASTMONOVOL | ||
786 | END_MIX_INTERFACE() | ||
787 | |||
788 | BEGIN_MIX_INTERFACE(FastMono16BitLinearMix) | ||
789 | SNDMIX_BEGINSAMPLELOOP16 | ||
790 | SNDMIX_GETMONOVOL16LINEAR | ||
791 | SNDMIX_STOREFASTMONOVOL | ||
792 | END_MIX_INTERFACE() | ||
793 | |||
794 | BEGIN_MIX_INTERFACE(FastMono8BitSplineMix) | ||
795 | SNDMIX_BEGINSAMPLELOOP8 | ||
796 | SNDMIX_GETMONOVOL8SPLINE | ||
797 | SNDMIX_STOREFASTMONOVOL | ||
798 | END_MIX_INTERFACE() | ||
799 | |||
800 | BEGIN_MIX_INTERFACE(FastMono16BitSplineMix) | ||
801 | SNDMIX_BEGINSAMPLELOOP16 | ||
802 | SNDMIX_GETMONOVOL16SPLINE | ||
803 | SNDMIX_STOREFASTMONOVOL | ||
804 | END_MIX_INTERFACE() | ||
805 | |||
806 | BEGIN_MIX_INTERFACE(FastMono8BitFirFilterMix) | ||
807 | SNDMIX_BEGINSAMPLELOOP8 | ||
808 | SNDMIX_GETMONOVOL8FIRFILTER | ||
809 | SNDMIX_STOREFASTMONOVOL | ||
810 | END_MIX_INTERFACE() | ||
811 | |||
812 | BEGIN_MIX_INTERFACE(FastMono16BitFirFilterMix) | ||
813 | SNDMIX_BEGINSAMPLELOOP16 | ||
814 | SNDMIX_GETMONOVOL16FIRFILTER | ||
815 | SNDMIX_STOREFASTMONOVOL | ||
816 | END_MIX_INTERFACE() | ||
817 | |||
818 | |||
819 | // Fast Ramps | ||
820 | BEGIN_FASTRAMPMIX_INTERFACE(FastMono8BitRampMix) | ||
821 | SNDMIX_BEGINSAMPLELOOP8 | ||
822 | SNDMIX_GETMONOVOL8NOIDO | ||
823 | SNDMIX_RAMPFASTMONOVOL | ||
824 | END_FASTRAMPMIX_INTERFACE() | ||
825 | |||
826 | BEGIN_FASTRAMPMIX_INTERFACE(FastMono16BitRampMix) | ||
827 | SNDMIX_BEGINSAMPLELOOP16 | ||
828 | SNDMIX_GETMONOVOL16NOIDO | ||
829 | SNDMIX_RAMPFASTMONOVOL | ||
830 | END_FASTRAMPMIX_INTERFACE() | ||
831 | |||
832 | BEGIN_FASTRAMPMIX_INTERFACE(FastMono8BitLinearRampMix) | ||
833 | SNDMIX_BEGINSAMPLELOOP8 | ||
834 | SNDMIX_GETMONOVOL8LINEAR | ||
835 | SNDMIX_RAMPFASTMONOVOL | ||
836 | END_FASTRAMPMIX_INTERFACE() | ||
837 | |||
838 | BEGIN_FASTRAMPMIX_INTERFACE(FastMono16BitLinearRampMix) | ||
839 | SNDMIX_BEGINSAMPLELOOP16 | ||
840 | SNDMIX_GETMONOVOL16LINEAR | ||
841 | SNDMIX_RAMPFASTMONOVOL | ||
842 | END_FASTRAMPMIX_INTERFACE() | ||
843 | |||
844 | BEGIN_FASTRAMPMIX_INTERFACE(FastMono8BitSplineRampMix) | ||
845 | SNDMIX_BEGINSAMPLELOOP8 | ||
846 | SNDMIX_GETMONOVOL8SPLINE | ||
847 | SNDMIX_RAMPFASTMONOVOL | ||
848 | END_FASTRAMPMIX_INTERFACE() | ||
849 | |||
850 | BEGIN_FASTRAMPMIX_INTERFACE(FastMono16BitSplineRampMix) | ||
851 | SNDMIX_BEGINSAMPLELOOP16 | ||
852 | SNDMIX_GETMONOVOL16SPLINE | ||
853 | SNDMIX_RAMPFASTMONOVOL | ||
854 | END_FASTRAMPMIX_INTERFACE() | ||
855 | |||
856 | BEGIN_FASTRAMPMIX_INTERFACE(FastMono8BitFirFilterRampMix) | ||
857 | SNDMIX_BEGINSAMPLELOOP8 | ||
858 | SNDMIX_GETMONOVOL8FIRFILTER | ||
859 | SNDMIX_RAMPFASTMONOVOL | ||
860 | END_FASTRAMPMIX_INTERFACE() | ||
861 | |||
862 | BEGIN_FASTRAMPMIX_INTERFACE(FastMono16BitFirFilterRampMix) | ||
863 | SNDMIX_BEGINSAMPLELOOP16 | ||
864 | SNDMIX_GETMONOVOL16FIRFILTER | ||
865 | SNDMIX_RAMPFASTMONOVOL | ||
866 | END_FASTRAMPMIX_INTERFACE() | ||
867 | |||
868 | |||
869 | ////////////////////////////////////////////////////// | ||
870 | // Stereo samples | ||
871 | |||
872 | BEGIN_MIX_INTERFACE(Stereo8BitMix) | ||
873 | SNDMIX_BEGINSAMPLELOOP8 | ||
874 | SNDMIX_GETSTEREOVOL8NOIDO | ||
875 | SNDMIX_STORESTEREOVOL | ||
876 | END_MIX_INTERFACE() | ||
877 | |||
878 | BEGIN_MIX_INTERFACE(Stereo16BitMix) | ||
879 | SNDMIX_BEGINSAMPLELOOP16 | ||
880 | SNDMIX_GETSTEREOVOL16NOIDO | ||
881 | SNDMIX_STORESTEREOVOL | ||
882 | END_MIX_INTERFACE() | ||
883 | |||
884 | BEGIN_MIX_INTERFACE(Stereo8BitLinearMix) | ||
885 | SNDMIX_BEGINSAMPLELOOP8 | ||
886 | SNDMIX_GETSTEREOVOL8LINEAR | ||
887 | SNDMIX_STORESTEREOVOL | ||
888 | END_MIX_INTERFACE() | ||
889 | |||
890 | BEGIN_MIX_INTERFACE(Stereo16BitLinearMix) | ||
891 | SNDMIX_BEGINSAMPLELOOP16 | ||
892 | SNDMIX_GETSTEREOVOL16LINEAR | ||
893 | SNDMIX_STORESTEREOVOL | ||
894 | END_MIX_INTERFACE() | ||
895 | |||
896 | BEGIN_MIX_INTERFACE(Stereo8BitSplineMix) | ||
897 | SNDMIX_BEGINSAMPLELOOP8 | ||
898 | SNDMIX_GETSTEREOVOL8SPLINE | ||
899 | SNDMIX_STORESTEREOVOL | ||
900 | END_MIX_INTERFACE() | ||
901 | |||
902 | BEGIN_MIX_INTERFACE(Stereo16BitSplineMix) | ||
903 | SNDMIX_BEGINSAMPLELOOP16 | ||
904 | SNDMIX_GETSTEREOVOL16SPLINE | ||
905 | SNDMIX_STORESTEREOVOL | ||
906 | END_MIX_INTERFACE() | ||
907 | |||
908 | BEGIN_MIX_INTERFACE(Stereo8BitFirFilterMix) | ||
909 | SNDMIX_BEGINSAMPLELOOP8 | ||
910 | SNDMIX_GETSTEREOVOL8FIRFILTER | ||
911 | SNDMIX_STORESTEREOVOL | ||
912 | END_MIX_INTERFACE() | ||
913 | |||
914 | BEGIN_MIX_INTERFACE(Stereo16BitFirFilterMix) | ||
915 | SNDMIX_BEGINSAMPLELOOP16 | ||
916 | SNDMIX_GETSTEREOVOL16FIRFILTER | ||
917 | SNDMIX_STORESTEREOVOL | ||
918 | END_MIX_INTERFACE() | ||
919 | |||
920 | |||
921 | // Volume Ramps | ||
922 | BEGIN_RAMPMIX_INTERFACE(Stereo8BitRampMix) | ||
923 | SNDMIX_BEGINSAMPLELOOP8 | ||
924 | SNDMIX_GETSTEREOVOL8NOIDO | ||
925 | SNDMIX_RAMPSTEREOVOL | ||
926 | END_RAMPMIX_INTERFACE() | ||
927 | |||
928 | BEGIN_RAMPMIX_INTERFACE(Stereo16BitRampMix) | ||
929 | SNDMIX_BEGINSAMPLELOOP16 | ||
930 | SNDMIX_GETSTEREOVOL16NOIDO | ||
931 | SNDMIX_RAMPSTEREOVOL | ||
932 | END_RAMPMIX_INTERFACE() | ||
933 | |||
934 | BEGIN_RAMPMIX_INTERFACE(Stereo8BitLinearRampMix) | ||
935 | SNDMIX_BEGINSAMPLELOOP8 | ||
936 | SNDMIX_GETSTEREOVOL8LINEAR | ||
937 | SNDMIX_RAMPSTEREOVOL | ||
938 | END_RAMPMIX_INTERFACE() | ||
939 | |||
940 | BEGIN_RAMPMIX_INTERFACE(Stereo16BitLinearRampMix) | ||
941 | SNDMIX_BEGINSAMPLELOOP16 | ||
942 | SNDMIX_GETSTEREOVOL16LINEAR | ||
943 | SNDMIX_RAMPSTEREOVOL | ||
944 | END_RAMPMIX_INTERFACE() | ||
945 | |||
946 | BEGIN_RAMPMIX_INTERFACE(Stereo8BitSplineRampMix) | ||
947 | SNDMIX_BEGINSAMPLELOOP8 | ||
948 | SNDMIX_GETSTEREOVOL8SPLINE | ||
949 | SNDMIX_RAMPSTEREOVOL | ||
950 | END_RAMPMIX_INTERFACE() | ||
951 | |||
952 | BEGIN_RAMPMIX_INTERFACE(Stereo16BitSplineRampMix) | ||
953 | SNDMIX_BEGINSAMPLELOOP16 | ||
954 | SNDMIX_GETSTEREOVOL16SPLINE | ||
955 | SNDMIX_RAMPSTEREOVOL | ||
956 | END_RAMPMIX_INTERFACE() | ||
957 | |||
958 | BEGIN_RAMPMIX_INTERFACE(Stereo8BitFirFilterRampMix) | ||
959 | SNDMIX_BEGINSAMPLELOOP8 | ||
960 | SNDMIX_GETSTEREOVOL8FIRFILTER | ||
961 | SNDMIX_RAMPSTEREOVOL | ||
962 | END_RAMPMIX_INTERFACE() | ||
963 | |||
964 | BEGIN_RAMPMIX_INTERFACE(Stereo16BitFirFilterRampMix) | ||
965 | SNDMIX_BEGINSAMPLELOOP16 | ||
966 | SNDMIX_GETSTEREOVOL16FIRFILTER | ||
967 | SNDMIX_RAMPSTEREOVOL | ||
968 | END_RAMPMIX_INTERFACE() | ||
969 | |||
970 | |||
971 | |||
972 | ////////////////////////////////////////////////////// | ||
973 | // Resonant Filter Mix | ||
974 | |||
975 | #ifndef NO_FILTER | ||
976 | |||
977 | // Mono Filter Mix | ||
978 | BEGIN_MIX_FLT_INTERFACE(FilterMono8BitMix) | ||
979 | SNDMIX_BEGINSAMPLELOOP8 | ||
980 | SNDMIX_GETMONOVOL8NOIDO | ||
981 | SNDMIX_PROCESSFILTER | ||
982 | SNDMIX_STOREMONOVOL | ||
983 | END_MIX_FLT_INTERFACE() | ||
984 | |||
985 | BEGIN_MIX_FLT_INTERFACE(FilterMono16BitMix) | ||
986 | SNDMIX_BEGINSAMPLELOOP16 | ||
987 | SNDMIX_GETMONOVOL16NOIDO | ||
988 | SNDMIX_PROCESSFILTER | ||
989 | SNDMIX_STOREMONOVOL | ||
990 | END_MIX_FLT_INTERFACE() | ||
991 | |||
992 | BEGIN_MIX_FLT_INTERFACE(FilterMono8BitLinearMix) | ||
993 | SNDMIX_BEGINSAMPLELOOP8 | ||
994 | SNDMIX_GETMONOVOL8LINEAR | ||
995 | SNDMIX_PROCESSFILTER | ||
996 | SNDMIX_STOREMONOVOL | ||
997 | END_MIX_FLT_INTERFACE() | ||
998 | |||
999 | BEGIN_MIX_FLT_INTERFACE(FilterMono16BitLinearMix) | ||
1000 | SNDMIX_BEGINSAMPLELOOP16 | ||
1001 | SNDMIX_GETMONOVOL16LINEAR | ||
1002 | SNDMIX_PROCESSFILTER | ||
1003 | SNDMIX_STOREMONOVOL | ||
1004 | END_MIX_FLT_INTERFACE() | ||
1005 | |||
1006 | BEGIN_MIX_FLT_INTERFACE(FilterMono8BitSplineMix) | ||
1007 | SNDMIX_BEGINSAMPLELOOP8 | ||
1008 | SNDMIX_GETMONOVOL8SPLINE | ||
1009 | SNDMIX_PROCESSFILTER | ||
1010 | SNDMIX_STOREMONOVOL | ||
1011 | END_MIX_FLT_INTERFACE() | ||
1012 | |||
1013 | BEGIN_MIX_FLT_INTERFACE(FilterMono16BitSplineMix) | ||
1014 | SNDMIX_BEGINSAMPLELOOP16 | ||
1015 | SNDMIX_GETMONOVOL16SPLINE | ||
1016 | SNDMIX_PROCESSFILTER | ||
1017 | SNDMIX_STOREMONOVOL | ||
1018 | END_MIX_FLT_INTERFACE() | ||
1019 | |||
1020 | BEGIN_MIX_FLT_INTERFACE(FilterMono8BitFirFilterMix) | ||
1021 | SNDMIX_BEGINSAMPLELOOP8 | ||
1022 | SNDMIX_GETMONOVOL8FIRFILTER | ||
1023 | SNDMIX_PROCESSFILTER | ||
1024 | SNDMIX_STOREMONOVOL | ||
1025 | END_MIX_FLT_INTERFACE() | ||
1026 | |||
1027 | BEGIN_MIX_FLT_INTERFACE(FilterMono16BitFirFilterMix) | ||
1028 | SNDMIX_BEGINSAMPLELOOP16 | ||
1029 | SNDMIX_GETMONOVOL16FIRFILTER | ||
1030 | SNDMIX_PROCESSFILTER | ||
1031 | SNDMIX_STOREMONOVOL | ||
1032 | END_MIX_FLT_INTERFACE() | ||
1033 | |||
1034 | // Filter + Ramp | ||
1035 | BEGIN_RAMPMIX_FLT_INTERFACE(FilterMono8BitRampMix) | ||
1036 | SNDMIX_BEGINSAMPLELOOP8 | ||
1037 | SNDMIX_GETMONOVOL8NOIDO | ||
1038 | SNDMIX_PROCESSFILTER | ||
1039 | SNDMIX_RAMPMONOVOL | ||
1040 | END_RAMPMIX_FLT_INTERFACE() | ||
1041 | |||
1042 | BEGIN_RAMPMIX_FLT_INTERFACE(FilterMono16BitRampMix) | ||
1043 | SNDMIX_BEGINSAMPLELOOP16 | ||
1044 | SNDMIX_GETMONOVOL16NOIDO | ||
1045 | SNDMIX_PROCESSFILTER | ||
1046 | SNDMIX_RAMPMONOVOL | ||
1047 | END_RAMPMIX_FLT_INTERFACE() | ||
1048 | |||
1049 | BEGIN_RAMPMIX_FLT_INTERFACE(FilterMono8BitLinearRampMix) | ||
1050 | SNDMIX_BEGINSAMPLELOOP8 | ||
1051 | SNDMIX_GETMONOVOL8LINEAR | ||
1052 | SNDMIX_PROCESSFILTER | ||
1053 | SNDMIX_RAMPMONOVOL | ||
1054 | END_RAMPMIX_FLT_INTERFACE() | ||
1055 | |||
1056 | BEGIN_RAMPMIX_FLT_INTERFACE(FilterMono16BitLinearRampMix) | ||
1057 | SNDMIX_BEGINSAMPLELOOP16 | ||
1058 | SNDMIX_GETMONOVOL16LINEAR | ||
1059 | SNDMIX_PROCESSFILTER | ||
1060 | SNDMIX_RAMPMONOVOL | ||
1061 | END_RAMPMIX_FLT_INTERFACE() | ||
1062 | |||
1063 | BEGIN_RAMPMIX_FLT_INTERFACE(FilterMono8BitSplineRampMix) | ||
1064 | SNDMIX_BEGINSAMPLELOOP8 | ||
1065 | SNDMIX_GETMONOVOL8SPLINE | ||
1066 | SNDMIX_PROCESSFILTER | ||
1067 | SNDMIX_RAMPMONOVOL | ||
1068 | END_RAMPMIX_FLT_INTERFACE() | ||
1069 | |||
1070 | BEGIN_RAMPMIX_FLT_INTERFACE(FilterMono16BitSplineRampMix) | ||
1071 | SNDMIX_BEGINSAMPLELOOP16 | ||
1072 | SNDMIX_GETMONOVOL16SPLINE | ||
1073 | SNDMIX_PROCESSFILTER | ||
1074 | SNDMIX_RAMPMONOVOL | ||
1075 | END_RAMPMIX_FLT_INTERFACE() | ||
1076 | |||
1077 | BEGIN_RAMPMIX_FLT_INTERFACE(FilterMono8BitFirFilterRampMix) | ||
1078 | SNDMIX_BEGINSAMPLELOOP8 | ||
1079 | SNDMIX_GETMONOVOL8FIRFILTER | ||
1080 | SNDMIX_PROCESSFILTER | ||
1081 | SNDMIX_RAMPMONOVOL | ||
1082 | END_RAMPMIX_FLT_INTERFACE() | ||
1083 | |||
1084 | BEGIN_RAMPMIX_FLT_INTERFACE(FilterMono16BitFirFilterRampMix) | ||
1085 | SNDMIX_BEGINSAMPLELOOP16 | ||
1086 | SNDMIX_GETMONOVOL16FIRFILTER | ||
1087 | SNDMIX_PROCESSFILTER | ||
1088 | SNDMIX_RAMPMONOVOL | ||
1089 | END_RAMPMIX_FLT_INTERFACE() | ||
1090 | |||
1091 | |||
1092 | // Stereo Filter Mix | ||
1093 | BEGIN_MIX_STFLT_INTERFACE(FilterStereo8BitMix) | ||
1094 | SNDMIX_BEGINSAMPLELOOP8 | ||
1095 | SNDMIX_GETSTEREOVOL8NOIDO | ||
1096 | SNDMIX_PROCESSSTEREOFILTER | ||
1097 | SNDMIX_STORESTEREOVOL | ||
1098 | END_MIX_STFLT_INTERFACE() | ||
1099 | |||
1100 | BEGIN_MIX_STFLT_INTERFACE(FilterStereo16BitMix) | ||
1101 | SNDMIX_BEGINSAMPLELOOP16 | ||
1102 | SNDMIX_GETSTEREOVOL16NOIDO | ||
1103 | SNDMIX_PROCESSSTEREOFILTER | ||
1104 | SNDMIX_STORESTEREOVOL | ||
1105 | END_MIX_STFLT_INTERFACE() | ||
1106 | |||
1107 | BEGIN_MIX_STFLT_INTERFACE(FilterStereo8BitLinearMix) | ||
1108 | SNDMIX_BEGINSAMPLELOOP8 | ||
1109 | SNDMIX_GETSTEREOVOL8LINEAR | ||
1110 | SNDMIX_PROCESSSTEREOFILTER | ||
1111 | SNDMIX_STORESTEREOVOL | ||
1112 | END_MIX_STFLT_INTERFACE() | ||
1113 | |||
1114 | BEGIN_MIX_STFLT_INTERFACE(FilterStereo16BitLinearMix) | ||
1115 | SNDMIX_BEGINSAMPLELOOP16 | ||
1116 | SNDMIX_GETSTEREOVOL16LINEAR | ||
1117 | SNDMIX_PROCESSSTEREOFILTER | ||
1118 | SNDMIX_STORESTEREOVOL | ||
1119 | END_MIX_STFLT_INTERFACE() | ||
1120 | |||
1121 | BEGIN_MIX_STFLT_INTERFACE(FilterStereo8BitSplineMix) | ||
1122 | SNDMIX_BEGINSAMPLELOOP8 | ||
1123 | SNDMIX_GETSTEREOVOL8SPLINE | ||
1124 | SNDMIX_PROCESSSTEREOFILTER | ||
1125 | SNDMIX_STORESTEREOVOL | ||
1126 | END_MIX_STFLT_INTERFACE() | ||
1127 | |||
1128 | BEGIN_MIX_STFLT_INTERFACE(FilterStereo16BitSplineMix) | ||
1129 | SNDMIX_BEGINSAMPLELOOP16 | ||
1130 | SNDMIX_GETSTEREOVOL16SPLINE | ||
1131 | SNDMIX_PROCESSSTEREOFILTER | ||
1132 | SNDMIX_STORESTEREOVOL | ||
1133 | END_MIX_STFLT_INTERFACE() | ||
1134 | |||
1135 | BEGIN_MIX_STFLT_INTERFACE(FilterStereo8BitFirFilterMix) | ||
1136 | SNDMIX_BEGINSAMPLELOOP8 | ||
1137 | SNDMIX_GETSTEREOVOL8FIRFILTER | ||
1138 | SNDMIX_PROCESSSTEREOFILTER | ||
1139 | SNDMIX_STORESTEREOVOL | ||
1140 | END_MIX_STFLT_INTERFACE() | ||
1141 | |||
1142 | BEGIN_MIX_STFLT_INTERFACE(FilterStereo16BitFirFilterMix) | ||
1143 | SNDMIX_BEGINSAMPLELOOP16 | ||
1144 | SNDMIX_GETSTEREOVOL16FIRFILTER | ||
1145 | SNDMIX_PROCESSSTEREOFILTER | ||
1146 | SNDMIX_STORESTEREOVOL | ||
1147 | END_MIX_STFLT_INTERFACE() | ||
1148 | |||
1149 | // Stereo Filter + Ramp | ||
1150 | BEGIN_RAMPMIX_STFLT_INTERFACE(FilterStereo8BitRampMix) | ||
1151 | SNDMIX_BEGINSAMPLELOOP8 | ||
1152 | SNDMIX_GETSTEREOVOL8NOIDO | ||
1153 | SNDMIX_PROCESSSTEREOFILTER | ||
1154 | SNDMIX_RAMPSTEREOVOL | ||
1155 | END_RAMPMIX_STFLT_INTERFACE() | ||
1156 | |||
1157 | BEGIN_RAMPMIX_STFLT_INTERFACE(FilterStereo16BitRampMix) | ||
1158 | SNDMIX_BEGINSAMPLELOOP16 | ||
1159 | SNDMIX_GETSTEREOVOL16NOIDO | ||
1160 | SNDMIX_PROCESSSTEREOFILTER | ||
1161 | SNDMIX_RAMPSTEREOVOL | ||
1162 | END_RAMPMIX_STFLT_INTERFACE() | ||
1163 | |||
1164 | BEGIN_RAMPMIX_STFLT_INTERFACE(FilterStereo8BitLinearRampMix) | ||
1165 | SNDMIX_BEGINSAMPLELOOP8 | ||
1166 | SNDMIX_GETSTEREOVOL8LINEAR | ||
1167 | SNDMIX_PROCESSSTEREOFILTER | ||
1168 | SNDMIX_RAMPSTEREOVOL | ||
1169 | END_RAMPMIX_STFLT_INTERFACE() | ||
1170 | |||
1171 | BEGIN_RAMPMIX_STFLT_INTERFACE(FilterStereo16BitLinearRampMix) | ||
1172 | SNDMIX_BEGINSAMPLELOOP16 | ||
1173 | SNDMIX_GETSTEREOVOL16LINEAR | ||
1174 | SNDMIX_PROCESSSTEREOFILTER | ||
1175 | SNDMIX_RAMPSTEREOVOL | ||
1176 | END_RAMPMIX_STFLT_INTERFACE() | ||
1177 | |||
1178 | BEGIN_RAMPMIX_STFLT_INTERFACE(FilterStereo8BitSplineRampMix) | ||
1179 | SNDMIX_BEGINSAMPLELOOP8 | ||
1180 | SNDMIX_GETSTEREOVOL8SPLINE | ||
1181 | SNDMIX_PROCESSSTEREOFILTER | ||
1182 | SNDMIX_RAMPSTEREOVOL | ||
1183 | END_RAMPMIX_STFLT_INTERFACE() | ||
1184 | |||
1185 | BEGIN_RAMPMIX_STFLT_INTERFACE(FilterStereo16BitSplineRampMix) | ||
1186 | SNDMIX_BEGINSAMPLELOOP16 | ||
1187 | SNDMIX_GETSTEREOVOL16SPLINE | ||
1188 | SNDMIX_PROCESSSTEREOFILTER | ||
1189 | SNDMIX_RAMPSTEREOVOL | ||
1190 | END_RAMPMIX_STFLT_INTERFACE() | ||
1191 | |||
1192 | BEGIN_RAMPMIX_STFLT_INTERFACE(FilterStereo8BitFirFilterRampMix) | ||
1193 | SNDMIX_BEGINSAMPLELOOP8 | ||
1194 | SNDMIX_GETSTEREOVOL8FIRFILTER | ||
1195 | SNDMIX_PROCESSSTEREOFILTER | ||
1196 | SNDMIX_RAMPSTEREOVOL | ||
1197 | END_RAMPMIX_STFLT_INTERFACE() | ||
1198 | |||
1199 | BEGIN_RAMPMIX_STFLT_INTERFACE(FilterStereo16BitFirFilterRampMix) | ||
1200 | SNDMIX_BEGINSAMPLELOOP16 | ||
1201 | SNDMIX_GETSTEREOVOL16FIRFILTER | ||
1202 | SNDMIX_PROCESSSTEREOFILTER | ||
1203 | SNDMIX_RAMPSTEREOVOL | ||
1204 | END_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 | |||
1265 | const 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 | |||
1295 | const 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 | |||
1328 | static 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 | |||
1434 | UINT 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 | ||
1589 | cliploop: | ||
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 | ||
1603 | cliprecover: | ||
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 | ||
1619 | updatemin: | ||
1620 | mov ecx, eax | ||
1621 | jmp cliprecover | ||
1622 | updatemax: | ||
1623 | mov edx, eax | ||
1624 | jmp cliprecover | ||
1625 | cliplow: | ||
1626 | mov ecx, MIXING_CLIPMIN | ||
1627 | mov edx, MIXING_CLIPMAX | ||
1628 | mov eax, MIXING_CLIPMIN | ||
1629 | jmp cliprecover | ||
1630 | cliphigh: | ||
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 | ||
1681 | cliploop: | ||
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 | ||
1696 | cliprecover: | ||
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 | ||
1713 | updatemin: | ||
1714 | mov ecx, eax | ||
1715 | jmp cliprecover | ||
1716 | updatemax: | ||
1717 | mov ebp, eax | ||
1718 | jmp cliprecover | ||
1719 | cliplow: | ||
1720 | mov ecx, MIXING_CLIPMIN | ||
1721 | mov ebp, MIXING_CLIPMAX | ||
1722 | mov eax, MIXING_CLIPMIN | ||
1723 | jmp cliprecover | ||
1724 | cliphigh: | ||
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 | ||
1774 | cliploop: | ||
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 | ||
1788 | cliprecover: | ||
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 | ||
1810 | updatemin: | ||
1811 | mov ecx, eax | ||
1812 | jmp cliprecover | ||
1813 | updatemax: | ||
1814 | mov edx, eax | ||
1815 | jmp cliprecover | ||
1816 | cliplow: | ||
1817 | mov ecx, MIXING_CLIPMIN | ||
1818 | mov edx, MIXING_CLIPMAX | ||
1819 | mov eax, MIXING_CLIPMIN | ||
1820 | jmp cliprecover | ||
1821 | cliphigh: | ||
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 | ||
1853 | cliploop: | ||
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 | ||
1865 | cliprecover: | ||
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 | ||
1881 | updatemin: | ||
1882 | mov ecx, eax | ||
1883 | jmp cliprecover | ||
1884 | updatemax: | ||
1885 | mov edx, eax | ||
1886 | jmp cliprecover | ||
1887 | cliplow: | ||
1888 | mov ecx, MIXING_CLIPMIN | ||
1889 | mov edx, MIXING_CLIPMAX | ||
1890 | mov eax, MIXING_CLIPMIN | ||
1891 | jmp cliprecover | ||
1892 | cliphigh: | ||
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 | ||
1910 | void 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 | ||
1921 | loop1x: | ||
1922 | add esi, 4 | ||
1923 | dec edx | ||
1924 | mov dword ptr [esi-4], eax | ||
1925 | jnz loop1x | ||
1926 | unroll4x: | ||
1927 | or ecx, ecx | ||
1928 | jnz loop4x | ||
1929 | jmp done | ||
1930 | loop4x: | ||
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 | ||
1938 | done:; | ||
1939 | } | ||
1940 | } | ||
1941 | #else | ||
1942 | //---GCCFIX: Asm replaced with C function | ||
1943 | // Will fill in later. | ||
1944 | void 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] | ||
1966 | interleaveloop: | ||
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 | ||
1997 | VOID MPPASMCALL X86_MonoFromStereo(int *pMixBuf, UINT nSamples) | ||
1998 | //------------------------------------------------------------- | ||
1999 | { | ||
2000 | _asm { | ||
2001 | mov ecx, nSamples | ||
2002 | mov esi, pMixBuf | ||
2003 | mov edi, esi | ||
2004 | stloop: | ||
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 | ||
2018 | VOID 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 | ||
2034 | void 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 | ||
2049 | ofsloop: | ||
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 | ||
2072 | fill_loop: | ||
2073 | mov ebx, ecx | ||
2074 | and ebx, 3 | ||
2075 | jz fill4x | ||
2076 | fill1x: | ||
2077 | mov [edi], eax | ||
2078 | mov [edi+4], edx | ||
2079 | add edi, 8 | ||
2080 | dec ebx | ||
2081 | jnz fill1x | ||
2082 | fill4x: | ||
2083 | shr ecx, 2 | ||
2084 | or ecx, ecx | ||
2085 | jz done | ||
2086 | fill4xloop: | ||
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 | ||
2098 | done: | ||
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 | ||
2135 | void 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 | ||
2146 | ofsloop: | ||
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 | ||
2169 | brkloop: | ||
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. | ||
2178 | void 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) | ||
2219 | agcloop: | ||
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 | ||
2228 | agcrecover: | ||
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 | ||
2238 | agcupdate: | ||
2239 | dec edi | ||
2240 | jmp agcrecover | ||
2241 | } | ||
2242 | } | ||
2243 | |||
2244 | #pragma warning (default:4100) | ||
2245 | |||
2246 | void 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 | |||
2273 | void 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 | |||
8 | typedef 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 | |||
35 | typedef 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) | ||
48 | typedef 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 | ||
74 | typedef 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 | ||
107 | typedef 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 | |||
133 | extern const BYTE autovibit2xm[8]; | ||
134 | extern 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 | |||
20 | typedef 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 | |||
33 | typedef 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 | |||
42 | BOOL 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 | |||
28 | typedef 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 | |||
39 | typedef 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 | ||
55 | extern void Log(LPCSTR, ...); | ||
56 | #endif | ||
57 | |||
58 | VOID 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 | |||
169 | BOOL 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 | |||
20 | typedef 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 | |||
32 | typedef 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 | |||
48 | BOOL 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 | |||
257 | typedef 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 | |||
266 | typedef 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 | |||
280 | typedef struct AMS2INSTRUMENT | ||
281 | { | ||
282 | BYTE samples; | ||
283 | BYTE notemap[120]; | ||
284 | } Q_PACKED AMS2INSTRUMENT; | ||
285 | |||
286 | typedef 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 | |||
296 | typedef 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 | |||
313 | BOOL 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 | |||
566 | void 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 | |||
37 | typedef 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 | |||
59 | typedef 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 | |||
71 | typedef 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 | |||
83 | typedef struct DBMPATTERN | ||
84 | { | ||
85 | WORD rows; | ||
86 | DWORD packedsize; | ||
87 | BYTE patterndata[2];// [packedsize] | ||
88 | } Q_PACKED DBMPATTERN; | ||
89 | |||
90 | typedef struct DBMSAMPLE | ||
91 | { | ||
92 | DWORD flags; | ||
93 | DWORD samplesize; | ||
94 | BYTE sampledata[2]; // [samplesize] | ||
95 | } Q_PACKED DBMSAMPLE; | ||
96 | |||
97 | #pragma pack() | ||
98 | |||
99 | |||
100 | BOOL 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 | |||
22 | typedef 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 | |||
32 | typedef struct DMFINFO | ||
33 | { | ||
34 | DWORD id; // "INFO" | ||
35 | DWORD infosize; | ||
36 | } Q_PACKED DMFINFO; | ||
37 | |||
38 | typedef 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 | |||
47 | typedef 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 | |||
56 | typedef 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 | |||
64 | typedef struct DMFSMPI | ||
65 | { | ||
66 | DWORD id; | ||
67 | DWORD size; | ||
68 | BYTE samples; | ||
69 | } Q_PACKED DMFSMPI; | ||
70 | |||
71 | typedef 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 | ||
85 | extern void Log(LPCSTR s, ...); | ||
86 | #endif | ||
87 | |||
88 | |||
89 | BOOL 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 | } | ||
475 | dmfexit: | ||
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 | |||
494 | typedef struct DMF_HNODE | ||
495 | { | ||
496 | short int left, right; | ||
497 | BYTE value; | ||
498 | } Q_PACKED DMF_HNODE; | ||
499 | |||
500 | typedef 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 | ||
513 | BYTE 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 | |||
538 | void 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 | |||
573 | int 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 | |||
25 | typedef struct DSMNOTE | ||
26 | { | ||
27 | BYTE note,ins,vol,cmd,inf; | ||
28 | } Q_PACKED DSMNOTE; | ||
29 | |||
30 | |||
31 | typedef 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 | |||
49 | typedef 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 | |||
59 | typedef 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 | |||
77 | typedef 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 | |||
88 | BOOL 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 | |||
22 | typedef 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 | |||
37 | typedef 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 | |||
46 | typedef 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 | |||
61 | BOOL 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 | |||
19 | const BYTE autovibit2xm[8] = | ||
20 | { 0, 3, 1, 4, 2, 0, 0, 0 }; | ||
21 | |||
22 | const BYTE autovibxm2it[8] = | ||
23 | { 0, 2, 4, 1, 3, 0, 0, 0 }; | ||
24 | |||
25 | ////////////////////////////////////////////////////////// | ||
26 | // Impulse Tracker IT file support (import only) | ||
27 | |||
28 | |||
29 | static inline UINT ConvertVolParam(UINT value) | ||
30 | //-------------------------------------------- | ||
31 | { | ||
32 | return (value > 9) ? 9 : value; | ||
33 | } | ||
34 | |||
35 | |||
36 | BOOL 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 | |||
157 | BOOL 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 | |||
595 | BOOL 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, ×tamp[0], ×tamp[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, ¶m, 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 | |||
1100 | DWORD 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 | ||
1127 | void 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 | |||
1209 | void 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 | |||
1293 | UINT 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 | |||
1360 | UINT 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 | |||
18 | typedef struct MDLSONGHEADER | ||
19 | { | ||
20 | DWORD id;// "DMDL" = 0x4C444D44 | ||
21 | BYTE version; | ||
22 | } Q_PACKED MDLSONGHEADER; | ||
23 | |||
24 | |||
25 | typedef 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 | |||
39 | typedef 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 | |||
48 | void 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 | |||
97 | void 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 | |||
182 | BOOL 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 | ||
492 | WORD 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 | ||
17 | extern 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 | |||
65 | typedef 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 | |||
88 | typedef 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... | ||
99 | typedef 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 | ||
127 | typedef 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 | ||
145 | typedef 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. | ||
181 | typedef 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. | ||
195 | typedef 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 | |||
203 | typedef 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. | ||
216 | typedef 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 | ||
229 | typedef 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 | |||
238 | typedef 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 | |||
268 | static 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 | |||
476 | BOOL 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 | |||
16 | extern WORD ProTrackerPeriodTable[6*12]; | ||
17 | |||
18 | ////////////////////////////////////////////////////////// | ||
19 | // ProTracker / NoiseTracker MOD/NST file support | ||
20 | |||
21 | void 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 | |||
65 | WORD 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 | |||
153 | typedef 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 | |||
163 | typedef 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 | |||
173 | BOOL IsMagic(LPCSTR s1, LPCSTR s2) | ||
174 | { | ||
175 | return ((*(DWORD *)s1) == (*(DWORD *)s2)) ? TRUE : FALSE; | ||
176 | } | ||
177 | |||
178 | |||
179 | BOOL 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 | |||
371 | BOOL 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 | |||
8 | typedef 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 | |||
28 | typedef struct _MT2PATTERN | ||
29 | { | ||
30 | WORD wLines; | ||
31 | DWORD wDataLen; | ||
32 | } Q_PACKED MT2PATTERN; | ||
33 | |||
34 | typedef 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 | |||
45 | typedef struct _MT2DRUMSDATA | ||
46 | { | ||
47 | WORD wDrumPatterns; | ||
48 | WORD wDrumSamples[8]; | ||
49 | BYTE DrumPatternOrder[256]; | ||
50 | } Q_PACKED MT2DRUMSDATA; | ||
51 | |||
52 | typedef struct _MT2AUTOMATION | ||
53 | { | ||
54 | DWORD dwFlags; | ||
55 | DWORD dwEffectId; | ||
56 | DWORD nEnvPoints; | ||
57 | } Q_PACKED MT2AUTOMATION; | ||
58 | |||
59 | typedef 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 | |||
76 | typedef 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 | |||
87 | typedef 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 | |||
98 | typedef 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 | |||
116 | typedef 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 | |||
127 | static 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 | |||
183 | BOOL 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 | |||
21 | typedef 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 | |||
33 | typedef 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 | |||
52 | BOOL 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 | |||
19 | typedef 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 | |||
31 | typedef 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 | |||
44 | BOOL 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 | |||
34 | typedef struct _PSMCHUNK | ||
35 | { | ||
36 | DWORD id; | ||
37 | DWORD len; | ||
38 | DWORD listid; | ||
39 | } Q_PACKED PSMCHUNK; | ||
40 | |||
41 | typedef struct _PSMSONGHDR | ||
42 | { | ||
43 | CHAR songname[8];// "MAINSONG" | ||
44 | BYTE reserved1; | ||
45 | BYTE reserved2; | ||
46 | BYTE channels; | ||
47 | } Q_PACKED PSMSONGHDR; | ||
48 | |||
49 | typedef struct _PSMPATTERN | ||
50 | { | ||
51 | DWORD size; | ||
52 | DWORD name; | ||
53 | WORD rows; | ||
54 | WORD reserved1; | ||
55 | BYTE data[4]; | ||
56 | } Q_PACKED PSMPATTERN; | ||
57 | |||
58 | typedef 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 | |||
81 | BOOL 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 | |||
388 | CONST | ||
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 | |||
21 | typedef 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 | |||
44 | typedef 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 | |||
65 | BOOL 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 | |||
16 | extern WORD S3MFineTuneTable[16]; | ||
17 | |||
18 | ////////////////////////////////////////////////////// | ||
19 | // ScreamTracker S3M file support | ||
20 | |||
21 | typedef 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 | |||
44 | typedef 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 | |||
69 | void 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 | |||
109 | void 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 | |||
188 | BOOL 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 | |||
406 | static 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 | |||
413 | BOOL 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, ¶m, 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 | |||
17 | typedef 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: | ||
27 | typedef 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: | ||
42 | typedef 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 | |||
62 | BOOL 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: | ||
22 | typedef 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: | ||
31 | typedef 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 | |||
47 | BOOL 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 | |||
16 | BOOL 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 | |||
20 | BOOL 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 | |||
151 | typedef struct IMAADPCMBLOCK | ||
152 | { | ||
153 | WORD sample; | ||
154 | BYTE index; | ||
155 | BYTE Reserved; | ||
156 | } Q_PACKED DVI_ADPCMBLOCKHEADER; | ||
157 | |||
158 | #pragma pack() | ||
159 | |||
160 | static 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 | |||
177 | BOOL 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) | ||
22 | typedef 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 | |||
37 | typedef 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 | |||
47 | typedef 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 | |||
62 | typedef 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 | |||
76 | typedef 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 | |||
87 | BOOL 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 | |||
605 | BOOL 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 | |||
25 | MemFile::MemFile() | ||
26 | { | ||
27 | } | ||
28 | |||
29 | MemFile::MemFile( const QString &name ) | ||
30 | : QFile( name ) | ||
31 | { | ||
32 | } | ||
33 | |||
34 | MemFile::~MemFile() | ||
35 | { | ||
36 | close(); | ||
37 | } | ||
38 | |||
39 | void MemFile::close() | ||
40 | { | ||
41 | unmap(); | ||
42 | QFile::close(); | ||
43 | } | ||
44 | |||
45 | void 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 | |||
56 | QByteArray &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 | |||
24 | class MemFile : public QFile | ||
25 | { | ||
26 | public: | ||
27 | MemFile(); | ||
28 | MemFile( const QString &name ); | ||
29 | virtual ~MemFile(); | ||
30 | |||
31 | virtual void close(); | ||
32 | |||
33 | QByteArray &data(); | ||
34 | |||
35 | private: | ||
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 | |||
13 | BOOL PP20_Unpack(LPCBYTE *ppMemFile, LPDWORD pdwMemLength); | ||
14 | |||
15 | typedef struct MMCMPFILEHEADER | ||
16 | { | ||
17 | DWORD id_ziRC;// "ziRC" | ||
18 | DWORD id_ONia;// "ONia" | ||
19 | WORD hdrsize; | ||
20 | } Q_PACKED MMCMPFILEHEADER, *LPMMCMPFILEHEADER; | ||
21 | |||
22 | typedef 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 | |||
32 | typedef 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 | |||
43 | typedef 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 | |||
56 | typedef 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 | |||
67 | DWORD 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 | ||
86 | extern void Log(LPCSTR s, ...); | ||
87 | #endif | ||
88 | |||
89 | const DWORD MMCMP8BitCommands[8] = | ||
90 | { | ||
91 | 0x01, 0x03, 0x07, 0x0F, 0x1E, 0x3C,0x78, 0xF8 | ||
92 | }; | ||
93 | |||
94 | const UINT MMCMP8BitFetch[8] = | ||
95 | { | ||
96 | 3, 3, 3, 3, 2, 1, 0, 0 | ||
97 | }; | ||
98 | |||
99 | const DWORD MMCMP16BitCommands[16] = | ||
100 | { | ||
101 | 0x01, 0x03, 0x07, 0x0F, 0x1E, 0x3C,0x78, 0xF0, | ||
102 | 0x1F0, 0x3F0, 0x7F0, 0xFF0, 0x1FF0, 0x3FF0, 0x7FF0, 0xFFF0 | ||
103 | }; | ||
104 | |||
105 | const 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 | |||
112 | BOOL 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 | |||
302 | typedef 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 | |||
313 | ULONG 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 | |||
333 | VOID 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 | |||
388 | BOOL 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 | ||
16 | DEPENDPATH += $(OPIEDIR)/include | ||
17 | LIBS += -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 | |||
26 | ModPlugin::ModPlugin() | ||
27 | { | ||
28 | } | ||
29 | |||
30 | ModPlugin::~ModPlugin() | ||
31 | { | ||
32 | close(); | ||
33 | } | ||
34 | |||
35 | const char *ModPlugin::pluginName() | ||
36 | { | ||
37 | return "ModPlugin"; | ||
38 | } | ||
39 | |||
40 | const char *ModPlugin::pluginComment() | ||
41 | { | ||
42 | return "LibModPlug based MOD/XM/S3M/IT module player plugin"; | ||
43 | } | ||
44 | |||
45 | double ModPlugin::pluginVersion() | ||
46 | { | ||
47 | return 1.0; | ||
48 | } | ||
49 | |||
50 | bool 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 | |||
68 | bool 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 | |||
95 | bool ModPlugin::close() | ||
96 | { | ||
97 | return Destroy(); | ||
98 | } | ||
99 | |||
100 | bool ModPlugin::isOpen() | ||
101 | { | ||
102 | return m_nType != MOD_TYPE_NONE; | ||
103 | } | ||
104 | |||
105 | const QString &ModPlugin::fileInfo() | ||
106 | { | ||
107 | return QString::null; // ### | ||
108 | } | ||
109 | |||
110 | int ModPlugin::audioStreams() | ||
111 | { | ||
112 | return 1; | ||
113 | } | ||
114 | |||
115 | int ModPlugin::audioChannels( int ) | ||
116 | { | ||
117 | return s_channels; | ||
118 | } | ||
119 | |||
120 | int ModPlugin::audioFrequency( int ) | ||
121 | { | ||
122 | return s_frequency; | ||
123 | } | ||
124 | |||
125 | int ModPlugin::audioSamples( int ) | ||
126 | { | ||
127 | return m_songTime * s_frequency; | ||
128 | } | ||
129 | |||
130 | bool 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 | |||
137 | long ModPlugin::audioGetSample( int ) | ||
138 | { | ||
139 | return GetCurrentPos() * s_frequency; | ||
140 | } | ||
141 | |||
142 | bool 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 | |||
159 | int ModPlugin::videoStreams() | ||
160 | { | ||
161 | return 0; | ||
162 | } | ||
163 | |||
164 | int ModPlugin::videoWidth( int ) | ||
165 | { | ||
166 | return 0; | ||
167 | } | ||
168 | |||
169 | int ModPlugin::videoHeight( int ) | ||
170 | { | ||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | double ModPlugin::videoFrameRate( int ) | ||
175 | { | ||
176 | return 0; | ||
177 | } | ||
178 | |||
179 | int ModPlugin::videoFrames( int ) | ||
180 | { | ||
181 | return 0; | ||
182 | } | ||
183 | |||
184 | bool ModPlugin::videoSetFrame( long, int ) | ||
185 | { | ||
186 | return 0; | ||
187 | } | ||
188 | |||
189 | long ModPlugin::videoGetFrame( int ) | ||
190 | { | ||
191 | return 0; | ||
192 | } | ||
193 | |||
194 | bool ModPlugin::videoReadFrame( unsigned char **, int, int, int, int, | ||
195 | ColorFormat, int ) | ||
196 | { | ||
197 | return false; | ||
198 | } | ||
199 | |||
200 | bool ModPlugin::videoReadScaledFrame( unsigned char **, int, int, int, int, | ||
201 | int, int, ColorFormat, int ) | ||
202 | { | ||
203 | return false; | ||
204 | } | ||
205 | |||
206 | bool ModPlugin::videoReadYUVFrame( char *, char *, char *, int, int, int, | ||
207 | int, int ) | ||
208 | { | ||
209 | return false; | ||
210 | } | ||
211 | |||
212 | double ModPlugin::getTime() | ||
213 | { | ||
214 | return 0.0; // ### | ||
215 | } | ||
216 | |||
217 | bool ModPlugin::setSMP( int ) | ||
218 | { | ||
219 | return false; | ||
220 | } | ||
221 | |||
222 | bool ModPlugin::setMMX( bool ) | ||
223 | { | ||
224 | return false; | ||
225 | } | ||
226 | |||
227 | bool ModPlugin::supportsAudio() | ||
228 | { | ||
229 | return true; | ||
230 | } | ||
231 | |||
232 | bool ModPlugin::supportsVideo() | ||
233 | { | ||
234 | return false; | ||
235 | } | ||
236 | |||
237 | bool ModPlugin::supportsYUV() | ||
238 | { | ||
239 | return false; | ||
240 | } | ||
241 | |||
242 | bool ModPlugin::supportsMMX() | ||
243 | { | ||
244 | return false; | ||
245 | } | ||
246 | |||
247 | bool ModPlugin::supportsSMP() | ||
248 | { | ||
249 | return false; | ||
250 | } | ||
251 | |||
252 | bool ModPlugin::supportsStereo() | ||
253 | { | ||
254 | return true; | ||
255 | } | ||
256 | |||
257 | bool 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 | |||
28 | class ModPlugin : public MediaPlayerDecoder, | ||
29 | public CSoundFile | ||
30 | { | ||
31 | public: | ||
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 | |||
82 | private: | ||
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 | |||
23 | ModPluginImpl::ModPluginImpl() | ||
24 | :m_plugin( 0 ), ref( 0 ) | ||
25 | { | ||
26 | } | ||
27 | |||
28 | ModPluginImpl::~ModPluginImpl() | ||
29 | { | ||
30 | delete m_plugin; | ||
31 | } | ||
32 | |||
33 | #ifndef QT_NO_COMPONENT | ||
34 | |||
35 | QRESULT 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 | |||
43 | Q_EXPORT_INTERFACE() | ||
44 | { | ||
45 | Q_CREATE_INSTANCE( ModPluginImpl ) | ||
46 | } | ||
47 | |||
48 | #endif | ||
49 | |||
50 | MediaPlayerDecoder *ModPluginImpl::decoder() | ||
51 | { | ||
52 | if ( !m_plugin ) | ||
53 | m_plugin = new ModPlugin; | ||
54 | return m_plugin; | ||
55 | } | ||
56 | |||
57 | MediaPlayerEncoder *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 | |||
24 | class ModPlugin; | ||
25 | |||
26 | class ModPluginImpl : public MediaPlayerPluginInterface | ||
27 | { | ||
28 | public: | ||
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 | |||
41 | private: | ||
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 @@ | |||
1 | Files: plugins/codecs/libmodplugin.so* | ||
2 | Priority: optional | ||
3 | Section: opie/plugins | ||
4 | Maintainer: Simon Hausmann <hausmann@kde.org>, L.J. Potter <llornkcor@handhelds.org> | ||
5 | Architecture: arm | ||
6 | Version: 2.0.2 | ||
7 | Depends: opie-base opie-player | ||
8 | Description: 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 | |||
3 | OPIEDIR=/opt/QtPalmtop | ||
4 | MIMEFILE=$OPIEDIR/etc/mime.types | ||
5 | MEDIAPLAYER=$OPIEDIR/apps/Applications/opieplayer.desktop | ||
6 | MIMETYPE="audio/x-mod" | ||
7 | MIMELINE="$MIMETYPE669 amf apun dsm far gdm imf it med mod mtm nst s3m stm stx ult uni xm" | ||
8 | |||
9 | grep -q "$MIMELINE" $MIMEFILE | ||
10 | if [ $? != 0 ]; then | ||
11 | echo "appending mod/s3m/etc to $MIMEFILE" | ||
12 | |||
13 | echo "$MIMELINE" >> $MIMEFILE | ||
14 | fi | ||
15 | |||
16 | grep -q "$MIMETYPE" $MEDIAPLAYER | ||
17 | if [ $? != 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 | ||
23 | fi | ||
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 | |||
3 | QPEDIR=/opt/QtPalmtop | ||
4 | MIMEFILE=$OPIEDIR/etc/mime.types | ||
5 | MEDIAPLAYER=$OPIEDIR/apps/Applications/opieplayer.desktop | ||
6 | MIMETYPE="audio/x-mod" | ||
7 | MIMELINE="$MIMETYPE669 amf apun dsm far gdm imf it med mod mtm nst s3m stm stx ult uni xm" | ||
8 | |||
9 | tmpfile=/tmp/qpe-modplugin$$.tmp | ||
10 | |||
11 | grep -q "$MIMELINE" $MIMEFILE | ||
12 | if [ $? == 0 ]; then | ||
13 | echo "removing mod/s3m/etc from $MIMEFILE" | ||
14 | |||
15 | grep -v "$MIMELINE" $MIMEFILE > $tmpfile | ||
16 | mv $tmpfile $MIMEFILE | ||
17 | fi | ||
18 | |||
19 | grep -q "$MIMETYPE" $MEDIAPLAYER | ||
20 | if [ $? == 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 | ||
25 | fi | ||
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 | ||
43 | UINT CSoundFile::m_nXBassDepth = 6; | ||
44 | UINT CSoundFile::m_nXBassRange = XBASS_DELAY; | ||
45 | UINT CSoundFile::m_nReverbDepth = 1; | ||
46 | UINT CSoundFile::m_nReverbDelay = 100; | ||
47 | UINT CSoundFile::m_nProLogicDepth = 12; | ||
48 | UINT CSoundFile::m_nProLogicDelay = 20; | ||
49 | |||
50 | //////////////////////////////////////////////////////////////////// | ||
51 | // DSP Effects internal state | ||
52 | |||
53 | // Bass Expansion: low-pass filter | ||
54 | static LONG nXBassSum = 0; | ||
55 | static LONG nXBassBufferPos = 0; | ||
56 | static LONG nXBassDlyPos = 0; | ||
57 | static LONG nXBassMask = 0; | ||
58 | |||
59 | // Noise Reduction: simple low-pass filter | ||
60 | static LONG nLeftNR = 0; | ||
61 | static LONG nRightNR = 0; | ||
62 | |||
63 | // Surround Encoding: 1 delay line + low-pass filter + high-pass filter | ||
64 | static LONG nSurroundSize = 0; | ||
65 | static LONG nSurroundPos = 0; | ||
66 | static LONG nDolbyDepth = 0; | ||
67 | static LONG nDolbyLoDlyPos = 0; | ||
68 | static LONG nDolbyLoFltPos = 0; | ||
69 | static LONG nDolbyLoFltSum = 0; | ||
70 | static LONG nDolbyHiFltPos = 0; | ||
71 | static LONG nDolbyHiFltSum = 0; | ||
72 | |||
73 | // Reverb: 4 delay lines + high-pass filter + low-pass filter | ||
74 | #ifndef NO_REVERB | ||
75 | static LONG nReverbSize = 0; | ||
76 | static LONG nReverbBufferPos = 0; | ||
77 | static LONG nReverbSize2 = 0; | ||
78 | static LONG nReverbBufferPos2 = 0; | ||
79 | static LONG nReverbSize3 = 0; | ||
80 | static LONG nReverbBufferPos3 = 0; | ||
81 | static LONG nReverbSize4 = 0; | ||
82 | static LONG nReverbBufferPos4 = 0; | ||
83 | static LONG nReverbLoFltSum = 0; | ||
84 | static LONG nReverbLoFltPos = 0; | ||
85 | static LONG nReverbLoDlyPos = 0; | ||
86 | static LONG nFilterAttn = 0; | ||
87 | static LONG gRvbLowPass[8]; | ||
88 | static LONG gRvbLPPos = 0; | ||
89 | static LONG gRvbLPSum = 0; | ||
90 | static LONG ReverbLoFilterBuffer[XBASSBUFFERSIZE]; | ||
91 | static LONG ReverbLoFilterDelay[XBASSBUFFERSIZE]; | ||
92 | static LONG ReverbBuffer[REVERBBUFFERSIZE]; | ||
93 | static LONG ReverbBuffer2[REVERBBUFFERSIZE2]; | ||
94 | static LONG ReverbBuffer3[REVERBBUFFERSIZE3]; | ||
95 | static LONG ReverbBuffer4[REVERBBUFFERSIZE4]; | ||
96 | #endif | ||
97 | static LONG XBassBuffer[XBASSBUFFERSIZE]; | ||
98 | static LONG XBassDelay[XBASSBUFFERSIZE]; | ||
99 | static LONG DolbyLoFilterBuffer[XBASSBUFFERSIZE]; | ||
100 | static LONG DolbyLoFilterDelay[XBASSBUFFERSIZE]; | ||
101 | static LONG DolbyHiFilterBuffer[FILTERBUFFERSIZE]; | ||
102 | static LONG SurroundBuffer[SURROUNDBUFFERSIZE]; | ||
103 | |||
104 | // Access the main temporary mix buffer directly: avoids an extra pointer | ||
105 | extern int MixSoundBuffer[MIXBUFFERSIZE*2]; | ||
106 | //cextern int MixReverbBuffer[MIXBUFFERSIZE*2]; | ||
107 | extern int MixReverbBuffer[MIXBUFFERSIZE*2]; | ||
108 | |||
109 | static UINT GetMaskFromSize(UINT len) | ||
110 | //----------------------------------- | ||
111 | { | ||
112 | UINT n = 2; | ||
113 | while (n <= len) n <<= 1; | ||
114 | return ((n >> 1) - 1); | ||
115 | } | ||
116 | |||
117 | |||
118 | void 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 | |||
203 | void 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 | |||
340 | void 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] | ||
430 | BOOL 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] | ||
445 | BOOL 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] | ||
461 | BOOL 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 | |||
474 | BOOL 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)) | ||
26 | static 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 | |||
56 | DWORD 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 | ||
74 | void 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 | ||
18 | extern const BYTE ImpulseTrackerPortaVolCmd[16]; | ||
19 | extern const WORD S3MFineTuneTable[16]; | ||
20 | extern const WORD ProTrackerPeriodTable[6*12]; | ||
21 | extern const WORD ProTrackerTunedPeriods[15*12]; | ||
22 | extern const WORD FreqS3MTable[]; | ||
23 | extern const WORD XMPeriodTable[96+8]; | ||
24 | extern const UINT XMLinearTable[768]; | ||
25 | extern const DWORD FineLinearSlideUpTable[16]; | ||
26 | extern const DWORD FineLinearSlideDownTable[16]; | ||
27 | extern const DWORD LinearSlideUpTable[256]; | ||
28 | extern const DWORD LinearSlideDownTable[256]; | ||
29 | extern const signed char retrigTable1[16]; | ||
30 | extern const signed char retrigTable2[16]; | ||
31 | extern const short int ModRandomTable[64]; | ||
32 | |||
33 | |||
34 | //////////////////////////////////////////////////////////// | ||
35 | // Length | ||
36 | |||
37 | DWORD 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 | } | ||
274 | EndMod: | ||
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 | |||
298 | void 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 | |||
427 | void 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 | |||
578 | UINT 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 | |||
611 | void 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 | |||
744 | BOOL 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 | |||
1269 | void 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 | |||
1296 | void 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 | |||
1319 | void 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 | |||
1343 | void 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 | |||
1367 | void 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 | |||
1391 | void 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 | ||
1416 | void 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 | |||
1453 | void 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 | |||
1462 | void 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 | |||
1471 | void 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 | |||
1480 | void 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 | |||
1528 | void 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 | |||
1575 | void 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 | |||
1588 | void 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 | |||
1601 | void 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 | |||
1610 | void 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 | |||
1640 | void 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 | |||
1687 | void 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 | |||
1771 | void 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 | |||
1827 | void 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 | |||
1926 | void 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 | |||
1987 | void 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 | |||
2022 | void 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 | |||
2035 | void 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 | |||
2080 | void 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 | |||
2102 | void 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 | |||
2124 | int 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 | |||
2152 | void 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 | |||
2183 | DWORD 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 | |||
2222 | BOOL 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 | |||
2271 | UINT 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 | |||
2305 | UINT 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 | |||
2367 | UINT 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 | ||
18 | extern BOOL MMCMP_Unpack(LPCBYTE *ppMemFile, LPDWORD pdwMemLength); | ||
19 | #endif | ||
20 | |||
21 | // External decompressors | ||
22 | extern void AMSUnpack(const char *psrc, UINT inputlen, char *pdest, UINT dmax, char packcharacter); | ||
23 | extern WORD MDLReadBits(DWORD &bitbuf, UINT &bitnum, LPBYTE &ibuf, CHAR n); | ||
24 | extern int DMFUnpack(LPBYTE psample, LPBYTE ibuf, LPBYTE ibufmax, UINT maxlen); | ||
25 | extern DWORD ITReadBits(DWORD &bitbuf, UINT &bitnum, LPBYTE &ibuf, CHAR n); | ||
26 | extern void ITUnpack8Bit(signed char *pSample, DWORD dwLen, LPBYTE lpMemFile, DWORD dwMemLength, BOOL b215); | ||
27 | extern 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 | ||
34 | static 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 | |||
51 | CSoundFile::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 | |||
80 | CSoundFile::~CSoundFile() | ||
81 | //----------------------- | ||
82 | { | ||
83 | Destroy(); | ||
84 | } | ||
85 | |||
86 | |||
87 | BOOL 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 | |||
273 | BOOL 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 | |||
335 | MODCOMMAND *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 | |||
344 | void CSoundFile::FreePattern(LPVOID pat) | ||
345 | //-------------------------------------- | ||
346 | { | ||
347 | if (pat) delete [] (signed char*)pat; | ||
348 | } | ||
349 | |||
350 | |||
351 | signed 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 | |||
360 | void CSoundFile::FreeSample(LPVOID p) | ||
361 | //----------------------------------- | ||
362 | { | ||
363 | if (p) | ||
364 | { | ||
365 | GlobalFreePtr(((LPSTR)p)-16); | ||
366 | } | ||
367 | } | ||
368 | |||
369 | |||
370 | ////////////////////////////////////////////////////////////////////////// | ||
371 | // Misc functions | ||
372 | |||
373 | void 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 | |||
387 | UINT 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 | |||
396 | UINT 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 | |||
417 | UINT 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 | |||
466 | BOOL 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 | |||
482 | BOOL 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 | |||
500 | BOOL 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 | |||
515 | void 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 | |||
529 | UINT CSoundFile::GetNumPatterns() const | ||
530 | //------------------------------------- | ||
531 | { | ||
532 | UINT i = 0; | ||
533 | while ((i < MAX_ORDERS) && (Order[i] < 0xFF)) i++; | ||
534 | return i; | ||
535 | } | ||
536 | |||
537 | |||
538 | UINT 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 | |||
547 | UINT 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 | |||
562 | UINT 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 | |||
573 | void 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 | |||
676 | void 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 | |||
709 | void 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 | |||
721 | void 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 | |||
741 | UINT 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 | |||
756 | UINT 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 | |||
776 | UINT 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 | |||
787 | UINT 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 | ||
805 | UINT 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 | |||
822 | BOOL 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 | |||
866 | UINT 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 | |||
1078 | UINT 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 | |||
1530 | void 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)) | ||
1624 | DWORD 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) | ||
1664 | int 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 | |||
1689 | void 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 | |||
1707 | void 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 | |||
1737 | BOOL 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 | |||
1766 | BOOL 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 | |||
1784 | UINT 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 | |||
1836 | BOOL 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 | |||
1852 | BOOL 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 | ||
19 | typedef 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) | ||
279 | enum { | ||
280 | REVERBTYPE_SMALLROOM, | ||
281 | REVERBTYPE_MEDIUMROOM, | ||
282 | REVERBTYPE_LARGEROOM, | ||
283 | REVERBTYPE_SMALLHALL, | ||
284 | REVERBTYPE_MEDIUMHALL, | ||
285 | REVERBTYPE_LARGEHALL, | ||
286 | NUM_REVERBTYPES | ||
287 | }; | ||
288 | |||
289 | |||
290 | enum { | ||
291 | SRCMODE_NEAREST, | ||
292 | SRCMODE_LINEAR, | ||
293 | SRCMODE_SPLINE, | ||
294 | SRCMODE_POLYPHASE, | ||
295 | NUM_SRC_MODES | ||
296 | }; | ||
297 | |||
298 | |||
299 | // Sample Struct | ||
300 | typedef 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 | ||
321 | typedef 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 | ||
370 | typedef 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 | |||
431 | typedef 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 | |||
441 | typedef 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 | |||
455 | class IMixPlugin | ||
456 | { | ||
457 | public: | ||
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 | |||
473 | typedef 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 | |||
482 | typedef 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 | |||
493 | typedef 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 | |||
506 | enum { | ||
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 | |||
519 | typedef 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 | |||
527 | typedef VOID (__cdecl * LPSNDMIXHOOKPROC)(int *, unsigned long, unsigned long); // buffer, samples, channels | ||
528 | |||
529 | |||
530 | |||
531 | //============== | ||
532 | class 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 | |||
576 | public: | ||
577 | CSoundFile(); | ||
578 | ~CSoundFile(); | ||
579 | |||
580 | public: | ||
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 | |||
655 | public: | ||
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 | |||
666 | public: | ||
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); | ||
694 | public: | ||
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 | ||
768 | public: | ||
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 | ||
774 | public: | ||
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 | |||
820 | typedef struct WAVEFILEHEADER | ||
821 | { | ||
822 | DWORD id_RIFF; // "RIFF" | ||
823 | DWORD filesize; // file length-8 | ||
824 | DWORD id_WAVE; | ||
825 | } WAVEFILEHEADER; | ||
826 | |||
827 | |||
828 | typedef 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 | |||
841 | typedef struct WAVEDATAHEADER | ||
842 | { | ||
843 | DWORD id_data; // "data" | ||
844 | DWORD length; // length of data | ||
845 | } WAVEDATAHEADER; | ||
846 | |||
847 | |||
848 | typedef 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 | |||
865 | typedef 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 | |||
876 | typedef struct WAVESAMPLERINFO | ||
877 | { | ||
878 | WAVESMPLHEADER wsiHdr; | ||
879 | SAMPLELOOPSTRUCT wsiLoops[2]; | ||
880 | } WAVESAMPLERINFO; | ||
881 | |||
882 | |||
883 | typedef struct WAVELISTHEADER | ||
884 | { | ||
885 | DWORD list_id;// "LIST" -> 0x5453494C | ||
886 | DWORD list_len; | ||
887 | DWORD info; // "INFO" | ||
888 | } WAVELISTHEADER; | ||
889 | |||
890 | |||
891 | typedef 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 | |||
933 | int _muldiv(long a, long b, long c); | ||
934 | int _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 | ||
946 | static __inline unsigned short int | ||
947 | bswap_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 | ||
961 | static __inline unsigned int | ||
962 | bswap_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 | ||
24 | UINT CSoundFile::m_nStereoSeparation = 128; | ||
25 | LONG CSoundFile::m_nStreamVolume = 0x8000; | ||
26 | UINT CSoundFile::m_nMaxMixChannels = 32; | ||
27 | // Mixing Configuration (SetWaveConfig) | ||
28 | DWORD CSoundFile::gdwSysInfo = 0; | ||
29 | DWORD CSoundFile::gnChannels = 1; | ||
30 | DWORD CSoundFile::gdwSoundSetup = 0; | ||
31 | DWORD CSoundFile::gdwMixingFreq = 44100; | ||
32 | DWORD CSoundFile::gnBitsPerSample = 16; | ||
33 | // Mixing data initialized in | ||
34 | UINT CSoundFile::gnAGC = AGC_UNITY; | ||
35 | UINT CSoundFile::gnVolumeRampSamples = 64; | ||
36 | UINT CSoundFile::gnVUMeter = 0; | ||
37 | UINT CSoundFile::gnCPUUsage = 0; | ||
38 | LPSNDMIXHOOKPROC CSoundFile::gpSndMixHook = NULL; | ||
39 | PMIXPLUGINCREATEPROC CSoundFile::gpMixPluginCreateProc = NULL; | ||
40 | LONG gnDryROfsVol = 0; | ||
41 | LONG gnDryLOfsVol = 0; | ||
42 | LONG gnRvbROfsVol = 0; | ||
43 | LONG gnRvbLOfsVol = 0; | ||
44 | int gbInitPlugins = 0; | ||
45 | |||
46 | typedef DWORD (MPPASMCALL * LPCONVERTPROC)(LPVOID, int *, DWORD, LPLONG, LPLONG); | ||
47 | |||
48 | extern DWORD MPPASMCALL X86_Convert32To8(LPVOID lpBuffer, int *, DWORD nSamples, LPLONG, LPLONG); | ||
49 | extern DWORD MPPASMCALL X86_Convert32To16(LPVOID lpBuffer, int *, DWORD nSamples, LPLONG, LPLONG); | ||
50 | extern DWORD MPPASMCALL X86_Convert32To24(LPVOID lpBuffer, int *, DWORD nSamples, LPLONG, LPLONG); | ||
51 | extern DWORD MPPASMCALL X86_Convert32To32(LPVOID lpBuffer, int *, DWORD nSamples, LPLONG, LPLONG); | ||
52 | extern UINT MPPASMCALL X86_AGC(int *pBuffer, UINT nSamples, UINT nAGC); | ||
53 | extern VOID MPPASMCALL X86_Dither(int *pBuffer, UINT nSamples, UINT nBits); | ||
54 | extern VOID MPPASMCALL X86_InterleaveFrontRear(int *pFrontBuf, int *pRearBuf, DWORD nSamples); | ||
55 | extern VOID MPPASMCALL X86_StereoFill(int *pBuffer, UINT nSamples, LPLONG lpROfs, LPLONG lpLOfs); | ||
56 | extern VOID MPPASMCALL X86_MonoFromStereo(int *pMixBuf, UINT nSamples); | ||
57 | |||
58 | extern const short int ModSinusTable[64]; | ||
59 | extern const short int ModRampDownTable[64]; | ||
60 | extern const short int ModSquareTable[64]; | ||
61 | extern const short int ModRandomTable[64]; | ||
62 | extern const DWORD LinearSlideUpTable[256]; | ||
63 | extern const DWORD LinearSlideDownTable[256]; | ||
64 | extern const DWORD FineLinearSlideUpTable[16]; | ||
65 | extern const DWORD FineLinearSlideDownTable[16]; | ||
66 | extern const signed char ft2VibratoTable[256];// -64 .. +64 | ||
67 | extern int MixSoundBuffer[MIXBUFFERSIZE*4]; | ||
68 | extern int MixRearBuffer[MIXBUFFERSIZE*2]; | ||
69 | UINT gnReverbSend; | ||
70 | |||
71 | |||
72 | // Log tables for pre-amp | ||
73 | // We don't want the tracker to get too loud | ||
74 | const 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 | |||
82 | const 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 | ||
92 | int _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 | ||
103 | aneg: | ||
104 | xor edx, ebx | ||
105 | or ebx, ebx | ||
106 | mov ecx, c | ||
107 | jge bneg | ||
108 | neg ebx | ||
109 | bneg: | ||
110 | xor edx, ecx | ||
111 | or ecx, ecx | ||
112 | mov sign, edx | ||
113 | jge cneg | ||
114 | neg ecx | ||
115 | cneg: | ||
116 | mul ebx | ||
117 | cmp edx, ecx | ||
118 | jae diverr | ||
119 | div ecx | ||
120 | jmp ok | ||
121 | diverr: | ||
122 | mov eax, 0x7fffffff | ||
123 | ok: | ||
124 | mov edx, sign | ||
125 | or edx, edx | ||
126 | jge rneg | ||
127 | neg eax | ||
128 | rneg: | ||
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 | ||
139 | int _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 | ||
150 | aneg: | ||
151 | xor edx, ebx | ||
152 | or ebx, ebx | ||
153 | mov ecx, c | ||
154 | jge bneg | ||
155 | neg ebx | ||
156 | bneg: | ||
157 | xor edx, ecx | ||
158 | or ecx, ecx | ||
159 | mov sign, edx | ||
160 | jge cneg | ||
161 | neg ecx | ||
162 | cneg: | ||
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 | ||
172 | diverr: | ||
173 | mov eax, 0x7fffffff | ||
174 | ok: | ||
175 | mov edx, sign | ||
176 | or edx, edx | ||
177 | jge rneg | ||
178 | neg eax | ||
179 | rneg: | ||
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 | |||
189 | BOOL 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 | |||
210 | BOOL 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 | |||
236 | BOOL 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 | |||
247 | UINT 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 | } | ||
342 | MixDone: | ||
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 | |||
358 | BOOL 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 | |||
473 | BOOL 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 | |||
26 | inline void ProcessPlugins(int n) {} | ||
27 | |||
28 | #else | ||
29 | #include <stdlib.h> | ||
30 | #include <stdio.h> | ||
31 | #include <string.h> | ||
32 | |||
33 | typedef signed char CHAR; | ||
34 | typedef unsigned char UCHAR; | ||
35 | typedef unsigned char* PUCHAR; | ||
36 | typedef unsigned short USHORT; | ||
37 | typedef unsigned long ULONG; | ||
38 | typedef unsigned long UINT; | ||
39 | typedef unsigned long DWORD; | ||
40 | typedef long LONG; | ||
41 | typedef unsigned short WORD; | ||
42 | typedef unsigned char BYTE; | ||
43 | typedef unsigned char * LPBYTE; | ||
44 | typedef bool BOOL; | ||
45 | typedef char * LPSTR; | ||
46 | typedef void * LPVOID; | ||
47 | typedef long * LPLONG; | ||
48 | typedef unsigned long * LPDWORD; | ||
49 | typedef unsigned short * LPWORD; | ||
50 | typedef const char * LPCSTR; | ||
51 | typedef long long LONGLONG; | ||
52 | typedef void * PVOID; | ||
53 | |||
54 | |||
55 | inline 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 | |||
77 | inline 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 | |||
85 | inline 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 | |||
17 | extern const BYTE ImpulseTrackerPortaVolCmd[16]; | ||
18 | const 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: | ||
25 | extern const WORD ProTrackerPeriodTable[6*12]; | ||
26 | const 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 | |||
37 | extern const WORD ProTrackerTunedPeriods[16*12]; | ||
38 | const 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 | ||
60 | extern const WORD FreqS3MTable[16]; | ||
61 | const 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 | ||
70 | extern const WORD S3MFineTuneTable[16]; | ||
71 | const 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 | ||
79 | extern const short int ModSinusTable[64]; | ||
80 | const 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) | ||
89 | extern const short int ModRampDownTable[64]; | ||
90 | const 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 | ||
99 | extern const short int ModSquareTable[64]; | ||
100 | const 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 | ||
109 | extern const short int ModRandomTable[64]; | ||
110 | const 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: | ||
120 | extern const signed char retrigTable1[16]; | ||
121 | const signed char retrigTable1[16] = | ||
122 | { 0, 0, 0, 0, 0, 0, 10, 8, 0, 0, 0, 0, 0, 0, 24, 32 }; | ||
123 | |||
124 | extern const signed char retrigTable2[16]; | ||
125 | const 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 | |||
131 | extern const WORD XMPeriodTable[104]; | ||
132 | const 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 | |||
144 | extern const UINT XMLinearTable[768]; | ||
145 | const 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 | |||
247 | extern const signed char ft2VibratoTable[256]; | ||
248 | const 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 | |||
270 | extern const DWORD FineLinearSlideUpTable[16]; | ||
271 | const 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 | |||
278 | extern const DWORD FineLinearSlideDownTable[16]; | ||
279 | const 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 | |||
286 | extern const DWORD LinearSlideUpTable[256]; | ||
287 | const 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 | |||
324 | extern const DWORD LinearSlideDownTable[256]; | ||
325 | const 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 | |||
363 | extern const int SpectrumSinusTable[256*2]; | ||
364 | const 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 | |||