From 5f7283161f0d3c4f95d4e6965305001141741246 Mon Sep 17 00:00:00 2001 From: 987123879113 <63495610+987123879113@users.noreply.github.com> Date: Thu, 11 Mar 2021 20:43:43 +0900 Subject: -firebeat.cpp: Added support for beatmania III FDD and spectrum analyzer. (#7835) * Added support for FDD and spectrum analyzer to beatmania III. * Promoted all Firebeat machines except pop'n music to working with imperfect sound. -sound/rf5c400.cpp: Added channels for effect outputs. Machines promoted to working -------------------------- ParaParaParadise ParaParaDancing ParaParaParadise v1.1 Keyboardmania Keyboardmania 2nd Mix Keyboardmania 3rd Mix Beatmania III Beatmania III Append 7th Mix Beatmania III The Final Clones promoted to working -------------------------- ParaParaParadise 1st Mix Plus Keyboardheaven (Korea) --- src/devices/sound/rf5c400.cpp | 44 +++- src/mame/drivers/firebeat.cpp | 462 ++++++++++++++++++++++++++++++------------ 2 files changed, 374 insertions(+), 132 deletions(-) diff --git a/src/devices/sound/rf5c400.cpp b/src/devices/sound/rf5c400.cpp index 9c650275aa1..f15b7923260 100644 --- a/src/devices/sound/rf5c400.cpp +++ b/src/devices/sound/rf5c400.cpp @@ -13,10 +13,12 @@ namespace { int volume_table[256]; -double pan_table[0x64]; +double pan_table[256]; void init_static_tables() { + std::fill(std::begin(pan_table), std::end(pan_table), 0.0); + // init volume/pan tables double max = 255.0; for (int i = 0; i < 256; i++) { @@ -26,9 +28,6 @@ void init_static_tables() for (int i = 0; i < 0x48; i++) { pan_table[i] = sqrt(double(0x47 - i)) / sqrt(double(0x47)); } - for (int i = 0x48; i < 0x64; i++) { - pan_table[i] = 0.0; - } } @@ -188,7 +187,7 @@ void rf5c400_device::device_start() save_item(STRUCT_MEMBER(m_channels, env_step)); save_item(STRUCT_MEMBER(m_channels, env_scale)); - m_stream = stream_alloc(0, 2, clock() / 384); + m_stream = stream_alloc(0, 4, clock() / 384); } //------------------------------------------------- @@ -211,18 +210,22 @@ void rf5c400_device::sound_stream_update(sound_stream &stream, std::vectorstartH & 0xFF00) << 8) | channel->startL; end = ((uint32_t)(channel->endHloopH & 0xFF) << 16) | channel->endL; @@ -231,6 +234,8 @@ void rf5c400_device::sound_stream_update(sound_stream &stream, std::vectorvolume & 0xFF; lvol = channel->pan & 0xFF; rvol = channel->pan >> 8; + effect_lvol = channel->effect & 0xFF; + effect_rvol = channel->effect >> 8; type = (channel->volume >> 8) & TYPE_MASK; env_phase = channel->env_phase; @@ -316,6 +321,8 @@ void rf5c400_device::sound_stream_update(sound_stream &stream, std::vector> 9) * env_level; buf0.add_int(i, sample * pan_table[lvol], 32768); buf1.add_int(i, sample * pan_table[rvol], 32768); + buf2.add_int(i, sample * pan_table[effect_lvol], 32768); + buf3.add_int(i, sample * pan_table[effect_rvol], 32768); pos += channel->step; if ((pos>>16) > end) @@ -578,6 +585,31 @@ void rf5c400_device::rf5c400_w(offs_t offset, uint16_t data, uint16_t mem_mask) case 0x07: // effect depth { // 0xCCRR: CC = chorus send depth, RR = reverb send depth + + // Note: beatmania III uses this register differently? + // When effects are off, it writes 0xe0e0 to this register: + // Changed ch 30 reg 6 to volume 18176 -> l: 71, r: 0 + // Changed ch 30 reg 7 to volume 57568 -> 0xe0e0 + // Changed ch 31 reg 6 to volume 71 -> l: 0, r: 71 + // Changed ch 31 reg 7 to volume 57568 -> 0xe0e0 + // When effects are on, it writes reg 6 information here: + // Changed ch 30 reg 6 to volume 57568 -> 0xe0e0 + // Changed ch 30 reg 7 to volume 18176 -> l: 71, r: 0 + // Changed ch 31 reg 6 to volume 57568 -> 0xe0e0 + // Changed ch 31 reg 7 to volume 71 -> l: 0, r: 71 + // + // I've observed values of 0xff instead of 0xe0 in some games like Gradius 4, + // so 0xe0 is not some kind of max value. + // + // When effects are enabled the audio is redirected to an external + // PCB board for effect processing before returning to the sound PCB. + // + // That makes me think that the effects are not internal and that + // this register is just used to adjust the volume of the channels + // being routed externally. + // + // Whether the effect is a chorus or reverb or something else would + // depend on how the PCB is using these external channels. channel->effect = data; break; } diff --git a/src/mame/drivers/firebeat.cpp b/src/mame/drivers/firebeat.cpp index 9e424055c9f..9f163b46aa1 100644 --- a/src/mame/drivers/firebeat.cpp +++ b/src/mame/drivers/firebeat.cpp @@ -143,6 +143,7 @@ #include "bus/ata/idehd.h" #include "cpu/m68000/m68000.h" #include "cpu/powerpc/ppc.h" +#include "machine/fdc37c665gt.h" #include "machine/ins8250.h" #include "machine/intelfsh.h" #include "machine/mb8421.h" @@ -154,14 +155,213 @@ #include "sound/ymz280b.h" #include "video/k057714.h" +#include "imagedev/floppy.h" + #include "emupal.h" #include "screen.h" #include "speaker.h" #include "osdcomm.h" +#include "wdlfft/fft.h" + +#include + #include "firebeat.lh" +/*****************************************************************************/ +DECLARE_DEVICE_TYPE(KONAMI_FIREBEAT_EXTEND_SPECTRUM_ANALYZER, firebeat_extend_spectrum_analyzer_device) + +class firebeat_extend_spectrum_analyzer_device : public device_t, public device_mixer_interface +{ +public: + firebeat_extend_spectrum_analyzer_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + uint8_t read(offs_t offset); + +protected: + // device-level overrides + virtual void device_start() override; + virtual void device_reset() override; + + // device_sound_interface-level overrides + void sound_stream_update(sound_stream &stream, std::vector const &inputs, std::vector &outputs) override; + +private: + enum { + TOTAL_BUFFERS = 2, + TOTAL_CHANNELS = 2, + TOTAL_BARS = 6, + + FFT_LENGTH = 512 + }; + + void update_fft(); + void apply_fft(uint32_t buf_index); + + float m_audio_buf[TOTAL_BUFFERS][TOTAL_CHANNELS][FFT_LENGTH]; + float m_fft_buf[TOTAL_CHANNELS][FFT_LENGTH]; + int m_audio_fill_index; + int m_audio_count[TOTAL_CHANNELS]; + + int m_bars[TOTAL_CHANNELS][TOTAL_BARS]; +}; + +firebeat_extend_spectrum_analyzer_device::firebeat_extend_spectrum_analyzer_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : + device_t(mconfig, KONAMI_FIREBEAT_EXTEND_SPECTRUM_ANALYZER, tag, owner, clock), + device_mixer_interface(mconfig, *this, 2) +{ +} + +void firebeat_extend_spectrum_analyzer_device::device_start() +{ + WDL_fft_init(); +} + +void firebeat_extend_spectrum_analyzer_device::device_reset() +{ + for (int ch = 0; ch < TOTAL_CHANNELS; ch++) + { + for (int i = 0; i < TOTAL_BUFFERS; i++) { + std::fill(std::begin(m_audio_buf[i][ch]), std::end(m_audio_buf[i][ch]), 0); + } + + std::fill(std::begin(m_fft_buf[ch]), std::end(m_fft_buf[ch]), 0); + std::fill(std::begin(m_bars[ch]), std::end(m_bars[ch]), 0); + + m_audio_count[ch] = 0; + } + + m_audio_fill_index = 0; +} + +void firebeat_extend_spectrum_analyzer_device::sound_stream_update(sound_stream &stream, std::vector const &inputs, std::vector &outputs) +{ + device_mixer_interface::sound_stream_update(stream, inputs, outputs); + + for (int pos = 0; pos < outputs[0].samples(); pos++) + { + for (int ch = 0; ch < outputs.size(); ch++) + { + const float sample = outputs[ch].get(pos); + m_audio_buf[m_audio_fill_index][ch][m_audio_count[m_audio_fill_index]] = sample; + } + + update_fft(); + } + + // Bandpass filter + find peak + // The results aren't accurate to the real circuit used on the PCB but the feature is very minor + // and does not affect gameplay in any way. + + // Band values taken directly from NJU7507 data sheet. + constexpr double NOTCHES[] = { 95, 240, 600, 1500, 3400, 8200, 18000 }; + constexpr int LAST_NOTCH = 7; + + auto srate = stream.sample_rate(); + auto order = WDL_fft_permute_tab(FFT_LENGTH / 2); + for (int ch = 0; ch < TOTAL_CHANNELS; ch++) { + double notch_max[TOTAL_BARS] = { -1, -1, -1, -1, -1, -1 }; + int cur_notch = 0; + + for (int i = 0; i <= FFT_LENGTH / 2; i++) { + const double freq = (double)i / FFT_LENGTH * srate; + + if (freq < NOTCHES[cur_notch]) { + continue; + } + + if (freq > NOTCHES[cur_notch+1]) { + cur_notch++; + } + + if (cur_notch >= LAST_NOTCH) { + // Don't need to calculate anything above this frequency + break; + } + + WDL_FFT_COMPLEX* bin = (WDL_FFT_COMPLEX*)m_fft_buf[ch] + order[i]; + + const double re = bin->re; + const double im = bin->im; + const double mag = sqrt(re*re + im*im); + + if (notch_max[cur_notch] == -1 && freq >= NOTCHES[cur_notch] && freq < NOTCHES[cur_notch+1]) { + notch_max[cur_notch] = mag; + } + } + + for (int i = 0; i < TOTAL_BARS; i++) { + double val = log10(notch_max[i] * 4096) * 20; + val = std::max(0, val); + m_bars[ch][i] = uint32_t(std::min(val, 255.0f)); + } + } +} + +void firebeat_extend_spectrum_analyzer_device::apply_fft(uint32_t buf_index) +{ + float *audio_l = m_audio_buf[buf_index][0]; + float *audio_r = m_audio_buf[buf_index][1]; + float *buf_l = m_fft_buf[0]; + float *buf_r = m_fft_buf[1]; + + for (int i = 0; i < FFT_LENGTH; i++) + { + *buf_l++ = *audio_l++; + *buf_r++ = *audio_r++; + } + + for (int ch = 0; ch < TOTAL_CHANNELS; ch++) { + WDL_real_fft((WDL_FFT_REAL*)m_fft_buf[ch], FFT_LENGTH, 0); + + for (int i = 0; i < FFT_LENGTH; i++) { + m_fft_buf[ch][i] /= (WDL_FFT_REAL)FFT_LENGTH; + } + } +} + +void firebeat_extend_spectrum_analyzer_device::update_fft() +{ + m_audio_count[m_audio_fill_index]++; + if (m_audio_count[m_audio_fill_index] >= FFT_LENGTH) + { + apply_fft(m_audio_fill_index); + + m_audio_fill_index = 1 - m_audio_fill_index; + m_audio_count[m_audio_fill_index] = 0; + } +} + +uint8_t firebeat_extend_spectrum_analyzer_device::read(offs_t offset) +{ + // Visible in the sound test menu and used for the spectral analyzer game skin + // The actual data is coming from a circuit built on the extend board made up of NJU7507 x2 for each channel of audio. + // The spectrum analyzer circuit is only populated on the extend board used by beatmania III but the footprints and + // labels are still on the PCB for other games that use the extend board. + + // Return values notes: + // - The values are based on the results of a chained NJU7507 which should give 14 bands worth of frequency data. However, only 6 bands are used in-game. + // - Anything <= 8 will not display anything in-game and seems unused in memory + // - It reads the upper and lower half of the register separately as bytes, but it the upper byte doesn't seem like it's actually used. + // - In-game the skin shows up to +9 dB but it actually caps out at -3 dB on the skin + + int ch = offset >= 0x40; // 0 = Left, 1 = Right + int notch = 6 - (((offset >> 2) & 0x0f) >> 1); + int is_upper = BIT(offset, 2); + + auto val = (ch < TOTAL_CHANNELS && notch >= 0 && notch < TOTAL_BARS) ? m_bars[ch][notch] : 0; + + if (is_upper) { + return (val >> 8) & 0xff; + } + + return val & 0xff; +} + +DEFINE_DEVICE_TYPE(KONAMI_FIREBEAT_EXTEND_SPECTRUM_ANALYZER, firebeat_extend_spectrum_analyzer_device, "firebeat_spectrum_analyzer", "Firebeat Spectrum Analyzer") + +/*****************************************************************************/ namespace { struct IBUTTON_SUBKEY @@ -194,6 +394,7 @@ static void dvdrom_config(device_t *device) downcast(*device).set_ultra_dma_mode(0x0102); } +/*****************************************************************************/ class firebeat_state : public driver_device { public: @@ -280,9 +481,10 @@ public: firebeat_spu_state(const machine_config &mconfig, device_type type, const char *tag) : firebeat_state(mconfig, type, tag), m_spuata(*this, "spu_ata"), + m_rf5c400(*this, "rf5c400"), m_audiocpu(*this, "audiocpu"), m_dpram(*this, "spuram"), - m_waveram(*this, "rf5c400"), + m_waveram(*this, "rf5c400_ram"), m_spu_status_leds(*this, "spu_status_led_%u", 0U) { } @@ -302,6 +504,7 @@ protected: TIMER_DEVICE_CALLBACK_MEMBER(spu_timer_callback); required_device m_spuata; + required_device m_rf5c400; private: void spu_status_led_w(uint16_t data); @@ -403,14 +606,15 @@ private: void init_keyboard(); uint8_t keyboard_wheel_r(offs_t offset); - uint8_t midi_uart_r(offs_t offset); - void midi_uart_w(offs_t offset, uint8_t data); void lamp_output_kbm_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0); + uint8_t midi_uart_r(offs_t offset); + void midi_uart_w(offs_t offset, uint8_t data); + // TIMER_CALLBACK_MEMBER(keyboard_timer_callback); - DECLARE_WRITE_LINE_MEMBER(midi_uart_ch0_irq_callback); - DECLARE_WRITE_LINE_MEMBER(midi_uart_ch1_irq_callback); + DECLARE_WRITE_LINE_MEMBER(midi_keyboard_right_irq_callback); + DECLARE_WRITE_LINE_MEMBER(midi_keyboard_left_irq_callback); // emu_timer *m_keyboard_timer; // int m_keyboard_state[2]; @@ -433,6 +637,10 @@ class firebeat_bm3_state : public firebeat_spu_state public: firebeat_bm3_state(const machine_config &mconfig, device_type type, const char *tag) : firebeat_spu_state(mconfig, type, tag), + m_fdc(*this, "fdc"), + m_floppy(*this, "fdc:fdc:0"), + m_spectrum_analyzer(*this, "spectrum_analyzer"), + m_duart_midi(*this, "duart_midi"), m_io(*this, "IO%u", 1U), m_io_turntables(*this, "TURNTABLE_P%u", 1U), m_io_effects(*this, "EFFECT%u", 1U) @@ -444,18 +652,24 @@ public: private: void firebeat_bm3_map(address_map &map); - uint32_t spectrum_analyzer_r(offs_t offset); + uint8_t spectrum_analyzer_r(offs_t offset); uint16_t sensor_r(offs_t offset); - // TODO: Floppy disk implementation - uint32_t fdd_unk_r(offs_t offset, uint32_t mem_mask = ~0); - void fdd_unk_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0); + uint8_t midi_uart_r(offs_t offset); + void midi_uart_w(offs_t offset, uint8_t data); - DECLARE_WRITE_LINE_MEMBER( bm3_vblank ); + DECLARE_WRITE_LINE_MEMBER(midi_st224_irq_callback); + + required_device m_fdc; + required_device m_floppy; + required_device m_spectrum_analyzer; + required_device m_duart_midi; required_ioport_array<4> m_io; required_ioport_array<2> m_io_turntables; required_ioport_array<7> m_io_effects; + + DECLARE_WRITE_LINE_MEMBER(floppy_irq_callback); }; class firebeat_popn_state : public firebeat_spu_state @@ -767,15 +981,14 @@ void firebeat_state::security_w(uint8_t data) m_maincpu->ppc4xx_spu_receive_byte(r); } -/*****************************************************************************/ - // Extend board IRQs // 0x01: MIDI UART channel 2 // 0x02: MIDI UART channel 1 -// 0x04: ? +// 0x04: FDD // 0x08: ? // 0x10: ? // 0x20: ? +// 0x40: Used by spectrum analyzer feature in beatmania III. Audio related? uint8_t firebeat_state::extend_board_irq_r(offs_t offset) { @@ -786,8 +999,15 @@ void firebeat_state::extend_board_irq_w(offs_t offset, uint8_t data) { // printf("extend_board_irq_w: %08X, %08X\n", data, offset); + auto is_fdd_irq_enabled = BIT(m_extend_board_irq_enable, 2); + m_extend_board_irq_active &= ~(data & 0xff); m_extend_board_irq_enable = data & 0xff; + + if (BIT(m_extend_board_irq_enable, 2) != is_fdd_irq_enabled) { + // Clearing the FDD IRQ here helps fix some issues with the FDD getting stuck + m_maincpu->set_input_line(INPUT_LINE_IRQ1, CLEAR_LINE); + } } /*****************************************************************************/ @@ -994,10 +1214,12 @@ void firebeat_spu_state::firebeat_spu_base(machine_config &config) m_dpram->intl_callback().set_inputline(m_audiocpu, INPUT_LINE_IRQ4); // address 0x3fe triggers M68K interrupt m_dpram->intr_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ3); // address 0x3ff triggers PPC interrupt - rf5c400_device &rf5c400(RF5C400(config, "rf5c400", XTAL(16'934'400))); - rf5c400.set_addrmap(0, &firebeat_spu_state::rf5c400_map); - rf5c400.add_route(0, "lspeaker", 0.5); - rf5c400.add_route(1, "rspeaker", 0.5); + RF5C400(config, m_rf5c400, XTAL(16'934'400)); + m_rf5c400->set_addrmap(0, &firebeat_spu_state::rf5c400_map); + + // Clean channel audio + m_rf5c400->add_route(0, "lspeaker", 0.5); + m_rf5c400->add_route(1, "rspeaker", 0.5); } void firebeat_spu_state::firebeat_spu_map(address_map &map) @@ -1019,13 +1241,13 @@ void firebeat_spu_state::spu_map(address_map &map) map(0x280000, 0x2807ff).rw(m_dpram, FUNC(cy7c131_device::left_r), FUNC(cy7c131_device::left_w)).umask16(0x00ff); map(0x300000, 0x30000f).rw(m_spuata, FUNC(ata_interface_device::cs0_r), FUNC(ata_interface_device::cs0_w)); map(0x340000, 0x34000f).rw(m_spuata, FUNC(ata_interface_device::cs1_r), FUNC(ata_interface_device::cs1_w)); - map(0x400000, 0x400fff).rw("rf5c400", FUNC(rf5c400_device::rf5c400_r), FUNC(rf5c400_device::rf5c400_w)); + map(0x400000, 0x400fff).rw(m_rf5c400, FUNC(rf5c400_device::rf5c400_r), FUNC(rf5c400_device::rf5c400_w)); map(0x800000, 0xffffff).rw(FUNC(firebeat_spu_state::firebeat_waveram_r), FUNC(firebeat_spu_state::firebeat_waveram_w)); } void firebeat_spu_state::rf5c400_map(address_map& map) { - map(0x0000000, 0x1ffffff).ram().share("rf5c400"); + map(0x0000000, 0x1ffffff).ram().share("rf5c400_ram"); } @@ -1195,6 +1417,20 @@ TIMER_DEVICE_CALLBACK_MEMBER(firebeat_spu_state::spu_timer_callback) /***************************************************************************** * beatmania III ******************************************************************************/ +static void pc_hd_floppies(device_slot_interface &device) +{ + device.option_add("35hd", FLOPPY_35_HD); +} + +WRITE_LINE_MEMBER(firebeat_bm3_state::floppy_irq_callback) +{ + if (BIT(m_extend_board_irq_enable, 2) == 0 && state) + { + m_extend_board_irq_active |= 0x04; + m_maincpu->set_input_line(INPUT_LINE_IRQ1, state); + } +} + void firebeat_bm3_state::firebeat_bm3(machine_config &config) { firebeat_spu_base(config); @@ -1205,7 +1441,6 @@ void firebeat_bm3_state::firebeat_bm3(machine_config &config) screen_device *screen = subdevice("screen"); screen->set_size(640, 480); screen->set_visarea(0, 639, 0, 479); - screen->screen_vblank().set(FUNC(firebeat_bm3_state::bm3_vblank)); ATA_INTERFACE(config, m_spuata).options(firebeat_ata_devices, "hdd", nullptr, true); m_spuata->irq_handler().set(FUNC(firebeat_bm3_state::spu_ata_interrupt)); @@ -1216,6 +1451,25 @@ void firebeat_bm3_state::firebeat_bm3(machine_config &config) // Any higher makes things act weird. // Lower doesn't have that huge of an effect compared to pop'n? (limited tested). TIMER(config, "spu_timer").configure_periodic(FUNC(firebeat_bm3_state::spu_timer_callback), attotime::from_hz(500)); + + FDC37C665GT(config, m_fdc, 24_MHz_XTAL, upd765_family_device::mode_t::PS2); + m_fdc->fintr().set(FUNC(firebeat_bm3_state::floppy_irq_callback)); + + FLOPPY_CONNECTOR(config, m_floppy, pc_hd_floppies, "35hd", floppy_image_device::default_pc_floppy_formats); + + PC16552D(config, m_duart_midi, 0); + NS16550(config, "duart_midi:chan0", XTAL(24'000'000)); + NS16550(config, "duart_midi:chan1", XTAL(24'000'000)).out_int_callback().set(FUNC(firebeat_bm3_state::midi_st224_irq_callback)); + + // Effects audio channel, routed to ST-224's audio input + m_rf5c400->add_route(2, "lspeaker", 0.5); + m_rf5c400->add_route(3, "rspeaker", 0.5); + + KONAMI_FIREBEAT_EXTEND_SPECTRUM_ANALYZER(config, m_spectrum_analyzer, 0); + m_rf5c400->add_route(0, m_spectrum_analyzer, 0.5, AUTO_ALLOC_INPUT, 0); + m_rf5c400->add_route(1, m_spectrum_analyzer, 0.5, AUTO_ALLOC_INPUT, 1); + m_rf5c400->add_route(2, m_spectrum_analyzer, 0.5, AUTO_ALLOC_INPUT, 0); + m_rf5c400->add_route(3, m_spectrum_analyzer, 0.5, AUTO_ALLOC_INPUT, 1); } void firebeat_bm3_state::init_bm3() @@ -1233,42 +1487,11 @@ void firebeat_bm3_state::init_bm3() void firebeat_bm3_state::firebeat_bm3_map(address_map &map) { firebeat_spu_map(map); - + map(0x70000000, 0x70000fff).rw(FUNC(firebeat_bm3_state::midi_uart_r), FUNC(firebeat_bm3_state::midi_uart_w)).umask32(0xff000000); + map(0x70001000, 0x70001fff).rw(m_fdc, FUNC(fdc37c665gt_device::read), FUNC(fdc37c665gt_device::write)).umask32(0xff000000); + map(0x70008000, 0x7000807f).r(m_spectrum_analyzer, FUNC(firebeat_extend_spectrum_analyzer_device::read)); map(0x7d000330, 0x7d00033f).nopw(); // ? map(0x7d000340, 0x7d00035f).r(FUNC(firebeat_bm3_state::sensor_r)); - map(0x70001fc0, 0x70001fdf).rw(FUNC(firebeat_bm3_state::fdd_unk_r), FUNC(firebeat_bm3_state::fdd_unk_w)); - map(0x70008000, 0x7000807f).r(FUNC(firebeat_bm3_state::spectrum_analyzer_r)); -} - -uint32_t firebeat_bm3_state::spectrum_analyzer_r(offs_t offset) -{ - // Visible in the sound test menu and most likely the spectral analyzer game skin - // - // Notes about where this could be coming from... - // - It's not the ST-224: Only sends audio in and out, with a MIDI in - // - It's not the RF5C400: There are no unimplemented registers or anything of that sort that could give this info - // - The memory address mapping is the same as Keyboardmania's wheel, which plugs into a connector on extend board - // but there's nothing actually plugged into that spot on a beatmania III configuration, so it's not external - // - Any place where the audio is directed somewhere (amps, etc) does not have a way to get back to the PCBs - // from what I can tell based on looking at the schematics in the beatmania III manual - // - I think it's probably calculated somewhere within one of the main boards (main/extend/SPU) but couldn't find any - // potentially interesting chips at a glance of PCB pics - // - The manual does not seem to make mention of this feature *at all* much less troubleshooting it, so no leads there - - // 6 notch spectrum analyzer - // No idea what frequency range each notch corresponds but it does not affect core gameplay in any way. - // Notch 1: 0x0c - // Notch 2: 0x0a - // Notch 3: 0x08 - // Notch 4: 0x06 - // Notch 5: 0x04 - // Notch 6: 0x02 - - // TODO: Fill in logic (reuse vgm_visualizer in some way?) - // auto ch = offset & 0xf0; // 0 = Left, 1 = Right - auto data = 0; - - return data; } uint16_t firebeat_bm3_state::sensor_r(offs_t offset) @@ -1295,52 +1518,25 @@ uint16_t firebeat_bm3_state::sensor_r(offs_t offset) return 0; } -uint32_t firebeat_bm3_state::fdd_unk_r(offs_t offset, uint32_t mem_mask) +WRITE_LINE_MEMBER(firebeat_bm3_state::midi_st224_irq_callback) { - // printf("%s: fdd_unk_r: %08X, %08X\n", machine().describe_context().c_str(), offset, mem_mask); - - return 0; + if (BIT(m_extend_board_irq_enable, 0) == 0 && state != CLEAR_LINE) + { + m_extend_board_irq_active |= 0x01; + m_maincpu->set_input_line(INPUT_LINE_IRQ1, ASSERT_LINE); + } + else + m_maincpu->set_input_line(INPUT_LINE_IRQ1, CLEAR_LINE); } -void firebeat_bm3_state::fdd_unk_w(offs_t offset, uint32_t data, uint32_t mem_mask) +uint8_t firebeat_bm3_state::midi_uart_r(offs_t offset) { - // printf("%s: fdd_unk_w: %08X, %08X, %08X\n", machine().describe_context().c_str(), data, offset, mem_mask); + return m_duart_midi->read(offset >> 6); } -WRITE_LINE_MEMBER(firebeat_bm3_state::bm3_vblank) +void firebeat_bm3_state::midi_uart_w(offs_t offset, uint8_t data) { - // Patch out FDD errors since the game otherwise runs fine without it - // and the FDD might not be implemented for a while - if (strcmp(machine().system().name, "bm3") == 0) - { - if (m_work_ram[0x918C / 4] == 0x4809202D) m_work_ram[0x918C / 4] = 0x38600000; - if (m_work_ram[0x3380C / 4] == 0x4BFFFD99) m_work_ram[0x3380C / 4] = 0x38600000; - if (m_work_ram[0x33834 / 4] == 0x4BFFFD71) m_work_ram[0x33834 / 4] = 0x38600000; - } - else if (strcmp(machine().system().name, "bm3core") == 0) - { - if (m_work_ram[0x91E4 / 4] == 0x480A19F5) m_work_ram[0x91E4 / 4] = 0x38600000; - if (m_work_ram[0x37BB0 / 4] == 0x4BFFFD71) m_work_ram[0x37BB0 / 4] = 0x38600000; - if (m_work_ram[0x37BD8 / 4] == 0x4BFFFD49) m_work_ram[0x37BD8 / 4] = 0x38600000; - } - else if (strcmp(machine().system().name, "bm36th") == 0) - { - if (m_work_ram[0x91E4 / 4] == 0x480BC8BD) m_work_ram[0x91E4 / 4] = 0x38600000; - if (m_work_ram[0x451D8 / 4] == 0x4BFFFD75) m_work_ram[0x451D8 / 4] = 0x38600000; - if (m_work_ram[0x45200 / 4] == 0x4BFFFD4D) m_work_ram[0x45200 / 4] = 0x38600000; - } - else if (strcmp(machine().system().name, "bm37th") == 0) - { - if (m_work_ram[0x91E4 / 4] == 0x480CF62D) m_work_ram[0x91E4 / 4] = 0x38600000; - if (m_work_ram[0x46A58 / 4] == 0x4BFFFD45) m_work_ram[0x46A58 / 4] = 0x38600000; - if (m_work_ram[0x46AB8 / 4] == 0x4BFFFCE5) m_work_ram[0x46AB8 / 4] = 0x38600000; - } - else if (strcmp(machine().system().name, "bm3final") == 0) - { - if (m_work_ram[0x47F8 / 4] == 0x480CEF91) m_work_ram[0x47F8 / 4] = 0x38600000; - if (m_work_ram[0x3FAF4 / 4] == 0x4BFFFD59) m_work_ram[0x3FAF4 / 4] = 0x38600000; - if (m_work_ram[0x3FB54 / 4] == 0x4BFFFCF9) m_work_ram[0x3FB54 / 4] = 0x38600000; - } + m_duart_midi->write(offset >> 6, data); } /***************************************************************************** @@ -1360,6 +1556,10 @@ void firebeat_popn_state::firebeat_popn(machine_config &config) // Any lower and sometimes you'll hear buzzing from certain keysounds, or fades take too long. // Any higher and keysounds get cut short. TIMER(config, "spu_timer").configure_periodic(FUNC(firebeat_popn_state::spu_timer_callback), attotime::from_hz(500)); + + // Effects audio channel, routed back to main (no external processing) + m_rf5c400->add_route(2, "lspeaker", 0.5); + m_rf5c400->add_route(3, "rspeaker", 0.5); } void firebeat_popn_state::init_popn_base() @@ -1642,18 +1842,20 @@ void firebeat_kbm_state::firebeat_kbm(machine_config &config) ymz.add_route(1, "lspeaker", 1.0); ymz.add_route(0, "rspeaker", 1.0); + // On the main PCB PC16552D(config, "duart_com", 0); NS16550(config, "duart_com:chan0", XTAL(19'660'800)); NS16550(config, "duart_com:chan1", XTAL(19'660'800)); - PC16552D(config, "duart_midi", 0); - ns16550_device &midi_chan0(NS16550(config, "duart_midi:chan0", XTAL(24'000'000))); - midi_chan0.out_int_callback().set(FUNC(firebeat_kbm_state::midi_uart_ch0_irq_callback)); - ns16550_device &midi_chan1(NS16550(config, "duart_midi:chan1", XTAL(24'000'000))); - midi_chan1.out_int_callback().set(FUNC(firebeat_kbm_state::midi_uart_ch1_irq_callback)); - + // On the extend board + PC16552D(config, m_duart_midi, 0); + auto &midi_chan1(NS16550(config, "duart_midi:chan1", XTAL(24'000'000))); MIDI_KBD(config, m_kbd[0], 31250).tx_callback().set(midi_chan1, FUNC(ins8250_uart_device::rx_w)); + midi_chan1.out_int_callback().set(FUNC(firebeat_kbm_state::midi_keyboard_left_irq_callback)); + + auto &midi_chan0(NS16550(config, "duart_midi:chan0", XTAL(24'000'000))); MIDI_KBD(config, m_kbd[1], 31250).tx_callback().set(midi_chan0, FUNC(ins8250_uart_device::rx_w)); + midi_chan0.out_int_callback().set(FUNC(firebeat_kbm_state::midi_keyboard_right_irq_callback)); } void firebeat_kbm_state::firebeat_kbm_map(address_map &map) @@ -1685,7 +1887,7 @@ void firebeat_kbm_state::midi_uart_w(offs_t offset, uint8_t data) m_duart_midi->write(offset >> 6, data); } -WRITE_LINE_MEMBER(firebeat_kbm_state::midi_uart_ch0_irq_callback) +WRITE_LINE_MEMBER(firebeat_kbm_state::midi_keyboard_right_irq_callback) { if (BIT(m_extend_board_irq_enable, 1) == 0 && state != CLEAR_LINE) { @@ -1696,7 +1898,7 @@ WRITE_LINE_MEMBER(firebeat_kbm_state::midi_uart_ch0_irq_callback) m_maincpu->set_input_line(INPUT_LINE_IRQ1, CLEAR_LINE); } -WRITE_LINE_MEMBER(firebeat_kbm_state::midi_uart_ch1_irq_callback) +WRITE_LINE_MEMBER(firebeat_kbm_state::midi_keyboard_left_irq_callback) { if (BIT(m_extend_board_irq_enable, 0) == 0 && state != CLEAR_LINE) { @@ -1804,6 +2006,10 @@ void firebeat_kbm_state::lamp_output_kbm_w(offs_t offset, uint32_t data, uint32_ static INPUT_PORTS_START( firebeat ) PORT_START("IN3") + // popn4/animelo: + // DIPSW 1 = Auto play mode + // popn5: + // DIPSW 5? = Network communication debug messages // popn6/popn7/popn8/others?: Requires debug type dongle (not included in ROMs) // DIPSW 8 = Auto play mode // DIPSW 6 = Mute song BGM @@ -2405,28 +2611,32 @@ ROM_END /*****************************************************************************/ -GAME( 2000, ppp, 0, firebeat_ppp, ppp, firebeat_ppp_state, init_ppp_jp, ROT0, "Konami", "ParaParaParadise", MACHINE_NOT_WORKING ) -GAME( 2000, ppd, 0, firebeat_ppp, ppp, firebeat_ppp_state, init_ppp_overseas, ROT0, "Konami", "ParaParaDancing", MACHINE_NOT_WORKING ) -GAME( 2000, ppp11, 0, firebeat_ppp, ppp, firebeat_ppp_state, init_ppp_jp, ROT0, "Konami", "ParaParaParadise v1.1", MACHINE_NOT_WORKING ) -GAME( 2000, ppp1mp, ppp, firebeat_ppp, ppp, firebeat_ppp_state, init_ppp_jp, ROT0, "Konami", "ParaParaParadise 1st Mix Plus", MACHINE_NOT_WORKING ) - -GAMEL( 2000, kbm, 0, firebeat_kbm, kbm, firebeat_kbm_state, init_kbm_jp, ROT270, "Konami", "Keyboardmania", MACHINE_NOT_WORKING, layout_firebeat ) -GAMEL( 2000, kbh, kbm, firebeat_kbm, kbm, firebeat_kbm_state, init_kbm_overseas, ROT270, "Konami", "Keyboardheaven (Korea)", MACHINE_NOT_WORKING, layout_firebeat ) -GAMEL( 2000, kbm2nd, 0, firebeat_kbm, kbm, firebeat_kbm_state, init_kbm_jp, ROT270, "Konami", "Keyboardmania 2nd Mix", MACHINE_NOT_WORKING, layout_firebeat ) -GAMEL( 2001, kbm3rd, 0, firebeat_kbm, kbm, firebeat_kbm_state, init_kbm_jp, ROT270, "Konami", "Keyboardmania 3rd Mix", MACHINE_NOT_WORKING, layout_firebeat ) - -GAME( 2000, popn4, 0, firebeat_popn, popn, firebeat_popn_state, init_popn_jp, ROT0, "Konami", "Pop'n Music 4", MACHINE_NOT_WORKING ) -GAME( 2000, popn5, 0, firebeat_popn, popn, firebeat_popn_state, init_popn_jp, ROT0, "Konami", "Pop'n Music 5", MACHINE_NOT_WORKING ) -GAME( 2001, popn6, 0, firebeat_popn, popn, firebeat_popn_state, init_popn_jp, ROT0, "Konami", "Pop'n Music 6", MACHINE_NOT_WORKING ) -GAME( 2001, popn7, 0, firebeat_popn, popn, firebeat_popn_state, init_popn_jp, ROT0, "Konami", "Pop'n Music 7", MACHINE_NOT_WORKING ) -GAME( 2002, popn8, 0, firebeat_popn, popn, firebeat_popn_state, init_popn_jp, ROT0, "Konami", "Pop'n Music 8", MACHINE_NOT_WORKING ) -GAME( 2000, popnmt, 0, firebeat_popn, popn, firebeat_popn_state, init_popn_rental, ROT0, "Konami", "Pop'n Music Mickey Tunes", MACHINE_NOT_WORKING ) -GAME( 2000, popnmt2, popnmt, firebeat_popn, popn, firebeat_popn_state, init_popn_rental, ROT0, "Konami", "Pop'n Music Mickey Tunes!", MACHINE_NOT_WORKING ) -GAME( 2000, popnanm, 0, firebeat_popn, popn, firebeat_popn_state, init_popn_jp, ROT0, "Konami", "Pop'n Music Animelo", MACHINE_NOT_WORKING ) -GAME( 2001, popnanm2, 0, firebeat_popn, popn, firebeat_popn_state, init_popn_jp, ROT0, "Konami", "Pop'n Music Animelo 2", MACHINE_NOT_WORKING ) - -GAME( 2000, bm3, 0, firebeat_bm3, bm3, firebeat_bm3_state, init_bm3, ROT0, "Konami", "Beatmania III", MACHINE_NOT_WORKING ) -GAME( 2000, bm3core, 0, firebeat_bm3, bm3, firebeat_bm3_state, init_bm3, ROT0, "Konami", "Beatmania III Append Core Remix", MACHINE_NOT_WORKING ) -GAME( 2001, bm36th, 0, firebeat_bm3, bm3, firebeat_bm3_state, init_bm3, ROT0, "Konami", "Beatmania III Append 6th Mix", MACHINE_NOT_WORKING ) -GAME( 2002, bm37th, 0, firebeat_bm3, bm3, firebeat_bm3_state, init_bm3, ROT0, "Konami", "Beatmania III Append 7th Mix", MACHINE_NOT_WORKING ) -GAME( 2003, bm3final, 0, firebeat_bm3, bm3, firebeat_bm3_state, init_bm3, ROT0, "Konami", "Beatmania III The Final", MACHINE_NOT_WORKING ) +GAME( 2000, ppp, 0, firebeat_ppp, ppp, firebeat_ppp_state, init_ppp_jp, ROT0, "Konami", "ParaParaParadise", MACHINE_IMPERFECT_SOUND ) +GAME( 2000, ppd, 0, firebeat_ppp, ppp, firebeat_ppp_state, init_ppp_overseas, ROT0, "Konami", "ParaParaDancing", MACHINE_IMPERFECT_SOUND ) +GAME( 2000, ppp11, 0, firebeat_ppp, ppp, firebeat_ppp_state, init_ppp_jp, ROT0, "Konami", "ParaParaParadise v1.1", MACHINE_IMPERFECT_SOUND ) +GAME( 2000, ppp1mp, ppp, firebeat_ppp, ppp, firebeat_ppp_state, init_ppp_jp, ROT0, "Konami", "ParaParaParadise 1st Mix Plus", MACHINE_IMPERFECT_SOUND ) + +// Keyboard sounds do not work: requires MU-100 emulation (ymu100.cpp) which is not in a fully working state yet +GAMEL( 2000, kbm, 0, firebeat_kbm, kbm, firebeat_kbm_state, init_kbm_jp, ROT270, "Konami", "Keyboardmania", MACHINE_IMPERFECT_SOUND, layout_firebeat ) +GAMEL( 2000, kbh, kbm, firebeat_kbm, kbm, firebeat_kbm_state, init_kbm_overseas, ROT270, "Konami", "Keyboardheaven (Korea)", MACHINE_IMPERFECT_SOUND, layout_firebeat ) +GAMEL( 2000, kbm2nd, 0, firebeat_kbm, kbm, firebeat_kbm_state, init_kbm_jp, ROT270, "Konami", "Keyboardmania 2nd Mix", MACHINE_IMPERFECT_SOUND, layout_firebeat ) +GAMEL( 2001, kbm3rd, 0, firebeat_kbm, kbm, firebeat_kbm_state, init_kbm_jp, ROT270, "Konami", "Keyboardmania 3rd Mix", MACHINE_IMPERFECT_SOUND, layout_firebeat ) + +// Requires DVD CHD support. Once DVD CHD support is implemented then MACHINE_NOT_WORKING can be removed +GAME( 2000, popn4, 0, firebeat_popn, popn, firebeat_popn_state, init_popn_jp, ROT0, "Konami", "Pop'n Music 4", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND ) +GAME( 2000, popn5, 0, firebeat_popn, popn, firebeat_popn_state, init_popn_jp, ROT0, "Konami", "Pop'n Music 5", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND ) +GAME( 2001, popn6, 0, firebeat_popn, popn, firebeat_popn_state, init_popn_jp, ROT0, "Konami", "Pop'n Music 6", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND ) +GAME( 2001, popn7, 0, firebeat_popn, popn, firebeat_popn_state, init_popn_jp, ROT0, "Konami", "Pop'n Music 7", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND ) +GAME( 2002, popn8, 0, firebeat_popn, popn, firebeat_popn_state, init_popn_jp, ROT0, "Konami", "Pop'n Music 8", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND ) +GAME( 2000, popnmt, 0, firebeat_popn, popn, firebeat_popn_state, init_popn_rental, ROT0, "Konami", "Pop'n Music Mickey Tunes", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND ) +GAME( 2000, popnmt2, popnmt, firebeat_popn, popn, firebeat_popn_state, init_popn_rental, ROT0, "Konami", "Pop'n Music Mickey Tunes!", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND ) +GAME( 2000, popnanm, 0, firebeat_popn, popn, firebeat_popn_state, init_popn_jp, ROT0, "Konami", "Pop'n Music Animelo", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND ) +GAME( 2001, popnanm2, 0, firebeat_popn, popn, firebeat_popn_state, init_popn_jp, ROT0, "Konami", "Pop'n Music Animelo 2", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND ) + +// Requires ST-224 emulation for optional toggleable external effects, but otherwise is fully playable +// Core Remix and 6th Mix are marked as MACHINE_NOT_WORKING because of missing HDD dumps +GAME( 2000, bm3, 0, firebeat_bm3, bm3, firebeat_bm3_state, init_bm3, ROT0, "Konami", "Beatmania III", MACHINE_IMPERFECT_SOUND ) +GAME( 2000, bm3core, 0, firebeat_bm3, bm3, firebeat_bm3_state, init_bm3, ROT0, "Konami", "Beatmania III Append Core Remix", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND ) +GAME( 2001, bm36th, 0, firebeat_bm3, bm3, firebeat_bm3_state, init_bm3, ROT0, "Konami", "Beatmania III Append 6th Mix", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND ) +GAME( 2002, bm37th, 0, firebeat_bm3, bm3, firebeat_bm3_state, init_bm3, ROT0, "Konami", "Beatmania III Append 7th Mix", MACHINE_IMPERFECT_SOUND ) +GAME( 2003, bm3final, 0, firebeat_bm3, bm3, firebeat_bm3_state, init_bm3, ROT0, "Konami", "Beatmania III The Final", MACHINE_IMPERFECT_SOUND ) -- cgit v1.2.3