diff --git a/emu/CMakeLists.txt b/emu/CMakeLists.txt index 627249e2..e826efa0 100644 --- a/emu/CMakeLists.txt +++ b/emu/CMakeLists.txt @@ -83,6 +83,7 @@ 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) +option(SNDEMU_MSM5232_ALL "Sound Device MSM5232: all cores" OFF) # console/computer presets option(SNDEMU__PRESET_SMS "Sound Dev. Preset: Sega Master System/Game Gear" OFF) @@ -145,6 +146,7 @@ if(SNDEMU__ALL) set(SNDEMU_K007232_ALL ON) set(SNDEMU_K005289_ALL ON) set(SNDEMU_MSM5205_ALL ON) + set(SNDEMU_MSM5232_ALL ON) endif() @@ -627,6 +629,11 @@ if(SNDEMU_MSM5205_ALL) set(EMU_FILES ${EMU_FILES} cores/msm5205.c) set(EMU_CORE_HEADERS ${EMU_CORE_HEADERS} cores/msm5205.h) endif() +if(SNDEMU_MSM5232_ALL) + set(EMU_DEFS ${EMU_DEFS} " SNDDEV_MSM5232") + set(EMU_FILES ${EMU_FILES} cores/msm5232.c) + set(EMU_CORE_HEADERS ${EMU_CORE_HEADERS} cores/msm5232.h) +endif() add_library(${PROJECT_NAME} ${LIBRARY_TYPE} ${EMU_FILES}) set_target_properties(${PROJECT_NAME} PROPERTIES POSITION_INDEPENDENT_CODE ON) diff --git a/emu/SoundDevs.h b/emu/SoundDevs.h index 6d28a48e..44453d22 100644 --- a/emu/SoundDevs.h +++ b/emu/SoundDevs.h @@ -46,4 +46,5 @@ #define DEVID_K007232 0x2A #define DEVID_K005289 0x2B #define DEVID_MSM5205 0x2C // variants: MSM5205, MSM6585 +#define DEVID_MSM5232 0x2D #endif // __SOUNDDEVS_H__ diff --git a/emu/SoundEmu.c b/emu/SoundEmu.c index abd2b687..fc1c5461 100644 --- a/emu/SoundEmu.c +++ b/emu/SoundEmu.c @@ -53,6 +53,7 @@ #define SNDDEV_K007232 #define SNDDEV_K005289 #define SNDDEV_MSM5205 +#define SNDDEV_MSM5232 #endif #ifdef SNDDEV_SN76496 @@ -178,6 +179,9 @@ #ifdef SNDDEV_MSM5205 #include "cores/msm5205.h" #endif +#ifdef SNDDEV_MSM5232 +#include "cores/msm5232.h" +#endif const DEV_DECL* sndEmu_Devices[] = { #ifdef SNDDEV_SN76496 @@ -314,6 +318,9 @@ const DEV_DECL* sndEmu_Devices[] = { #endif #ifdef SNDDEV_MSM5205 &sndDev_MSM5205, +#endif +#ifdef SNDDEV_MSM5232 + &sndDev_MSM5232, #endif NULL // list end }; diff --git a/emu/cores/msm5232.c b/emu/cores/msm5232.c new file mode 100644 index 00000000..48ac39df --- /dev/null +++ b/emu/cores/msm5232.c @@ -0,0 +1,567 @@ +// license:GPL-2.0+ +// copyright-holders:Jarek Burczynski, Hiromitsu Shioya, Angelo Salese +/* + OKI MSM5232 + 8 channel tone generator + + Modified for libvgm by Mao(RN22), cam900(MATRIX) + It's basically MAME code with improvements. + TA7630P emulation code (BSD-3-Clause) by Angelo Salese, adapted by Mao(RN22) and fully revised by cam900(MATRIX) +*/ + +#include +#include +#include + +#include "../../stdtype.h" +#include "../snddef.h" +#include "../EmuHelper.h" +#include "../EmuCores.h" +#include "../logging.h" +#include "../SoundDevs.h" +#include "../EmuHelper.h" +#include "../RatioCntr.h" +#include "msm5232.h" + +#define MSM5232_NUM_CHANNELS 8 +#define MSM5232_NUM_OUTPUTS 11 +#define CLOCK_RATE_DIVIDER 16 +#define STEP_SH 16 +#define VMIN 0 +#define VMAX 32768 +#define MSM5232_EXTVOL_GROUPS 2 + +// MAME's ROM table, 88 entries (12 bits: 9 for counter, 3 for divider) +#define ROM(counter, bindiv) ((counter) | ((bindiv) << 9)) +static const uint16_t MSM5232_ROM[88] = { + ROM(506, 7), ROM(478, 7), ROM(451, 7), ROM(426, 7), ROM(402, 7), ROM(379, 7), ROM(358, 7), ROM(338, 7), + ROM(319, 7), ROM(301, 7), ROM(284, 7), ROM(268, 7), ROM(253, 7), ROM(478, 6), ROM(451, 6), ROM(426, 6), + ROM(402, 6), ROM(379, 6), ROM(358, 6), ROM(338, 6), ROM(319, 6), ROM(301, 6), ROM(284, 6), ROM(268, 6), + ROM(253, 6), ROM(478, 5), ROM(451, 5), ROM(426, 5), ROM(402, 5), ROM(379, 5), ROM(358, 5), ROM(338, 5), + ROM(319, 5), ROM(301, 5), ROM(284, 5), ROM(268, 5), ROM(253, 5), ROM(478, 4), ROM(451, 4), ROM(426, 4), + ROM(402, 4), ROM(379, 4), ROM(358, 4), ROM(338, 4), ROM(319, 4), ROM(301, 4), ROM(284, 4), ROM(268, 4), + ROM(253, 4), ROM(478, 3), ROM(451, 3), ROM(426, 3), ROM(402, 3), ROM(379, 3), ROM(358, 3), ROM(338, 3), + ROM(319, 3), ROM(301, 3), ROM(284, 3), ROM(268, 3), ROM(253, 3), ROM(478, 2), ROM(451, 2), ROM(426, 2), + ROM(402, 2), ROM(379, 2), ROM(358, 2), ROM(338, 2), ROM(319, 2), ROM(301, 2), ROM(284, 2), ROM(268, 2), + ROM(253, 2), ROM(478, 1), ROM(451, 1), ROM(426, 1), ROM(402, 1), ROM(379, 1), ROM(358, 1), ROM(338, 1), + ROM(319, 1), ROM(301, 1), ROM(284, 1), ROM(268, 1), ROM(253, 1), ROM(253, 1), ROM(253, 1), ROM(13, 7) +}; +#undef ROM + +typedef struct { + uint8_t mode; // 0=tone, 1=noise + int TG_count_period; + int TG_count; + uint8_t TG_cnt; + uint8_t TG_out16, TG_out8, TG_out4, TG_out2; + int egvol; + int eg_sect; // 0=attack, 1=decay, 2=release, -1=off + int counter; + int eg; + uint8_t eg_arm; + double ar_rate, dr_rate, rr_rate; + int pitch; + int GF; +} MSM5232_VOICE; + +typedef struct { + DEV_DATA _devData; + + MSM5232_VOICE voi[MSM5232_NUM_CHANNELS]; + uint32_t noise_rng; + uint32_t noise_out; + int noise_step; + int noise_cnt; + int noise_clocks; + + uint8_t control1, control2; + uint32_t EN_out16[2], EN_out8[2], EN_out4[2], EN_out2[2]; + + uint32_t clock, sample_rate; + unsigned int UpdateStep; + RATIO_CNTR cycle_cntr; + + double capacitors[8]; + double ar_tbl[8], dr_tbl[16]; + + // --- TA7630 external volume (0..15, as used by Taito hardware) --- + uint8_t ext_vol[MSM5232_EXTVOL_GROUPS]; // [0]=group1 0..3, [1]=group2 4..7 + double ext_vol_gain[MSM5232_EXTVOL_GROUPS]; // multiplier for output + + UINT8 per_out_vol[MSM5232_NUM_OUTPUTS]; // per-output volume + UINT8 Muted[MSM5232_NUM_OUTPUTS]; + double vol_ctrl[16]; +} MSM5232_STATE; + +// Forward declarations +static UINT8 device_start_msm5232(const MSM5232_CFG* cfg, DEV_INFO* retDevInf); +static void device_stop_msm5232(void* info); +static void device_reset_msm5232(void* info); +static void device_update_msm5232(void* info, UINT32 samples, DEV_SMPL** outputs); +static void msm5232_write(void* info, UINT8 reg, UINT8 value); +static void msm5232_set_mute_mask(void* info, UINT32 muteMask); + +static DEVDEF_RWFUNC devFunc[] = { + {RWF_REGISTER | RWF_WRITE, DEVRW_A8D8, 0, msm5232_write}, + {RWF_CHN_MUTE | RWF_WRITE, DEVRW_ALL, 0, msm5232_set_mute_mask}, + {0x00, 0x00, 0, NULL} +}; + +static DEV_DEF devDef = { + "MSM5232", "MAME", FCC_MAME, + (DEVFUNC_START)device_start_msm5232, + device_stop_msm5232, + device_reset_msm5232, + device_update_msm5232, + NULL, msm5232_set_mute_mask, NULL, NULL, NULL, NULL, devFunc +}; +static const char* DeviceName(const DEV_GEN_CFG* devCfg) +{ + return "MSM5232"; +} +static UINT16 DeviceChannels(const DEV_GEN_CFG* devCfg) { return MSM5232_NUM_OUTPUTS; } +static const char** DeviceChannelNames(const DEV_GEN_CFG* devCfg) { return NULL; } + +const DEV_DECL sndDev_MSM5232 = +{ + DEVID_MSM5232, + DeviceName, + DeviceChannels, + DeviceChannelNames, + { // cores + &devDef, + NULL + } +}; + +// --- Helper Functions --- + +static void init_tables(MSM5232_STATE* chip) +{ + const double R51 = 870.0, R52 = 17400.0, R53 = 101000.0; + chip->UpdateStep = (unsigned int)((1 << STEP_SH) * (double)chip->sample_rate / (double)chip->clock); + + for (int i = 0; i < 8; i++) { + double clockscale = (double)chip->clock / 2119040.0; + int rcp_duty_cycle = 1 << ((i & 4) ? (i & ~2) : i); + chip->ar_tbl[i] = (rcp_duty_cycle / clockscale) * R51; + } + for (int i = 0; i < 8; i++) { + double clockscale = (double)chip->clock / 2119040.0; + int rcp_duty_cycle = 1 << ((i & 4) ? (i & ~2) : i); + chip->dr_tbl[i] = (rcp_duty_cycle / clockscale) * R52; + chip->dr_tbl[i + 8] = (rcp_duty_cycle / clockscale) * R53; + } + chip->noise_step = (int)((1 << STEP_SH) / 128.0 * ((double)chip->clock / chip->sample_rate)); +} + +static void init_voice(MSM5232_STATE* chip, int i) +{ + MSM5232_VOICE* v = &chip->voi[i]; + v->ar_rate = chip->ar_tbl[0] * chip->capacitors[i]; + v->dr_rate = chip->dr_tbl[0] * chip->capacitors[i]; + v->rr_rate = chip->dr_tbl[0] * chip->capacitors[i]; + v->eg_sect = -1; + v->eg = 0; + v->egvol = 0; + v->counter = 0; + v->mode = 0; + v->pitch = -1; + v->GF = 0; + + v->TG_count_period = 1; + v->TG_count = 1; + v->TG_cnt = 0; + v->TG_out16 = v->TG_out8 = v->TG_out4 = v->TG_out2 = 0; +} + +// --- Core Functions --- + +static UINT8 device_start_msm5232(const MSM5232_CFG* cfg, DEV_INFO* retDevInf) +{ + MSM5232_STATE* chip; + + chip = (MSM5232_STATE*)calloc(1, sizeof(MSM5232_STATE)); + if (!chip) return 0xFF; + + chip->clock = cfg->_genCfg.clock; + for (int i = 0; i < 8; i++) + chip->capacitors[i] = cfg->capacitors[i]; + + chip->sample_rate = chip->clock / CLOCK_RATE_DIVIDER; + SRATE_CUSTOM_HIGHEST(cfg->_genCfg.srMode, chip->sample_rate, cfg->_genCfg.smplRate); + + double db = 0.0; + double db_step = 0; /* 1.50 dB step (at least, maybe more) */ + double db_step_inc = 0.125; + for (int i = 0; i < 16; i++) + { + double max = 100.0 / pow(10.0, db / 20.0); + chip->vol_ctrl[15 - i] = max / 100.0; + db += db_step; + db_step += db_step_inc; + } + + init_tables(chip); + for (int i = 0; i < MSM5232_NUM_CHANNELS; i++) + { + init_voice(chip, i); + } + msm5232_set_mute_mask(chip, 0); + + chip->noise_rng = 1; + chip->noise_out = 0; + chip->noise_cnt = 0; + chip->noise_clocks = 0; + chip->control1 = chip->control2 = 0; + chip->EN_out16[0] = chip->EN_out8[0] = chip->EN_out4[0] = chip->EN_out2[0] = 0; + chip->EN_out16[1] = chip->EN_out8[1] = chip->EN_out4[1] = chip->EN_out2[1] = 0; + + // --- TA7630 external volume defaults: max (0) --- + chip->ext_vol[0] = 0; + chip->ext_vol[1] = 0; + chip->ext_vol_gain[0] = chip->vol_ctrl[0]; + chip->ext_vol_gain[1] = chip->vol_ctrl[0]; + + // initialize per-output volume (0x80 = 100%) + for (int i = 0; i < MSM5232_NUM_OUTPUTS; i++) + { + chip->per_out_vol[i] = (i >= 8) ? 0 : 0x80; + } + + RC_SET_RATIO(&chip->cycle_cntr, chip->clock, chip->sample_rate); + chip->_devData.chipInf = chip; + INIT_DEVINF(retDevInf, &chip->_devData, chip->sample_rate, &devDef); + return 0x00; +} + +static void device_stop_msm5232(void* info) { free(info); } + +static void device_reset_msm5232(void* info) +{ + MSM5232_STATE* chip = (MSM5232_STATE*)info; + for (int i = 0; i < MSM5232_NUM_CHANNELS; i++) { + init_voice(chip, i); + msm5232_write(chip, i, 0x80); + msm5232_write(chip, i, 0x00); + } + chip->noise_cnt = 0; + chip->noise_rng = 1; + chip->noise_out = 0; + chip->noise_clocks = 0; + chip->control1 = chip->control2 = 0; + chip->EN_out16[0] = chip->EN_out8[0] = chip->EN_out4[0] = chip->EN_out2[0] = 0; + chip->EN_out16[1] = chip->EN_out8[1] = chip->EN_out4[1] = chip->EN_out2[1] = 0; +} + +// Envelope handling, closely following MAME +static void EG_voices_advance(MSM5232_STATE* chip) +{ + for (int i = 0; i < MSM5232_NUM_CHANNELS; i++) { + MSM5232_VOICE* v = &chip->voi[i]; + switch (v->eg_sect) { + case 0: // attack + if (v->eg < VMAX) { + v->counter -= (int)((VMAX - v->eg) / v->ar_rate); + if (v->counter <= 0) { + int n = -v->counter / chip->sample_rate + 1; + v->counter += n * chip->sample_rate; + v->eg += n; + if (v->eg > VMAX) + v->eg = VMAX; + } + } + if (!v->eg_arm) { + if (v->eg >= VMAX * 80 / 100) + v->eg_sect = 1; + } + // ARM=1: stay at max until key off + v->egvol = v->eg / 16; + break; + + case 1: // decay + if (v->eg > VMIN) { + v->counter -= (int)((v->eg - VMIN) / v->dr_rate); + if (v->counter <= 0) { + int n = -v->counter / chip->sample_rate + 1; + v->counter += n * chip->sample_rate; + v->eg -= n; + if (v->eg < VMIN) + v->eg = VMIN; + } + } else { + v->eg_sect = -1; + } + v->egvol = v->eg / 16; + break; + + case 2: // release + if (v->eg > VMIN) { + v->counter -= (int)((v->eg - VMIN) / v->rr_rate); + if (v->counter <= 0) { + int n = -v->counter / chip->sample_rate + 1; + v->counter += n * chip->sample_rate; + v->eg -= n; + if (v->eg < VMIN) + v->eg = VMIN; + } + } else { + v->eg_sect = -1; + } + v->egvol = v->eg / 16; + break; + default: + break; + } + } +} + +// Tone generator, closely following MAME's TG_group_advance +typedef struct { + INT32 o2, o4, o8, o16; + INT32 solo8, solo16; +} MSM5232_GROUP_OUT; + +static void TG_group_advance(MSM5232_STATE* chip, int groupidx, MSM5232_GROUP_OUT* out) +{ + memset(out, 0, sizeof(*out)); + MSM5232_VOICE* v = &chip->voi[groupidx*4]; + for (int i = 0; i < 4; i++, v++) { + int out2 = 0, out4 = 0, out8 = 0, out16 = 0; + // GUARD: skip if TG_count_period is zero (not initialized yet) + if (v->TG_count_period == 0) + continue; + if (v->mode == 0) { // tone + int left = 1 << STEP_SH; + do { + int nextevent = left; + if (v->TG_cnt & v->TG_out16) out16 += v->TG_count; + if (v->TG_cnt & v->TG_out8) out8 += v->TG_count; + if (v->TG_cnt & v->TG_out4) out4 += v->TG_count; + if (v->TG_cnt & v->TG_out2) out2 += v->TG_count; + + v->TG_count -= nextevent; + while (v->TG_count <= 0) { + v->TG_count += v->TG_count_period; + v->TG_cnt++; + if (v->TG_cnt & v->TG_out16) out16 += v->TG_count_period; + if (v->TG_cnt & v->TG_out8) out8 += v->TG_count_period; + if (v->TG_cnt & v->TG_out4) out4 += v->TG_count_period; + if (v->TG_cnt & v->TG_out2) out2 += v->TG_count_period; + if (v->TG_count > 0) break; + v->TG_count += v->TG_count_period; + v->TG_cnt++; + if (v->TG_cnt & v->TG_out16) out16 += v->TG_count_period; + if (v->TG_cnt & v->TG_out8) out8 += v->TG_count_period; + if (v->TG_cnt & v->TG_out4) out4 += v->TG_count_period; + if (v->TG_cnt & v->TG_out2) out2 += v->TG_count_period; + } + if (v->TG_cnt & v->TG_out16) out16 -= v->TG_count; + if (v->TG_cnt & v->TG_out8) out8 -= v->TG_count; + if (v->TG_cnt & v->TG_out4) out4 -= v->TG_count; + if (v->TG_cnt & v->TG_out2) out2 -= v->TG_count; + left -= nextevent; + } while (left > 0); + } else { // noise + if (chip->noise_clocks & 8) out16 += (1<noise_clocks & 4) out8 += (1<noise_clocks & 2) out4 += (1<noise_clocks & 1) out2 += (1<Muted[(groupidx*4)+i]) + { + out->o16 += ((out16 - (1 << (STEP_SH-1))) * v->egvol) >> STEP_SH; + out->o8 += ((out8 - (1 << (STEP_SH-1))) * v->egvol) >> STEP_SH; + out->o4 += ((out4 - (1 << (STEP_SH-1))) * v->egvol) >> STEP_SH; + out->o2 += ((out2 - (1 << (STEP_SH-1))) * v->egvol) >> STEP_SH; + } + if (i == 3 && groupidx == 1) + { + if (!chip->Muted[8]) + out->solo16 += ((out16 - (1 << (STEP_SH-1))) << 11) >> STEP_SH; + if (!chip->Muted[9]) + out->solo8 += ((out8 - (1 << (STEP_SH-1))) << 11) >> STEP_SH; + } + } + // Mask outputs + out->o16 &= chip->EN_out16[groupidx]; + out->o8 &= chip->EN_out8 [groupidx]; + out->o4 &= chip->EN_out4 [groupidx]; + out->o2 &= chip->EN_out2 [groupidx]; +} + +// Noise generator logic from MAME +static void update_noise(MSM5232_STATE* chip) +{ + int cnt = (chip->noise_cnt += chip->noise_step) >> STEP_SH; + chip->noise_cnt &= ((1< 0) { + int tmp = chip->noise_rng & (1<<16); + if (chip->noise_rng&1) + chip->noise_rng ^= 0x24000; + chip->noise_rng >>= 1; + if ((chip->noise_rng & (1<<16)) != tmp) + chip->noise_clocks++; + cnt--; + } + chip->noise_out = ((!chip->Muted[10]) && (chip->noise_rng & (1<<16))) ? chip->per_out_vol[10] : 0; +} + +// --- Main Update --- +static void device_update_msm5232(void* info, UINT32 samples, DEV_SMPL** outputs) +{ + MSM5232_STATE* chip = (MSM5232_STATE*)info; + DEV_SMPL* outL = outputs[0]; + DEV_SMPL* outR = outputs[1]; + if (!outL || !outR) return; + + for (UINT32 i = 0; i < samples; i++) { + RC_STEP(&chip->cycle_cntr); + + // 1. Advance envelopes + EG_voices_advance(chip); + + // 2. Tone groups + MSM5232_GROUP_OUT group1, group2; + TG_group_advance(chip, 0, &group1); + TG_group_advance(chip, 1, &group2); + + // 3. Noise update (advance RNG) + update_noise(chip); + + // 4. Mix output, apply TA7630 external volume + INT32 g1o2 = (group1.o2 * chip->per_out_vol[0]) >> 7; + INT32 g1o4 = (group1.o4 * chip->per_out_vol[1]) >> 7; + INT32 g1o8 = (group1.o8 * chip->per_out_vol[2]) >> 7; + INT32 g1o16 = (group1.o16 * chip->per_out_vol[3]) >> 7; + INT32 g2o2 = (group2.o2 * chip->per_out_vol[4]) >> 7; + INT32 g2o4 = (group2.o4 * chip->per_out_vol[5]) >> 7; + INT32 g2o8 = (group2.o8 * chip->per_out_vol[6]) >> 7; + INT32 g2o16 = (group2.o16 * chip->per_out_vol[7]) >> 7; + INT32 mix = + (INT32)((double)(g1o2 + g1o4 + g1o8 + g1o16) * chip->ext_vol_gain[0]) + + (INT32)((double)(g2o2 + g2o4 + g2o8 + g2o16) * chip->ext_vol_gain[1]) + + (((INT32)(group2.solo16) * chip->per_out_vol[8]) >> 7) + + (((INT32)(group2.solo8) * chip->per_out_vol[9]) >> 7) + + ((INT32)chip->noise_out); + + outL[i] = (DEV_SMPL)(mix / 8); + outR[i] = (DEV_SMPL)(mix / 8); + RC_MASK(&chip->cycle_cntr); + } +} + +// --- Register Write Handler --- (add 0x0E/0x0F for TA7630 volume) +static void msm5232_write(void* info, UINT8 reg, UINT8 value) +{ + MSM5232_STATE* chip = (MSM5232_STATE*)info; + if (reg < 0x08) { + int ch = reg & 7; + MSM5232_VOICE* v = &chip->voi[ch]; + v->GF = (value & 0x80) >> 7; + if (value & 0x80) { + if (value >= 0xd8) { + v->mode = 1; // noise + v->eg_sect = 0; // key on + } else { + int pitch_index = value & 0x7f; + if (pitch_index >= 88) + pitch_index = 0x57; // Clamp to valid ROM entry + + uint16_t pg = MSM5232_ROM[pitch_index]; + v->pitch = pitch_index; + v->TG_count_period = ((pg & 0x1ff) * chip->UpdateStep) / 2; + if (!v->TG_count_period) + v->TG_count_period = 1; + v->TG_count = v->TG_count_period; + v->TG_cnt = 0; + int n = (pg >> 9) & 7; + v->TG_out16 = 1 << n; + n = (n > 0) ? n-1 : 0; v->TG_out8 = 1 << n; + n = (n > 0) ? n-1 : 0; v->TG_out4 = 1 << n; + n = (n > 0) ? n-1 : 0; v->TG_out2 = 1 << n; + v->mode = 0; + v->eg_sect = 0; + } + } else { + if (!v->eg_arm) + v->eg_sect = 2; // release + else + v->eg_sect = 1; // decay + } + } else { + switch (reg) { + case 0x08: // group1 attack + for (int i = 0; i < 4; i++) + chip->voi[i].ar_rate = chip->ar_tbl[value & 7] * chip->capacitors[i]; + break; + case 0x09: // group2 attack + for (int i = 0; i < 4; i++) + chip->voi[i+4].ar_rate = chip->ar_tbl[value & 7] * chip->capacitors[i+4]; + break; + case 0x0A: // group1 decay + for (int i = 0; i < 4; i++) + chip->voi[i].dr_rate = chip->dr_tbl[value & 0xf] * chip->capacitors[i]; + break; + case 0x0B: // group2 decay + for (int i = 0; i < 4; i++) + chip->voi[i+4].dr_rate = chip->dr_tbl[value & 0xf] * chip->capacitors[i+4]; + break; + case 0x0C: // group1 control + chip->control1 = value; + for (int i = 0; i < 4; i++) { + if ((value & 0x10) && (chip->voi[i].eg_sect == 1)) + chip->voi[i].eg_sect = 0; + chip->voi[i].eg_arm = value & 0x10; + } + chip->EN_out16[0] = (value & 1) ? ~0 : 0; + chip->EN_out8[0] = (value & 2) ? ~0 : 0; + chip->EN_out4[0] = (value & 4) ? ~0 : 0; + chip->EN_out2[0] = (value & 8) ? ~0 : 0; + break; + case 0x0D: // group2 control + chip->control2 = value; + for (int i = 0; i < 4; i++) { + if ((value & 0x10) && (chip->voi[i+4].eg_sect == 1)) + chip->voi[i+4].eg_sect = 0; + chip->voi[i+4].eg_arm = value & 0x10; + } + chip->EN_out16[1] = (value & 1) ? ~0 : 0; + chip->EN_out8[1] = (value & 2) ? ~0 : 0; + chip->EN_out4[1] = (value & 4) ? ~0 : 0; + chip->EN_out2[1] = (value & 8) ? ~0 : 0; + break; + // --- TA7630 external volume for MSM5232 --- + case 0x0E: // external volume for group 1 (ch 0..3) + chip->ext_vol[0] = value & 0x0F; + chip->ext_vol_gain[0] = chip->vol_ctrl[value & 0x0F]; + break; + case 0x0F: // external volume for group 2 (ch 4..7) + chip->ext_vol[1] = value & 0x0F; + chip->ext_vol_gain[1] = chip->vol_ctrl[value & 0x0F]; + break; + // per output volume (0x80 = 100%) + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1A: + chip->per_out_vol[reg & 0x0F] = (value > 0x80) ? 0x80 : value; + break; + } + } +} + +static void msm5232_set_mute_mask(void* info, UINT32 muteMask) +{ + MSM5232_STATE* chip = (MSM5232_STATE*)info; + for (int i = 0; i < MSM5232_NUM_OUTPUTS; i++) + chip->Muted[i] = (muteMask >> i) & 1; +} diff --git a/emu/cores/msm5232.h b/emu/cores/msm5232.h new file mode 100644 index 00000000..576c37d7 --- /dev/null +++ b/emu/cores/msm5232.h @@ -0,0 +1,13 @@ +#ifndef __MSM5232_H__ +#define __MSM5232_H__ + +#include "../EmuStructs.h" + +typedef struct { + DEV_GEN_CFG _genCfg; + double capacitors[8]; // external capacitor values for each channel (in Farads) +} MSM5232_CFG; + +extern const DEV_DECL sndDev_MSM5232; + +#endif // __MSM5232_H__ \ No newline at end of file diff --git a/libEmu.vcxproj b/libEmu.vcxproj index 89ce80bc..33724064 100644 --- a/libEmu.vcxproj +++ b/libEmu.vcxproj @@ -184,6 +184,7 @@ + @@ -273,6 +274,7 @@ + diff --git a/libEmu.vcxproj.filters b/libEmu.vcxproj.filters index 45668166..f370bee0 100644 --- a/libEmu.vcxproj.filters +++ b/libEmu.vcxproj.filters @@ -258,6 +258,9 @@ Quelldateien + + Quelldateien + @@ -554,5 +557,8 @@ Headerdateien + + Headerdateien + diff --git a/player/vgmplayer.cpp b/player/vgmplayer.cpp index e53d7431..52a94866 100644 --- a/player/vgmplayer.cpp +++ b/player/vgmplayer.cpp @@ -25,6 +25,7 @@ #include "../emu/cores/qsoundintf.h" #include "../emu/cores/scsp.h" #include "../emu/cores/msm5205.h" // for MSM5205_CFG +#include "../emu/cores/msm5232.h" //for MSM5232_CFG #include "dblk_compr.h" #include "../utils/StrUtils.h" @@ -42,7 +43,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_MSM5205, + DEVID_GA20, DEVID_MIKEY, DEVID_K007232, DEVID_K005289, DEVID_MSM5205, DEVID_MSM5232, }; /*static*/ const DEV_ID VGMPlayer::_DEV_LIST[_CHIP_COUNT] = @@ -52,7 +53,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_MSM5205, + DEVID_GA20, DEVID_MIKEY, DEVID_K007232, DEVID_K005289, DEVID_MSM5205, DEVID_MSM5232, }; /*static*/ const UINT32 VGMPlayer::_CHIPCLK_OFS[_CHIP_COUNT] = @@ -62,7 +63,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, 0xF0, + 0xE0, 0xE4, 0xE8, 0xEC, 0xF0, 0xF4, }; /*static*/ const UINT16 VGMPlayer::_CHIP_VOLUME[_CHIP_COUNT] = { 0x80, 0x200, 0x100, 0x100, 0x180, 0xB0, 0x100, 0x80, @@ -70,7 +71,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, 0x100, + 0x280, 0x100, 0x100, 0x100, 0x100, 0x1000, }; /*static*/ const UINT16 VGMPlayer::_PB_VOL_AMNT[_CHIP_COUNT] = { 0x100, 0x80, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, @@ -78,7 +79,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, 0x200, + 0x100, 0x200, 0x100, 0x100, 0x200, 0x10, }; /*static*/ const char* const VGMPlayer::_TAG_TYPE_LIST[_TAG_COUNT] = @@ -117,6 +118,18 @@ INLINE UINT32 ReadLE32(const UINT8* data) #endif } +INLINE double ReadLE64d(const UINT8* data) +{ +#ifdef VGM_LITTLE_ENDIAN + return *(UINT64*)data; +#else + return (data[0x07] << 56) | (data[0x06] << 48) | + (data[0x05] << 40) | (data[0x04] << 32) | + (data[0x03] << 24) | (data[0x02] << 16) | + (data[0x01] << 8) | (data[0x00] << 0); +#endif +} + INLINE UINT32 ReadRelOfs(const UINT8* data, UINT32 fileOfs) { // read a VGM-style (relative) offset @@ -1321,6 +1334,23 @@ void VGMPlayer::GenerateDeviceConfig(void) devCfg.clock *= 512; // (for backwards compatibility with old VGM logs from 2012-14) SaveDeviceConfig(sdCfg.cfgData, &devCfg, sizeof(DEV_GEN_CFG)); break; + case DEVID_MSM5232: + { + MSM5232_CFG okiCfg; + + okiCfg._genCfg = devCfg; + // default value for now + okiCfg.capacitors[0] = (double)(1e-6); + okiCfg.capacitors[1] = (double)(1e-6); + okiCfg.capacitors[2] = (double)(1e-6); + okiCfg.capacitors[3] = (double)(1e-6); + okiCfg.capacitors[4] = (double)(1e-6); + okiCfg.capacitors[5] = (double)(1e-6); + okiCfg.capacitors[6] = (double)(1e-6); + okiCfg.capacitors[7] = (double)(1e-6); + SaveDeviceConfig(sdCfg.cfgData, &okiCfg, sizeof(MSM5232_CFG)); + break; + } default: SaveDeviceConfig(sdCfg.cfgData, &devCfg, sizeof(DEV_GEN_CFG)); break; diff --git a/player/vgmplayer.hpp b/player/vgmplayer.hpp index 97a51107..71755244 100644 --- a/player/vgmplayer.hpp +++ b/player/vgmplayer.hpp @@ -282,8 +282,8 @@ class VGMPlayer : public PlayerBase enum { _HDR_BUF_SIZE = 0x100, - _OPT_DEV_COUNT = 0x2d, - _CHIP_COUNT = 0x2d, + _OPT_DEV_COUNT = 0x2e, + _CHIP_COUNT = 0x2e, _PCM_BANK_COUNT = 0x40 }; diff --git a/player/vgmplayer_cmdhandler.cpp b/player/vgmplayer_cmdhandler.cpp index 747ffd86..a5f24de7 100644 --- a/player/vgmplayer_cmdhandler.cpp +++ b/player/vgmplayer_cmdhandler.cpp @@ -89,7 +89,7 @@ {0x2B, 0x03, &VGMPlayer::Cmd_Ofs4_Data12}, // 42 K005289 register write {0xFF, 0x03, &VGMPlayer::Cmd_unknown}, // 43 {0xFF, 0x03, &VGMPlayer::Cmd_unknown}, // 44 - {0xFF, 0x03, &VGMPlayer::Cmd_unknown}, // 45 + {0x2B, 0x03, &VGMPlayer::Cmd_Ofs8_Data8}, // 45 MSM5232 register write {0xFF, 0x03, &VGMPlayer::Cmd_unknown}, // 46 {0xFF, 0x03, &VGMPlayer::Cmd_unknown}, // 47 {0xFF, 0x03, &VGMPlayer::Cmd_unknown}, // 48