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