1 // ---------------------------------------------------------------------------
2 //	PSG Sound Implementation
3 //	Copyright (C) cisc 1997, 1999.
4 // ---------------------------------------------------------------------------
5 //	$Id: psg.cpp,v 1.10 2002/05/15 21:38:01 cisc Exp $
6 
7 #include "fmgen_headers.h"
8 #include "fmgen_misc.h"
9 #include "fmgen_psg.h"
10 
11 // ---------------------------------------------------------------------------
12 //	コンストラクタ・デストラクタ
13 //
PSG()14 PSG::PSG()
15 {
16 	SetVolume(0);
17 	MakeNoiseTable();
18 	Reset();
19 	mask = 0x3f;
20 }
21 
~PSG()22 PSG::~PSG()
23 {
24 
25 }
26 
27 // ---------------------------------------------------------------------------
28 //	PSG を初期化する(RESET)
29 //
Reset()30 void PSG::Reset()
31 {
32 	for (int i=0; i<14; i++)
33 		SetReg(i, 0);
34 	SetReg(7, 0xff);
35 	SetReg(14, 0xff);
36 	SetReg(15, 0xff);
37 }
38 
39 // ---------------------------------------------------------------------------
40 //	クロック周波数の設定
41 //
SetClock(int clock,int rate)42 void PSG::SetClock(int clock, int rate)
43 {
44 	tperiodbase = int((1 << toneshift ) / 4.0 * clock / rate);
45 	eperiodbase = int((1 << envshift  ) / 4.0 * clock / rate);
46 	nperiodbase = int((1 << noiseshift) / 4.0 * clock / rate);
47 
48 	// 各データの更新
49 	int tmp;
50 	tmp = ((reg[0] + reg[1] * 256) & 0xfff);
51 	speriod[0] = tmp ? tperiodbase / tmp : tperiodbase;
52 	tmp = ((reg[2] + reg[3] * 256) & 0xfff);
53 	speriod[1] = tmp ? tperiodbase / tmp : tperiodbase;
54 	tmp = ((reg[4] + reg[5] * 256) & 0xfff);
55 	speriod[2] = tmp ? tperiodbase / tmp : tperiodbase;
56 	tmp = reg[6] & 0x1f;
57 	nperiod = tmp ? nperiodbase / tmp / 2 : nperiodbase / 2;
58 	tmp = ((reg[11] + reg[12] * 256) & 0xffff);
59 	eperiod = tmp ? eperiodbase / tmp : eperiodbase * 2;
60 }
61 
62 // ---------------------------------------------------------------------------
63 //	ノイズテーブルを作成する
64 //
MakeNoiseTable()65 void PSG::MakeNoiseTable()
66 {
67 	if (!noisetable[0])
68 	{
69 		int noise = 14321;
70 		for (int i=0; i<noisetablesize; i++)
71 		{
72 			int n = 0;
73 			for (int j=0; j<32; j++)
74 			{
75 				n = n * 2 + (noise & 1);
76 				noise = (noise >> 1) | (((noise << 14) ^ (noise << 16)) & 0x10000);
77 			}
78 			noisetable[i] = n;
79 		}
80 	}
81 }
82 
83 // ---------------------------------------------------------------------------
84 //	出力テーブルを作成
85 //	素直にテーブルで持ったほうが省スペース。
86 //
SetVolume(int volume)87 void PSG::SetVolume(int volume)
88 {
89 	double base = 0x4000 / 3.0 * pow(10.0, volume / 40.0);
90 	for (int i=31; i>=2; i--)
91 	{
92 		EmitTable[i] = int(base);
93 		base /= 1.189207115;
94 	}
95 	EmitTable[1] = 0;
96 	EmitTable[0] = 0;
97 	MakeEnvelopTable();
98 
99 	SetChannelMask(~mask);
100 }
101 
SetChannelMask(int c)102 void PSG::SetChannelMask(int c)
103 {
104 	mask = ~c;
105 	for (int i=0; i<3; i++)
106 		olevel[i] = mask & (1 << i) ? EmitTable[(reg[8+i] & 15) * 2 + 1] : 0;
107 }
108 
109 // ---------------------------------------------------------------------------
110 //	エンベロープ波形テーブル
111 //
MakeEnvelopTable()112 void PSG::MakeEnvelopTable()
113 {
114 	// 0 lo  1 up 2 down 3 hi
115 	static uint8 table1[16*2] =
116 	{
117 		2,0, 2,0, 2,0, 2,0, 1,0, 1,0, 1,0, 1,0,
118 		2,2, 2,0, 2,1, 2,3, 1,1, 1,3, 1,2, 1,0,
119 	};
120 	static uint8 table2[4] = {  0,  0, 31, 31 };
121 	static int8 table3[4] = {  0,  1, -1,  0 };
122 
123 	uint* ptr = enveloptable[0];
124 
125 	for (int i=0; i<16*2; i++)
126 	{
127 		uint8 v = table2[table1[i]];
128 
129 		for (int j=0; j<32; j++)
130 		{
131 			*ptr++ = EmitTable[v];
132 			v += table3[table1[i]];
133 		}
134 	}
135 }
136 
137 // ---------------------------------------------------------------------------
138 //	PSG のレジスタに値をセットする
139 //	regnum		レジスタの番号 (0 - 15)
140 //	data		セットする値
141 //
SetReg(uint regnum,uint8 data)142 void PSG::SetReg(uint regnum, uint8 data)
143 {
144 	if (regnum < 0x10)
145 	{
146 		reg[regnum] = data;
147 		switch (regnum)
148 		{
149 			int tmp;
150 
151 		case 0:		// ChA Fine Tune
152 		case 1:		// ChA Coarse Tune
153 			tmp = ((reg[0] + reg[1] * 256) & 0xfff);
154 			speriod[0] = tmp ? tperiodbase / tmp : tperiodbase;
155 			break;
156 
157 		case 2:		// ChB Fine Tune
158 		case 3:		// ChB Coarse Tune
159 			tmp = ((reg[2] + reg[3] * 256) & 0xfff);
160 			speriod[1] = tmp ? tperiodbase / tmp : tperiodbase;
161 			break;
162 
163 		case 4:		// ChC Fine Tune
164 		case 5:		// ChC Coarse Tune
165 			tmp = ((reg[4] + reg[5] * 256) & 0xfff);
166 			speriod[2] = tmp ? tperiodbase / tmp : tperiodbase;
167 			break;
168 
169 		case 6:		// Noise generator control
170 			data &= 0x1f;
171 			nperiod = data ? nperiodbase / data : nperiodbase;
172 			break;
173 
174 		case 8:
175 			olevel[0] = mask & 1 ? EmitTable[(data & 15) * 2 + 1] : 0;
176 			break;
177 
178 		case 9:
179 			olevel[1] = mask & 2 ? EmitTable[(data & 15) * 2 + 1] : 0;
180 			break;
181 
182 		case 10:
183 			olevel[2] = mask & 4 ? EmitTable[(data & 15) * 2 + 1] : 0;
184 			break;
185 
186 		case 11:	// Envelop period
187 		case 12:
188 			tmp = ((reg[11] + reg[12] * 256) & 0xffff);
189 			eperiod = tmp ? eperiodbase / tmp : eperiodbase * 2;
190 			break;
191 
192 		case 13:	// Envelop shape
193 			ecount = 0;
194 			envelop = enveloptable[data & 15];
195 			break;
196 		}
197 	}
198 }
199 
200 // ---------------------------------------------------------------------------
DataSave(struct PSGData * data)201 void PSG::DataSave(struct PSGData* data) {
202 	memcpy(data->reg, reg, 16);
203 	memcpy(data->olevel, olevel, sizeof(uint) * 6);
204 	memcpy(data->scount, scount, sizeof(uint32) * 3);
205 	memcpy(data->speriod, speriod, sizeof(uint32) * 3);
206 	data->ecount = ecount;
207 	data->eperiod = eperiod;
208 	data->ncount = ncount;
209 	data->nperiod = nperiod;
210 	data->tperiodbase = tperiodbase;
211 	data->eperiodbase = eperiodbase;
212 	data->nperiodbase = nperiodbase;
213 	data->volume = volume;
214 	data->mask = mask;
215 }
216 
217 // ---------------------------------------------------------------------------
DataLoad(struct PSGData * data)218 void PSG::DataLoad(struct PSGData* data) {
219 	memcpy(reg, data->reg, 16);
220 	memcpy(olevel, data->olevel, sizeof(uint) * 6);
221 	memcpy(scount, data->scount, sizeof(uint32) * 3);
222 	memcpy(speriod, data->speriod, sizeof(uint32) * 3);
223 	ecount = data->ecount;
224 	eperiod = data->eperiod;
225 	ncount = data->ncount;
226 	nperiod = data->nperiod;
227 	tperiodbase = data->tperiodbase;
228 	eperiodbase = data->eperiodbase;
229 	nperiodbase = data->nperiodbase;
230 	volume = data->volume;
231 	mask = data->mask;
232 }
233 
234 // ---------------------------------------------------------------------------
235 //
236 //
StoreSample(Sample & dest,int32 data)237 inline void PSG::StoreSample(Sample& dest, int32 data)
238 {
239 	if (sizeof(Sample) == 2)
240 		dest = (Sample) Limit(dest + data, 0x7fff, -0x8000);
241 	else
242 		dest += data;
243 }
244 
245 // ---------------------------------------------------------------------------
246 //	PCM データを吐き出す(2ch)
247 //	dest		PCM データを展開するポインタ
248 //	nsamples	展開する PCM のサンプル数
249 //
Mix(Sample * dest,int nsamples)250 void PSG::Mix(Sample* dest, int nsamples)
251 {
252 	uint8 chenable[3], nenable[3];
253 	uint8 r7 = ~reg[7];
254 
255 	if ((r7 & 0x3f) | ((reg[8] | reg[9] | reg[10]) & 0x1f))
256 	{
257 		chenable[0] = (r7 & 0x01) && (speriod[0] <= (1 << toneshift));
258 		chenable[1] = (r7 & 0x02) && (speriod[1] <= (1 << toneshift));
259 		chenable[2] = (r7 & 0x04) && (speriod[2] <= (1 << toneshift));
260 		nenable[0]  = (r7 >> 3) & 1;
261 		nenable[1]  = (r7 >> 4) & 1;
262 		nenable[2]  = (r7 >> 5) & 1;
263 
264 		int noise, sample;
265 		uint env;
266 		uint* p1 = ((mask & 1) && (reg[ 8] & 0x10)) ? &env : &olevel[0];
267 		uint* p2 = ((mask & 2) && (reg[ 9] & 0x10)) ? &env : &olevel[1];
268 		uint* p3 = ((mask & 4) && (reg[10] & 0x10)) ? &env : &olevel[2];
269 
270 		#define SCOUNT(ch)	(scount[ch] >> (toneshift+oversampling))
271 
272 		if (p1 != &env && p2 != &env && p3 != &env)
273 		{
274 			// エンベロープ無し
275 			if ((r7 & 0x38) == 0)
276 			{
277 				// ノイズ無し
278 				for (int i=0; i<nsamples; i++)
279 				{
280 					sample = 0;
281 					for (int j=0; j < (1 << oversampling); j++)
282 					{
283 						int x, y, z;
284 						x = (SCOUNT(0) & chenable[0]) - 1;
285 						sample += (olevel[0] + x) ^ x;
286 						scount[0] += speriod[0];
287 						y = (SCOUNT(1) & chenable[1]) - 1;
288 						sample += (olevel[1] + y) ^ y;
289 						scount[1] += speriod[1];
290 						z = (SCOUNT(2) & chenable[2]) - 1;
291 						sample += (olevel[2] + z) ^ z;
292 						scount[2] += speriod[2];
293 					}
294 					sample /= (1 << oversampling);
295 					StoreSample(dest[0], sample);
296 					StoreSample(dest[1], sample);
297 					dest += 2;
298 				}
299 			}
300 			else
301 			{
302 				// ノイズ有り
303 				for (int i=0; i<nsamples; i++)
304 				{
305 					sample = 0;
306 					for (int j=0; j < (1 << oversampling); j++)
307 					{
308 #ifdef _M_IX86
309 						noise = noisetable[(ncount >> (noiseshift+oversampling+6)) & (noisetablesize-1)]
310 							>> (ncount >> (noiseshift+oversampling+1));
311 #else
312 						noise = noisetable[(ncount >> (noiseshift+oversampling+6)) & (noisetablesize-1)]
313 							>> (ncount >> (noiseshift+oversampling+1) & 31);
314 #endif
315 						ncount += nperiod;
316 
317 						int x, y, z;
318 						x = ((SCOUNT(0) & chenable[0]) | (nenable[0] & noise)) - 1;		// 0 or -1
319 						sample += (olevel[0] + x) ^ x;
320 						scount[0] += speriod[0];
321 						y = ((SCOUNT(1) & chenable[1]) | (nenable[1] & noise)) - 1;
322 						sample += (olevel[1] + y) ^ y;
323 						scount[1] += speriod[1];
324 						z = ((SCOUNT(2) & chenable[2]) | (nenable[2] & noise)) - 1;
325 						sample += (olevel[2] + z) ^ z;
326 						scount[2] += speriod[2];
327 					}
328 					sample /= (1 << oversampling);
329 					StoreSample(dest[0], sample);
330 					StoreSample(dest[1], sample);
331 					dest += 2;
332 				}
333 			}
334 
335 			// エンベロープの計算をさぼった帳尻あわせ
336 			ecount = (ecount >> 8) + (eperiod >> (8-oversampling)) * nsamples;
337 			if (ecount >= (1 << (envshift+6+oversampling-8)))
338 			{
339 				if ((reg[0x0d] & 0x0b) != 0x0a)
340 					ecount |= (1 << (envshift+5+oversampling-8));
341 				ecount &= (1 << (envshift+6+oversampling-8)) - 1;
342 			}
343 			ecount <<= 8;
344 		}
345 		else
346 		{
347 			// エンベロープあり
348 			for (int i=0; i<nsamples; i++)
349 			{
350 				sample = 0;
351 				for (int j=0; j < (1 << oversampling); j++)
352 				{
353 					env = envelop[ecount >> (envshift+oversampling)];
354 					ecount += eperiod;
355 					if (ecount >= (1 << (envshift+6+oversampling)))
356 					{
357 						if ((reg[0x0d] & 0x0b) != 0x0a)
358 							ecount |= (1 << (envshift+5+oversampling));
359 						ecount &= (1 << (envshift+6+oversampling)) - 1;
360 					}
361 #ifdef _M_IX86
362 					noise = noisetable[(ncount >> (noiseshift+oversampling+6)) & (noisetablesize-1)]
363 						>> (ncount >> (noiseshift+oversampling+1));
364 #else
365 					noise = noisetable[(ncount >> (noiseshift+oversampling+6)) & (noisetablesize-1)]
366 						>> (ncount >> (noiseshift+oversampling+1) & 31);
367 #endif
368 					ncount += nperiod;
369 
370 					int x, y, z;
371 					x = ((SCOUNT(0) & chenable[0]) | (nenable[0] & noise)) - 1;		// 0 or -1
372 					sample += (*p1 + x) ^ x;
373 					scount[0] += speriod[0];
374 					y = ((SCOUNT(1) & chenable[1]) | (nenable[1] & noise)) - 1;
375 					sample += (*p2 + y) ^ y;
376 					scount[1] += speriod[1];
377 					z = ((SCOUNT(2) & chenable[2]) | (nenable[2] & noise)) - 1;
378 					sample += (*p3 + z) ^ z;
379 					scount[2] += speriod[2];
380 				}
381 				sample /= (1 << oversampling);
382 				StoreSample(dest[0], sample);
383 				StoreSample(dest[1], sample);
384 				dest += 2;
385 			}
386 		}
387 	}
388 }
389 
390 // ---------------------------------------------------------------------------
391 //	テーブル
392 //
393 uint	PSG::noisetable[noisetablesize] = { 0, };
394 int		PSG::EmitTable[0x20] = { -1, };
395 uint	PSG::enveloptable[16][64] = { {0, } };
396