Merge pull request #873 from loganmc10/vru

VRU support and Hey You Pikachu audio fix
This commit is contained in:
Richard Goedeken 2022-06-23 17:31:17 -07:00 committed by GitHub
commit 6efa95f5dd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 429 additions and 20 deletions

View file

@ -6294,6 +6294,7 @@ CRC=D3F10E5D 052EA579
Players=1
SaveType=Eeprom 4KB
Rumble=Yes
AiDmaModifier=88
[DCC316EFFC4928F5B0AE8D273D8024BF]
GoodName=HiRes CFB Demo (PD)
@ -11893,6 +11894,7 @@ CRC=3F245305 FC0B74AA
Players=1
SaveType=Eeprom 4KB
Rumble=Yes
AiDmaModifier=88
[D0AE6C07AC0481EBA5FF9CE798A69574]
GoodName=Pikachu Genki Dechu (J) [b1]

View file

@ -128,4 +128,6 @@ This is the most complicated interface, because it involves 3 components: the vi
* '''FRONTEND_API_VERSION''' version 2.1.4:
** added "M64CMD_ROM_SET_SETTINGS" command to allow setting ROM settings for the currently opened ROM until the ROM is closed.
* '''CONFIG_API_VERSION''' version 2.3.2:
** add ConfigOverrideUserPaths() function to allow front-ends to override user paths.
** add ConfigOverrideUserPaths() function to allow front-ends to override user paths.
* '''INPUT_API_VERSION''' version 2.1.1:
** add optional functions: SendVRUWord(), SetMicState(), ReadVRUResults(), ClearVRUWords(), SetVRUWordMask(). These functions add support for the VRU (Voice Recognition Unit). Also added a new int to the CONTROL struct: Type. Type can be CONT_TYPE_STANDARD (0) or CONT_TYPE_VRU (1).

View file

@ -224,6 +224,21 @@ These functions are present in all of the plugins.
|-
|<tt>void SDL_KeyUp(int keymod, int keysym);</tt>
|Pass a SDL_KEYUP-style message to the input plugin
|-
|<tt>void SendVRUWord(uint16_t length, uint16_t *word, uint8_t lang);</tt>
|Load a word/phrase into the VRU dictionary. length specifies the length of the buffer. lang is 0 for English and 1 for Japanese. Japanese words are encoding using S-JIS. English words are encoded using a phonetic alphabet explained here: https://pastebin.com/ajLzRLze
|-
|<tt>void SetMicState(int state);</tt>
|A state of 1 tells the input plugin to enable the microphone. A state of 0 tells the input plugin to disable the microphone
|-
|<tt>void ReadVRUResults(uint16_t *error_flags, uint16_t *num_results, uint16_t *mic_level, uint16_t *voice_level, uint16_t *voice_length, uint16_t *matches);</tt>
|Refer to https://pastebin.com/6UiErk5h and https://ultra64.ca/files/documentation/online-manuals/man/pro-man/pro26/index26.8.html for an explanation of these variables. This function is called after the player has finished speaking. The purpose is for the VRU/input plugin to tell the core if any matches were found against the dictionary that was provided earlier
|-
|<tt>void ClearVRUWords(uint8_t length);</tt>
|Clears and initializes the word/phrase dictionary with a max length as provided by the variable
|-
|<tt>void SetVRUWordMask(uint8_t length, uint8_t *mask);</tt>
|Assign a mask to the words in the dictionary. A bit of 1 means to recognize the word, 0 means to ignore the word. See https://ultra64.ca/files/documentation/online-manuals/man/pro-man/pro26/index26.8.html
|}
=== Remove From Older Input API ===

View file

@ -136,6 +136,7 @@
<ClCompile Include="..\..\src\device\cart\is_viewer.c" />
<ClCompile Include="..\..\src\device\cart\sram.c" />
<ClCompile Include="..\..\src\device\controllers\game_controller.c" />
<ClCompile Include="..\..\src\device\controllers\vru_controller.c" />
<ClCompile Include="..\..\src\device\controllers\paks\biopak.c" />
<ClCompile Include="..\..\src\device\controllers\paks\mempak.c" />
<ClCompile Include="..\..\src\device\controllers\paks\rumblepak.c" />
@ -440,6 +441,7 @@
<ClInclude Include="..\..\src\device\cart\is_viewer.h" />
<ClInclude Include="..\..\src\device\cart\sram.h" />
<ClInclude Include="..\..\src\device\controllers\game_controller.h" />
<ClInclude Include="..\..\src\device\controllers\vru_controller.h" />
<ClInclude Include="..\..\src\device\controllers\paks\biopak.h" />
<ClInclude Include="..\..\src\device\controllers\paks\mempak.h" />
<ClInclude Include="..\..\src\device\controllers\paks\rumblepak.h" />

