Skip to content

Commit

Permalink
Implement .bnvib and jcvib HD Rumble Player
Browse files Browse the repository at this point in the history
For now it can play only the .bnvib with 0x04 at offset 0x00.

The .jcvib file format is simple HD Rumble file I created with raw (Joycon protocol) values.

It can be created using look up tables and converting the frequencies and amplitudes to the correct commands.

The structure is:
Raw HD Rumble file format [.jcvib] (Joy-Con Format):
Big-Endian
Offset - size - Remarks
0x00 - uint32_t - Magic. 0x52524157 or RRAW in ASCII
0x04 - uint16_t - Sample rate in ms.
0x06 - uint32_t - Number of rumble patterns. This is how many groups of 4 bytes we have.
0x0A - uint32_t - Here the raw data starts. This should be in the values that joycon understand.
0x0E - uint32_t - 2nd Rumble pattern
And so on....

Example raw rumble pattern:
0x08C9C040:
0x08 is HF,
0xC9 is 0xC8 HA + 0x01 HF higher frequency bit.
0xC0 is 0x40 LF + 0x80 intermediate LA byte
0x40 is LA
  • Loading branch information
CTCaer committed Aug 17, 2017
1 parent 4c3bf27 commit 999afff
Show file tree
Hide file tree
Showing 6 changed files with 578 additions and 3 deletions.
476 changes: 473 additions & 3 deletions jctool/FormJoy.h

Large diffs are not rendered by default.

86 changes: 86 additions & 0 deletions jctool/jctool.cpp
Expand Up @@ -560,6 +560,92 @@ int play_tune() {

}

int play_hd_rumble_file(int file_type, u16 sample_rate, int samples) {
int res;
u8 buf[0x100];
u8 buf2[0x100];

//Enable Vibration
memset(buf, 0, sizeof(buf));
auto hdr = (brcm_hdr *)buf;
auto pkt = (brcm_cmd_01 *)(hdr + 1);
hdr->cmd = 0x01;
hdr->rumble[0] = timming_byte;
timming_byte++;
if (timming_byte > 0xF)
timming_byte = 0x0;
pkt->subcmd = 0x48;
pkt->spi_read.offset = 0x01;
pkt->spi_read.size = 0x00;
res = hid_write(handle, buf, sizeof(*hdr) + sizeof(*pkt));
res = hid_read(handle, buf2, 0);

for (int i = 0; i < samples * 4; i = i + 4) {
Sleep(sample_rate);
memset(buf, 0, sizeof(buf));
hdr = (brcm_hdr *)buf;
pkt = (brcm_cmd_01 *)(hdr + 1);
hdr->cmd = 0x10;
hdr->rumble[0] = timming_byte;
timming_byte++;
if (timming_byte > 0xF)
timming_byte = 0x0;
if (file_type == 1) {
hdr->rumble[1] = hdr->rumble[5] = FormJoy::myform1->vib_loaded_file[0x0A + i];
hdr->rumble[2] = hdr->rumble[6] = FormJoy::myform1->vib_loaded_file[0x0B + i];
hdr->rumble[3] = hdr->rumble[7] = FormJoy::myform1->vib_loaded_file[0x0C + i];
hdr->rumble[4] = hdr->rumble[8] = FormJoy::myform1->vib_loaded_file[0x0D + i];
}
else if (file_type == 2) {
hdr->rumble[1] = hdr->rumble[5] = FormJoy::myform1->vib_file_converted[0x0C + i];
hdr->rumble[2] = hdr->rumble[6] = FormJoy::myform1->vib_file_converted[0x0D + i];
hdr->rumble[3] = hdr->rumble[7] = FormJoy::myform1->vib_file_converted[0x0E + i];
hdr->rumble[4] = hdr->rumble[8] = FormJoy::myform1->vib_file_converted[0x0F + i];
}
res = hid_write(handle, buf, sizeof(*hdr));
//FormJoy::myform1->label_samples->Text = L"Samples: " + i / 4 + L"/" + samples;

Application::DoEvents();
}

//FormJoy::myform1->label_samples->Text = L"Samples: " + samples;
//Application::DoEvents();

Sleep(sample_rate);
//Disable vibration
memset(buf, 0, sizeof(buf));
hdr = (brcm_hdr *)buf;
pkt = (brcm_cmd_01 *)(hdr + 1);
hdr->cmd = 0x01;
hdr->rumble[0] = timming_byte;
timming_byte++;
if (timming_byte > 0xF)
timming_byte = 0x0;
hdr->rumble[1] = 0x00; hdr->rumble[2] = 0x01; hdr->rumble[3] = 0x40; hdr->rumble[4] = 0x40;
hdr->rumble[5] = 0x00; hdr->rumble[6] = 0x01; hdr->rumble[7] = 0x40; hdr->rumble[8] = 0x40;
pkt->subcmd = 0x48;
pkt->spi_read.offset = 0x00;
pkt->spi_read.size = 0x00;
res = hid_write(handle, buf, sizeof(*hdr) + sizeof(*pkt));
res = hid_read(handle, buf, 0);

memset(buf, 0, sizeof(buf));
hdr = (brcm_hdr *)buf;
pkt = (brcm_cmd_01 *)(hdr + 1);
hdr->cmd = 0x01;
hdr->rumble[0] = timming_byte;
timming_byte++;
if (timming_byte > 0xF)
timming_byte = 0x0;
pkt->subcmd = 0x30;
pkt->spi_read.offset = 0x01;
pkt->spi_read.size = 0x00;
res = hid_write(handle, buf, sizeof(*hdr) + sizeof(*pkt));
res = hid_read(handle, buf, 0);

return 0;
}

