1 /***************************************************************************
2 	polepos.c
3 	Sound handler
4 ****************************************************************************/
5 #include "driver.h"
6 
7 static int sample_msb = 0;
8 static int sample_lsb = 0;
9 static int sample_enable = 0;
10 
11 static int current_position;
12 static int sound_stream;
13 
14 /* speech section */
15 static int channel;
16 static INT8 *speech;
17 /* macro to convert 4-bit unsigned samples to 8-bit signed samples */
18 #define SAMPLE_CONV4(a) (0x11*((a&0x0f))-0x80)
19 #define SAMPLE_SIZE 0x8000
20 
21 #define AMP(r)	(r*128/10100)
22 static int volume_table[8] =
23 {
24 	AMP(2200), AMP(3200), AMP(4400), AMP(5400),
25 	AMP(6900), AMP(7900), AMP(9100), AMP(10100)
26 };
27 static int sample_offsets[5];
28 
29 /************************************/
30 /* Stream updater                   */
31 /************************************/
engine_sound_update(int num,INT16 * buffer,int length)32 static void engine_sound_update(int num, INT16 *buffer, int length)
33 {
34 	UINT32 current = current_position, step, clock, slot, volume;
35 	UINT8 *base;
36 
37 
38 	/* if we're not enabled, just fill with 0 */
39 	if (!sample_enable || Machine->sample_rate == 0)
40 	{
41 		memset(buffer, 0, length * sizeof(INT16));
42 		return;
43 	}
44 
45 	/* determine the effective clock rate */
46 	clock = (Machine->drv->cpu[0].cpu_clock / 64) * ((sample_msb + 1) * 64 + sample_lsb + 1) / (16*64);
47 	step = (clock << 12) / Machine->sample_rate;
48 
49 	/* determine the volume */
50 	slot = (sample_msb >> 3) & 7;
51 	volume = volume_table[slot];
52 	base = &memory_region(REGION_SOUND1)[0x1000 + slot * 0x800];
53 
54 	/* fill in the sample */
55 	while (length--)
56 	{
57 		*buffer++ = (base[(current >> 12) & 0x7ff] * volume);
58 		current += step;
59 	}
60 
61 	current_position = current;
62 }
63 
64 /************************************/
65 /* Sound handler start              */
66 /************************************/
polepos_sh_start(const struct MachineSound * msound)67 int polepos_sh_start(const struct MachineSound *msound)
68 {
69 	int i, bits, last=0;
70 
71 	channel = mixer_allocate_channel(25);
72 	mixer_set_name(channel,"Speech");
73 
74 	speech = (INT8*)malloc(16*SAMPLE_SIZE);
75 	if (!speech)
76 		return 1;
77 
78 	/* decode the rom samples, interpolating to make it sound a little better */
79 	for (i = 0;i < SAMPLE_SIZE;i++)
80 	{
81 		bits = memory_region(REGION_SOUND1)[0x5000+i] & 0x0f;
82 		bits = SAMPLE_CONV4(bits);
83 		speech[16*i+0] = (7 * last + 1 * bits) / 8;
84 		speech[16*i+1] = (6 * last + 2 * bits) / 8;
85 		speech[16*i+2] = (5 * last + 3 * bits) / 8;
86 		speech[16*i+3] = (4 * last + 4 * bits) / 8;
87 		speech[16*i+4] = (3 * last + 5 * bits) / 8;
88 		speech[16*i+5] = (2 * last + 6 * bits) / 8;
89 		speech[16*i+6] = (1 * last + 7 * bits) / 8;
90 		speech[16*i+7] = bits;
91 		last = bits;
92 
93 		bits = (memory_region(REGION_SOUND1)[0x5000+i] & 0xf0) >> 4;
94 		bits = SAMPLE_CONV4(bits);
95 		speech[16*i+8] = (7 * last + 1 * bits) / 8;
96 		speech[16*i+9] = (6 * last + 2 * bits) / 8;
97 		speech[16*i+10] = (5 * last + 3 * bits) / 8;
98 		speech[16*i+11] = (4 * last + 4 * bits) / 8;
99 		speech[16*i+12] = (3 * last + 5 * bits) / 8;
100 		speech[16*i+13] = (2 * last + 6 * bits) / 8;
101 		speech[16*i+14] = (1 * last + 7 * bits) / 8;
102 		speech[16*i+15] = bits;
103 		last = bits;
104 	}
105 
106 	/* Japanese or US PROM? */
107 	if (memory_region(REGION_SOUND1)[0x5000] == 0)
108 	{
109 		/* US */
110 		sample_offsets[0] = 0x0020;
111 		sample_offsets[1] = 0x0c00;
112 		sample_offsets[2] = 0x1c00;
113 		sample_offsets[3] = 0x2000;
114 		sample_offsets[4] = 0x2000;
115 	}
116 	else
117 	{
118 		/* Japan */
119 		sample_offsets[0] = 0x0020;
120 		sample_offsets[1] = 0x0900;
121 		sample_offsets[2] = 0x1f00;
122 		sample_offsets[3] = 0x4000;
123 		sample_offsets[4] = 0x6000;		/* How is this triggered? */
124 	}
125 
126 	sound_stream = stream_init("Engine Sound", 50, Machine->sample_rate, 0, engine_sound_update);
127 	current_position = 0;
128 	sample_msb = sample_lsb = 0;
129 	sample_enable = 0;
130     return 0;
131 }
132 
133 /************************************/
134 /* Sound handler stop               */
135 /************************************/
polepos_sh_stop(void)136 void polepos_sh_stop(void)
137 {
138 	if (speech)
139 		free(speech);
140 	speech = NULL;
141 }
142 
143 /************************************/
144 /* Sound handler update 			*/
145 /************************************/
polepos_sh_update(void)146 void polepos_sh_update(void)
147 {
148 }
149 
150 /************************************/
151 /* Write LSB of engine sound		*/
152 /************************************/
WRITE_HANDLER(polepos_engine_sound_lsb_w)153 WRITE_HANDLER( polepos_engine_sound_lsb_w )
154 {
155 	stream_update(sound_stream, 0);
156 	sample_lsb = data & 62;
157     sample_enable = data & 1;
158 }
159 
160 /************************************/
161 /* Write MSB of engine sound		*/
162 /************************************/
WRITE_HANDLER(polepos_engine_sound_msb_w)163 WRITE_HANDLER( polepos_engine_sound_msb_w )
164 {
165 	stream_update(sound_stream, 0);
166 	sample_msb = data & 63;
167 }
168 
169 /************************************/
170 /* Play speech sample				*/
171 /************************************/
polepos_sample_play(int sample)172 void polepos_sample_play(int sample)
173 {
174 	int start = sample_offsets[sample];
175 	int len = sample_offsets[sample + 1] - start;
176 
177 	if (Machine->sample_rate == 0)
178 		return;
179 
180 	mixer_play_sample(channel, speech + start * 16, len * 16, 4000*8, 0);
181 }
182