diff --git a/emu/CMakeLists.txt b/emu/CMakeLists.txt index 3290ab32..878ce3ba 100644 --- a/emu/CMakeLists.txt +++ b/emu/CMakeLists.txt @@ -82,6 +82,7 @@ option(SNDEMU_GA20_ALL "Sound Device Irem GA20: all cores" OFF) option(SNDEMU_MIKEY_ALL "Sound Device Mikey: all cores" OFF) option(SNDEMU_K007232_ALL "Sound Device K007232: all cores" OFF) option(SNDEMU_K005289_ALL "Sound Device K005289: all cores" OFF) +option(SNDEMU_MSM5205_ALL "Sound Device MSM5205: all cores" OFF) # console/computer presets option(SNDEMU__PRESET_SMS "Sound Dev. Preset: Sega Master System/Game Gear" OFF) @@ -142,7 +143,8 @@ if(SNDEMU__ALL) set(SNDEMU_GA20_ALL ON) set(SNDEMU_MIKEY_ALL ON) set(SNDEMU_K007232_ALL ON) - set(SNDEMU_K005289_ALL ON) + set(SNDEMU_K005289_ALL ON) + set(SNDEMU_MSM5205_ALL ON) endif() @@ -620,6 +622,11 @@ if(SNDEMU_K005289_ALL) set(EMU_FILES ${EMU_FILES} cores/k005289.c) set(EMU_CORE_HEADERS ${EMU_CORE_HEADERS} cores/k005289.h) endif() +if(SNDEMU_MSM5205_ALL) + set(EMU_DEFS ${EMU_DEFS} " SNDDEV_MSM5205") + set(EMU_FILES ${EMU_FILES} cores/msm5205.c) + set(EMU_CORE_HEADERS ${EMU_CORE_HEADERS} cores/msm5205.h) +endif() add_library(${PROJECT_NAME} ${LIBRARY_TYPE} ${EMU_FILES}) set_target_properties(${PROJECT_NAME} PROPERTIES POSITION_INDEPENDENT_CODE ON) diff --git a/emu/EmuCores.h b/emu/EmuCores.h index f0dfc316..67f067f9 100644 --- a/emu/EmuCores.h +++ b/emu/EmuCores.h @@ -17,5 +17,6 @@ #define FCC_CTR_ 0x43545200 // superctr #define FCC_LAOO 0x4C414F4F // laoo #define FCC_RN22 0x524E3232 // Mao757 (RN22) +#define FCC_EITO 0x4549544f // eito #endif // __EMUCORES_H__ diff --git a/emu/SoundDevs.h b/emu/SoundDevs.h index 7d7feca7..6ff26769 100644 --- a/emu/SoundDevs.h +++ b/emu/SoundDevs.h @@ -45,5 +45,5 @@ #define DEVID_MIKEY 0x29 #define DEVID_K007232 0x2A #define DEVID_K005289 0x2B - +#define DEVID_MSM5205 0x2C //Variants: MSM5205, MSM6585 #endif // __SOUNDDEVS_H__ diff --git a/emu/SoundEmu.c b/emu/SoundEmu.c index fe130b4f..abd2b687 100644 --- a/emu/SoundEmu.c +++ b/emu/SoundEmu.c @@ -52,6 +52,7 @@ #define SNDDEV_MIKEY #define SNDDEV_K007232 #define SNDDEV_K005289 +#define SNDDEV_MSM5205 #endif #ifdef SNDDEV_SN76496 @@ -174,6 +175,9 @@ #ifdef SNDDEV_K005289 #include "cores/k005289.h" #endif +#ifdef SNDDEV_MSM5205 +#include "cores/msm5205.h" +#endif const DEV_DECL* sndEmu_Devices[] = { #ifdef SNDDEV_SN76496 @@ -307,6 +311,9 @@ const DEV_DECL* sndEmu_Devices[] = { #endif #ifdef SNDDEV_K005289 &sndDev_K005289, +#endif +#ifdef SNDDEV_MSM5205 + &sndDev_MSM5205, #endif NULL // list end }; diff --git a/emu/cores/msm5205.c b/emu/cores/msm5205.c new file mode 100644 index 00000000..13b8babd --- /dev/null +++ b/emu/cores/msm5205.c @@ -0,0 +1,415 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/* + * streaming ADPCM driver + * by Aaron Giles + * + * Library to transcode from an ADPCM source to raw PCM. + * Written by Buffoni Mirko in 08/06/97 + * References: various sources and documents. + * + * HJB 08/31/98 + * modified to use an automatically selected oversampling factor + * for the current sample rate + * + * 01/06/99 + * separate MSM5205 emulator form adpcm.c and some fix + * + * 07/29/12 + * added basic support for the MSM6585 + */ +/* + + MSM 5205 ADPCM chip: + + Data is streamed from a CPU by means of a clock generated on the chip. + + Holding the rate selector lines (S1 and S2) both high places the MSM5205 in an undocumented + mode which disables the sampling clock generator and makes VCK an input line. + + A reset signal is set high or low to determine whether playback (and interrupts) are occurring. + + MSM6585: is an upgraded MSM5205 voice synth IC. + Improvements: + More precise internal DA converter + Built in low-pass filter + Expanded sampling frequency + + Differences between MSM6585 & MSM5205: + + MSM6585 MSM5205 + Master clock frequency 640kHz 384k/768kHz + Sampling frequency 4k/8k/16k/32kHz at 640kHz 4k/6k/8kHz at 384kHz + ADPCM bit length 4-bit 3-bit/4-bit + Data capture timing 3µsec at 640kHz 15.6µsec at 384kHz + DA converter 12-bit 10-bit + Low-pass filter -40dB/oct N/A + Overflow prevent circuit Included N/A + Cutoff Frequency (Sampling Frequency/2.5)kHz N/A + + Data capture follows VCK falling edge on MSM5205 (VCK rising edge on MSM6585) + + TODO: + - lowpass filter for MSM6585 + + */ + +/********************************************************************************************** + OKI MSM5205 ADPCM (Full Working Implementation for libvgm) +// copyright-holders:eito, cam900, Valley Bell, Mao + + References: + https://vgmrips.net/forum/viewtopic.php?t=3436 + https://gitlab.com/cam900/vgsound_emu/-/tree/main/vgsound_emu/src/msm5205?ref_type=heads + https://github.com/mamedev/mame/blob/master/src/devices/sound/msm5205.cpp (for the 6585) + https://consolemods.org/wiki/images/f/f8/MSM5205.pdf + +***********************************************************************************************/ + +#include +#include +#include + +#include "../../stdtype.h" +#include "../snddef.h" +#include "../EmuHelper.h" +#include "../EmuCores.h" +#include "../logging.h" +#include "../SoundDevs.h" +#include "../dac_control.h" +#include "msm5205.h" + +#define PIN_RESET 0x01 +#define PIN_4B3B 0x01 +#define PIN_S2 0x02 +#define PIN_S1 0x01 +#define PIN_DATA 0x0F + +// ========== Function Prototypes ========== +static UINT8 device_start_msm5205(const MSM5205_CFG *cfg, DEV_INFO *retDevInf); +static void device_stop_msm5205(void *chip); +static void device_reset_msm5205(void *chip); +static void msm5205_update(void *param, UINT32 samples, DEV_SMPL **outputs); +static UINT32 msm5205_get_rate(void *chip); +static void msm5205_set_clock(void *chip, UINT32 clock); +static void msm5205_write(void *chip, UINT8 offset, UINT8 data); +static void msm5205_set_mute_mask(void *chip, UINT32 MuteMask); +static void msm5205_set_srchg_cb(void *chip, DEVCB_SRATE_CHG CallbackFunc, void *DataPtr); +static void msm5205_set_log_cb(void *chip, DEVCB_LOG func, void *param); + +// ========== Core Structure ========== +typedef struct _msm5205_state { + DEV_DATA _devData; + DEV_LOGGER logger; + + UINT32 master_clock; + INT32 signal; + INT32 step; + UINT8 vclk; + + UINT8 data_buf[8]; + UINT8 data_in_last; + UINT8 data_buf_pos; + UINT8 data_empty; + + UINT8 reset; + UINT8 init_prescaler; + UINT8 prescaler; + UINT8 init_bitwidth; + UINT8 bitwidth; + UINT8 output_mask; + UINT8 Muted; + + UINT8 is_msm6585; // 0 = MSM5205, 1 = MSM6585 + + DEVCB_SRATE_CHG SmpRateFunc; + void* SmpRateData; +} msm5205_state; + +// ========== Global Tables ========== +static const int index_shift[8] = {-1, -1, -1, -1, 2, 4, 6, 8}; +static int diff_lookup[49*16]; +static UINT8 tables_computed = 0; + +// ========== Device Definition ========== +static DEVDEF_RWFUNC devFunc[] = { + {RWF_REGISTER | RWF_WRITE, DEVRW_A8D8, 0, msm5205_write}, + {RWF_CLOCK | RWF_WRITE, DEVRW_VALUE, 0, msm5205_set_clock}, + {RWF_SRATE | RWF_READ, DEVRW_VALUE, 0, msm5205_get_rate}, + {RWF_CHN_MUTE | RWF_WRITE, DEVRW_ALL, 0, msm5205_set_mute_mask}, + {0x00, 0x00, 0, NULL} +}; + +static DEV_DEF devDef = { + "MSM5205", "eito", FCC_EITO, + (DEVFUNC_START)device_start_msm5205, + device_stop_msm5205, + device_reset_msm5205, + msm5205_update, + NULL, + msm5205_set_mute_mask, + NULL, + msm5205_set_srchg_cb, + msm5205_set_log_cb, + NULL, + devFunc +}; + +static const char* DeviceName(const DEV_GEN_CFG* devCfg) +{ + if (devCfg != NULL && devCfg->flags) + return "MSM6585"; + return "MSM5205"; +} + +static UINT16 DeviceChannels(const DEV_GEN_CFG* devCfg) +{ + return 1; +} + +static const char** DeviceChannelNames(const DEV_GEN_CFG* devCfg) +{ + return NULL; +} + +const DEV_DECL sndDev_MSM5205 = +{ + DEVID_MSM5205, + DeviceName, + DeviceChannels, + DeviceChannelNames, + { // cores + &devDef, + NULL + } +}; + +// ========== Helper Functions ========== +static void compute_tables(void) { + static const int nbl2bit[16][4] = { + {1,0,0,0}, {1,0,0,1}, {1,0,1,0}, {1,0,1,1}, + {1,1,0,0}, {1,1,0,1}, {1,1,1,0}, {1,1,1,1}, + {-1,0,0,0}, {-1,0,0,1}, {-1,0,1,0}, {-1,0,1,1}, + {-1,1,0,0}, {-1,1,0,1}, {-1,1,1,0}, {-1,1,1,1} + }; + + if (tables_computed) return; + + for (int step = 0; step <= 48; step++) { + int stepval = (int)floor(16.0 * pow(11.0 / 10.0, (double)step)); + for (int nib = 0; nib < 16; nib++) { + diff_lookup[step*16 + nib] = nbl2bit[nib][0] * + (stepval * nbl2bit[nib][1] + + stepval/2 * nbl2bit[nib][2] + + stepval/4 * nbl2bit[nib][3] + + stepval/8); + } + } + tables_computed = 1; +} + +INLINE UINT32 get_prescaler(msm5205_state *info) { + if (info->is_msm6585) { + return (info->prescaler & PIN_S1) ? + ((info->prescaler & PIN_S2) ? 20 : 80) : + ((info->prescaler & PIN_S2) ? 40 : 160); + } else { + return (info->prescaler & PIN_S1) ? + ((info->prescaler & PIN_S2) ? 1/* Slave mode */ : 64) : + ((info->prescaler & PIN_S2) ? 48 : 96); + } +} + +// ========== Core ADPCM Processing ========== +static INT16 clock_adpcm(msm5205_state *chip, UINT8 data) { + if (chip->reset) { + chip->step = 0; + chip->signal = 0; + return 0; + } + + if (!(chip->bitwidth & PIN_4B3B)) data <<= 1; + data &= PIN_DATA; + + int sample = diff_lookup[chip->step * 16 + (data & 15)]; + chip->signal = ((sample << 8) + (chip->signal * 245)) >> 8; + + chip->signal = (chip->signal > 2047) ? 2047 : + ((chip->signal < -2048) ? -2048 : chip->signal); + + chip->step += index_shift[data & 7]; + chip->step = (chip->step > 48) ? 48 : + ((chip->step < 0) ? 0 : chip->step); + + return (INT16)(chip->signal << 4); +} + +// ========== Device Interface ========== +static UINT8 device_start_msm5205(const MSM5205_CFG *cfg, DEV_INFO *retDevInf) { + msm5205_state *info; + + compute_tables(); + + info = (msm5205_state*)calloc(1, sizeof(msm5205_state)); + if (!info) return 0xFF; + + info->master_clock = cfg->_genCfg.clock; + info->signal = -2; + info->step = 0; + info->vclk = 0; + info->Muted = 0; + info->data_empty = 0xFF; + info->init_prescaler = cfg->prescaler; + info->prescaler = info->init_prescaler; + info->init_bitwidth = cfg->adpcmBits; + info->bitwidth = info->init_bitwidth; + info->data_buf[0] = 0; + info->is_msm6585 = (cfg->_genCfg.flags & 0x01); // new flag! + + info->_devData.chipInf = info; + INIT_DEVINF(retDevInf, &info->_devData, msm5205_get_rate(info), &devDef); + return 0x00; +} + +static void device_stop_msm5205(void *chip) { + free((msm5205_state*)chip); +} + +static void device_reset_msm5205(void *chip) { + msm5205_state *info = (msm5205_state*)chip; + + info->signal = -2; + info->step = 0; + info->vclk = 0; + memset(info->data_buf, 0, sizeof(info->data_buf)); + info->data_buf_pos = 0; + info->data_empty = 0xFF; + info->prescaler = info->init_prescaler; + info->bitwidth = info->init_bitwidth; + info->data_buf[0] = 0; + + if (info->SmpRateFunc) + info->SmpRateFunc(info->SmpRateData, msm5205_get_rate(info)); +} + +// ========== Audio Generation ========== +static void msm5205_update(void *param, UINT32 samples, DEV_SMPL **outputs) { + msm5205_state *info = (msm5205_state*)param; + DEV_SMPL *bufL = outputs[0]; + DEV_SMPL *bufR = outputs[1]; + UINT32 i; + + for (i = 0; i < samples; i++) { + INT16 sample = 0; + + if (!info->Muted && !(info->reset)) { + UINT8 read_pos = info->data_buf_pos & 0x0F; + UINT8 write_pos = (info->data_buf_pos >> 4) & 0x07; + + if ((read_pos != write_pos) && (get_prescaler(info) != 1)) { // if not slave mode + UINT8 data = info->data_buf[read_pos]; + sample = clock_adpcm(info, data); + info->data_buf_pos = (write_pos << 4) | ((read_pos + 1) & 0x07); + } else { + sample = (INT16)(info->signal << 4); + } + } + + bufL[i] = bufR[i] = sample; + } +} + +// ========== I/O Handling ========== +static void msm5205_write(void *chip, UINT8 offset, UINT8 data) { + msm5205_state *info = (msm5205_state*)chip; + + switch (offset) + { + case 0: /* reset */ { + UINT8 old = info->reset; + info->reset = data; + + if ((old ^ data) & PIN_RESET) { + info->signal = 0; + info->step = 0; + } + break; + } + case 1: /* data_w */ { + UINT8 write_pos = (info->data_buf_pos >> 4) & 0x07; + UINT8 read_pos = info->data_buf_pos & 0x07; + + if (((write_pos + 1) & 0x07) == read_pos) { + emu_logf(&info->logger, DEVLOG_DEBUG, "MSM5205 FIFO overflow\n"); + return; + } + + info->data_buf[write_pos] = data; + info->data_buf_pos = ((write_pos + 1) << 4) | read_pos; + break; + } + case 2: { // vclk + UINT8 old = info->vclk; + info->vclk = data; + + if (get_prescaler(info) == 1) { // if slave mode + if (((old ^ data) & 1) && info->vclk) { + if (!info->Muted && !(info->reset)) { + UINT8 read_pos = info->data_buf_pos & 0x0F; + UINT8 write_pos = (info->data_buf_pos >> 4) & 0x07; + + if (read_pos != write_pos) { + UINT8 data = info->data_buf[read_pos]; + clock_adpcm(info, data); + info->data_buf_pos = (write_pos << 4) | ((read_pos + 1) & 0x07); + } + } + } + } + break; + } + case 4: /* set prescaler */ { + UINT8 old = info->prescaler; + info->prescaler = data; + + if ((old ^ data) & (PIN_S1|PIN_S2)) { + if (info->SmpRateFunc) + info->SmpRateFunc(info->SmpRateData, msm5205_get_rate(info)); + } + break; + } + case 5: /* set bitwidth */ { + info->bitwidth = data; + break; + } + } +} + +// ========== Configuration ========== +static UINT32 msm5205_get_rate(void *chip) { + msm5205_state *info = (msm5205_state*)chip; + return info->master_clock / get_prescaler(info); +} + +static void msm5205_set_clock(void *chip, UINT32 clock) { + msm5205_state *info = (msm5205_state*)chip; + info->master_clock = clock; + if (info->SmpRateFunc) + info->SmpRateFunc(info->SmpRateData, msm5205_get_rate(info)); +} + +static void msm5205_set_mute_mask(void *chip, UINT32 MuteMask) { + msm5205_state *info = (msm5205_state*)chip; + info->Muted = MuteMask & 0x01; +} + +static void msm5205_set_srchg_cb(void *chip, DEVCB_SRATE_CHG CallbackFunc, void *DataPtr) { + msm5205_state *info = (msm5205_state*)chip; + info->SmpRateFunc = CallbackFunc; + info->SmpRateData = DataPtr; +} + +static void msm5205_set_log_cb(void *chip, DEVCB_LOG func, void *param) { + msm5205_state *info = (msm5205_state*)chip; + dev_logger_set(&info->logger, info, func, param); +} diff --git a/emu/cores/msm5205.h b/emu/cores/msm5205.h new file mode 100644 index 00000000..8bd5af29 --- /dev/null +++ b/emu/cores/msm5205.h @@ -0,0 +1,22 @@ +#ifndef __MSM5205_H__ +#define __MSM5205_H__ +#include "../EmuStructs.h" + +// Configuration flags (bit 31 for MSM6585) +#define MSM5205_S1 0 +#define MSM5205_S2 1 + +#define MSM5205_ADPCM_3B 2 +#define MSM5205_ADPCM_4B 0 + +typedef struct msm5205_config +{ + DEV_GEN_CFG _genCfg; + + UINT8 prescaler; // prescaler, Bit 0 = S1, Bit 1 = S2 + UINT8 adpcmBits; // bits per ADPCM sample (3, 4), 0 = default (3) +} MSM5205_CFG; + +extern const DEV_DECL sndDev_MSM5205; + +#endif // __MSM5205_H__ diff --git a/emu/dac_control.c b/emu/dac_control.c index dd38868c..fdfe9788 100644 --- a/emu/dac_control.c +++ b/emu/dac_control.c @@ -186,12 +186,14 @@ INLINE void daccontrol_SendCommand(dac_control* chip) case DEVID_ES5503: case DEVID_GA20: // TODO: Verify case DEVID_MIKEY: + case DEVID_MSM5205: if (chip->Write.A8D8 == NULL) return; Command = (chip->DstCommand & 0x00FF) >> 0; Data = ChipData[0x00]; chip->Write.A8D8(chip->chipData, Command, Data); break; + // 16-bit Register, 8-bit Data case DEVID_YM2612: case DEVID_YM2608: @@ -427,6 +429,9 @@ void daccontrol_setup_chip(void* info, DEV_INFO* devInf, UINT8 ChType, UINT16 Co case DEVID_K005289: chip->CmdSize = 0x02; break; + case DEVID_MSM5205: + chip->CmdSize = 0x03; + break; default: chip->CmdSize = 0x01; break; diff --git a/libEmu.vcxproj b/libEmu.vcxproj index d30486d5..89ce80bc 100644 --- a/libEmu.vcxproj +++ b/libEmu.vcxproj @@ -183,6 +183,7 @@ + @@ -271,6 +272,7 @@ + diff --git a/libEmu.vcxproj.filters b/libEmu.vcxproj.filters index c91045d3..45668166 100644 --- a/libEmu.vcxproj.filters +++ b/libEmu.vcxproj.filters @@ -255,6 +255,9 @@ Quelldateien + + Quelldateien + @@ -548,5 +551,8 @@ Headerdateien + + Headerdateien + diff --git a/player/vgmplayer.cpp b/player/vgmplayer.cpp index a1cf8ee9..0e39a36f 100644 --- a/player/vgmplayer.cpp +++ b/player/vgmplayer.cpp @@ -24,6 +24,7 @@ #include "../emu/cores/c140.h" #include "../emu/cores/qsoundintf.h" #include "../emu/cores/scsp.h" +#include "../emu/cores/msm5205.h" // for MSM5205_CFG #include "dblk_compr.h" #include "../utils/StrUtils.h" @@ -41,7 +42,7 @@ DEVID_32X_PWM, DEVID_AY8910, DEVID_GB_DMG, DEVID_NES_APU, DEVID_YMW258, DEVID_uPD7759, DEVID_OKIM6258, DEVID_OKIM6295, DEVID_K051649, DEVID_K054539, DEVID_C6280, DEVID_C140, DEVID_C219, DEVID_K053260, DEVID_POKEY, DEVID_QSOUND, DEVID_SCSP, DEVID_WSWAN, DEVID_VBOY_VSU, DEVID_SAA1099, DEVID_ES5503, DEVID_ES5506, DEVID_X1_010, DEVID_C352, - DEVID_GA20, DEVID_MIKEY, DEVID_K007232, DEVID_K005289, + DEVID_GA20, DEVID_MIKEY, DEVID_K007232, DEVID_K005289, DEVID_MSM5205, }; /*static*/ const DEV_ID VGMPlayer::_DEV_LIST[_CHIP_COUNT] = @@ -51,7 +52,7 @@ DEVID_RF5C68, DEVID_32X_PWM, DEVID_AY8910, DEVID_GB_DMG, DEVID_NES_APU, DEVID_YMW258, DEVID_uPD7759, DEVID_OKIM6258, DEVID_OKIM6295, DEVID_K051649, DEVID_K054539, DEVID_C6280, DEVID_C140, DEVID_K053260, DEVID_POKEY, DEVID_QSOUND, DEVID_SCSP, DEVID_WSWAN, DEVID_VBOY_VSU, DEVID_SAA1099, DEVID_ES5503, DEVID_ES5506, DEVID_X1_010, DEVID_C352, - DEVID_GA20, DEVID_MIKEY, DEVID_K007232, DEVID_K005289, + DEVID_GA20, DEVID_MIKEY, DEVID_K007232, DEVID_K005289, DEVID_MSM5205, }; /*static*/ const UINT32 VGMPlayer::_CHIPCLK_OFS[_CHIP_COUNT] = @@ -61,7 +62,7 @@ 0x6C, 0x70, 0x74, 0x80, 0x84, 0x88, 0x8C, 0x90, 0x98, 0x9C, 0xA0, 0xA4, 0xA8, 0xAC, 0xB0, 0xB4, 0xB8, 0xC0, 0xC4, 0xC8, 0xCC, 0xD0, 0xD8, 0xDC, - 0xE0, 0xE4, 0xE8, 0xEC, + 0xE0, 0xE4, 0xE8, 0xEC, 0xF0, }; /*static*/ const UINT16 VGMPlayer::_CHIP_VOLUME[_CHIP_COUNT] = { 0x80, 0x200, 0x100, 0x100, 0x180, 0xB0, 0x100, 0x80, @@ -69,7 +70,7 @@ 0x80, 0xE0, 0x100, 0xC0, 0x100, 0x40, 0x11E, 0x1C0, 0x100, 0xA0, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x20, 0x100, 0x100, 0x100, 0x40, 0x20, 0x100, 0x40, - 0x280, 0x100, 0x100, 0x100, + 0x280, 0x100, 0x100, 0x100, 0x80, }; /*static*/ const UINT16 VGMPlayer::_PB_VOL_AMNT[_CHIP_COUNT] = { 0x100, 0x80, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, @@ -77,7 +78,7 @@ 0x200, 0x100, 0x200, 0x400, 0x200, 0x400, 0x100, 0x200, 0x200, 0x100, 0x100, 0x100, 0x180, 0x100, 0x100, 0x100, 0x800, 0x100, 0x100, 0x100, 0x800, 0x1000, 0x100, 0x800, - 0x100, 0x200, 0x100, 0x100, + 0x100, 0x200, 0x100, 0x100, 0x100, }; /*static*/ const char* const VGMPlayer::_TAG_TYPE_LIST[_TAG_COUNT] = @@ -1287,6 +1288,17 @@ void VGMPlayer::GenerateDeviceConfig(void) } SaveDeviceConfig(sdCfg.cfgData, &devCfg, sizeof(DEV_GEN_CFG)); break; + case DEVID_MSM5205: + { + MSM5205_CFG okiCfg; + + okiCfg._genCfg = devCfg; + okiCfg.prescaler = (_hdrBuffer[0x97] & 0x03) >> 0; + okiCfg.adpcmBits = (_hdrBuffer[0x97] & 0x04) ? MSM5205_ADPCM_4B : MSM5205_ADPCM_3B; + + SaveDeviceConfig(sdCfg.cfgData, &okiCfg, sizeof(MSM5205_CFG)); + } + break; case DEVID_C352: devCfg.clock = devCfg.clock * 72 / _hdrBuffer[0xD6]; // real clock = VGM clock / (VGM clkDiv * 4) * 288 SaveDeviceConfig(sdCfg.cfgData, &devCfg, sizeof(DEV_GEN_CFG)); diff --git a/player/vgmplayer.hpp b/player/vgmplayer.hpp index 6e0ed0a7..97a51107 100644 --- a/player/vgmplayer.hpp +++ b/player/vgmplayer.hpp @@ -248,6 +248,7 @@ class VGMPlayer : public PlayerBase void Cmd_GGStereo(void); // command 4F - set GameGear Stereo mask void Cmd_SN76489(void); // command 50 - SN76489 register write void Cmd_Reg8_Data8(void); // command 51/54/55/5A..5D - Register, Data (8-bit) + void Cmd_MSM5205_Reg(void); // command 32 - MSM5205 register write (4-bit offset, 4-bit data) void Cmd_CPort_Reg8_Data8(void); // command 52/53/56..59/5E/5F - Port (in command byte), Register, Data (8-bit) void Cmd_Port_Reg8_Data8(void); // command D0..D2 - Port, Register, Data (8-bit) void Cmd_Ofs8_Data8(void); // command B3/B5..BB/BE/BF - Offset (8-bit), Data (8-bit) @@ -281,8 +282,8 @@ class VGMPlayer : public PlayerBase enum { _HDR_BUF_SIZE = 0x100, - _OPT_DEV_COUNT = 0x2c, - _CHIP_COUNT = 0x2c, + _OPT_DEV_COUNT = 0x2d, + _CHIP_COUNT = 0x2d, _PCM_BANK_COUNT = 0x40 }; diff --git a/player/vgmplayer_cmdhandler.cpp b/player/vgmplayer_cmdhandler.cpp index 01fdd32f..bf6863ba 100644 --- a/player/vgmplayer_cmdhandler.cpp +++ b/player/vgmplayer_cmdhandler.cpp @@ -70,7 +70,7 @@ {0xFF, 0x00, &VGMPlayer::Cmd_invalid}, // 2F {0x00, 0x02, &VGMPlayer::Cmd_SN76489}, // 30 SN76489 register write (2nd chip) {0xFF, 0x02, &VGMPlayer::Cmd_AY_Stereo}, // 31 AY8910 stereo mask [chip type depends on data] - {0xFF, 0x02, &VGMPlayer::Cmd_unknown}, // 32 + {0x2B, 0x02, &VGMPlayer::Cmd_MSM5205_Reg}, // 32 MSM5205 register write {0xFF, 0x02, &VGMPlayer::Cmd_unknown}, // 33 {0xFF, 0x02, &VGMPlayer::Cmd_unknown}, // 34 {0xFF, 0x02, &VGMPlayer::Cmd_unknown}, // 35 @@ -288,7 +288,7 @@ 0x1B, // 05 HuC6280 0x20, // 06 SCSP 0x14, // 07 NES APU - 0xFF, // 08 + 0x2B, // 08 MSM5205 0xFF, // 09 0xFF, // 0A 0xFF, // 0B @@ -1058,6 +1058,18 @@ void VGMPlayer::Cmd_Port_Reg8_Data8(void) return; } +void VGMPlayer::Cmd_MSM5205_Reg(void) +{ + UINT8 chipType = _CMD_INFO[fData[0x00]].chipType; + UINT8 chipID = (fData[0x01] & 0x80) >> 7; + CHIP_DEVICE* cDev = GetDevicePtr(chipType, chipID); + if (cDev == NULL || cDev->write8 == NULL) + return; + + cDev->write8(cDev->base.defInf.dataPtr, (fData[0x01] >> 4) & 0x7, fData[0x01] & 0xF); + return; +} + void VGMPlayer::Cmd_Ofs8_Data8(void) { UINT8 chipType = _CMD_INFO[fData[0x00]].chipType;