// license:BSD-3-Clause // copyright-holders:superctr, Valley Bell /********************************************************* Capcom QSound DL-1425 (HLE) *********************************************************/ #ifndef MAME_SOUND_QSOUNDHLE_H #define MAME_SOUND_QSOUNDHLE_H #pragma once #include "cpu/dsp16/dsp16.h" #include "dirom.h" class qsound_hle_device : public device_t, public device_sound_interface, public device_rom_interface<24> { public: // default 60MHz clock (divided by 2 for DSP core clock, and then by 1248 for sample rate) qsound_hle_device(machine_config const &mconfig, char const *tag, device_t *owner, uint32_t clock = 60'000'000); void qsound_w(offs_t offset, uint8_t data); uint8_t qsound_r(); protected: // device_t implementation tiny_rom_entry const *device_rom_region() const override; virtual void device_start() override; virtual void device_reset() override; // device_sound_interface implementation virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override; // device_rom_interface implementation virtual void rom_bank_updated() override; private: // DSP ROM sample map enum { DATA_PAN_TAB = 0x110, DATA_ADPCM_TAB = 0x9dc, DATA_FILTER_TAB = 0xd53, // dual filter mode, 5 tables * 95 taps each DATA_FILTER_TAB2 = 0xf2e, // overlapping data (95+15+95) STATE_BOOT = 0x000, STATE_INIT1 = 0x288, STATE_INIT2 = 0x61a, STATE_REFRESH1 = 0x039, STATE_REFRESH2 = 0x04f, STATE_NORMAL1 = 0x314, STATE_NORMAL2 = 0x6b2 }; const uint16_t PAN_TABLE_DRY = 0; const uint16_t PAN_TABLE_WET = 98; const uint16_t PAN_TABLE_CH_OFFSET = 196; const uint16_t FILTER_ENTRY_SIZE = 95; const uint16_t DELAY_BASE_OFFSET = 0x554; const uint16_t DELAY_BASE_OFFSET2 = 0x53c; struct qsound_voice { uint16_t m_bank = 0; int16_t m_addr = 0; // top word is the sample address uint16_t m_phase = 0; uint16_t m_rate = 0; int16_t m_loop_len = 0; int16_t m_end_addr = 0; int16_t m_volume = 0; int16_t m_echo = 0; int16_t update(qsound_hle_device &dsp, int32_t *echo_out); }; struct qsound_adpcm { uint16_t m_start_addr = 0; uint16_t m_end_addr = 0; uint16_t m_bank = 0; int16_t m_volume = 0; uint16_t m_flag = 0; int16_t m_cur_vol = 0; int16_t m_step_size = 0; uint16_t m_cur_addr = 0; int16_t update(qsound_hle_device &dsp, int16_t curr_sample, int nibble); }; // Q1 Filter struct qsound_fir { int m_tap_count = 0; // usually 95 int m_delay_pos = 0; uint16_t m_table_pos = 0; int16_t m_taps[95] = { 0 }; int16_t m_delay_line[95] = { 0 }; int32_t apply(int16_t input); }; // Delay line struct qsound_delay { int16_t m_delay = 0; int16_t m_volume = 0; int16_t m_write_pos = 0; int16_t m_read_pos = 0; int16_t m_delay_line[51] = { 0 }; int32_t apply(const int32_t input); void update(); }; struct qsound_echo { uint16_t m_end_pos = 0; int16_t m_feedback = 0; int16_t m_length = 0; int16_t m_last_sample = 0; int16_t m_delay_line[1024] = { 0 }; int16_t m_delay_pos = 0; int16_t apply(int32_t input); }; // MAME resources sound_stream *m_stream; required_region_ptr m_dsp_rom; uint16_t m_data_latch; int16_t m_out[2]; qsound_voice m_voice[16]; qsound_adpcm m_adpcm[3]; uint16_t m_voice_pan[16+3]; int16_t m_voice_output[16+3]; qsound_echo m_echo; qsound_fir m_filter[2]; qsound_fir m_alt_filter[2]; qsound_delay m_wet[2]; qsound_delay m_dry[2]; uint16_t m_state; uint16_t m_next_state; uint16_t m_delay_update; int m_state_counter; int m_ready_flag; uint16_t *m_register_map[256]; inline uint16_t read_dsp_rom(uint16_t addr) { return m_dsp_rom[addr&0xfff]; } void write_data(uint8_t addr, uint16_t data); uint16_t read_data(uint8_t addr); void init_register_map(); void update_sample(); // DSP states void state_init(); void state_refresh_filter_1(); void state_refresh_filter_2(); void state_normal_update(); // sub functions int16_t read_sample(uint16_t bank, uint16_t address); }; DECLARE_DEVICE_TYPE(QSOUND_HLE, qsound_hle_device) #endif // MAME_SOUND_QSOUNDHLE_H