1 /*********************************************************/
2 /*    SEGA 16ch 8bit PCM                                 */
3 /*********************************************************/
4 
5 #include "driver.h"
6 #include "osinline.h"
7 #include <math.h>
8 
9 #define  PCM_NORMALIZE
10 
11 #define SPCM_CENTER    (0x80)
12 #define SEGA_SAMPLE_RATE    (15800)
13 #define SEGA_SAMPLE_SHIFT   (5)
14 #define SEGA_SAMPLE_RATE_OLD    (15800*2)
15 #define SEGA_SAMPLE_SHIFT_OLD   (5)
16 
17 #define  MIN_SLICE    (44/2)
18 
19 #define  PCM_ADDR_SHIFT   (12)
20 
21 static SEGAPCM    spcm;
22 static int emulation_rate;
23 static int buffer_len;
24 static unsigned char *pcm_rom;
25 static int  sample_rate, sample_shift;
26 
27 static int stream;
28 
29 static int SEGAPCM_samples[][2] = {
30 	{ SEGA_SAMPLE_RATE, SEGA_SAMPLE_SHIFT, },
31 	{ SEGA_SAMPLE_RATE_OLD, SEGA_SAMPLE_SHIFT_OLD, },
32 };
33 
34 #if 0
35 static int segapcm_gaintable[] = {
36 	0x00,0x02,0x04,0x06,0x08,0x0a,0x0c,0x0e,0x10,0x12,0x14,0x16,0x18,0x1a,0x1c,0x1e,
37 	0x20,0x22,0x24,0x26,0x28,0x2a,0x2c,0x2e,0x30,0x32,0x34,0x36,0x38,0x3a,0x3c,0x3e,
38 	0x40,0x42,0x44,0x46,0x48,0x4a,0x4c,0x4e,0x50,0x52,0x54,0x56,0x58,0x5a,0x5c,0x5e,
39 	0x60,0x62,0x64,0x66,0x68,0x6a,0x6c,0x6e,0x70,0x72,0x74,0x76,0x78,0x7a,0x7c,0x7e,
40 
41 	0x00,0x02,0x04,0x06,0x08,0x0a,0x0c,0x0e,0x10,0x12,0x14,0x16,0x18,0x1a,0x1c,0x1e,
42 	0x20,0x22,0x24,0x26,0x28,0x2a,0x2c,0x2e,0x30,0x32,0x34,0x36,0x38,0x3a,0x3c,0x3e,
43 	0x40,0x42,0x44,0x46,0x48,0x4a,0x4c,0x4e,0x50,0x52,0x54,0x56,0x58,0x5a,0x5c,0x5e,
44 	0x60,0x62,0x64,0x66,0x68,0x6a,0x6c,0x6e,0x70,0x72,0x74,0x76,0x78,0x7a,0x7c,0x7e,
45 
46 #if 0
47 	0x00,0x04,0x08,0x0c,0x10,0x14,0x18,0x1c,0x20,0x24,0x28,0x2c,0x30,0x34,0x38,0x3c,
48 	0x40,0x42,0x44,0x46,0x48,0x4a,0x4c,0x4e,0x50,0x52,0x54,0x56,0x58,0x5a,0x5c,0x5e,
49 	0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
50 	0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
51 #endif
52 #if 0
53 	0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
54 	0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
55 	0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
56 	0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
57 #endif
58 };
59 #endif
60 
61 
62 static void SEGAPCMUpdate( int num, INT16 **buffer, int length );
63 
64 
65 /************************************************/
66 /*                                              */
67 /************************************************/
SEGAPCM_sh_start(const struct MachineSound * msound)68 int SEGAPCM_sh_start( const struct MachineSound *msound )
69 {
70 	struct SEGAPCMinterface *intf = (struct SEGAPCMinterface *)msound->sound_interface;
71 	if (Machine->sample_rate == 0) return 0;
72 	if( SEGAPCMInit( msound, intf->bank&0x00ffffff, intf->mode, (unsigned char *)memory_region(intf->region), intf->volume ) )
73 		return 1;
74 	return 0;
75 }
76 /************************************************/
77 /*                                              */
78 /************************************************/
SEGAPCM_sh_stop(void)79 void SEGAPCM_sh_stop( void )
80 {
81 	SEGAPCMShutdown();
82 }
83 /************************************************/
84 /*                                              */
85 /************************************************/
SEGAPCM_sh_update(void)86 void SEGAPCM_sh_update( void )
87 {
88 }
89 
90 /************************************************/
91 /*    initial SEGAPCM                           */
92 /************************************************/
SEGAPCMInit(const struct MachineSound * msound,int banksize,int mode,unsigned char * inpcm,int volume)93 int SEGAPCMInit( const struct MachineSound *msound, int banksize, int mode, unsigned char *inpcm, int volume )
94 {
95 	int i;
96 	int rate = Machine->sample_rate;
97 	buffer_len = rate / Machine->drv->frames_per_second;
98 	emulation_rate = buffer_len * Machine->drv->frames_per_second;
99 	sample_rate = SEGAPCM_samples[mode][0];
100 	sample_shift = SEGAPCM_samples[mode][1];
101 	pcm_rom = inpcm;
102 
103 	//printf( "segaPCM in\n" );
104 
105 	/**** interface init ****/
106 	spcm.bankshift = banksize&0xffffff;
107 	if( (banksize>>16) == 0x00 )
108 	{
109 		spcm.bankmask = (BANK_MASK7>>16)&0x00ff;	/* default */
110 	}
111 	else
112 	{
113 		spcm.bankmask = (banksize>>16)&0x00ff;
114 	}
115 
116 	for( i = 0; i < SEGAPCM_MAX; i++ )
117 	{
118 		spcm.gain[i][L_PAN] = spcm.gain[i][R_PAN] = (unsigned char)0;
119 		spcm.vol[i][L_PAN] = spcm.vol[i][R_PAN] = 0;
120 		spcm.addr_l[i] = 0;
121 		spcm.addr_h[i] = 0;
122 		spcm.bank[i] = 0;
123 		spcm.end_h[i] = 0;
124 		spcm.delta_t[i] = 0x80;
125 		spcm.flag[i] = 1;
126 		spcm.add_addr[i] = 0;
127 		spcm.step[i] = (int)(((float)sample_rate / (float)emulation_rate) * (float)(0x80<<5));
128 		spcm.pcmd[i] = 0;
129 	}
130 	//printf( "segaPCM work init end\n" );
131 
132 	{
133 		char buf[LR_PAN][40];
134 		const char *name[LR_PAN];
135 		int  vol[2];
136 		name[0] = buf[0];
137 		name[1] = buf[1];
138 		sprintf( buf[0], "%s L", sound_name(msound) );
139 		sprintf( buf[1], "%s R", sound_name(msound) );
140 		vol[0] = (MIXER_PAN_LEFT<<8)  | (volume&0xff);
141 		vol[1] = (MIXER_PAN_RIGHT<<8) | (volume&0xff);
142 		stream = stream_init_multi( LR_PAN, name, vol, rate, 0, SEGAPCMUpdate );
143 	}
144 	//printf( "segaPCM end\n" );
145 	return 0;
146 }
147 
148 /************************************************/
149 /*    shutdown SEGAPCM                          */
150 /************************************************/
SEGAPCMShutdown(void)151 void SEGAPCMShutdown( void )
152 {
153 }
154 
155 /************************************************/
156 /*    reset SEGAPCM                             */
157 /************************************************/
SEGAPCMResetChip(void)158 void SEGAPCMResetChip( void )
159 {
160 	int i;
161 	for( i = 0; i < SEGAPCM_MAX; i++ )
162 	{
163 		spcm.gain[i][L_PAN] = spcm.gain[i][R_PAN] = (unsigned char)0;
164 		spcm.vol[i][L_PAN] = spcm.vol[i][R_PAN] = 0;
165 		spcm.addr_l[i] = 0;
166 		spcm.addr_h[i] = 0;
167 		spcm.bank[i] = 0;
168 		spcm.end_h[i] = 0;
169 		spcm.delta_t[i] = 0;
170 		spcm.flag[i] = 1;
171 		spcm.add_addr[i] = 0;
172 		spcm.step[i] = (int)(((float)sample_rate / (float)emulation_rate) * (float)(0x80<<5));
173 	}
174 }
175 
176 /************************************************/
177 /*    update SEGAPCM                            */
178 /************************************************/
179 
ILimit(int v,int max,int min)180 static INLINE int ILimit(int v, int max, int min) { return v > max ? max : (v < min ? min : v); }
181 
SEGAPCMUpdate(int num,INT16 ** buffer,int length)182 static void SEGAPCMUpdate( int num, INT16 **buffer, int length )
183 {
184 	int i, j;
185 	unsigned int addr, old_addr, end_addr, end_check_addr;
186 	unsigned char *pcm_buf;
187 	int  lv, rv;
188 	INT16  *datap[2];
189 	int tmp;
190 
191 	if( Machine->sample_rate == 0 ) return;
192 	if( pcm_rom == NULL )    return;
193 
194 	datap[0] = buffer[0];
195 	datap[1] = buffer[1];
196 
197 	memset( datap[0], 0x00, length * sizeof(INT16) );
198 	memset( datap[1], 0x00, length * sizeof(INT16) );
199 
200 	for( i = 0; i < SEGAPCM_MAX; i++ )
201 	{
202 		if( spcm.flag[i] == 2)
203 		{
204 			spcm.flag[i]=0;
205 			spcm.add_addr[i] = (( (((int)spcm.addr_h[i]<<8)&0xff00) |
206 				  (spcm.addr_l[i]&0x00ff) ) << PCM_ADDR_SHIFT) &0x0ffff000;
207 		}
208 		if( !spcm.flag[i] )
209 		{
210 			lv = spcm.vol[i][L_PAN];   rv = spcm.vol[i][R_PAN];
211 			if(lv==0 && rv==0) continue;
212 
213 			pcm_buf = pcm_rom + (((int)spcm.bank[i]&spcm.bankmask)<<spcm.bankshift);
214 			addr = (spcm.add_addr[i]>>PCM_ADDR_SHIFT)&0x0000ffff;
215 			end_addr = ((((unsigned int)spcm.end_h[i]<<8)&0xff00) + 0x00ff);
216 			if(spcm.end_h[i] < spcm.addr_h[i]) end_addr+=0x10000;
217 
218 			for( j = 0; j < length; j++ )
219 			{
220 				old_addr = addr;
221 				/**** make address ****/
222 				end_check_addr = (spcm.add_addr[i]>>PCM_ADDR_SHIFT);
223 				addr = end_check_addr&0x0000ffff;
224 				for(; old_addr <= addr; old_addr++ )
225 				{
226 					/**** end address check ****/
227 					if( end_check_addr >= end_addr )
228 					{
229 						if(spcm.writeram[i*8+0x86] & 0x02)
230 						{
231 							spcm.flag[i] = 1;
232 							spcm.writeram[i*8+0x86] = (spcm.writeram[i*8+0x86]&0xfe)|1;
233 							break;
234 						}
235 						else
236 						{ /* Loop */
237 							spcm.add_addr[i] = (( (((int)spcm.addr_h[i]<<8)&0xff00) |
238 									(spcm.addr_l[i]&0x00ff) ) << PCM_ADDR_SHIFT) &0x0ffff000;
239 						}
240 					}
241 #ifdef PCM_NORMALIZE
242 					tmp = spcm.pcmd[i];
243 					spcm.pcmd[i] = (int)(*(pcm_buf + old_addr) - SPCM_CENTER);
244 					spcm.pcma[i] = (tmp - spcm.pcmd[i]) / 2;
245 					spcm.pcmd[i] += spcm.pcma[i];
246 #endif
247 				}
248 				spcm.add_addr[i] += spcm.step[i];
249 				if( spcm.flag[i] == 1 )  break;
250 #ifndef PCM_NORMALIZE
251 #ifndef clip_short_ret
252 				*(datap[0] + j) = ILimit( (int)*(datap[0] + j) + ((int)(*(pcm_buf + addr) - SPCM_CENTER)*lv), 32767, -32768 );
253 				*(datap[1] + j) = ILimit( (int)*(datap[1] + j) + ((int)(*(pcm_buf + addr) - SPCM_CENTER)*rv), 32767, -32768 );
254 #else
255 				*(datap[0] + j) = clip_short_ret( (int)*(datap[0] + j) + ((int)(*(pcm_buf + addr) - SPCM_CENTER)*lv));
256 				*(datap[1] + j) = clip_short_ret( (int)*(datap[1] + j) + ((int)(*(pcm_buf + addr) - SPCM_CENTER)*rv));
257 #endif
258 #else
259 #ifndef clip_short_ret
260 				*(datap[0] + j) = ILimit( (int)*(datap[0] + j) + (spcm.pcmd[i] * lv), 32767, -32768 );
261 				*(datap[1] + j) = ILimit( (int)*(datap[1] + j) + (spcm.pcmd[i] * rv), 32767, -32768 );
262 #else
263 				*(datap[0] + j) = clip_short_ret( (int)*(datap[0] + j) + (spcm.pcmd[i] * lv));
264 				*(datap[1] + j) = clip_short_ret( (int)*(datap[1] + j) + (spcm.pcmd[i] * rv));
265 #endif
266 #endif
267 			}
268 			/**** end of length ****/
269 		}
270 		/**** end flag check ****/
271 	}
272 	/**** pcm channel end ****/
273 
274 }
275 
276 /************************************************/
277 /*    wrtie register SEGAPCM                    */
278 /************************************************/
WRITE_HANDLER(SegaPCM_w)279 WRITE_HANDLER( SegaPCM_w )
280 {
281 	int r = offset;
282 	int v = data;
283 	int rate;
284 	int  lv, rv, cen;
285 
286 	int channel = (r>>3)&0x0f;
287 
288 	spcm.writeram[r&0x07ff] = (char)v;		/* write value data */
289 	switch( (r&0x87) )
290 	{
291 		case 0x00:
292 		case 0x01:
293 		case 0x84:  case 0x85:
294 		case 0x87:
295 			break;
296 
297 		case 0x02:
298 			spcm.gain[channel][L_PAN] = v&0xff;
299 remake_vol:
300 			lv = spcm.gain[channel][L_PAN];   rv = spcm.gain[channel][R_PAN];
301 			cen = (lv + rv) / 4;
302 //			spcm.vol[channel][L_PAN] = (lv + cen)<<1;
303 //			spcm.vol[channel][R_PAN] = (rv + cen)<<1;
304 			spcm.vol[channel][L_PAN] = (lv + cen)*9/5;	// too much clipping
305 			spcm.vol[channel][R_PAN] = (rv + cen)*9/5;
306 			break;
307 		case 0x03:
308 			spcm.gain[channel][R_PAN] = v&0xff;
309 			goto remake_vol;
310 
311 
312 		case 0x04:
313 			spcm.addr_l[channel]= v;
314 			break;
315 		case 0x05:
316 			spcm.addr_h[channel]= v;
317 			break;
318 		case 0x06:
319 			spcm.end_h[channel]= v;
320 			break;
321 		case 0x07:
322 			spcm.delta_t[channel]= v;
323 			rate = (v&0x00ff)<<sample_shift;
324 			spcm.step[channel] = (int)(((float)sample_rate / (float)emulation_rate) * (float)rate);
325 			break;
326 		case 0x86:
327 			spcm.bank[channel]= v;
328 			if( v&1 )    spcm.flag[channel] = 1; /* stop D/A */
329 			else
330 			{
331 				/**** start D/A ****/
332 //				spcm.flag[channel] = 0;
333 				spcm.flag[channel] = 2;
334 //				spcm.add_addr[channel] = (( (((int)spcm.addr_h[channel]<<8)&0xff00) |
335 //					  (spcm.addr_l[channel]&0x00ff) ) << PCM_ADDR_SHIFT) &0x0ffff000;
336 				spcm.pcmd[channel] = 0;
337 			}
338 			break;
339 		/*
340 		default:
341 			printf( "unknown %d = %02x : %02x\n", channel, r, v );
342 			break;
343 		*/
344 	}
345 }
346 
347 /************************************************/
348 /*    read register SEGAPCM                     */
349 /************************************************/
READ_HANDLER(SegaPCM_r)350 READ_HANDLER( SegaPCM_r )
351 {
352 	return spcm.writeram[offset & 0x07ff];		/* read value data */
353 }
354 
355 /**************** end of file ****************/
356