1 // license:BSD-3-Clause
2 // copyright-holders:superctr, Valley Bell
3 /***************************************************************************
4
5 Capcom QSound DL-1425 (HLE)
6 ===========================
7
8 Driver by superctr with thanks to Valley Bell.
9
10 Based on disassembled DSP code.
11
12 Links:
13 https://siliconpr0n.org/map/capcom/dl-1425
14
15 ***************************************************************************/
16
17 #include "emu.h"
18 #include "qsoundhle.h"
19
20 #include <algorithm>
21 #include <limits>
22
23 // device type definition
24 DEFINE_DEVICE_TYPE(QSOUND_HLE, qsound_hle_device, "qsound_hle", "QSound (HLE)")
25
26 // DSP internal ROM region
ROM_START(qsound_hle)27 ROM_START( qsound_hle )
28 ROM_REGION16_LE( 0x2000, "dsp", 0 )
29 // removing WORD_SWAP from original definition
30 ROM_LOAD16_WORD( "dl-1425.bin", 0x0000, 0x2000, CRC(d6cf5ef5) SHA1(555f50fe5cdf127619da7d854c03f4a244a0c501) )
31 ROM_IGNORE( 0x4000 )
32 ROM_END
33
34 //**************************************************************************
35 // LIVE DEVICE
36 //**************************************************************************
37
38 //-------------------------------------------------
39 // qsound_hle_device - constructor
40 //-------------------------------------------------
41
42 qsound_hle_device::qsound_hle_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
43 : device_t(mconfig, QSOUND_HLE, tag, owner, clock)
44 , device_sound_interface(mconfig, *this)
45 , device_rom_interface(mconfig, *this)
46 , m_stream(nullptr)
47 , m_dsp_rom(*this, "dsp")
48 , m_data_latch(0)
49 {
50 }
51
52 //-------------------------------------------------
53 // rom_bank_updated - the rom bank has changed
54 //-------------------------------------------------
55
rom_bank_updated()56 void qsound_hle_device::rom_bank_updated()
57 {
58 m_stream->update();
59 }
60
61 //-------------------------------------------------
62 // device_start - device-specific startup
63 //-------------------------------------------------
64
device_start()65 void qsound_hle_device::device_start()
66 {
67 m_stream = stream_alloc(0, 2, clock() / 2 / 1248); // DSP program uses 1248 machine cycles per iteration
68
69 init_register_map();
70
71 // state save
72 // PCM registers
73 // PCM voices
74 save_item(STRUCT_MEMBER(m_voice, m_bank));
75 save_item(STRUCT_MEMBER(m_voice, m_addr));
76 save_item(STRUCT_MEMBER(m_voice, m_phase));
77 save_item(STRUCT_MEMBER(m_voice, m_rate));
78 save_item(STRUCT_MEMBER(m_voice, m_loop_len));
79 save_item(STRUCT_MEMBER(m_voice, m_end_addr));
80 save_item(STRUCT_MEMBER(m_voice, m_volume));
81 save_item(STRUCT_MEMBER(m_voice, m_echo));
82
83 // ADPCM voices
84 save_item(STRUCT_MEMBER(m_adpcm, m_start_addr));
85 save_item(STRUCT_MEMBER(m_adpcm, m_end_addr));
86 save_item(STRUCT_MEMBER(m_adpcm, m_bank));
87 save_item(STRUCT_MEMBER(m_adpcm, m_volume));
88 save_item(STRUCT_MEMBER(m_adpcm, m_flag));
89 save_item(STRUCT_MEMBER(m_adpcm, m_cur_vol));
90 save_item(STRUCT_MEMBER(m_adpcm, m_step_size));
91 save_item(STRUCT_MEMBER(m_adpcm, m_cur_addr));
92
93 // PCM voices
94 save_item(NAME(m_voice_pan));
95
96 // QSound registers
97 save_item(NAME(m_echo.m_end_pos));
98 save_item(NAME(m_echo.m_feedback));
99 save_item(NAME(m_echo.m_length));
100 save_item(NAME(m_echo.m_last_sample));
101 save_item(NAME(m_echo.m_delay_line));
102 save_item(NAME(m_echo.m_delay_pos));
103
104 // left, right
105 save_item(STRUCT_MEMBER(m_filter, m_tap_count));
106 save_item(STRUCT_MEMBER(m_filter, m_delay_pos));
107 save_item(STRUCT_MEMBER(m_filter, m_table_pos));
108 save_item(STRUCT_MEMBER(m_filter, m_taps));
109 save_item(STRUCT_MEMBER(m_filter, m_delay_line));
110
111 save_item(STRUCT_MEMBER(m_alt_filter, m_tap_count));
112 save_item(STRUCT_MEMBER(m_alt_filter, m_delay_pos));
113 save_item(STRUCT_MEMBER(m_alt_filter, m_table_pos));
114 save_item(STRUCT_MEMBER(m_alt_filter, m_taps));
115 save_item(STRUCT_MEMBER(m_alt_filter, m_delay_line));
116
117 save_item(STRUCT_MEMBER(m_wet, m_delay));
118 save_item(STRUCT_MEMBER(m_wet, m_volume));
119 save_item(STRUCT_MEMBER(m_wet, m_write_pos));
120 save_item(STRUCT_MEMBER(m_wet, m_read_pos));
121 save_item(STRUCT_MEMBER(m_wet, m_delay_line));
122
123 save_item(STRUCT_MEMBER(m_dry, m_delay));
124 save_item(STRUCT_MEMBER(m_dry, m_volume));
125 save_item(STRUCT_MEMBER(m_dry, m_write_pos));
126 save_item(STRUCT_MEMBER(m_dry, m_read_pos));
127 save_item(STRUCT_MEMBER(m_dry, m_delay_line));
128
129 save_item(NAME(m_state));
130 save_item(NAME(m_next_state));
131 save_item(NAME(m_delay_update));
132 save_item(NAME(m_state_counter));
133 save_item(NAME(m_ready_flag));
134 save_item(NAME(m_data_latch));
135 save_item(NAME(m_out));
136 }
137
138 //-------------------------------------------------
139 // rom_region - return a pointer to the device's
140 // internal ROM region
141 //-------------------------------------------------
142
device_rom_region() const143 const tiny_rom_entry *qsound_hle_device::device_rom_region() const
144 {
145 return ROM_NAME( qsound_hle );
146 }
147
148 //-------------------------------------------------
149 // device_reset - device-specific reset
150 //-------------------------------------------------
151
device_reset()152 void qsound_hle_device::device_reset()
153 {
154 m_ready_flag = 0;
155 m_out[0] = m_out[1] = 0;
156 m_state = STATE_BOOT;
157 m_state_counter = 0;
158 }
159
160 //-------------------------------------------------
161 // sound_stream_update - handle a stream update
162 //-------------------------------------------------
163
sound_stream_update(sound_stream & stream,std::vector<read_stream_view> const & inputs,std::vector<write_stream_view> & outputs)164 void qsound_hle_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
165 {
166 for (int i = 0; i < outputs[0].samples(); i ++)
167 {
168 update_sample();
169 outputs[0].put_int(i, m_out[0], 32768);
170 outputs[1].put_int(i, m_out[1], 32768);
171 }
172 }
173
174
qsound_w(offs_t offset,uint8_t data)175 void qsound_hle_device::qsound_w(offs_t offset, uint8_t data)
176 {
177 switch (offset)
178 {
179 case 0:
180 m_data_latch = (m_data_latch & 0x00ff) | (data << 8);
181 break;
182
183 case 1:
184 m_data_latch = (m_data_latch & 0xff00) | data;
185 break;
186
187 case 2:
188 m_stream->update();
189 write_data(data, m_data_latch);
190 break;
191
192 default:
193 logerror("%s: qsound_w %d = %02x\n", machine().describe_context(), offset, data);
194 break;
195 }
196 }
197
198
qsound_r()199 uint8_t qsound_hle_device::qsound_r()
200 {
201 // ready bit (0x00 = busy, 0x80 == ready)
202 m_stream->update();
203 return m_ready_flag;
204 }
205
206
write_data(uint8_t address,uint16_t data)207 void qsound_hle_device::write_data(uint8_t address, uint16_t data)
208 {
209 uint16_t *destination = m_register_map[address];
210 if (destination)
211 *destination = data;
212 m_ready_flag = 0;
213 }
214
init_register_map()215 void qsound_hle_device::init_register_map()
216 {
217 // unused registers
218 std::fill(std::begin(m_register_map), std::end(m_register_map), nullptr);
219
220 // PCM registers
221 for (int i = 0; i < 16; i++) // PCM voices
222 {
223 m_register_map[(i << 3) + 0] = (uint16_t*)&m_voice[(i + 1) % 16].m_bank; // Bank applies to the next channel
224 m_register_map[(i << 3) + 1] = (uint16_t*)&m_voice[i].m_addr; // Current sample position and start position.
225 m_register_map[(i << 3) + 2] = (uint16_t*)&m_voice[i].m_rate; // 4.12 fixed point decimal.
226 m_register_map[(i << 3) + 3] = (uint16_t*)&m_voice[i].m_phase;
227 m_register_map[(i << 3) + 4] = (uint16_t*)&m_voice[i].m_loop_len;
228 m_register_map[(i << 3) + 5] = (uint16_t*)&m_voice[i].m_end_addr;
229 m_register_map[(i << 3) + 6] = (uint16_t*)&m_voice[i].m_volume;
230 m_register_map[(i << 3) + 7] = nullptr; // unused
231 m_register_map[i + 0x80] = (uint16_t*)&m_voice_pan[i];
232 m_register_map[i + 0xba] = (uint16_t*)&m_voice[i].m_echo;
233 }
234
235 // ADPCM registers
236 for (int i = 0; i < 3; i++) // ADPCM voices
237 {
238 // ADPCM sample rate is fixed to 8khz. (one channel is updated every third sample)
239 m_register_map[(i << 2) + 0xca] = (uint16_t*)&m_adpcm[i].m_start_addr;
240 m_register_map[(i << 2) + 0xcb] = (uint16_t*)&m_adpcm[i].m_end_addr;
241 m_register_map[(i << 2) + 0xcc] = (uint16_t*)&m_adpcm[i].m_bank;
242 m_register_map[(i << 2) + 0xcd] = (uint16_t*)&m_adpcm[i].m_volume;
243 m_register_map[i + 0xd6] = (uint16_t*)&m_adpcm[i].m_flag; // non-zero to start ADPCM playback
244 m_register_map[i + 0x90] = (uint16_t*)&m_voice_pan[16 + i];
245 }
246
247 // QSound registers
248 m_register_map[0x93] = (uint16_t*)&m_echo.m_feedback;
249 m_register_map[0xd9] = (uint16_t*)&m_echo.m_end_pos;
250 m_register_map[0xe2] = (uint16_t*)&m_delay_update; // non-zero to update delays
251 m_register_map[0xe3] = (uint16_t*)&m_next_state;
252 for (int i = 0; i < 2; i++) // left, right
253 {
254 // Wet
255 m_register_map[(i << 1) + 0xda] = (uint16_t*)&m_filter[i].m_table_pos;
256 m_register_map[(i << 1) + 0xde] = (uint16_t*)&m_wet[i].m_delay;
257 m_register_map[(i << 1) + 0xe4] = (uint16_t*)&m_wet[i].m_volume;
258 // Dry
259 m_register_map[(i << 1) + 0xdb] = (uint16_t*)&m_alt_filter[i].m_table_pos;
260 m_register_map[(i << 1) + 0xdf] = (uint16_t*)&m_dry[i].m_delay;
261 m_register_map[(i << 1) + 0xe5] = (uint16_t*)&m_dry[i].m_volume;
262 }
263 }
264
read_sample(uint16_t bank,uint16_t address)265 int16_t qsound_hle_device::read_sample(uint16_t bank, uint16_t address)
266 {
267 bank &= 0x7FFF;
268 const uint32_t rom_addr = (bank << 16) | (address << 0);
269 const uint8_t sample_data = read_byte(rom_addr);
270 return (int16_t)(sample_data << 8); // bit0-7 is tied to ground
271 }
272
273 /********************************************************************/
274
275 // updates one DSP sample
update_sample()276 void qsound_hle_device::update_sample()
277 {
278 switch (m_state)
279 {
280 default:
281 case STATE_INIT1:
282 case STATE_INIT2:
283 return state_init();
284 case STATE_REFRESH1:
285 return state_refresh_filter_1();
286 case STATE_REFRESH2:
287 return state_refresh_filter_2();
288 case STATE_NORMAL1:
289 case STATE_NORMAL2:
290 return state_normal_update();
291 }
292 }
293
294 // Initialization routine
state_init()295 void qsound_hle_device::state_init()
296 {
297 int mode = (m_state == STATE_INIT2) ? 1 : 0;
298
299 // we're busy for 4 samples, including the filter refresh.
300 if (m_state_counter >= 2)
301 {
302 m_state_counter = 0;
303 m_state = m_next_state;
304 return;
305 }
306 else if (m_state_counter == 1)
307 {
308 m_state_counter++;
309 return;
310 }
311
312 std::fill(std::begin(m_voice), std::end(m_voice), qsound_voice());
313 std::fill(std::begin(m_adpcm), std::end(m_adpcm), qsound_adpcm());
314 std::fill(std::begin(m_filter), std::end(m_filter), qsound_fir());
315 std::fill(std::begin(m_alt_filter), std::end(m_alt_filter), qsound_fir());
316 std::fill(std::begin(m_wet), std::end(m_wet), qsound_delay());
317 std::fill(std::begin(m_dry), std::end(m_dry), qsound_delay());
318 m_echo = qsound_echo();
319
320 for (int i = 0; i < 19; i++)
321 {
322 m_voice_pan[i] = DATA_PAN_TAB + 0x10;
323 m_voice_output[i] = 0;
324 }
325
326 for (int i = 0; i < 16; i++)
327 m_voice[i].m_bank = 0x8000;
328 for (int i = 0; i < 3; i++)
329 m_adpcm[i].m_bank = 0x8000;
330
331 if (mode == 0)
332 {
333 // mode 1
334 m_wet[0].m_delay = 0;
335 m_dry[0].m_delay = 46;
336 m_wet[1].m_delay = 0;
337 m_dry[1].m_delay = 48;
338 m_filter[0].m_table_pos = DATA_FILTER_TAB + (FILTER_ENTRY_SIZE*1);
339 m_filter[1].m_table_pos = DATA_FILTER_TAB + (FILTER_ENTRY_SIZE*2);
340 m_echo.m_end_pos = DELAY_BASE_OFFSET + 6;
341 m_next_state = STATE_REFRESH1;
342 }
343 else
344 {
345 // mode 2
346 m_wet[0].m_delay = 1;
347 m_dry[0].m_delay = 0;
348 m_wet[1].m_delay = 0;
349 m_dry[1].m_delay = 0;
350 m_filter[0].m_table_pos = 0xf73;
351 m_filter[1].m_table_pos = 0xfa4;
352 m_alt_filter[0].m_table_pos = 0xf73;
353 m_alt_filter[1].m_table_pos = 0xfa4;
354 m_echo.m_end_pos = DELAY_BASE_OFFSET2 + 6;
355 m_next_state = STATE_REFRESH2;
356 }
357
358 m_wet[0].m_volume = 0x3fff;
359 m_dry[0].m_volume = 0x3fff;
360 m_wet[1].m_volume = 0x3fff;
361 m_dry[1].m_volume = 0x3fff;
362
363 m_delay_update = 1;
364 m_ready_flag = 0;
365 m_state_counter = 1;
366 }
367
368 // Updates filter parameters for mode 1
state_refresh_filter_1()369 void qsound_hle_device::state_refresh_filter_1()
370 {
371 for (int ch = 0; ch < 2; ch++)
372 {
373 m_filter[ch].m_delay_pos = 0;
374 m_filter[ch].m_tap_count = 95;
375
376 for (int i = 0; i < 95; i++)
377 m_filter[ch].m_taps[i] = read_dsp_rom(m_filter[ch].m_table_pos + i);
378 }
379
380 m_state = m_next_state = STATE_NORMAL1;
381 }
382
383 // Updates filter parameters for mode 2
state_refresh_filter_2()384 void qsound_hle_device::state_refresh_filter_2()
385 {
386 for (int ch = 0; ch < 2; ch++)
387 {
388 m_filter[ch].m_delay_pos = 0;
389 m_filter[ch].m_tap_count = 45;
390
391 for (int i = 0; i < 45; i++)
392 m_filter[ch].m_taps[i] = (int16_t)read_dsp_rom(m_filter[ch].m_table_pos + i);
393
394 m_alt_filter[ch].m_delay_pos = 0;
395 m_alt_filter[ch].m_tap_count = 44;
396
397 for (int i = 0; i < 44; i++)
398 m_alt_filter[ch].m_taps[i] = (int16_t)read_dsp_rom(m_alt_filter[ch].m_table_pos + i);
399 }
400
401 m_state = m_next_state = STATE_NORMAL2;
402 }
403
404 // Updates a PCM voice. There are 16 voices, each are updated every sample
405 // with full rate and volume control.
update(qsound_hle_device & dsp,int32_t * echo_out)406 int16_t qsound_hle_device::qsound_voice::update(qsound_hle_device &dsp, int32_t *echo_out)
407 {
408 // Read sample from rom and apply volume
409 const int16_t output = (m_volume * dsp.read_sample(m_bank, m_addr)) >> 14;
410
411 *echo_out += (output * m_echo) << 2;
412
413 // Add delta to the phase and loop back if required
414 int32_t new_phase = m_rate + ((m_addr << 12) | (m_phase >> 4));
415
416 if ((new_phase >> 12) >= m_end_addr)
417 new_phase -= (m_loop_len << 12);
418
419 new_phase = std::min<int32_t>(std::max<int32_t>(new_phase, -0x8000000), 0x7FFFFFF);
420 m_addr = new_phase >> 12;
421 m_phase = (new_phase << 4)&0xffff;
422
423 return output;
424 }
425
426 // Updates an ADPCM voice. There are 3 voices, one is updated every sample
427 // (effectively making the ADPCM rate 1/3 of the master sample rate), and
428 // volume is set when starting samples only.
429 // The ADPCM algorithm is supposedly similar to Yamaha ADPCM. It also seems
430 // like Capcom never used it, so this was not emulated in the earlier QSound
431 // emulators.
update(qsound_hle_device & dsp,int16_t curr_sample,int nibble)432 int16_t qsound_hle_device::qsound_adpcm::update(qsound_hle_device &dsp, int16_t curr_sample, int nibble)
433 {
434 int8_t step;
435 if (!nibble)
436 {
437 // Mute voice when it reaches the end address.
438 if (m_cur_addr == m_end_addr)
439 m_cur_vol = 0;
440
441 // Playback start flag
442 if (m_flag)
443 {
444 curr_sample = 0;
445 m_flag = 0;
446 m_step_size = 10;
447 m_cur_vol = m_volume;
448 m_cur_addr = m_start_addr;
449 }
450
451 // get top nibble
452 step = dsp.read_sample(m_bank, m_cur_addr) >> 8;
453 }
454 else
455 {
456 // get bottom nibble
457 step = dsp.read_sample(m_bank, m_cur_addr++) >> 4;
458 }
459
460 // shift with sign extend
461 step >>= 4;
462
463 // delta = (0.5 + abs(step)) * m_step_size
464 int32_t delta = ((1 + abs(step << 1)) * m_step_size) >> 1;
465 if (step <= 0)
466 delta = -delta;
467 delta += curr_sample;
468 delta = std::min<int32_t>(std::max<int32_t>(delta, -32768), 32767);
469
470 m_step_size = (dsp.read_dsp_rom(DATA_ADPCM_TAB + 8 + step) * m_step_size) >> 6;
471 m_step_size = std::min<int16_t>(std::max<int16_t>(m_step_size, 1), 2000);
472
473 return (delta * m_cur_vol) >> 16;
474 }
475
476 // The echo effect is pretty simple. A moving average filter is used on
477 // the output from the delay line to smooth samples over time.
apply(int32_t input)478 int16_t qsound_hle_device::qsound_echo::apply(int32_t input)
479 {
480 // get average of last 2 samples from the delay line
481 int32_t old_sample = m_delay_line[m_delay_pos];
482 const int32_t last_sample = m_last_sample;
483 m_last_sample = old_sample;
484 old_sample = (old_sample + last_sample) >> 1;
485
486 // add current sample to the delay line
487 int32_t new_sample = input + ((old_sample * m_feedback) << 2);
488 m_delay_line[m_delay_pos++] = new_sample >> 16;
489
490 if (m_delay_pos >= m_length)
491 m_delay_pos = 0;
492
493 return old_sample;
494 }
495
496 // Process a sample update
state_normal_update()497 void qsound_hle_device::state_normal_update()
498 {
499 m_ready_flag = 0x80;
500
501 // recalculate echo length
502 if (m_state == STATE_NORMAL2)
503 m_echo.m_length = m_echo.m_end_pos - DELAY_BASE_OFFSET2;
504 else
505 m_echo.m_length = m_echo.m_end_pos - DELAY_BASE_OFFSET;
506
507 m_echo.m_length = std::min<int16_t>(std::max<int16_t>(m_echo.m_length, 0), 1024);
508
509 // update PCM voices
510 int32_t echo_input = 0;
511 for (int i = 0; i < 16; i++)
512 m_voice_output[i] = m_voice[i].update(*this, &echo_input);
513
514 // update ADPCM voices (one every third sample)
515 const int adpcm_voice = m_state_counter % 3;
516 m_voice_output[16 + adpcm_voice] = m_adpcm[adpcm_voice].update(*this, m_voice_output[16 + adpcm_voice], m_state_counter / 3);
517
518 int16_t echo_output = m_echo.apply(echo_input);
519
520 // now, we do the magic stuff
521 for (int ch = 0; ch < 2; ch++)
522 {
523 // Echo is output on the unfiltered component of the left channel and
524 // the filtered component of the right channel.
525 int32_t wet = (ch == 1) ? echo_output << 14 : 0;
526 int32_t dry = (ch == 0) ? echo_output << 14 : 0;
527
528 for (int i = 0; i < 19; i++)
529 {
530 uint16_t pan_index = m_voice_pan[i] + (ch * PAN_TABLE_CH_OFFSET);
531
532 // Apply different volume tables on the dry and wet inputs.
533 dry -= (m_voice_output[i] * (int16_t)read_dsp_rom(pan_index + PAN_TABLE_DRY));
534 wet -= (m_voice_output[i] * (int16_t)read_dsp_rom(pan_index + PAN_TABLE_WET));
535 }
536 // Saturate accumulated voices
537 dry = (std::min<int32_t>(std::max<int32_t>(dry, -0x1fffffff), 0x1fffffff)) << 2;
538 wet = (std::min<int32_t>(std::max<int32_t>(wet, -0x1fffffff), 0x1fffffff)) << 2;
539
540 // Apply FIR filter on 'wet' input
541 wet = m_filter[ch].apply(wet >> 16);
542
543 // in mode 2, we do this on the 'dry' input too
544 if (m_state == STATE_NORMAL2)
545 dry = m_alt_filter[ch].apply(dry >> 16);
546
547 // output goes through a delay line and attenuation
548 int32_t output = (m_wet[ch].apply(wet) + m_dry[ch].apply(dry));
549
550 // DSP round function
551 output = (output + 0x2000) & ~0x3fff;
552 m_out[ch] = (std::min<int32_t>(std::max<int32_t>(output >> 14, -0x7fff), 0x7fff));
553
554 if (m_delay_update)
555 {
556 m_wet[ch].update();
557 m_dry[ch].update();
558 }
559 }
560
561 m_delay_update = 0;
562
563 // after 6 samples, the next state is executed.
564 m_state_counter++;
565 if (m_state_counter > 5)
566 {
567 m_state_counter = 0;
568 m_state = m_next_state;
569 }
570 }
571
572 // Apply the FIR filter used as the Q1 transfer function
apply(int16_t input)573 int32_t qsound_hle_device::qsound_fir::apply(int16_t input)
574 {
575 int32_t output = 0, tap = 0;
576 for (; tap < (m_tap_count - 1); tap++)
577 {
578 output -= (m_taps[tap] * m_delay_line[m_delay_pos++]) << 2;
579
580 if (m_delay_pos >= m_tap_count - 1)
581 m_delay_pos = 0;
582 }
583
584 output -= (m_taps[tap] * input) << 2;
585
586 m_delay_line[m_delay_pos++] = input;
587 if (m_delay_pos >= m_tap_count - 1)
588 m_delay_pos = 0;
589
590 return output;
591 }
592
593 // Apply delay line and component volume
apply(const int32_t input)594 int32_t qsound_hle_device::qsound_delay::apply(const int32_t input)
595 {
596 m_delay_line[m_write_pos++] = input >> 16;
597 if (m_write_pos >= 51)
598 m_write_pos = 0;
599
600 const int32_t output = m_delay_line[m_read_pos++] * m_volume;
601 if (m_read_pos >= 51)
602 m_read_pos = 0;
603
604 return output;
605 }
606
607 // Update the delay read position to match new delay length
update()608 void qsound_hle_device::qsound_delay::update()
609 {
610 const int16_t new_read_pos = (m_write_pos - m_delay) % 51;
611 if (new_read_pos < 0)
612 m_read_pos = new_read_pos + 51;
613 else
614 m_read_pos = new_read_pos;
615 }
616