View file

@ -360,6 +360,9 @@
<ClCompile Include="..\..\src\device\controllers\game_controller.c">
<Filter>device\controllers</Filter>
</ClCompile>
<ClCompile Include="..\..\src\device\controllers\vru_controller.c">
<Filter>device\controllers</Filter>
</ClCompile>
<ClCompile Include="..\..\src\device\rdram\rdram.c">
<Filter>device\rdram</Filter>
</ClCompile>
@ -704,6 +707,9 @@
<ClInclude Include="..\..\src\device\controllers\game_controller.h">
<Filter>device\controllers</Filter>
</ClInclude>
<ClInclude Include="..\..\src\device\controllers\vru_controller.h">
<Filter>device\controllers</Filter>
</ClInclude>
<ClInclude Include="..\..\src\device\rdram\rdram.h">
<Filter>device\rdram</Filter>
</ClInclude>

View file

@ -540,6 +540,7 @@ SOURCE = \
$(SRCDIR)/device/cart/is_viewer.c \
$(SRCDIR)/device/cart/sram.c \
$(SRCDIR)/device/controllers/game_controller.c \
$(SRCDIR)/device/controllers/vru_controller.c \
$(SRCDIR)/device/controllers/paks/biopak.c \
$(SRCDIR)/device/controllers/paks/mempak.c \
$(SRCDIR)/device/controllers/paks/rumblepak.c \

View file

@ -428,6 +428,7 @@ EXPORT m64p_error CALL CoreGetRomSettings(m64p_rom_settings *RomSettings, int Ro
RomSettings->countperop = entry->countperop;
RomSettings->savetype = entry->savetype;
RomSettings->sidmaduration = entry->sidmaduration;
RomSettings->aidmamodifier = entry->aidmamodifier;
return M64ERR_SUCCESS;
}

View file

@ -136,10 +136,15 @@ typedef struct {
void (*CheckInterrupts)(void);
} AUDIO_INFO;
/*** Controller types ****/
#define CONT_TYPE_STANDARD 0
#define CONT_TYPE_VRU 1
typedef struct {
int Present;
int RawData;
int Plugin;
int Type;
} CONTROL;
typedef union {
@ -260,6 +265,11 @@ typedef void (*ptr_ReadController)(int Control, unsigned char *Command);
typedef void (*ptr_SDL_KeyDown)(int keymod, int keysym);
typedef void (*ptr_SDL_KeyUp)(int keymod, int keysym);
typedef void (*ptr_RenderCallback)(void);
typedef void (*ptr_SendVRUWord)(uint16_t length, uint16_t *word, uint8_t lang);
typedef void (*ptr_SetMicState)(int state);
typedef void (*ptr_ReadVRUResults)(uint16_t *error_flags, uint16_t *num_results, uint16_t *mic_level, uint16_t *voice_level, uint16_t *voice_length, uint16_t *matches);
typedef void (*ptr_ClearVRUWords)(uint8_t length);
typedef void (*ptr_SetVRUWordMask)(uint8_t length, uint8_t *mask);
#if defined(M64P_PLUGIN_PROTOTYPES)
EXPORT void CALL ControllerCommand(int Control, unsigned char *Command);
EXPORT void CALL GetKeys(int Control, BUTTONS *Keys);
@ -268,6 +278,11 @@ EXPORT void CALL ReadController(int Control, unsigned char *Command);
EXPORT void CALL SDL_KeyDown(int keymod, int keysym);
EXPORT void CALL SDL_KeyUp(int keymod, int keysym);
EXPORT void CALL RenderCallback(void);
EXPORT void CALL SendVRUWord(uint16_t length, uint16_t *word, uint8_t lang);
EXPORT void CALL SetMicState(int state);
EXPORT void CALL ReadVRUResults(uint16_t *error_flags, uint16_t *num_results, uint16_t *mic_level, uint16_t *voice_level, uint16_t *voice_length, uint16_t *matches);
EXPORT void CALL ClearVRUWords(uint8_t length);
EXPORT void CALL SetVRUWordMask(uint8_t length, uint8_t *mask);
#endif
/* RSP plugin function pointers */

View file

@ -282,6 +282,7 @@ typedef struct
unsigned char disableextramem; /* 0 - No, 1 - Yes boolean for disabling 4MB expansion RAM pack */
unsigned int countperop; /* Number of CPU cycles per instruction. */
unsigned int sidmaduration; /* Default SI DMA duration */
unsigned int aidmamodifier; /* Percentage modifier for AI DMA duration */
} m64p_rom_settings;
/* ----------------------------------------- */