/*
//usb test
int usb_init(hid_device *handle) {
Expand Down
1 change: 1 addition & 0 deletions jctool/jctool.h
Expand Up @@ -36,6 +36,7 @@ extern int get_battery(u8* test_buf);
extern int dump_spi(const char *dev_name);
extern int send_rumble();
extern int play_tune();
extern int play_hd_rumble_file(int file_type, u16 sample_rate, int samples);
extern int send_custom_command(u8* arg);
extern int device_connection();
extern int set_led_busy();
Expand Down
1 change: 1 addition & 0 deletions jctool/jctool.vcxproj
Expand Up @@ -78,6 +78,7 @@
<ClInclude Include="FormJoy.h">
<FileType>CppForm</FileType>
</ClInclude>
<ClInclude Include="luts.h" />
<ClInclude Include="tune.h" />
<ClInclude Include="Overrides.h">
<DependentUpon>FormJoy.h</DependentUpon>
Expand Down
3 changes: 3 additions & 0 deletions jctool/jctool.vcxproj.filters
Expand Up @@ -41,6 +41,9 @@
<ClInclude Include="tune.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="luts.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="FormJoy.resx">
Expand Down
14 changes: 14 additions & 0 deletions jctool/luts.h
@@ -0,0 +1,14 @@
#pragma once
#include <cstdint>
struct lut_amp {
float amp_float[101];
uint8_t ha[101];
uint16_t la[101];
};

lut_amp lut_joy_amp{
{ 0.0f, 0.009942f, 0.011823f, 0.014061f, 0.01672f, 0.019885f, 0.023648f, 0.028123f, 0.033442f, 0.039771f, 0.047296f, 0.056246f, 0.066886f, 0.079542f, 0.094592f, 0.112491f, 0.117471f, 0.122671f, 0.128102f, 0.133774f, 0.139697f, 0.145882f, 0.152341f, 0.159085f, 0.166129f, 0.173484f, 0.181166f, 0.189185f, 0.197561f, 0.206308f, 0.215442f, 0.224982f, 0.229908f, 0.234943f, 0.240087f, 0.245345f, 0.250715f, 0.256206f, 0.261816f, 0.267549f, 0.273407f, 0.279394f, 0.285514f, 0.291765f, 0.298154f, 0.304681f, 0.311353f, 0.318171f, 0.325138f, 0.332258f, 0.339534f, 0.346969f, 0.354566f, 0.362331f, 0.370265f, 0.378372f, 0.386657f, 0.395124f, 0.403777f, 0.412619f, 0.421652f, 0.430885f, 0.440321f, 0.449964f, 0.459817f, 0.469885f, 0.480174f, 0.490689f, 0.501433f, 0.512413f, 0.523633f, 0.5351f, 0.546816f, 0.55879f, 0.571027f, 0.58353f, 0.596307f, 0.609365f, 0.622708f, 0.636344f, 0.650279f, 0.664518f, 0.679069f, 0.693939f, 0.709133f, 0.724662f, 0.740529f, 0.756745f, 0.773316f, 0.790249f, 0.807554f, 0.825237f, 0.843307f, 0.861772f, 0.880643f, 0.899928f, 0.919633f, 0.939771f, 0.960348f, 0.981378f, 1.002867f },
{ 0x0, 0x2, 0x4, 0x6, 0x8, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e, 0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e, 0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e, 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e, 0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe, 0xc0, 0xc2, 0xc4, 0xc6, 0xc8 },
{ 0x0040, 0x8040, 0x0041, 0x8041, 0x0042, 0x8042, 0x0043, 0x8043, 0x0044, 0x8044, 0x0045, 0x8045, 0x0046, 0x8046, 0x0047, 0x8047, 0x0048, 0x8048, 0x0049, 0x8049, 0x004a, 0x804a, 0x004b, 0x804b, 0x004c, 0x804c, 0x004d, 0x804d, 0x004e, 0x804e, 0x004f, 0x804f, 0x0050, 0x8050, 0x0051, 0x8051, 0x0052, 0x8052, 0x0053, 0x8053, 0x0054, 0x8054, 0x0055, 0x8055, 0x0056, 0x8056, 0x0057, 0x8057, 0x0058, 0x8058, 0x0059, 0x8059, 0x005a, 0x805a, 0x005b, 0x805b, 0x005c, 0x805c, 0x005d, 0x805d, 0x005e, 0x805e, 0x005f, 0x805f, 0x0060, 0x8060, 0x0061, 0x8061, 0x0062, 0x8062, 0x0063, 0x8063, 0x0064, 0x8064, 0x0065, 0x8065, 0x0066, 0x8066, 0x0067, 0x8067, 0x0068, 0x8068, 0x0069, 0x8069, 0x006a, 0x806a, 0x006b, 0x806b, 0x006c, 0x806c, 0x006d, 0x806d, 0x006e, 0x806e, 0x006f, 0x806f, 0x0070, 0x8070, 0x0071, 0x8071, 0x0072 }
};

0 comments on commit 999afff

Please sign in to comment.