Contents

VSD2JSON

See the source code here: raineycat/vsd2json

About

This is just a small tool I wrote to dump the song information found in vivid/stasis data files, on account of the game using a proprietary binary format.

It uses binary-reader to help parse the format, and serde/serde_json to write it out in a sensible format.

In this post, I’ll refer to these song info files (song_information.bin) as VSDs, since that’s the magic number they use, and also how they’re referred to in the game’s code. These are not to be confused with other files that use the .vsd extension, since as far as I’ve seen nothing else uses this binary format.

The format

VSDs are very similar to chart files in structure, as the header and tagged chunk format are very similar.

---
title: Empty/simplest VSD file, not including the signature
config:
    packet:
        bitsPerRow: 48
        bitWidth: 16
---
packet
+24: "Magic number: \"VSD\" (0x565344)"
+8: "Version: 0x01"
+8: "Null byte"
+8: "End marker: 0xFF"

After the header, the data is made up of tagged sections. Each tag is 1 byte, and the data after it has no fixed length. After all chunks are read, there must be a termination byte (0xFF).

There is also a 384 byte RSA signature after this, however at the time of writing this is never verified, so it can just be zeroed out.

The only top level chunk is a song info chunk, where the tag byte is 0xA0. This contains an arbitrary amount of song field (tag 0xA2) chunks, up to four chart info (0xC0) chunks, and has a 0xA1 terminator tag.


Each song info chunk has the following fields:


And each chart info chunk stores:


If you want to see the full logic behind reading the song data, you can see the code here. Otherwise, this is as far as I’ll go here to avoid this post getting too long.

Finishing up

As you can guess, having this in a simpler (and saner) format is very useful, (example: the tourney code maker on this site), which is why I made this tool.

The output JSON schema is detailed in the README, but it’s easy to transform it into whatever format you need.

For example, the nushell code I used to generate data for the code maker is:

open song_information.json | get songs | select song_id song_name song_artist charts | update charts { $in | where difficulty_constant > 0 | length } | save tourney_song_data.json

Anyway, bye for now, and stay silly™!