1 // Based on MAME sources by Luca Elia
2 
3 #include "burnint.h"
4 #include "msm6295.h"
5 #include "x1010.h"
6 
7 UINT8 *X1010SNDROM;
8 INT32 X1010_Arbalester_Mode = 0;
9 
10 struct x1_010_info * x1_010_chip = NULL;
11 
x1010_sound_bank_w(UINT32 offset,UINT16 data)12 void x1010_sound_bank_w(UINT32 offset, UINT16 data)
13 {
14 #if defined FBA_DEBUG
15 	if (!DebugSnd_X1010Initted) bprintf(PRINT_ERROR, _T("x1010_sound_bank_w called without init\n"));
16 #endif
17 
18 	//int banks = (memory_region_length( REGION_SOUND1 ) - 0x100000) / 0x20000;
19 	//if ( data >= banks ) {
20 	//	bprintf(PRINT_NORMAL, _T("invalid sound bank %04x\n"), data);
21 	//	data %= banks;
22 	//}
23 	memcpy(X1010SNDROM + offset * 0x20000, X1010SNDROM + 0x100000 + data * 0x20000, 0x20000);
24 
25 	// backup sound bank index, need when game load status
26 	x1_010_chip->sound_banks[ offset ] = data;
27 }
28 
x1010_sound_read(UINT32 offset)29 UINT8 x1010_sound_read(UINT32 offset)
30 {
31 #if defined FBA_DEBUG
32 	if (!DebugSnd_X1010Initted) bprintf(PRINT_ERROR, _T("x1010_sound_read called without init\n"));
33 #endif
34 
35 	offset ^= x1_010_chip->address;
36 	return x1_010_chip->reg[offset];
37 }
38 
x1010_sound_read_word(UINT32 offset)39 UINT16 x1010_sound_read_word(UINT32 offset)
40 {
41 #if defined FBA_DEBUG
42 	if (!DebugSnd_X1010Initted) bprintf(PRINT_ERROR, _T("x1010_sound_read_word called without init\n"));
43 #endif
44 
45 	UINT16 ret;
46 
47 	ret = x1_010_chip->HI_WORD_BUF[offset] << 8;
48 	ret += x1010_sound_read(offset);
49 
50 	return ret;
51 }
52 
x1010_sound_update()53 void x1010_sound_update()
54 {
55 #if defined FBA_DEBUG
56 	if (!DebugSnd_X1010Initted) bprintf(PRINT_ERROR, _T("x1010_sound_update called without init\n"));
57 #endif
58 
59 	INT16* pSoundBuf = pBurnSoundOut;
60 	memset(pSoundBuf, 0, nBurnSoundLen * sizeof(INT16) * 2);
61 
62 	X1_010_CHANNEL	*reg;
63 	INT32 ch, i, volL, volR, freq, mempos, div;
64 	INT8 *start, *end, data;
65 	UINT8 *env;
66 	UINT32 smp_offs, smp_step, env_offs, env_step, delta;
67 
68 	for( ch = 0; ch < SETA_NUM_CHANNELS; ch++ ) {
69 		reg = (X1_010_CHANNEL *) & (x1_010_chip->reg[ch * sizeof(X1_010_CHANNEL)]);
70 		if( reg->status & 1 ) {	// Key On
71 			INT16 *bufL = pSoundBuf + 0;
72 			INT16 *bufR = pSoundBuf + 1;
73 			div = (reg->status&0x80) ? 1 : 0;
74 			if( (reg->status & 2) == 0 ) { // PCM sampling
75 				start    = (INT8*)( reg->start * 0x1000 + X1010SNDROM );
76 				mempos   = reg->start * 0x1000; // used only for bounds checking
77 				end      = (INT8*)((0x100 - reg->end) * 0x1000 + X1010SNDROM );
78 				volL     = ((reg->volume >> 4) & 0xf) * VOL_BASE;
79 				volR     = ((reg->volume >> 0) & 0xf) * VOL_BASE;
80 				smp_offs = x1_010_chip->smp_offset[ch];
81 				freq     = reg->frequency>>div;
82 				if (!volL) volL = volR;       // dink aug.17,2016: fix missing samples in ms gundam
83 				if (!volR) volR = volL;
84 				// Meta Fox does not write the frequency register. Ever
85 				if( freq == 0 ) freq = 4;
86 				// Special handling for Arbalester -dink
87 				if( X1010_Arbalester_Mode && ch==0x0f && reg->start != 0xc0 && reg->start != 0xc8 )
88 					freq = 8;
89 
90 				smp_step = (UINT32)((float)x1_010_chip->rate / (float)nBurnSoundRate / 8.0 * freq * (1 << FREQ_BASE_BITS) );
91 #if 0
92 				if( smp_offs == 0 ) {
93 					bprintf(PRINT_ERROR, _T("Play sample %06X - %06X, channel %X volumeL %d volumeR %d freq %X step %X offset %X\n"),
94 							reg->start, reg->end, ch, volL, volR, freq, smp_step, smp_offs);
95 				}
96 #endif
97 				for( i = 0; i < nBurnSoundLen; i++ ) {
98 					delta = smp_offs >> FREQ_BASE_BITS;
99 					// sample ended?
100 					if( start + delta >= end) {
101 						reg->status &= 0xfe;					// Key off
102 						break;
103 					}
104 
105 					if (mempos + delta >= 0xfffff) {            // bounds checking
106 						reg->status &= 0xfe;					// Key off
107 						bprintf(0, _T("X1-010: Overflow detected (PCM)!\n"));
108 						break;
109 					}
110 
111 					data = *(start + delta);
112 
113 					INT32 nLeftSample = 0, nRightSample = 0;
114 
115 					if ((x1_010_chip->output_dir[BURN_SND_X1010_ROUTE_1] & BURN_SND_ROUTE_LEFT) == BURN_SND_ROUTE_LEFT) {
116 						nLeftSample += (INT32)((data * volL / 256) * x1_010_chip->gain[BURN_SND_X1010_ROUTE_1]);
117 					}
118 					if ((x1_010_chip->output_dir[BURN_SND_X1010_ROUTE_1] & BURN_SND_ROUTE_RIGHT) == BURN_SND_ROUTE_RIGHT) {
119 						nRightSample += (INT32)((data * volL / 256) * x1_010_chip->gain[BURN_SND_X1010_ROUTE_1]);
120 					}
121 
122 					if ((x1_010_chip->output_dir[BURN_SND_X1010_ROUTE_2] & BURN_SND_ROUTE_LEFT) == BURN_SND_ROUTE_LEFT) {
123 						nLeftSample += (INT32)((data * volR / 256) * x1_010_chip->gain[BURN_SND_X1010_ROUTE_2]);
124 					}
125 					if ((x1_010_chip->output_dir[BURN_SND_X1010_ROUTE_2] & BURN_SND_ROUTE_RIGHT) == BURN_SND_ROUTE_RIGHT) {
126 						nRightSample += (INT32)((data * volR / 256) * x1_010_chip->gain[BURN_SND_X1010_ROUTE_2]);
127 					}
128 
129 					nLeftSample = BURN_SND_CLIP(nLeftSample);
130 					nRightSample = BURN_SND_CLIP(nRightSample);
131 
132 					*bufL = BURN_SND_CLIP(*bufL + nLeftSample); bufL += 2;;
133 					*bufR = BURN_SND_CLIP(*bufR + nRightSample); bufR += 2;
134 
135 					smp_offs += smp_step;
136 				}
137 				x1_010_chip->smp_offset[ch] = smp_offs;
138 
139 			} else { // Wave form
140 				start    = (INT8*) & (x1_010_chip->reg[reg->volume * 128 + 0x1000]);
141 				mempos   = reg->volume * 128 + 0x1000; // used only for bounds checking
142 				smp_offs = x1_010_chip->smp_offset[ch];
143 				freq     = ((reg->pitch_hi << 8) + reg->frequency)>>div;
144 				smp_step = (UINT32)((float)x1_010_chip->rate / (float)nBurnSoundRate / 128.0 / 4.0 * freq * (1 << FREQ_BASE_BITS) );
145 
146 				env      = (UINT8*) & (x1_010_chip->reg[reg->end * 128]);
147 				env_offs = x1_010_chip->env_offset[ch];
148 				env_step = (UINT32)((float)x1_010_chip->rate / (float)nBurnSoundRate / 128.0 / 4.0 * reg->start * (1 << ENV_BASE_BITS) );
149 #if 0
150 				if( smp_offs == 0 ) {
151 					bprintf(PRINT_ERROR, _T("Play waveform %X, channel %X volume %X freq %4X step %X offset %X dlta %X\n"),
152        						reg->volume, ch, reg->end, freq, smp_step, smp_offs, env_offs>>ENV_BASE_BITS );
153 				}
154 #endif
155 				if (mempos > 0x2000 - 0x80) {            // bounds checking
156 					reg->status &= 0xfe;					// Key off
157 					bprintf(0, _T("X1-010: Overflow detected (Waveform)!\n"));
158 					break;
159 				}
160 
161 				for( i = 0; i < nBurnSoundLen; i++ ) {
162 					INT32 vol;
163 					delta = env_offs>>ENV_BASE_BITS;
164 	 				// Envelope one shot mode
165 					if( (reg->status&4) != 0 && delta >= 0x80 ) {
166 						reg->status &= 0xfe;					// Key off
167 						break;
168 					}
169 
170 					vol = *(env + (delta & 0x7f));
171 					volL = ((vol >> 4) & 0xf) * VOL_BASE;
172 					volR = ((vol >> 0) & 0xf) * VOL_BASE;
173 					data  = *(start + ((smp_offs >> FREQ_BASE_BITS) & 0x7f));
174 
175 					INT32 nLeftSample = 0, nRightSample = 0;
176 
177 					if ((x1_010_chip->output_dir[BURN_SND_X1010_ROUTE_1] & BURN_SND_ROUTE_LEFT) == BURN_SND_ROUTE_LEFT) {
178 						nLeftSample += (INT32)((data * volL / 256) * x1_010_chip->gain[BURN_SND_X1010_ROUTE_1]);
179 					}
180 					if ((x1_010_chip->output_dir[BURN_SND_X1010_ROUTE_1] & BURN_SND_ROUTE_RIGHT) == BURN_SND_ROUTE_RIGHT) {
181 						nRightSample += (INT32)((data * volL / 256) * x1_010_chip->gain[BURN_SND_X1010_ROUTE_1]);
182 					}
183 
184 					if ((x1_010_chip->output_dir[BURN_SND_X1010_ROUTE_2] & BURN_SND_ROUTE_LEFT) == BURN_SND_ROUTE_LEFT) {
185 						nLeftSample += (INT32)((data * volR / 256) * x1_010_chip->gain[BURN_SND_X1010_ROUTE_2]);
186 					}
187 					if ((x1_010_chip->output_dir[BURN_SND_X1010_ROUTE_2] & BURN_SND_ROUTE_RIGHT) == BURN_SND_ROUTE_RIGHT) {
188 						nRightSample += (INT32)((data * volR / 256) * x1_010_chip->gain[BURN_SND_X1010_ROUTE_2]);
189 					}
190 
191 					nLeftSample = BURN_SND_CLIP(nLeftSample);
192 					nRightSample = BURN_SND_CLIP(nRightSample);
193 
194 					*bufL = BURN_SND_CLIP(*bufL + nLeftSample); bufL += 2;;
195 					*bufR = BURN_SND_CLIP(*bufR + nRightSample); bufR += 2;
196 
197 					smp_offs += smp_step;
198 					env_offs += env_step;
199 				}
200 
201 				x1_010_chip->smp_offset[ch] = smp_offs;
202 				x1_010_chip->env_offset[ch] = env_offs;
203 			}
204 		}
205 	}
206 }
207 
x1010_sound_init(UINT32 base_clock,INT32 address)208 void x1010_sound_init(UINT32 base_clock, INT32 address)
209 {
210 	DebugSnd_X1010Initted = 1;
211 
212 	x1_010_chip = (struct x1_010_info *) BurnMalloc( sizeof(struct x1_010_info) );
213 
214 	memset(x1_010_chip, 0, sizeof(struct x1_010_info));
215 
216 	x1_010_chip->base_clock = base_clock;
217 	x1_010_chip->rate = x1_010_chip->base_clock / 1024;
218 	x1_010_chip->address = address;
219 
220 	x1_010_chip->gain[BURN_SND_X1010_ROUTE_1] = 1.00;
221 	x1_010_chip->gain[BURN_SND_X1010_ROUTE_2] = 1.00;
222 	x1_010_chip->output_dir[BURN_SND_X1010_ROUTE_1] = BURN_SND_ROUTE_BOTH;
223 	x1_010_chip->output_dir[BURN_SND_X1010_ROUTE_2] = BURN_SND_ROUTE_BOTH;
224 }
225 
x1010_set_route(INT32 nIndex,double nVolume,INT32 nRouteDir)226 void x1010_set_route(INT32 nIndex, double nVolume, INT32 nRouteDir)
227 {
228 #if defined FBA_DEBUG
229 	if (!DebugSnd_X1010Initted) bprintf(PRINT_ERROR, _T("x1010_set_route called without init\n"));
230 	if (nIndex < 0 || nIndex > 1) bprintf(PRINT_ERROR, _T("x1010_set_route called with invalid index %i\n"), nIndex);
231 #endif
232 
233 	x1_010_chip->gain[nIndex] = nVolume;
234 	x1_010_chip->output_dir[nIndex] = nRouteDir;
235 }
236 
x1010_scan(INT32 nAction,INT32 * pnMin)237 void x1010_scan(INT32 nAction,INT32 *pnMin)
238 {
239 #if defined FBA_DEBUG
240 	if (!DebugSnd_X1010Initted) bprintf(PRINT_ERROR, _T("x1010_scan called without init\n"));
241 #endif
242 
243 	struct BurnArea ba;
244 
245 	if (pnMin != NULL) {
246 		*pnMin =  0x029672;
247 	}
248 
249 	if ( nAction & ACB_DRIVER_DATA ) {
250 		memset(&ba, 0, sizeof(ba));
251 		ba.Data	  = x1_010_chip;
252 		ba.nLen	  = sizeof(struct x1_010_info);
253 		ba.szName = "X1-010";
254 		BurnAcb(&ba);
255 	}
256 }
257 
x1010_exit()258 void x1010_exit()
259 {
260 #if defined FBA_DEBUG
261 	if (!DebugSnd_X1010Initted) bprintf(PRINT_ERROR, _T("x1010_exit called without init\n"));
262 #endif
263 
264 	BurnFree(x1_010_chip);
265 
266 	X1010_Arbalester_Mode = 0;
267 
268 	DebugSnd_X1010Initted = 0;
269 }
270