trunk/src/emu/sound/qsound.c
| r28769 | r28770 | |
| 10 | 10 | |
| 11 | 11 | QSpace position is simulated by panning the sound in the stereo space. |
| 12 | 12 | |
| 13 | | Register |
| 14 | | 0 xxbb xx = unknown bb = start high address |
| 15 | | 1 ssss ssss = sample start address |
| 16 | | 2 pitch |
| 17 | | 3 unknown (always 0x8000) |
| 18 | | 4 loop offset from end address |
| 19 | | 5 end |
| 20 | | 6 master channel volume |
| 21 | | 7 not used |
| 22 | | 8 Balance (left=0x0110 centre=0x0120 right=0x0130) |
| 23 | | 9 unknown (most fixed samples use 0 for this register) |
| 24 | | |
| 25 | 13 | Many thanks to CAB (the author of Amuse), without whom this probably would |
| 26 | 14 | never have been finished. |
| 27 | 15 | |
| r28769 | r28770 | |
| 34 | 22 | #include "emu.h" |
| 35 | 23 | #include "qsound.h" |
| 36 | 24 | |
| 37 | | // Debug defines |
| 38 | | #define LOG_WAVE 0 |
| 39 | | #define VERBOSE 0 |
| 40 | | #define LOG(x) do { if (VERBOSE) logerror x; } while (0) |
| 41 | | |
| 42 | | |
| 43 | 25 | // device type definition |
| 44 | 26 | const device_type QSOUND = &device_creator<qsound_device>; |
| 45 | 27 | |
| 46 | 28 | |
| 47 | | //************************************************************************** |
| 48 | | // GLOBAL VARIABLES |
| 49 | | //************************************************************************** |
| 50 | | |
| 51 | 29 | // program map for the DSP (points to internal 4096 words of internal ROM) |
| 52 | 30 | static ADDRESS_MAP_START( dsp16_program_map, AS_PROGRAM, 16, qsound_device ) |
| 53 | 31 | AM_RANGE(0x0000, 0x0fff) AM_ROM |
| r28769 | r28770 | |
| 92 | 70 | m_stream(NULL), |
| 93 | 71 | m_sample_rom_length(0), |
| 94 | 72 | m_sample_rom(NULL), |
| 95 | | m_cpu(NULL), |
| 96 | | m_frq_ratio(0.0f), |
| 97 | | m_fpRawDataL(NULL), |
| 98 | | m_fpRawDataR(NULL) |
| 73 | m_cpu(NULL) |
| 99 | 74 | { |
| 100 | 75 | } |
| 101 | 76 | |
| r28769 | r28770 | |
| 128 | 103 | |
| 129 | 104 | void qsound_device::device_start() |
| 130 | 105 | { |
| 131 | | int i; |
| 132 | | |
| 133 | 106 | // find our CPU |
| 134 | 107 | m_cpu = subdevice<dsp16_device>("qsound"); |
| 135 | 108 | |
| 136 | | m_sample_rom = (QSOUND_SRC_SAMPLE *)*region(); |
| 109 | m_sample_rom = (INT8*)*region(); |
| 137 | 110 | m_sample_rom_length = region()->bytes(); |
| 138 | 111 | |
| 139 | 112 | memset(m_channel, 0, sizeof(m_channel)); |
| 140 | 113 | |
| 141 | | m_frq_ratio = 16.0; |
| 142 | | |
| 143 | 114 | /* Create pan table */ |
| 144 | | for (i=0; i<33; i++) |
| 145 | | { |
| 146 | | m_pan_table[i]=(int)((256/sqrt(32.0)) * sqrt((double)i)); |
| 147 | | } |
| 115 | for (int i = 0; i < 33; i++) |
| 116 | m_pan_table[i] = (int)((256 / sqrt(32.0)) * sqrt((double)i)); |
| 148 | 117 | |
| 149 | | LOG(("Pan table\n")); |
| 150 | | for (i=0; i<33; i++) |
| 151 | | LOG(("%02x ", m_pan_table[i])); |
| 152 | | |
| 153 | 118 | /* Allocate stream */ |
| 154 | | m_stream = stream_alloc(0, 2, clock() / QSOUND_CLOCKDIV); |
| 119 | m_stream = stream_alloc(0, 2, clock() / 166); // /166 clock divider |
| 155 | 120 | |
| 156 | | if (LOG_WAVE) |
| 157 | | { |
| 158 | | m_fpRawDataR=fopen("qsoundr.raw", "w+b"); |
| 159 | | m_fpRawDataL=fopen("qsoundl.raw", "w+b"); |
| 160 | | } |
| 161 | | |
| 162 | 121 | /* state save */ |
| 163 | | for (i=0; i<QSOUND_CHANNELS; i++) |
| 122 | for (int i = 0; i < 16; i++) |
| 164 | 123 | { |
| 165 | 124 | save_item(NAME(m_channel[i].bank), i); |
| 166 | 125 | save_item(NAME(m_channel[i].address), i); |
| 167 | | save_item(NAME(m_channel[i].pitch), i); |
| 126 | save_item(NAME(m_channel[i].freq), i); |
| 168 | 127 | save_item(NAME(m_channel[i].loop), i); |
| 169 | 128 | save_item(NAME(m_channel[i].end), i); |
| 170 | 129 | save_item(NAME(m_channel[i].vol), i); |
| 171 | | save_item(NAME(m_channel[i].pan), i); |
| 172 | | save_item(NAME(m_channel[i].key), i); |
| 130 | save_item(NAME(m_channel[i].enabled), i); |
| 173 | 131 | save_item(NAME(m_channel[i].lvol), i); |
| 174 | 132 | save_item(NAME(m_channel[i].rvol), i); |
| 175 | | save_item(NAME(m_channel[i].lastdt), i); |
| 176 | | save_item(NAME(m_channel[i].offset), i); |
| 133 | save_item(NAME(m_channel[i].sample), i); |
| 134 | save_item(NAME(m_channel[i].step_ptr), i); |
| 177 | 135 | } |
| 178 | 136 | } |
| 179 | 137 | |
| 180 | | //------------------------------------------------- |
| 181 | | // device_stop - device-specific stop |
| 182 | | //------------------------------------------------- |
| 183 | 138 | |
| 184 | | void qsound_device::device_stop() |
| 185 | | { |
| 186 | | if (m_fpRawDataR) |
| 187 | | { |
| 188 | | fclose(m_fpRawDataR); |
| 189 | | } |
| 190 | | m_fpRawDataR = NULL; |
| 191 | | if (m_fpRawDataL) |
| 192 | | { |
| 193 | | fclose(m_fpRawDataL); |
| 194 | | } |
| 195 | | m_fpRawDataL = NULL; |
| 196 | | } |
| 197 | | |
| 198 | | |
| 199 | 139 | //------------------------------------------------- |
| 200 | 140 | // sound_stream_update - handle a stream update |
| 201 | 141 | //------------------------------------------------- |
| 202 | 142 | |
| 203 | 143 | void qsound_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) |
| 204 | 144 | { |
| 205 | | int i,j; |
| 206 | | int rvol, lvol, count; |
| 207 | | struct QSOUND_CHANNEL *pC=&m_channel[0]; |
| 208 | | stream_sample_t *datap[2]; |
| 145 | // Clear the buffers |
| 146 | memset(outputs[0], 0, samples * sizeof(*outputs[0])); |
| 147 | memset(outputs[1], 0, samples * sizeof(*outputs[1])); |
| 209 | 148 | |
| 210 | | datap[0] = outputs[0]; |
| 211 | | datap[1] = outputs[1]; |
| 212 | | memset( datap[0], 0x00, samples * sizeof(*datap[0]) ); |
| 213 | | memset( datap[1], 0x00, samples * sizeof(*datap[1]) ); |
| 214 | | |
| 215 | | for (i=0; i<QSOUND_CHANNELS; i++) |
| 149 | for (int ch = 0; ch < 16; ch++) |
| 216 | 150 | { |
| 217 | | if (pC->key) |
| 151 | if (m_channel[ch].enabled) |
| 218 | 152 | { |
| 219 | | QSOUND_SAMPLE *pOutL=datap[0]; |
| 220 | | QSOUND_SAMPLE *pOutR=datap[1]; |
| 221 | | rvol=(pC->rvol*pC->vol)>>8; |
| 222 | | lvol=(pC->lvol*pC->vol)>>8; |
| 153 | stream_sample_t *lmix=outputs[0]; |
| 154 | stream_sample_t *rmix=outputs[1]; |
| 155 | int rvol = (m_channel[ch].rvol * m_channel[ch].vol) >> 8; |
| 156 | int lvol = (m_channel[ch].lvol * m_channel[ch].vol) >> 8; |
| 223 | 157 | |
| 224 | | for (j=samples-1; j>=0; j--) |
| 158 | // Go through the buffer and add voice contributions |
| 159 | for (int i = 0; i < samples; i++) |
| 225 | 160 | { |
| 226 | | count=(pC->offset)>>16; |
| 227 | | pC->offset &= 0xffff; |
| 228 | | if (count) |
| 161 | if (m_channel[ch].step_ptr & ~0xfff) |
| 229 | 162 | { |
| 230 | | pC->address += count; |
| 231 | | if (pC->address >= pC->end) |
| 163 | m_channel[ch].address += (m_channel[ch].step_ptr >> 12); |
| 164 | m_channel[ch].step_ptr &= 0xfff; |
| 165 | |
| 166 | if (m_channel[ch].address >= m_channel[ch].end) |
| 232 | 167 | { |
| 233 | | if (!pC->loop) |
| 168 | if (m_channel[ch].loop) |
| 234 | 169 | { |
| 235 | | /* Reached the end of a non-looped sample */ |
| 236 | | pC->key=0; |
| 170 | // Reached the end, restart the loop |
| 171 | m_channel[ch].address = (m_channel[ch].end - m_channel[ch].loop) & 0xffff; |
| 172 | } |
| 173 | else |
| 174 | { |
| 175 | // Reached the end of a non-looped sample |
| 176 | m_channel[ch].enabled = false; |
| 237 | 177 | break; |
| 238 | 178 | } |
| 239 | | /* Reached the end, restart the loop */ |
| 240 | | pC->address = (pC->end - pC->loop) & 0xffff; |
| 241 | 179 | } |
| 242 | | pC->lastdt=m_sample_rom[(pC->bank+pC->address)%(m_sample_rom_length)]; |
| 180 | m_channel[ch].sample = read_sample(m_channel[ch].bank | m_channel[ch].address); |
| 243 | 181 | } |
| 244 | 182 | |
| 245 | | (*pOutL) += ((pC->lastdt * lvol) >> 6); |
| 246 | | (*pOutR) += ((pC->lastdt * rvol) >> 6); |
| 247 | | pOutL++; |
| 248 | | pOutR++; |
| 249 | | pC->offset += pC->pitch; |
| 183 | *lmix++ += ((m_channel[ch].sample * lvol) >> 6); |
| 184 | *rmix++ += ((m_channel[ch].sample * rvol) >> 6); |
| 185 | m_channel[ch].step_ptr += m_channel[ch].freq; |
| 250 | 186 | } |
| 251 | 187 | } |
| 252 | | pC++; |
| 253 | 188 | } |
| 254 | | |
| 255 | | if (m_fpRawDataL) |
| 256 | | fwrite(datap[0], samples*sizeof(QSOUND_SAMPLE), 1, m_fpRawDataL); |
| 257 | | if (m_fpRawDataR) |
| 258 | | fwrite(datap[1], samples*sizeof(QSOUND_SAMPLE), 1, m_fpRawDataR); |
| 259 | 189 | } |
| 260 | 190 | |
| 261 | 191 | |
| 262 | | WRITE8_MEMBER( qsound_device::qsound_w ) |
| 192 | WRITE8_MEMBER(qsound_device::qsound_w) |
| 263 | 193 | { |
| 264 | 194 | switch (offset) |
| 265 | 195 | { |
| 266 | 196 | case 0: |
| 267 | | m_data=(m_data&0xff)|(data<<8); |
| 197 | m_data = (m_data & 0x00ff) | (data << 8); |
| 268 | 198 | break; |
| 269 | 199 | |
| 270 | 200 | case 1: |
| 271 | | m_data=(m_data&0xff00)|data; |
| 201 | m_data = (m_data & 0xff00) | data; |
| 272 | 202 | break; |
| 273 | 203 | |
| 274 | 204 | case 2: |
| 275 | | qsound_set_command(data, m_data); |
| 205 | write_data(data, m_data); |
| 276 | 206 | break; |
| 277 | 207 | |
| 278 | 208 | default: |
| 279 | | logerror("%s: unexpected qsound write to offset %d == %02X\n", machine().describe_context(), offset, data); |
| 209 | logerror("%s: qsound_w %d = %02x\n", machine().describe_context(), offset, data); |
| 280 | 210 | break; |
| 281 | 211 | } |
| 282 | 212 | } |
| 283 | 213 | |
| 284 | 214 | |
| 285 | | READ8_MEMBER( qsound_device::qsound_r ) |
| 215 | READ8_MEMBER(qsound_device::qsound_r) |
| 286 | 216 | { |
| 287 | 217 | /* Port ready bit (0x80 if ready) */ |
| 288 | 218 | return 0x80; |
| 289 | 219 | } |
| 290 | 220 | |
| 291 | 221 | |
| 292 | | void qsound_device::qsound_set_command(int data, int value) |
| 222 | void qsound_device::write_data(UINT8 address, UINT16 data) |
| 293 | 223 | { |
| 294 | | int ch=0,reg=0; |
| 295 | | if (data < 0x80) |
| 224 | int ch = 0, reg = 0; |
| 225 | |
| 226 | if (address < 0x80) |
| 296 | 227 | { |
| 297 | | ch=data>>3; |
| 298 | | reg=data & 0x07; |
| 228 | ch = address >> 3; |
| 229 | reg = address & 7; |
| 299 | 230 | } |
| 231 | else if (address < 0x90) |
| 232 | { |
| 233 | ch = address & 0xf; |
| 234 | reg = 8; |
| 235 | } |
| 236 | else if (address >= 0xba && address < 0xca) |
| 237 | { |
| 238 | ch = address - 0xba; |
| 239 | reg = 9; |
| 240 | } |
| 300 | 241 | else |
| 301 | 242 | { |
| 302 | | if (data < 0x90) |
| 303 | | { |
| 304 | | ch=data-0x80; |
| 305 | | reg=8; |
| 306 | | } |
| 307 | | else |
| 308 | | { |
| 309 | | if (data >= 0xba && data < 0xca) |
| 310 | | { |
| 311 | | ch=data-0xba; |
| 312 | | reg=9; |
| 313 | | } |
| 314 | | else |
| 315 | | { |
| 316 | | /* Unknown registers */ |
| 317 | | ch=99; |
| 318 | | reg=99; |
| 319 | | } |
| 320 | | } |
| 243 | // unknown |
| 244 | reg = address; |
| 321 | 245 | } |
| 322 | 246 | |
| 323 | 247 | switch (reg) |
| 324 | 248 | { |
| 325 | | case 0: /* Bank */ |
| 326 | | ch=(ch+1)&0x0f; /* strange ... */ |
| 327 | | m_channel[ch].bank=(value&0x7f)<<16; |
| 328 | | #ifdef MAME_DEBUG |
| 329 | | if (!(value & 0x8000)) |
| 330 | | popmessage("Register3=%04x",value); |
| 331 | | #endif |
| 249 | case 0: |
| 250 | // bank, high bits unknown |
| 251 | ch = (ch + 1) & 0xf; // strange ... |
| 252 | m_channel[ch].bank = (data & 0x7f) << 16; |
| 253 | break; |
| 332 | 254 | |
| 255 | case 1: |
| 256 | // start/cur address |
| 257 | m_channel[ch].address = data; |
| 333 | 258 | break; |
| 334 | | case 1: /* start */ |
| 335 | | m_channel[ch].address=value; |
| 336 | | break; |
| 337 | | case 2: /* pitch */ |
| 338 | | m_channel[ch].pitch=value * 16; |
| 339 | | if (!value) |
| 259 | |
| 260 | case 2: |
| 261 | // frequency |
| 262 | m_channel[ch].freq = data; |
| 263 | if (data == 0) |
| 340 | 264 | { |
| 341 | | /* Key off */ |
| 342 | | m_channel[ch].key=0; |
| 265 | // key off |
| 266 | m_channel[ch].enabled = false; |
| 343 | 267 | } |
| 344 | 268 | break; |
| 345 | | case 3: /* unknown */ |
| 346 | | m_channel[ch].reg3=value; |
| 347 | | #ifdef MAME_DEBUG |
| 348 | | if (value != 0x8000) |
| 349 | | popmessage("Register3=%04x",value); |
| 350 | | #endif |
| 269 | |
| 270 | case 3: |
| 271 | // unknown, always 0x8000? |
| 351 | 272 | break; |
| 352 | | case 4: /* loop offset */ |
| 353 | | m_channel[ch].loop=value; |
| 273 | |
| 274 | case 4: |
| 275 | // loop address |
| 276 | m_channel[ch].loop = data; |
| 354 | 277 | break; |
| 355 | | case 5: /* end */ |
| 356 | | m_channel[ch].end=value; |
| 278 | |
| 279 | case 5: |
| 280 | // end address |
| 281 | m_channel[ch].end = data; |
| 357 | 282 | break; |
| 358 | | case 6: /* master volume */ |
| 359 | | if (value==0) |
| 283 | |
| 284 | case 6: |
| 285 | // master volume |
| 286 | if (data == 0) |
| 360 | 287 | { |
| 361 | | /* Key off */ |
| 362 | | m_channel[ch].key=0; |
| 288 | // key off |
| 289 | m_channel[ch].enabled = false; |
| 363 | 290 | } |
| 364 | | else if (m_channel[ch].key==0) |
| 291 | else if (!m_channel[ch].enabled) |
| 365 | 292 | { |
| 366 | | /* Key on */ |
| 367 | | m_channel[ch].key=1; |
| 368 | | m_channel[ch].offset=0; |
| 369 | | m_channel[ch].lastdt=0; |
| 293 | // key off -> key on |
| 294 | m_channel[ch].enabled = true; |
| 295 | m_channel[ch].step_ptr = 0; |
| 296 | m_channel[ch].sample = 0; |
| 370 | 297 | } |
| 371 | | m_channel[ch].vol=value; |
| 298 | m_channel[ch].vol = data; |
| 372 | 299 | break; |
| 373 | 300 | |
| 374 | | case 7: /* unused */ |
| 375 | | #ifdef MAME_DEBUG |
| 376 | | popmessage("UNUSED QSOUND REG 7=%04x",value); |
| 377 | | #endif |
| 378 | | |
| 301 | case 7: |
| 302 | // unused? |
| 379 | 303 | break; |
| 304 | |
| 380 | 305 | case 8: |
| 306 | { |
| 307 | // panning (left=0x0110, centre=0x0120, right=0x0130) |
| 308 | int pandata = (data - 0x10) & 0x3f; |
| 309 | if (pandata > 32) |
| 381 | 310 | { |
| 382 | | int pandata=(value-0x10)&0x3f; |
| 383 | | if (pandata > 32) |
| 384 | | { |
| 385 | | pandata=32; |
| 386 | | } |
| 387 | | m_channel[ch].rvol=m_pan_table[pandata]; |
| 388 | | m_channel[ch].lvol=m_pan_table[32-pandata]; |
| 389 | | m_channel[ch].pan = value; |
| 311 | pandata = 32; |
| 390 | 312 | } |
| 313 | m_channel[ch].rvol = m_pan_table[pandata]; |
| 314 | m_channel[ch].lvol = m_pan_table[32 - pandata]; |
| 391 | 315 | break; |
| 392 | | case 9: |
| 393 | | m_channel[ch].reg9=value; |
| 394 | | /* |
| 395 | | #ifdef MAME_DEBUG |
| 396 | | popmessage("QSOUND REG 9=%04x",value); |
| 397 | | #endif |
| 398 | | */ |
| 316 | } |
| 317 | |
| 318 | case 9: |
| 319 | // unknown (most fixed samples use 0 for this register) |
| 399 | 320 | break; |
| 321 | |
| 322 | default: |
| 323 | //logerror("%s: write_data %02x = %04x\n", machine().describe_context(), address, data); |
| 324 | break; |
| 400 | 325 | } |
| 401 | | LOG(("QSOUND WRITE %02x CH%02d-R%02d =%04x\n", data, ch, reg, value)); |
| 402 | 326 | } |
trunk/src/emu/sound/qsound.h
| r28769 | r28770 | |
| 13 | 13 | |
| 14 | 14 | #define QSOUND_CLOCK 4000000 /* default 4MHz clock */ |
| 15 | 15 | |
| 16 | | #define QSOUND_CLOCKDIV 166 /* Clock divider */ |
| 17 | | #define QSOUND_CHANNELS 16 |
| 18 | | typedef INT8 QSOUND_SRC_SAMPLE; /* 8 bit source ROM samples */ |
| 19 | | typedef stream_sample_t QSOUND_SAMPLE; |
| 20 | 16 | |
| 21 | | |
| 22 | 17 | //************************************************************************** |
| 23 | 18 | // INTERFACE CONFIGURATION MACROS |
| 24 | 19 | //************************************************************************** |
| r28769 | r28770 | |
| 29 | 24 | MCFG_DEVICE_REPLACE(_tag, QSOUND, _clock) |
| 30 | 25 | |
| 31 | 26 | |
| 32 | | //************************************************************************** |
| 33 | | // TYPE DEFINITIONS |
| 34 | | //************************************************************************** |
| 35 | | |
| 36 | | struct QSOUND_CHANNEL |
| 37 | | { |
| 38 | | INT32 bank; // bank (x16) |
| 39 | | INT32 address; // start address |
| 40 | | INT32 pitch; // pitch |
| 41 | | INT32 reg3; // unknown (always 0x8000) |
| 42 | | INT32 loop; // loop address |
| 43 | | INT32 end; // end address |
| 44 | | INT32 vol; // master volume |
| 45 | | INT32 pan; // Pan value |
| 46 | | INT32 reg9; // unknown |
| 47 | | |
| 48 | | /* Work variables */ |
| 49 | | INT32 key; // Key on / key off |
| 50 | | INT32 lvol; // left volume |
| 51 | | INT32 rvol; // right volume |
| 52 | | INT32 lastdt; // last sample value |
| 53 | | INT32 offset; // current offset counter |
| 54 | | }; |
| 55 | | |
| 56 | | |
| 57 | 27 | // ======================> qsound_device |
| 58 | 28 | |
| 59 | 29 | class qsound_device : public device_t, |
| r28769 | r28770 | |
| 63 | 33 | qsound_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); |
| 64 | 34 | ~qsound_device() { } |
| 65 | 35 | |
| 36 | DECLARE_WRITE8_MEMBER(qsound_w); |
| 37 | DECLARE_READ8_MEMBER(qsound_r); |
| 38 | |
| 66 | 39 | protected: |
| 67 | 40 | // device-level overrides |
| 68 | 41 | const rom_entry *device_rom_region() const; |
| 69 | 42 | machine_config_constructor device_mconfig_additions() const; |
| 70 | 43 | virtual void device_start(); |
| 71 | | virtual void device_stop(); |
| 72 | 44 | |
| 73 | 45 | // sound stream update overrides |
| 74 | 46 | virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); |
| 75 | 47 | |
| 76 | | public: |
| 77 | | DECLARE_WRITE8_MEMBER( qsound_w ); |
| 78 | | DECLARE_READ8_MEMBER( qsound_r ); |
| 79 | | |
| 80 | 48 | private: |
| 81 | | void qsound_set_command(int data, int value); |
| 49 | struct qsound_channel |
| 50 | { |
| 51 | UINT32 bank; // bank |
| 52 | UINT32 address; // start/cur address |
| 53 | UINT16 loop; // loop address |
| 54 | UINT16 end; // end address |
| 55 | UINT32 freq; // frequency |
| 56 | UINT16 vol; // master volume |
| 82 | 57 | |
| 83 | | private: |
| 84 | | int m_data; // register latch data |
| 85 | | sound_stream *m_stream; // Audio stream |
| 86 | | QSOUND_CHANNEL m_channel[QSOUND_CHANNELS]; |
| 58 | // work variables |
| 59 | bool enabled; // key on / key off |
| 60 | int lvol; // left volume |
| 61 | int rvol; // right volume |
| 62 | INT8 sample; // last sample value |
| 63 | UINT32 step_ptr; // current offset counter |
| 64 | } m_channel[16]; |
| 65 | |
| 66 | int m_pan_table[33]; // pan volume table |
| 67 | UINT16 m_data; // register latch data |
| 68 | sound_stream *m_stream; // audio stream |
| 87 | 69 | UINT32 m_sample_rom_length; |
| 88 | | QSOUND_SRC_SAMPLE *m_sample_rom; // Q sound sample ROM |
| 70 | INT8 *m_sample_rom; // Q-Sound sample ROM |
| 89 | 71 | dsp16_device *m_cpu; |
| 90 | 72 | |
| 91 | | int m_pan_table[33]; // Pan volume table |
| 92 | | float m_frq_ratio; // Frequency ratio |
| 93 | | |
| 94 | | FILE *m_fpRawDataL; |
| 95 | | FILE *m_fpRawDataR; |
| 73 | inline INT8 read_sample(UINT32 offset) { return m_sample_rom[offset % m_sample_rom_length]; } |
| 74 | void write_data(UINT8 address, UINT16 data); |
| 96 | 75 | }; |
| 97 | 76 | |
| 98 | 77 | extern const device_type QSOUND; |