diff options
Diffstat (limited to 'src/mame/machine/k573fpga.cpp')
-rw-r--r-- | src/mame/machine/k573fpga.cpp | 286 |
1 files changed, 106 insertions, 180 deletions
diff --git a/src/mame/machine/k573fpga.cpp b/src/mame/machine/k573fpga.cpp index f184f99211b..d28a9e076bb 100644 --- a/src/mame/machine/k573fpga.cpp +++ b/src/mame/machine/k573fpga.cpp @@ -5,15 +5,18 @@ #include "k573fpga.h" -// TODO: Check if this is optimal -#define MINIMUM_BUFFER 1 - -// TODO: Is this really needed? Confirm -#define MAX_FRAME_SYNC_MATCHES 1 +// This will delay playback until there are SAMPLES_BUFFER samples in the buffer. +// This fixes some timing issues. Increase value to delay playback. +// The current value was decided by finding a delay that allowed the Konami logo +// to playback on the Drummania 10th Mix loading sequence, but finish just in time +// for the game to send the stop playback command before it looped again. +// TODO: Verify this with real hardware somehow. +#define SAMPLES_BUFFER 1152 * 30 #define MINIMP3_ONLY_MP3 #define MINIMP3_NO_STDIO #define MINIMP3_IMPLEMENTATION +#define MAX_FRAME_SYNC_MATCHES 1 #include "minimp3/minimp3.h" #include "minimp3/minimp3_ex.h" @@ -28,7 +31,7 @@ k573fpga_device::k573fpga_device(const machine_config &mconfig, const char *tag, void k573fpga_device::device_start() { ram_swap = std::make_unique<uint16_t[]>(32 * 1024 * 1024); - save_pointer(NAME(ram_swap), 32 * 1024 * 1024 ); + save_pointer(NAME(ram_swap), 32 * 1024 * 1024); device_reset(); } @@ -40,7 +43,6 @@ void k573fpga_device::device_reset() crypto_key1 = 0; crypto_key2 = 0; crypto_key3 = 0; - mp3_last_frame = 0; mp3_last_adr = 0; mp3_last_decrypt_adr = 0; mp3_next_sync = 0; @@ -61,7 +63,7 @@ void k573fpga_device::device_reset() channel_r_pcm = nullptr; last_buffer_size_channel_r = 0; - memset((void*)ram_swap.get(), 0, 12 * 1024 * 1024 * 2); + memset((void*)ram_swap.get(), 0, 32 * 1024 * 1024 * 2); memset(&mp3_info, 0, sizeof(mp3_info)); mas3507d->set_samples(m_samples); @@ -85,24 +87,21 @@ void k573fpga_device::device_add_mconfig(machine_config &config) } uint32_t k573fpga_device::get_mp3_playback() { - if (mp3_start_adr == 0) { - if (m_samples->get_position(0) == 0 && decrypt_finished) { - // The game is still requesting position updates after the song has ended. - // This happens in some games like DDR 4th Mix Plus where it uses - // the position in song for actual game engine timings. - // The counter will properly end when the game signals to the FPGA to stop playback. - last_position_update += position_diff; - } else { + if (m_samples->get_position(0) == 0 && decrypt_finished) { + // The game is still requesting position updates after the song has ended. + // This happens in some games like DDR 4th Mix Plus where it uses + // the position in song for actual game engine timings. + // The counter will properly end when the game signals to the FPGA to stop playback. + last_position_update += position_diff; + } else { + if (m_samples->get_position(0) - last_position_update > 0) { position_diff = m_samples->get_position(0) - last_position_update; - last_position_update = m_samples->get_position(0); } last_position_update = m_samples->get_position(0); - - return last_position_update; } - return 0; + return last_position_update; } uint16_t k573fpga_device::i2c_read() @@ -121,12 +120,12 @@ void k573fpga_device::i2c_write(uint16_t data) uint16_t k573fpga_device::get_mpeg_ctrl() { - if (mpeg_ctrl_flag == 0xe000 || (m_samples->get_position(0) > 0 && mp3_decrypt_mode)) { + if (mpeg_ctrl_flag == 0xe000 || m_samples->get_position(0) > 0) { // This has been tested with real hardware, but this flag is always held 0x1000 when the audio is being played - return mpeg_ctrl_flag | 0x1000; + return 0x1000; } - return mpeg_ctrl_flag; + return 0x0000; } void k573fpga_device::set_mpeg_ctrl(uint16_t data) @@ -147,7 +146,6 @@ void k573fpga_device::set_mpeg_ctrl(uint16_t data) if ((data & 0xa000) == 0xa000) { // Reset playback state for start and stop events - mp3_last_frame = 0; mp3_next_sync = 0; mp3_last_adr = mp3_start_adr; mp3_last_decrypt_adr = mp3_start_adr; @@ -169,12 +167,6 @@ void k573fpga_device::set_mpeg_ctrl(uint16_t data) channel_r_pcm = nullptr; } } - - if ((data & 0xe000) == 0xe000) { - mp3_decrypt_mode = true; - } else { - mp3_decrypt_mode = false; - } } inline uint16_t k573fpga_device::fpga_decrypt_byte_real(uint16_t v) @@ -268,30 +260,38 @@ inline uint16_t k573fpga_device::fpga_decrypt_byte_ddrsbm(uint16_t data, uint32_ SAMPLES_UPDATE_CB_MEMBER(k573fpga_device::k573fpga_stream_update) { - if ((mpeg_ctrl_flag & 0xe000) != 0xe000 || mp3_last_adr >= mp3_end_adr || (m_samples->get_position(0) < mp3_next_sync && mp3_next_sync != 0)) { + if (mp3_last_adr >= mp3_end_adr) { + mp3_next_sync = 0; + return; + } + + if ((mpeg_ctrl_flag & 0xe000) != 0xe000 || (m_samples->get_position(0) < mp3_next_sync && mp3_next_sync != 0)) { return; } - int new_samples = 0; - - if (!use_ddrsbm_fpga && mp3_start_adr != mp3_dynamic_base) { - // Base addresses are kind of a "hack" and should be dealt with eventually. - // Files that are loaded at he base address are dynamic, meaning the data constantly changes. - // Data will not get loaded outside of the base address region past the boot sequence, however. - // As such, it's possible to decrypt and play the full file if it's not at the designated base address. - // Only 4 games seem to use a base address that is non-0: GF11DM10 (0x00540000) and GF10DM9 (0x00500000). - // This way of doing things seems kind of arbitrary, so it most likely doesn't need to be handled in a - // specific case like this, but this leads to much better performance overall since the data is usually - // small (<1mb). - // Another interesting thing about base addresses is that non-base address files are almost always looped - // in-game, with the exception of the Konami logo sound. Without looping non-base address sounds, things - // like system BGMs and song wheel previews will stop looping. + int new_samples = mp3_info.samples; + int decrypt_buffer_speed = buffer_speed; + if (mp3_next_sync == 0 && last_copied_samples == 0) { crypto_key1 = orig_crypto_key1; crypto_key2 = orig_crypto_key2; crypto_key3 = orig_crypto_key3; - for (int32_t cur_idx = mp3_start_adr; cur_idx < mp3_end_adr; cur_idx += 2) { + mp3_last_decrypt_adr = mp3_start_adr; + + // Cover a large chunk of ID3 or junk at the beginning of a file when decrypting first frame + decrypt_buffer_speed = buffer_speed = 0xe00; + + last_position_update = 0; + position_diff = 0; + decrypt_finished = false; + } + + // Decrypt chunk of data + if (mp3_last_decrypt_adr < mp3_end_adr && mp3_last_adr + decrypt_buffer_speed >= mp3_last_decrypt_adr) { + int32_t cur_idx; + + for (cur_idx = mp3_last_decrypt_adr; cur_idx - mp3_last_decrypt_adr < decrypt_buffer_speed && cur_idx < mp3_end_adr; cur_idx += 2) { if (use_ddrsbm_fpga) { ram_swap[cur_idx >> 1] = fpga_decrypt_byte_ddrsbm(ram[cur_idx >> 1], (cur_idx - mp3_start_adr) / 2); } else { @@ -309,139 +309,74 @@ SAMPLES_UPDATE_CB_MEMBER(k573fpga_device::k573fpga_stream_update) crypto_key3++; } - // Decrypt entire block of memory - if (mp3_info.buffer != NULL) { - free(mp3_info.buffer); - } - - mp3dec_load_buf(&mp3_dec, ((uint8_t*)ram_swap.get()) + mp3_start_adr, mp3_end_adr - mp3_start_adr, &mp3_info, NULL, NULL); - new_samples = mp3_info.samples; - last_copied_samples = 0; - mp3_last_adr += mp3_end_adr - mp3_start_adr; - } else { - // For base address files, decrypt in a streaming manner. - // By the time the play flag is set, there's usually enough data to decode the first frame or two. - // Some files (specifcially GFDM's audio) has a large 0x600 byte ID3 header, so in order to guarantee that - // the first frame is found, I've found it best to decrypt 0x2000 bytes in the first go and then a smaller - // amount after that for every subsequent update. + mp3_last_decrypt_adr = cur_idx; + } - new_samples = mp3_info.samples; + int samples; + int free_format_bytes = 0, frame_size = 0; + int buf_size = decrypt_buffer_speed; + uint8_t *buf = (uint8_t*)ram_swap.get() + mp3_last_adr; - int decrypt_buffer = MINIMUM_BUFFER; - int decrypt_buffer_speed = buffer_speed; + // Detect first frame in MP3 data + if (mp3_next_sync == 0 && last_copied_samples == 0) { + buf_size = 0xe00; - if (mp3_next_sync == 0) { - crypto_key1 = orig_crypto_key1; - crypto_key2 = orig_crypto_key2; - crypto_key3 = orig_crypto_key3; + // Everything on the System 573 has a header 0x600 or less from what I've seen, but just ot be sure, check the first 0xe00 bytes + uint32_t first_frame = mp3d_find_frame(buf, buf_size, &free_format_bytes, &frame_size); + buf += first_frame; + mp3_last_adr += first_frame; + buf_size -= first_frame; - mp3_last_decrypt_adr = mp3_start_adr; + buffer_speed = hdr_frame_bytes(buf, free_format_bytes) * 2; + } - // Cover a large chunk of ID3 or junk at the beginning of a file when decrypting first frame - decrypt_buffer = 1; - decrypt_buffer_speed = 0x2000; + if (mp3_last_adr >= mp3_end_adr) { + mp3_next_sync = 0; + return; + } - last_position_update = 0; - position_diff = 0; - decrypt_finished = false; + if (mp3_next_sync == 0 && last_copied_samples == 0) { + // For the first iteration, we need to set up the MP3 state and such + if (mp3_info.buffer != NULL) { + free(mp3_info.buffer); } - // Decrypt chunk of data - if (mp3_last_decrypt_adr < mp3_end_adr && mp3_last_adr + decrypt_buffer_speed * decrypt_buffer >= mp3_last_decrypt_adr) { - int32_t cur_idx; + memset(&mp3_info, 0, sizeof(mp3_info)); + memset(&mp3_frame_info, 0, sizeof(mp3_frame_info)); + new_samples = 0; - for (cur_idx = mp3_last_decrypt_adr; cur_idx - mp3_last_decrypt_adr < decrypt_buffer_speed * decrypt_buffer && cur_idx < mp3_end_adr; cur_idx += 2) { - if (use_ddrsbm_fpga) { - ram_swap[cur_idx >> 1] = fpga_decrypt_byte_ddrsbm(ram[cur_idx >> 1], (cur_idx - mp3_start_adr) / 2); - } else { - ram_swap[cur_idx >> 1] = fpga_decrypt_byte_real(ram[cur_idx >> 1]); - } + /* try to make allocation size assumption by first frame */ + mp3dec_init(&mp3_dec); - if (!use_ddrsbm_fpga) { - crypto_key1 = (crypto_key1 & 0x8000) | ((crypto_key1 << 1) & 0x7FFE) | ((crypto_key1 >> 14) & 1); + samples = mp3dec_decode_frame(&mp3_dec, buf, buf_size, mp3_pcm, &mp3_frame_info); - if ((((crypto_key1 >> 15) ^ crypto_key1) & 1) != 0) { - crypto_key2 = (crypto_key2 << 1) | (crypto_key2 >> 15); - } - } - - crypto_key3++; - } - - mp3_last_decrypt_adr = cur_idx; + if (!samples) { + return; } - int samples; - int free_format_bytes = 0, frame_size = 0; - int buf_size = decrypt_buffer_speed * decrypt_buffer; - - uint8_t *buf = (uint8_t*)ram_swap.get() + mp3_last_adr; + samples *= mp3_frame_info.channels; - // Detect first frame in MP3 data - if (mp3_next_sync == 0) { - buf_size = 0x2000; - - // Everything on the System 573 has a header 0x600 or less from what I've seen, but just ot be sure, check the first 0x2000 bytes - uint32_t first_frame = mp3d_find_frame(buf, buf_size, &free_format_bytes, &frame_size); - buf += first_frame; - mp3_last_adr += first_frame; - buf_size -= first_frame; - } + mp3_allocated = (buf_size / mp3_frame_info.frame_bytes) * samples * sizeof(mp3d_sample_t) + MINIMP3_MAX_SAMPLES_PER_FRAME * sizeof(mp3d_sample_t); + mp3_info.buffer = (mp3d_sample_t*)malloc(mp3_allocated); - // Skip x amount of samples previously read (this fixes some weird glitches) - for (int frame_skip = 0; frame_skip < mp3_last_frame && buf < (uint8_t*)ram_swap.get() + mp3_end_adr; frame_skip++) { - mp3d_find_frame(buf, buf_size, &free_format_bytes, &frame_size); - buf += frame_size; - mp3_last_adr += frame_size; + if (!mp3_info.buffer) { + return; } - mp3_last_frame = 0; - - if (mp3_next_sync == 0) { - // For the first iteration, we need to set up the MP3 state and such - if (mp3_info.buffer != NULL) { - free(mp3_info.buffer); - } - - memset(&mp3_info, 0, sizeof(mp3_info)); - memset(&mp3_frame_info, 0, sizeof(mp3_frame_info)); - new_samples = 0; - - /* try to make allocation size assumption by first frame */ - mp3dec_init(&mp3_dec); - - samples = mp3dec_decode_frame(&mp3_dec, buf, buf_size, mp3_pcm, &mp3_frame_info); - - if (!samples) { - return; - } - - samples *= mp3_frame_info.channels; - - mp3_allocated = (buf_size / mp3_frame_info.frame_bytes) * samples * sizeof(mp3d_sample_t) + MINIMP3_MAX_SAMPLES_PER_FRAME * sizeof(mp3d_sample_t); - mp3_info.buffer = (mp3d_sample_t*)malloc(mp3_allocated); - - if (!mp3_info.buffer) { - return; - } - - mp3_info.samples = samples; - memcpy(mp3_info.buffer, mp3_pcm, mp3_info.samples * sizeof(mp3d_sample_t)); - - /* save info */ - mp3_info.channels = mp3_frame_info.channels; - mp3_info.hz = mp3_frame_info.hz; - mp3_info.layer = mp3_frame_info.layer; - mp3_last_frame = 0; - - decrypt_buffer = 8; - } + mp3_info.samples = samples; + memcpy(mp3_info.buffer, mp3_pcm, mp3_info.samples * sizeof(mp3d_sample_t)); + /* save info */ + mp3_info.channels = mp3_frame_info.channels; + mp3_info.hz = mp3_frame_info.hz; + mp3_info.layer = mp3_frame_info.layer; + mp3_last_adr += mp3_frame_info.frame_bytes; + } else { /* decode rest frames */ buf_size = decrypt_buffer_speed * 2; - for (int frame_skip = 0; frame_skip < decrypt_buffer && buf < (uint8_t*)ram_swap.get() + mp3_end_adr; frame_skip++) { + if (buf < (uint8_t*)ram_swap.get() + mp3_end_adr) { if (buf + buf_size > (uint8_t*)ram_swap.get() + mp3_end_adr) { buf_size = ((uint8_t*)ram_swap.get() + mp3_end_adr) - buf; } @@ -452,36 +387,25 @@ SAMPLES_UPDATE_CB_MEMBER(k573fpga_device::k573fpga_stream_update) samples = mp3dec_decode_frame(&mp3_dec, buf, buf_size, mp3_info.buffer + mp3_info.samples, &mp3_frame_info); - if (buf + buf_size >= (uint8_t*)ram_swap.get() + mp3_end_adr) { - // Some songs have a weird frame at the very end of the song which can be skipped usually. - mp3_last_adr += buf_size; - break; - } - if (!samples) { mp3_last_decrypt_adr = mp3_start_adr; // Force it to redecrypt everything in case the previous decrypt was too fast to find a full frame crypto_key1 = orig_crypto_key1; crypto_key2 = orig_crypto_key2; crypto_key3 = orig_crypto_key3; - break; - } - if (mp3_info.hz != mp3_frame_info.hz || mp3_info.layer != mp3_frame_info.layer) { - break; - } - - if (mp3_info.channels && mp3_info.channels != mp3_frame_info.channels) { - break; + if (buf + buf_size >= (uint8_t*)ram_swap.get() + mp3_end_adr) { + // Some songs have a weird frame at the very end of the song which can be skipped usually. + mp3_last_adr += buf_size; + } + } else if (mp3_info.hz == mp3_frame_info.hz && mp3_info.layer == mp3_frame_info.layer && mp3_info.channels && mp3_info.channels == mp3_frame_info.channels) { + mp3_last_adr += mp3_frame_info.frame_bytes; + mp3_info.samples += samples * mp3_frame_info.channels; } - - buf += mp3_frame_info.frame_bytes; - mp3_info.samples += samples * mp3_frame_info.channels; - mp3_last_frame++; } - - new_samples = mp3_info.samples - new_samples; } + new_samples = mp3_info.samples - new_samples; + if (new_samples > 0) { size_t buffer_size = 0; @@ -541,10 +465,12 @@ SAMPLES_UPDATE_CB_MEMBER(k573fpga_device::k573fpga_stream_update) last_copied_samples = buffer_size; - m_samples->update_raw(0, channel_l_pcm, buffer_size, mp3_info.hz, mp3_start_adr != mp3_dynamic_base); - m_samples->update_raw(1, channel_r_pcm, buffer_size, mp3_info.hz, mp3_start_adr != mp3_dynamic_base); + if (last_copied_samples > SAMPLES_BUFFER) { + m_samples->update_raw(0, channel_l_pcm, buffer_size, mp3_info.hz, mp3_start_adr != mp3_dynamic_base); + m_samples->update_raw(1, channel_r_pcm, buffer_size, mp3_info.hz, mp3_start_adr != mp3_dynamic_base); - mp3_next_sync = buffer_size - (buffer_size / 3); // Grab more data sometime before the current buffer ends. This is arbitrary and kinda hacky, but it worked best between various games in my testing. + mp3_next_sync = buffer_size - (buffer_size / 4); // Grab more data sometime before the current buffer ends. This is arbitrary and kinda hacky, but it worked best between various games in my testing. + } } if (mp3_last_adr >= mp3_end_adr) { |