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