1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 /*
23  * VGMTrans (c) 2002-2019
24  * Licensed under the zlib license,
25  * refer to the included VGMTrans_LICENSE.txt file
26  */
27 #ifndef AUDIO_SOUNDFONT_PSXSPU_H
28 #define AUDIO_SOUNDFONT_PSXSPU_H
29 
30 #include "audio/soundfont/common.h"
31 #include "common/str.h"
32 #include "audio/soundfont/vgminstrset.h"
33 #include "audio/soundfont/vgmsamp.h"
34 #include "audio/soundfont/vgmitem.h"
35 
36 // All of the ADSR calculations herein (except where inaccurate) are derived from Neill Corlett's
37 // work in reverse-engineering the Playstation 1/2 SPU unit.
38 
39 //**************************************************************************************************
40 // Type Redefinitions
41 
42 typedef void v0;
43 
44 #ifdef __cplusplus
45 #if defined __BORLANDC__
46 typedef bool b8;
47 #else
48 typedef unsigned char b8;
49 #endif
50 #else
51 typedef char b8;
52 #endif
53 
54 typedef float f32;
55 //***********************************************************************************************
56 
57 static unsigned long RateTable[160];
58 static bool bRateTableInitialized = 0;
59 
60 // VAG format -----------------------------------
61 
62 // Sample Block
63 typedef struct _VAGBlk {
64 	uint8 range;
65 	uint8 filter;
66 
67 	struct {
68 		b8 end: 1;      // End block
69 		b8 looping: 1;  // VAG loops
70 		b8 loop: 1;     // Loop start point
71 	} flag;
72 
73 	int8 brr[14];  // Compressed samples
74 } VAGBlk;
75 
76 double LinAmpDecayTimeToLinDBDecayTime(double secondsToFullAtten, int linearVolumeRange);
77 
78 // InitADSR is shamelessly ripped from P.E.Op.S
InitADSR()79 static inline void InitADSR() {
80 	unsigned long r, rs, rd;
81 	int i;
82 
83 	// build the rate table according to Neill's rules
84 	memset(RateTable, 0, sizeof(unsigned long) * 160);
85 
86 	r = 3;
87 	rs = 1;
88 	rd = 0;
89 
90 	// we start at pos 32 with the real values... everything before is 0
91 	for (i = 32; i < 160; i++) {
92 		if (r < 0x3FFFFFFF) {
93 			r += rs;
94 			rd++;
95 			if (rd == 5) {
96 				rd = 1;
97 				rs *= 2;
98 			}
99 		}
100 		if (r > 0x3FFFFFFF)
101 			r = 0x3FFFFFFF;
102 
103 		RateTable[i] = r;
104 	}
105 }
106 
RoundToZero(int val)107 inline int RoundToZero(int val) {
108 	if (val < 0)
109 		val = 0;
110 	return val;
111 }
112 
113 template<class T>
PSXConvADSR(T * realADSR,unsigned short ADSR1,unsigned short ADSR2,bool bPS2)114 void PSXConvADSR(T *realADSR, unsigned short ADSR1, unsigned short ADSR2, bool bPS2) {
115 	uint8 Am = (ADSR1 & 0x8000) >> 15;  // if 1, then Exponential, else linear
116 	uint8 Ar = (ADSR1 & 0x7F00) >> 8;
117 	uint8 Dr = (ADSR1 & 0x00F0) >> 4;
118 	uint8 Sl = ADSR1 & 0x000F;
119 	uint8 Rm = (ADSR2 & 0x0020) >> 5;
120 	uint8 Rr = ADSR2 & 0x001F;
121 
122 	// The following are unimplemented in conversion (because DLS and SF2 do not support Sustain
123 	// Rate)
124 	uint8 Sm = (ADSR2 & 0x8000) >> 15;
125 	uint8 Sd = (ADSR2 & 0x4000) >> 14;
126 	uint8 Sr = (ADSR2 >> 6) & 0x7F;
127 
128 	PSXConvADSR(realADSR, Am, Ar, Dr, Sl, Sm, Sd, Sr, Rm, Rr, bPS2);
129 }
130 
131 template<class T>
PSXConvADSR(T * realADSR,uint8 Am,uint8 Ar,uint8 Dr,uint8 Sl,uint8 Sm,uint8 Sd,uint8 Sr,uint8 Rm,uint8 Rr,bool bPS2)132 void PSXConvADSR(T *realADSR, uint8 Am, uint8 Ar, uint8 Dr, uint8 Sl, uint8 Sm,
133 				 uint8 Sd, uint8 Sr, uint8 Rm, uint8 Rr, bool bPS2) {
134 	// Make sure all the ADSR values are within the valid ranges
135 	if (((Am & ~0x01) != 0) || ((Ar & ~0x7F) != 0) || ((Dr & ~0x0F) != 0) || ((Sl & ~0x0F) != 0) ||
136 		((Rm & ~0x01) != 0) || ((Rr & ~0x1F) != 0) || ((Sm & ~0x01) != 0) || ((Sd & ~0x01) != 0) ||
137 		((Sr & ~0x7F) != 0)) {
138 		error("ADSR parameter(s) out of range");
139 	}
140 
141 	// PS1 games use 44k, PS2 uses 48k
142 	double sampleRate = bPS2 ? 48000 : 44100;
143 
144 	long envelope_level;
145 	double samples = 0.0;
146 	unsigned long rate;
147 	unsigned long remainder;
148 	double timeInSecs;
149 	int l;
150 
151 	if (!bRateTableInitialized) {
152 		InitADSR();
153 		bRateTableInitialized = true;
154 	}
155 
156 	// to get the dls 32 bit time cents, take log base 2 of number of seconds * 1200 * 65536
157 	// (dls1v11a.pdf p25).
158 
159 	//	if (RateTable[(Ar^0x7F)-0x10 + 32] == 0)
160 	//		realADSR->attack_time = 0;
161 	//	else
162 	//	{
163 	if ((Ar ^ 0x7F) < 0x10)
164 		Ar = 0;
165 	// if linear Ar Mode
166 	if (Am == 0) {
167 		rate = RateTable[RoundToZero((Ar ^ 0x7F) - 0x10) + 32];
168 		samples = ceil(0x7FFFFFFF / (double) rate);
169 	} else if (Am == 1) {
170 		rate = RateTable[RoundToZero((Ar ^ 0x7F) - 0x10) + 32];
171 		samples = (unsigned long)(0x60000000 / rate);
172 		remainder = 0x60000000 % rate;
173 		rate = RateTable[RoundToZero((Ar ^ 0x7F) - 0x18) + 32];
174 		samples += ceil(fmax(0, 0x1FFFFFFF - (long) remainder) / (double) rate);
175 	}
176 	timeInSecs = samples / sampleRate;
177 	realADSR->_attack_time = timeInSecs;
178 	//	}
179 
180 	// Decay Time
181 
182 	envelope_level = 0x7FFFFFFF;
183 
184 	bool bSustainLevFound = false;
185 	uint32 realSustainLevel = 0x7FFFFFFF;
186 	// DLS decay rate value is to -96db (silence) not the sustain level
187 	for (l = 0; envelope_level > 0; l++) {
188 		if (4 * (Dr ^ 0x1F) < 0x18)
189 			Dr = 0;
190 		switch ((envelope_level >> 28) & 0x7) {
191 		case 0:
192 			envelope_level -= RateTable[RoundToZero((4 * (Dr ^ 0x1F)) - 0x18 + 0) + 32];
193 			break;
194 		case 1:
195 			envelope_level -= RateTable[RoundToZero((4 * (Dr ^ 0x1F)) - 0x18 + 4) + 32];
196 			break;
197 		case 2:
198 			envelope_level -= RateTable[RoundToZero((4 * (Dr ^ 0x1F)) - 0x18 + 6) + 32];
199 			break;
200 		case 3:
201 			envelope_level -= RateTable[RoundToZero((4 * (Dr ^ 0x1F)) - 0x18 + 8) + 32];
202 			break;
203 		case 4:
204 			envelope_level -= RateTable[RoundToZero((4 * (Dr ^ 0x1F)) - 0x18 + 9) + 32];
205 			break;
206 		case 5:
207 			envelope_level -= RateTable[RoundToZero((4 * (Dr ^ 0x1F)) - 0x18 + 10) + 32];
208 			break;
209 		case 6:
210 			envelope_level -= RateTable[RoundToZero((4 * (Dr ^ 0x1F)) - 0x18 + 11) + 32];
211 			break;
212 		case 7:
213 			envelope_level -= RateTable[RoundToZero((4 * (Dr ^ 0x1F)) - 0x18 + 12) + 32];
214 			break;
215 		}
216 		if (!bSustainLevFound && ((envelope_level >> 27) & 0xF) <= Sl) {
217 			realSustainLevel = envelope_level;
218 			bSustainLevFound = true;
219 		}
220 	}
221 	samples = l;
222 	timeInSecs = samples / sampleRate;
223 	realADSR->_decay_time = timeInSecs;
224 
225 	// Sustain Rate
226 
227 	envelope_level = 0x7FFFFFFF;
228 	// increasing... we won't even bother
229 	if (Sd == 0) {
230 		realADSR->_sustain_time = -1;
231 	} else {
232 		if (Sr == 0x7F)
233 			realADSR->_sustain_time = -1;  // this is actually infinite
234 		else {
235 			// linear
236 			if (Sm == 0) {
237 				rate = RateTable[RoundToZero((Sr ^ 0x7F) - 0x0F) + 32];
238 				samples = ceil(0x7FFFFFFF / (double) rate);
239 			} else {
240 				l = 0;
241 				// DLS decay rate value is to -96db (silence) not the sustain level
242 				while (envelope_level > 0) {
243 					long envelope_level_diff;
244 					long envelope_level_target;
245 
246 					switch ((envelope_level >> 28) & 0x7) {
247 					case 0:
248 					default:
249 						envelope_level_target = 0x00000000;
250 						envelope_level_diff =
251 								RateTable[RoundToZero((Sr ^ 0x7F) - 0x1B + 0) + 32];
252 						break;
253 					case 1:
254 						envelope_level_target = 0x0fffffff;
255 						envelope_level_diff =
256 								RateTable[RoundToZero((Sr ^ 0x7F) - 0x1B + 4) + 32];
257 						break;
258 					case 2:
259 						envelope_level_target = 0x1fffffff;
260 						envelope_level_diff =
261 								RateTable[RoundToZero((Sr ^ 0x7F) - 0x1B + 6) + 32];
262 						break;
263 					case 3:
264 						envelope_level_target = 0x2fffffff;
265 						envelope_level_diff =
266 								RateTable[RoundToZero((Sr ^ 0x7F) - 0x1B + 8) + 32];
267 						break;
268 					case 4:
269 						envelope_level_target = 0x3fffffff;
270 						envelope_level_diff =
271 								RateTable[RoundToZero((Sr ^ 0x7F) - 0x1B + 9) + 32];
272 						break;
273 					case 5:
274 						envelope_level_target = 0x4fffffff;
275 						envelope_level_diff =
276 								RateTable[RoundToZero((Sr ^ 0x7F) - 0x1B + 10) + 32];
277 						break;
278 					case 6:
279 						envelope_level_target = 0x5fffffff;
280 						envelope_level_diff =
281 								RateTable[RoundToZero((Sr ^ 0x7F) - 0x1B + 11) + 32];
282 						break;
283 					case 7:
284 						envelope_level_target = 0x6fffffff;
285 						envelope_level_diff =
286 								RateTable[RoundToZero((Sr ^ 0x7F) - 0x1B + 12) + 32];
287 						break;
288 					}
289 
290 					long steps =
291 							(envelope_level - envelope_level_target + (envelope_level_diff - 1)) /
292 							envelope_level_diff;
293 					envelope_level -= (envelope_level_diff * steps);
294 					l += steps;
295 				}
296 				samples = l;
297 			}
298 			timeInSecs = samples / sampleRate;
299 			realADSR->_sustain_time =
300 					/*Sm ? timeInSecs : */ LinAmpDecayTimeToLinDBDecayTime(timeInSecs, 0x800);
301 		}
302 	}
303 
304 	// Sustain Level
305 	// realADSR->sustain_level =
306 	// (double)envelope_level/(double)0x7FFFFFFF;//(long)ceil((double)envelope_level *
307 	// 0.030517578139210854);	//in DLS, sustain level is measured as a percentage
308 	if (Sl == 0)
309 		realSustainLevel = 0x07FFFFFF;
310 	realADSR->_sustain_level = realSustainLevel / (double) 0x7FFFFFFF;
311 
312 	// If decay is going unused, and there's a sustain rate with sustain level close to max...
313 	//  we'll put the sustain_rate in place of the decay rate.
314 	if ((realADSR->_decay_time < 2 || (Dr == 0x0F && Sl >= 0x0C)) && Sr < 0x7E && Sd == 1) {
315 		realADSR->_sustain_level = 0;
316 		realADSR->_decay_time = realADSR->_sustain_time;
317 		// realADSR->decay_time = 0.5;
318 	}
319 
320 	// Release Time
321 
322 	// sustain_envelope_level = envelope_level;
323 
324 	// We do this because we measure release time from max volume to 0, not from sustain level to 0
325 	envelope_level = 0x7FFFFFFF;
326 
327 	// if linear Rr Mode
328 	if (Rm == 0) {
329 		rate = RateTable[RoundToZero((4 * (Rr ^ 0x1F)) - 0x0C) + 32];
330 
331 		if (rate != 0)
332 			samples = ceil((double) envelope_level / (double) rate);
333 		else
334 			samples = 0;
335 	} else if (Rm == 1) {
336 		if ((Rr ^ 0x1F) * 4 < 0x18)
337 			Rr = 0;
338 		for (l = 0; envelope_level > 0; l++) {
339 			switch ((envelope_level >> 28) & 0x7) {
340 			case 0:
341 				envelope_level -= RateTable[RoundToZero((4 * (Rr ^ 0x1F)) - 0x18 + 0) + 32];
342 				break;
343 			case 1:
344 				envelope_level -= RateTable[RoundToZero((4 * (Rr ^ 0x1F)) - 0x18 + 4) + 32];
345 				break;
346 			case 2:
347 				envelope_level -= RateTable[RoundToZero((4 * (Rr ^ 0x1F)) - 0x18 + 6) + 32];
348 				break;
349 			case 3:
350 				envelope_level -= RateTable[RoundToZero((4 * (Rr ^ 0x1F)) - 0x18 + 8) + 32];
351 				break;
352 			case 4:
353 				envelope_level -= RateTable[RoundToZero((4 * (Rr ^ 0x1F)) - 0x18 + 9) + 32];
354 				break;
355 			case 5:
356 				envelope_level -= RateTable[RoundToZero((4 * (Rr ^ 0x1F)) - 0x18 + 10) + 32];
357 				break;
358 			case 6:
359 				envelope_level -= RateTable[RoundToZero((4 * (Rr ^ 0x1F)) - 0x18 + 11) + 32];
360 				break;
361 			case 7:
362 				envelope_level -= RateTable[RoundToZero((4 * (Rr ^ 0x1F)) - 0x18 + 12) + 32];
363 				break;
364 			}
365 		}
366 		samples = l;
367 	}
368 	timeInSecs = samples / sampleRate;
369 
370 	// theRate = timeInSecs / sustain_envelope_level;
371 	// timeInSecs = 0x7FFFFFFF * theRate;	//the release time value is more like a rate.  It is the
372 	// time from max value to 0, not from sustain level. if (Rm == 0) // if it's linear 	timeInSecs *=
373 	//LINEAR_RELEASE_COMPENSATION;
374 
375 	realADSR->_release_time =
376 			/*Rm ? timeInSecs : */ LinAmpDecayTimeToLinDBDecayTime(timeInSecs, 0x800);
377 
378 	// We need to compensate the decay and release times to represent them as the time from full vol
379 	// to -100db where the drop in db is a fixed amount per time unit (SoundFont2 spec for vol
380 	// envelopes, pg44.)
381 	//  We assume the psx envelope is using a linear scale wherein envelope_level / 2 == half
382 	//  loudness. For a linear release mode (Rm == 0), the time to reach half volume is simply half
383 	//  the time to reach 0.
384 	// Half perceived loudness is -10db. Therefore, time_to_half_vol * 10 == full_time * 5 == the
385 	// correct SF2 time
386 	// realADSR->decay_time = LinAmpDecayTimeToLinDBDecayTime(realADSR->decay_time, 0x800);
387 	// realADSR->sustain_time = LinAmpDecayTimeToLinDBDecayTime(realADSR->sustain_time, 0x800);
388 	// realADSR->release_time = LinAmpDecayTimeToLinDBDecayTime(realADSR->release_time, 0x800);
389 
390 	// Calculations are done, so now add the articulation data
391 	// artic->AddADSR(attack_time, Am, decay_time, sustain_lev, release_time, 0);
392 }
393 
394 class PSXSampColl : public VGMSampColl {
395 public:
396 	PSXSampColl(VGMInstrSet *instrset, uint32 offset, uint32 length,
397 				const Common::Array<SizeOffsetPair> &vagLocations);
398 
399 	virtual bool
400 	GetSampleInfo();  // retrieve sample info, including pointers to data, # channels, rate, etc.
401 
402 protected:
403 	Common::Array<SizeOffsetPair> _vagLocations;
404 };
405 
406 class PSXSamp : public VGMSamp {
407 public:
408 	PSXSamp(VGMSampColl *sampColl, uint32 offset, uint32 length, uint32 dataOffset,
409 			uint32 dataLen, uint8 nChannels, uint16 theBPS, uint32 theRate,
410 			Common::String name, bool bSetLoopOnConversion = true);
411 
~PSXSamp()412 	~PSXSamp() override {}
413 
414 	// ratio of space conserved.  should generally be > 1
415 	// used to calculate both uncompressed sample size and loopOff after conversion
416 	double GetCompressionRatio() override;
417 
418 	void ConvertToStdWave(uint8 *buf) override;
419 
420 private:
421 	void DecompVAGBlk(int16 *pSmp, VAGBlk *pVBlk, f32 *prev1, f32 *prev2);
422 
423 public:
424 
425 	bool _setLoopOnConversion;
426 };
427 
428 #endif // AUDIO_SOUNDFONT_PSXSPU_H
429