View file

@ -35,6 +35,11 @@ enum joybus_commands
JCMD_AF_RTC_STATUS = 0x06,
JCMD_AF_RTC_READ = 0x07,
JCMD_AF_RTC_WRITE = 0x08,
JCMD_VRU_READ = 0x09,
JCMD_VRU_WRITE = 0x0A,
JCMD_VRU_READ_STATUS = 0x0B,
JCMD_VRU_WRITE_CONFIG = 0x0C,
JCMD_VRU_WRITE_INIT = 0x0D,
JCMD_RESET = 0xff,
};
@ -44,6 +49,7 @@ enum joybus_device_types
JDT_JOY_ABS_COUNTERS = 0x0001, /* joystick with absolute coordinates */
JDT_JOY_REL_COUNTERS = 0x0002, /* joystick with relative coordinates (= mouse) */
JDT_JOY_PORT = 0x0004, /* has port for external paks */
JDT_VRU = 0x0100, /* VRU */
JDT_AF_RTC = 0x1000, /* RTC */
JDT_EEPROM_4K = 0x8000, /* 4k EEPROM */
JDT_EEPROM_16K = 0xc000, /* 16k EEPROM */

View file

@ -155,7 +155,6 @@ const struct game_controller_flavor g_mouse_controller_flavor =
mouse_controller_reset
};
void init_game_controller(struct game_controller* cont,
const struct game_controller_flavor* flavor,
void* cin, const struct controller_input_backend_interface* icin,

View file

@ -59,6 +59,12 @@ struct game_controller
void* pak;
const struct pak_interface* ipak;
/* VRU */
uint8_t voice_state;
uint8_t load_offset;
uint8_t voice_init;
uint16_t word[40];
};
void init_game_controller(struct game_controller* cont,

View file

@ -0,0 +1,254 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - vru_controller.c *
* Mupen64Plus homepage: https://mupen64plus.org/ *
* Copyright (C) 2014 Bobby Smiles *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "game_controller.h"
#include "vru_controller.h"
#include "api/callbacks.h"
#include "api/m64p_types.h"
#include "backends/api/controller_input_backend.h"
#include "backends/api/joybus.h"
#include "plugin/plugin.h"
#include "main/rom.h"
#ifdef COMPARE_CORE
#include "api/debugger.h"
#endif
#include <stdint.h>
#include <string.h>
enum voice_status
{
VOICE_STATUS_READY = 0x00,
VOICE_STATUS_START = 0x01,
VOICE_STATUS_CANCEL = 0x03,
VOICE_STATUS_BUSY = 0x05,
VOICE_STATUS_END = 0x07
};
static uint8_t vru_data_crc(const uint8_t* data, size_t size)
{
size_t i;
uint8_t crc = 0;
for(i = 0; i <= size; ++i)
{
int mask;
for (mask = 0x80; mask >= 1; mask >>= 1)
{
uint8_t xor_tap = (crc & 0x80) ? 0x85 : 0x00;
crc <<= 1;
if (i != size && (data[i] & mask)) crc |= 1;
crc ^= xor_tap;
}
}
return crc;
}
/* VRU controller */
static void vru_controller_reset(struct game_controller* cont)
{
cont->status = 0x00;
if (ROM_HEADER.Country_code == 0x4A /* Japan */ || ROM_HEADER.Country_code == 0x00 /* Demo */)
cont->voice_state = VOICE_STATUS_READY;
else
cont->voice_state = VOICE_STATUS_START;
cont->load_offset = 0;
cont->voice_init = 1;
memset(cont->word, 0, 80);
}
const struct game_controller_flavor g_vru_controller_flavor =
{
"VRU controller",
JDT_VRU,
vru_controller_reset
};
static void poweron_vru_controller(void* jbd)
{
struct game_controller* cont = (struct game_controller*)jbd;
cont->flavor->reset(cont);
}
static void process_vru_command(void* jbd,
const uint8_t* tx, const uint8_t* tx_buf,
uint8_t* rx, uint8_t* rx_buf)
{
struct game_controller* cont = (struct game_controller*)jbd;
uint32_t input_ = 0;
uint8_t cmd = tx_buf[0];
/* if controller can't successfully be polled, consider it to be absent */
if (cont->icin->get_input(cont->cin, &input_) != M64ERR_SUCCESS) {
*rx |= 0x80;
return;
}
switch (cmd)
{
case JCMD_RESET:
cont->flavor->reset(cont);
/* fall through */
case JCMD_STATUS: {
JOYBUS_CHECK_COMMAND_FORMAT(1, 3)
if (cont->voice_init == 2)
{
/* words have been loaded, we can change the state from READY to START */
cont->voice_state = VOICE_STATUS_START;
cont->voice_init = 1;
}
else if ((input_ & 0x0020) && (cont->voice_state == VOICE_STATUS_START))
{
/* HACK: The Z input on the VRU controller is used to indicate that someone is talking */
/* On Densha de Go, if the player is talking for more than ~2.5 seconds, the input is ignored */
cont->voice_state = VOICE_STATUS_BUSY;
cont->status = 0; /* setting the status to 0 tells the game to check the voice_status */
}
else if (!(input_ & 0x0020) && (cont->voice_state == VOICE_STATUS_BUSY))
{
cont->voice_state = VOICE_STATUS_READY;
cont->status = 0; /* setting the status to 0 tells the game to check the voice_status */
}
rx_buf[0] = (uint8_t)(cont->flavor->type >> 0);
rx_buf[1] = (uint8_t)(cont->flavor->type >> 8);
rx_buf[2] = cont->status;
} break;
case JCMD_CONTROLLER_READ: {
JOYBUS_CHECK_COMMAND_FORMAT(1, 4)
#ifdef COMPARE_CORE
CoreCompareDataSync(4, rx_buf);
#endif
} break;
case JCMD_VRU_READ_STATUS: {
JOYBUS_CHECK_COMMAND_FORMAT(3, 3)
rx_buf[0] = cont->voice_init ? cont->voice_state : 0;
rx_buf[1] = 0;
rx_buf[2] = vru_data_crc(&rx_buf[0], 2);
if (cont->load_offset > 0)
{
uint8_t offset = 0;
while (cont->word[offset] == 0 && offset < 40)
++offset;
if (offset == 40)
{
DebugMessage(M64MSG_WARNING, "Empty JCMD_VRU_WRITE.");
}
else if (cont->word[offset] == 3)
{
offset += 3;
uint16_t length = cont->word[offset];
if (ROM_HEADER.Country_code == 0x4A /* Japan */ || ROM_HEADER.Country_code == 0x00 /* Demo */)
{
offset -= 1;
length = 0;
while (cont->word[offset + length] != 0)
{
++length;
}
input.sendVRUWord(length, &cont->word[offset], 1);
}
else
{
++offset;
input.sendVRUWord(length, &cont->word[offset], 0);
}
}
else
{
/* Unhandled command, could be a string/word mask.
For a mask:
"Data is right-aligned and padded with zeroes to an even length, followed with command 0004. Set bits allow strings, unset ignores."
I haven't seen Hey You Pikachu or Densha de GO use the mask command, so I wasn't able to test.
TODO: Call input.SetVRUWordMask() to tell the input plugin about the mask settings */
DebugMessage(M64MSG_WARNING, "Unknown command in JCMD_VRU_WRITE.");
}
cont->load_offset = 0;
}
cont->status = 1;
} break;
case JCMD_VRU_WRITE_CONFIG: {
JOYBUS_CHECK_COMMAND_FORMAT(7, 1)
rx_buf[0] = vru_data_crc(&tx_buf[3], 4);
if (rx_buf[0] == 0x4E)
{
input.setMicState(1);
cont->voice_init = 2;
}
else if (rx_buf[0] == 0xEF)
{
input.setMicState(0);
}
else if (tx_buf[3] == 0x2)
{
cont->voice_init = 0;
input.clearVRUWords(tx_buf[5]);
}
cont->status = 0; /* status is always set to 0 after a write */
} break;
case JCMD_VRU_WRITE_INIT: {
JOYBUS_CHECK_COMMAND_FORMAT(3, 1)
if (*((uint16_t*)(&tx_buf[1])) == 0)
input.setMicState(0);
rx_buf[0] = 0;
} break;
case JCMD_VRU_READ: {
JOYBUS_CHECK_COMMAND_FORMAT(3, 37)
*((uint16_t*)(&rx_buf[0])) = 0x8000; /* as per zoinkity https://pastebin.com/6UiErk5h */
*((uint16_t*)(&rx_buf[2])) = 0x0F00; /* as per zoinkity https://pastebin.com/6UiErk5h */
*((uint16_t*)(&rx_buf[34])) = 0x0040; /* as per zoinkity https://pastebin.com/6UiErk5h */
input.readVRUResults((uint16_t*)&rx_buf[4] /*error flags*/, (uint16_t*)&rx_buf[6] /*number of results*/, (uint16_t*)&rx_buf[8] /*mic level*/, \
(uint16_t*)&rx_buf[10] /*voice level*/, (uint16_t*)&rx_buf[12] /*voice length*/, (uint16_t*)&rx_buf[14] /*matches*/);
rx_buf[36] = vru_data_crc(&rx_buf[0], 36);
cont->voice_state = VOICE_STATUS_START;
} break;
case JCMD_VRU_WRITE: {
JOYBUS_CHECK_COMMAND_FORMAT(23, 1)
rx_buf[0] = vru_data_crc(&tx_buf[3], 20);
if (cont->load_offset == 0)
memset(cont->word, 0, 80);
memcpy(&cont->word[cont->load_offset], &tx_buf[3], 20);
cont->load_offset += 10;
cont->status = 0; /* status is always set to 0 after a write */
} break;
default:
DebugMessage(M64MSG_WARNING, "cont: Unknown command %02x %02x %02x",
*tx, *rx, cmd);
}
}
const struct joybus_device_interface g_ijoybus_vru_controller =
{
poweron_vru_controller,
process_vru_command,
NULL
};

View file

@ -0,0 +1,37 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - vru_controller.h *
* Mupen64Plus homepage: https://mupen64plus.org/ *
* Copyright (C) 2014 Bobby Smiles *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef M64P_DEVICE_SI_VRU_CONTROLLER_H
#define M64P_DEVICE_SI_VRU_CONTROLLER_H
#include "backends/api/joybus.h"
#include <stddef.h>
#include <stdint.h>
/* Controller Joybus interface */
extern const struct joybus_device_interface
g_ijoybus_vru_controller;
/* Controller flavors */
extern const struct game_controller_flavor g_vru_controller_flavor;
#endif

View file

@ -88,7 +88,7 @@ void init_device(struct device* dev,
int randomize_interrupt,
uint32_t start_address,
/* ai */
void* aout, const struct audio_out_backend_interface* iaout,
void* aout, const struct audio_out_backend_interface* iaout, float dma_modifier,
/* si */
unsigned int si_dma_duration,
/* rdram */
@ -182,7 +182,7 @@ void init_device(struct device* dev,
emumode, count_per_op, count_per_op_denom_pot, no_compiled_jump, randomize_interrupt, start_address);
init_rdp(&dev->dp, &dev->sp, &dev->mi, &dev->mem, &dev->rdram, &dev->r4300);
init_rsp(&dev->sp, mem_base_u32(base, MM_RSP_MEM), &dev->mi, &dev->dp, &dev->ri);
init_ai(&dev->ai, &dev->mi, &dev->ri, &dev->vi, aout, iaout);
init_ai(&dev->ai, &dev->mi, &dev->ri, &dev->vi, aout, iaout, dma_modifier);
init_mi(&dev->mi, &dev->r4300);
init_pi(&dev->pi,
get_pi_dma_handler,

View file

@ -126,7 +126,7 @@ void init_device(struct device* dev,
int randomize_interrupt,
uint32_t start_address,
/* ai */
void* aout, const struct audio_out_backend_interface* iaout,
void* aout, const struct audio_out_backend_interface* iaout, float dma_modifier,
/* si */
unsigned int si_dma_duration,
/* rdram */

View file

@ -100,7 +100,7 @@ static void do_dma(struct ai_controller* ai, struct ai_dma* dma)
static void fifo_push(struct ai_controller* ai)
{
unsigned int duration = get_dma_duration(ai);
unsigned int duration = get_dma_duration(ai) * ai->dma_modifier;
if (ai->regs[AI_STATUS_REG] & AI_STATUS_BUSY)
{
@ -144,13 +144,15 @@ void init_ai(struct ai_controller* ai,
struct ri_controller* ri,
struct vi_controller* vi,
void* aout,
const struct audio_out_backend_interface* iaout)
const struct audio_out_backend_interface* iaout,
float dma_modifier)
{
ai->mi = mi;
ai->ri = ri;
ai->vi = vi;
ai->aout = aout;
ai->iaout = iaout;
ai->dma_modifier = dma_modifier;
}
void poweron_ai(struct ai_controller* ai)

View file

@ -59,6 +59,7 @@ struct ai_controller
unsigned int samples_format_changed;
uint32_t last_read;
uint32_t delayed_carry;
float dma_modifier;
struct mi_controller* mi;
struct ri_controller* ri;
@ -78,7 +79,8 @@ void init_ai(struct ai_controller* ai,
struct ri_controller* ri,
struct vi_controller* vi,
void* aout,
const struct audio_out_backend_interface* iaout);
const struct audio_out_backend_interface* iaout,
float dma_modifier);
void poweron_ai(struct ai_controller* ai);

View file

@ -57,6 +57,7 @@
#include "cheat.h"
#include "device/device.h"
#include "device/dd/disk.h"
#include "device/controllers/vru_controller.h"
#include "device/controllers/paks/biopak.h"
#include "device/controllers/paks/mempak.h"
#include "device/controllers/paks/rumblepak.h"
@ -1641,6 +1642,27 @@ m64p_error main_run(void)
joybus_devices[i] = &control_ids[i];
ijoybus_devices[i] = &g_ijoybus_device_plugin_compat;
}
else if (Controls[i].Type == CONT_TYPE_VRU) {
const struct game_controller_flavor* cont_flavor =
&g_vru_controller_flavor;
joybus_devices[i] = &g_dev.controllers[i];
ijoybus_devices[i] = &g_ijoybus_vru_controller;
cin_compats[i].control_id = (int)i;
cin_compats[i].cont = &g_dev.controllers[i];
cin_compats[i].last_pak_type = Controls[i].Plugin;
cin_compats[i].last_input = 0;
cin_compats[i].netplay_count = 0;
cin_compats[i].event_first = NULL;
Controls[i].Plugin = PLUGIN_NONE;
/* init vru_controller */
init_game_controller(&g_dev.controllers[i],
cont_flavor,
&cin_compats[i], &g_icontroller_input_backend_plugin_compat,
NULL, NULL);
}
/* otherwise let the core do the processing */
else {
/* select appropriate controller
@ -1761,7 +1783,6 @@ m64p_error main_run(void)
ijoybus_devices[i] = &g_ijoybus_device_cart;
}
init_device(&g_dev,
g_mem_base,
emumode,
@ -1770,7 +1791,7 @@ m64p_error main_run(void)
no_compiled_jump,
randomize_interrupt,
g_start_address,
&g_dev.ai, &g_iaudio_out_backend_plugin_compat,
&g_dev.ai, &g_iaudio_out_backend_plugin_compat, ((float)ROM_SETTINGS.aidmamodifier / 100.0),
si_dma_duration,
rdram_size,
joybus_devices, ijoybus_devices,
@ -1845,7 +1866,7 @@ m64p_error main_run(void)
#endif
/* release gb_carts */
for(i = 0; i < GAME_CONTROLLERS_COUNT; ++i) {
if (!Controls[i].RawData && g_dev.gb_carts[i].read_gb_cart != NULL) {
if (!Controls[i].RawData && (Controls[i].Type == CONT_TYPE_STANDARD) && g_dev.gb_carts[i].read_gb_cart != NULL) {
release_gb_rom(&l_gb_carts_data[i]);
release_gb_ram(&l_gb_carts_data[i]);
}
@ -1883,7 +1904,7 @@ on_audio_open_failure:
on_gfx_open_failure:
/* release gb_carts */
for(i = 0; i < GAME_CONTROLLERS_COUNT; ++i) {
if (!Controls[i].RawData && g_dev.gb_carts[i].read_gb_cart != NULL) {
if (!Controls[i].RawData && (Controls[i].Type == CONT_TYPE_STANDARD) && g_dev.gb_carts[i].read_gb_cart != NULL) {
release_gb_rom(&l_gb_carts_data[i]);
release_gb_ram(&l_gb_carts_data[i]);
}

View file

@ -52,6 +52,8 @@ enum { DEFAULT_COUNT_PER_OP = 2 };
enum { DEFAULT_DISABLE_EXTRA_MEM = 0 };
/* Default SI DMA duration */
enum { DEFAULT_SI_DMA_DURATION = 0x900 };
/* Default AI DMA modifier */
enum { DEFAULT_AI_DMA_MODIFIER = 100 };
static romdatabase_entry* ini_search_by_md5(md5_byte_t* md5);
@ -188,6 +190,7 @@ m64p_error open_rom(const unsigned char* romimage, unsigned int size)
ROM_SETTINGS.countperop = entry->countperop;
ROM_SETTINGS.disableextramem = entry->disableextramem;
ROM_SETTINGS.sidmaduration = entry->sidmaduration;
ROM_SETTINGS.aidmamodifier = entry->aidmamodifier;
ROM_PARAMS.cheats = entry->cheats;
}
else
@ -205,6 +208,7 @@ m64p_error open_rom(const unsigned char* romimage, unsigned int size)
ROM_SETTINGS.countperop = DEFAULT_COUNT_PER_OP;
ROM_SETTINGS.disableextramem = DEFAULT_DISABLE_EXTRA_MEM;
ROM_SETTINGS.sidmaduration = DEFAULT_SI_DMA_DURATION;
ROM_SETTINGS.aidmamodifier = DEFAULT_AI_DMA_MODIFIER;
ROM_PARAMS.cheats = NULL;
}
@ -373,6 +377,12 @@ static size_t romdatabase_resolve_round(void)
entry->entry.set_flags |= ROMDATABASE_ENTRY_SIDMADURATION;
}
if (!isset_bitmask(entry->entry.set_flags, ROMDATABASE_ENTRY_AIDMAMODIFIER) &&
isset_bitmask(ref->set_flags, ROMDATABASE_ENTRY_AIDMAMODIFIER)) {
entry->entry.aidmamodifier = ref->aidmamodifier;
entry->entry.set_flags |= ROMDATABASE_ENTRY_AIDMAMODIFIER;
}
free(entry->entry.refmd5);
entry->entry.refmd5 = NULL;
}
@ -469,6 +479,7 @@ void romdatabase_open(void)
search->entry.mempak = 1;
search->entry.biopak = 0;
search->entry.sidmaduration = DEFAULT_SI_DMA_DURATION;
search->entry.aidmamodifier = DEFAULT_AI_DMA_MODIFIER;
search->entry.set_flags = ROMDATABASE_ENTRY_NONE;
search->next_entry = NULL;
@ -665,6 +676,15 @@ void romdatabase_open(void)
DebugMessage(M64MSG_WARNING, "ROM Database: Invalid SiDmaDuration on line %i", lineno);
}
}
else if(!strcmp(l.name, "AiDmaModifier"))
{
if (string_to_int(l.value, &value) && value >= 0 && value <= 200) {
search->entry.aidmamodifier = value;
search->entry.set_flags |= ROMDATABASE_ENTRY_AIDMAMODIFIER;
} else {
DebugMessage(M64MSG_WARNING, "ROM Database: Invalid AiDmaModifier on line %i", lineno);
}
}
else
{
DebugMessage(M64MSG_WARNING, "ROM Database: Unknown property on line %i", lineno);

View file

@ -113,6 +113,7 @@ typedef struct
unsigned char mempak; /* 0 - No, 1 - Yes boolean for mempak support. */
unsigned char biopak; /* 0 - No, 1 - Yes boolean for biopak support. */
unsigned int sidmaduration;
unsigned int aidmamodifier;
uint32_t set_flags;
} romdatabase_entry;
@ -130,6 +131,7 @@ typedef struct
#define ROMDATABASE_ENTRY_MEMPAK BIT(10)
#define ROMDATABASE_ENTRY_BIOPAK BIT(11)
#define ROMDATABASE_ENTRY_SIDMADURATION BIT(12)
#define ROMDATABASE_ENTRY_AIDMAMODIFIER BIT(13)
typedef struct _romdatabase_search
{

View file

@ -565,7 +565,7 @@ static int savestates_load_m64p(struct device* dev, char *filepath)
COPYARRAY(cam_regs, curr, uint8_t, POCKET_CAM_REGS_COUNT);
}
if (ROM_SETTINGS.transferpak && !Controls[i].RawData) {
if (ROM_SETTINGS.transferpak && !Controls[i].RawData && (Controls[i].Type == CONT_TYPE_STANDARD)) {
/* init transferpak state if enabled and not controlled by input plugin */
dev->transferpaks[i].enabled = enabled;
@ -675,7 +675,7 @@ static int savestates_load_m64p(struct device* dev, char *filepath)
uint8_t rpk_state = GETDATA(curr, uint8_t);
/* init rumble pak state if enabled and not controlled by the input plugin */
if (ROM_SETTINGS.rumble && !Controls[i].RawData) {
if (ROM_SETTINGS.rumble && !Controls[i].RawData && (Controls[i].Type == CONT_TYPE_STANDARD)) {
set_rumble_reg(&dev->rumblepaks[i], rpk_state);
}
}
@ -710,7 +710,7 @@ static int savestates_load_m64p(struct device* dev, char *filepath)
COPYARRAY(cam_regs, curr, uint8_t, POCKET_CAM_REGS_COUNT);
}
if (ROM_SETTINGS.transferpak && !Controls[i].RawData) {
if (ROM_SETTINGS.transferpak && !Controls[i].RawData && (Controls[i].Type == CONT_TYPE_STANDARD)) {
/* init transferpak state if enabled and not controlled by input plugin */
dev->transferpaks[i].enabled = enabled;
@ -892,10 +892,10 @@ static int savestates_load_m64p(struct device* dev, char *filepath)
dev->controllers[i].flavor->reset(&dev->controllers[i]);
if (ROM_SETTINGS.rumble) {
if (ROM_SETTINGS.rumble && (Controls[i].Type == CONT_TYPE_STANDARD)) {
poweron_rumblepak(&dev->rumblepaks[i]);
}
if (ROM_SETTINGS.transferpak) {
if (ROM_SETTINGS.transferpak && (Controls[i].Type == CONT_TYPE_STANDARD)) {
poweron_transferpak(&dev->transferpaks[i]);
}
}
@ -1263,10 +1263,10 @@ static int savestates_load_pj64(struct device* dev,
dev->controllers[i].flavor->reset(&dev->controllers[i]);
if (ROM_SETTINGS.rumble) {
if (ROM_SETTINGS.rumble && (Controls[i].Type == CONT_TYPE_STANDARD)) {
poweron_rumblepak(&dev->rumblepaks[i]);
}
if (ROM_SETTINGS.transferpak) {
if (ROM_SETTINGS.transferpak && (Controls[i].Type == CONT_TYPE_STANDARD)) {
poweron_transferpak(&dev->transferpaks[i]);
}
}

View file

@ -394,6 +394,15 @@ static m64p_error plugin_connect_input(m64p_dynlib_handle plugin_handle)
return M64ERR_INPUT_INVALID;
}
if (!GET_FUNC(ptr_SendVRUWord, input.sendVRUWord, "SendVRUWord") ||
!GET_FUNC(ptr_SetMicState, input.setMicState, "SetMicState") ||
!GET_FUNC(ptr_ReadVRUResults, input.readVRUResults, "ReadVRUResults") ||
!GET_FUNC(ptr_ClearVRUWords, input.clearVRUWords, "ClearVRUWords") ||
!GET_FUNC(ptr_SetVRUWordMask, input.setVRUWordMask, "SetVRUWordMask"))
{
DebugMessage(M64MSG_WARNING, "Input plugin does not contain VRU support.");
}
/* check the version info */
(*input.getVersion)(&PluginType, &PluginVersion, &APIVersion, NULL, NULL);
if (PluginType != M64PLUGIN_INPUT || (APIVersion & 0xffff0000) != (INPUT_API_VERSION & 0xffff0000) || APIVersion < 0x020100)
@ -427,6 +436,7 @@ static m64p_error plugin_start_input(void)
Controls[i].Present = 0;
Controls[i].RawData = 0;
Controls[i].Plugin = PLUGIN_NONE;
Controls[i].Type = CONT_TYPE_STANDARD;
}
/* call the input plugin */

View file

@ -38,7 +38,7 @@ extern CONTROL Controls[NUM_CONTROLLER];
#define RSP_API_VERSION 0x20000
#define GFX_API_VERSION 0x20200
#define AUDIO_API_VERSION 0x20000
#define INPUT_API_VERSION 0x20100
#define INPUT_API_VERSION 0x20101
/* video plugin function pointers */
typedef struct _gfx_plugin_functions
@ -101,6 +101,11 @@ typedef struct _input_plugin_functions
ptr_SDL_KeyDown keyDown;
ptr_SDL_KeyUp keyUp;
ptr_RenderCallback renderCallback;
ptr_SendVRUWord sendVRUWord;
ptr_SetMicState setMicState;
ptr_ReadVRUResults readVRUResults;
ptr_ClearVRUWords clearVRUWords;
ptr_SetVRUWordMask setVRUWordMask;
} input_plugin_functions;
extern input_plugin_functions input;