Rhythm Open Exchange (ROX)
A universal, compact binary format for Vertical Scrolling Rhythm Games (VSRG). ROX serves as a pivot format for converting between different rhythm game formats like osu!mania, Quaver, StepMania, Etterna, and BMS.
"so i'm just trying to make a ffmpeg of vsrg game idk where i'm going"
Overview
ROX is designed to be:
- Compact — Uses bincode for minimal file size with variable-length integer encoding
- Precise — Microsecond timestamp precision (i64) for accurate timing
- Universal — Supports all common VSRG features across different games
- Verifiable — BLAKE3 content hashing for integrity verification
Features
- Support for any key count (4K, 7K, 9K, etc.)
- Multiple note types: Tap, Hold (LN), Burst/Roll, Mine
- BPM changes and Scroll Velocity (SV) modifications
- Keysound support for BMS/O2Jam style charts
- Comprehensive metadata (title, artist, difficulty, tags, etc.)
- Content-based hashing for chart identification
Installation
Add to your Cargo.toml:
[]
= "0.1"
Or clone and build locally:
Quick Start
Creating a Chart
use ;
// Create a 4K chart
let mut chart = new;
// Set metadata
chart.metadata = Metadata ;
// Add a BPM timing point at the start
chart.timing_points.push;
// Add notes (time in microseconds, column index)
chart.notes.push; // Tap at 1s, column 0
chart.notes.push; // Tap at 1.5s, column 1
chart.notes.push; // Hold at 2s, 0.5s duration
Encoding and Decoding
use ;
// Encode to bytes
let bytes = encode?;
// Save to file
encode_to_path?;
// Load from file
let loaded = decode_from_path?;
// Decode from bytes
let decoded = decode?;
Chart Hashing
// Get full BLAKE3 hash (64 hex characters)
let hash = chart.hash;
// Get short hash for display (16 hex characters)
let short = chart.short_hash;
println!;
Converting osu!mania files
use ;
use ;
// Load .osu file
let chart = decode_from_path?;
println!;
// Convert to .rox (compact binary)
encode_to_path?;
// Or export back to .osu
encode_to_path?;
API Reference
Core Types
| Type | Description |
|---|---|
RoxChart |
Main chart container with metadata, timing, notes, and hitsounds |
Metadata |
Song and chart information (title, artist, difficulty, etc.) |
Note |
A single note with type, timing, column, and optional keysound |
NoteType |
Enum: Tap, Hold, Burst, Mine |
TimingPoint |
BPM or scroll velocity change |
Hitsound |
Keysound sample reference |
Traits
| Trait | Description |
|---|---|
Encoder |
Encode a chart to bytes or file |
Decoder |
Decode a chart from bytes or file |
Note Constructors
tap // Single tap
hold // Long note
burst // Roll/burst
mine // Mine (avoid)
TimingPoint Constructors
bpm // BPM change
sv // Scroll velocity change
File Format
ROX files use the .rox extension and have the following structure:
| Offset | Field | Type | Description |
|---|---|---|---|
| 0x00 | Magic | [u8; 4] |
ROX\0 (0x524F5800) |
| 0x04 | Data | zstd + bincode | Compressed, serialized RoxChart |
The chart data is serialized using bincode with:
- Little-endian byte order
- Variable-length integer encoding
- Zstd compression (level 3)
Performance
ROX is built for extreme efficiency. Benchmarks on a massive 50,000 note chart (4K) show:
| Metric | .osu Format | .rox Format | Improvement |
|---|---|---|---|
| File Size | 1.55 MB | 50 KB | 97% Smaller |
| Decode Speed | ~26 ms | ~2.7 ms | 10x Faster |
| Encode Speed | N/A | ~4.2 ms | Lightning Fast |
Benchmarks run on release build with cargo bench.
Roadmap
Format Converters
| Format | Status | Import | Export |
|---|---|---|---|
| osu!mania (.osu) | Implemented | Yes | Yes |
| osu!taiko (.osu) | Implemented | Yes | No |
| StepMania / Etterna (.sm/.ssc) | Implemented | Yes | Yes |
| Quaver (.qua) | Implemented | Yes | Yes |
| Friday Night Funkin' (.json) | Implemented | Yes | Yes |
| Malody (.mc) | Planned | Yes | Yes |
| RoBeats | Planned | Yes | Yes |
| Clone Hero (.chart/.mid) | Planned (Experimental) | Yes | Yes |
| BMS (.bms/.bme/.bml) | Planned | Yes | No |
| O2Jam (.ojn/.ojm) | Planned | Yes | No |
Alternative Formats
| Extension | Format | Use Case |
|---|---|---|
.rox |
Binary (zstd compressed) | Production, distribution |
.jrox |
JSON | Human-readable, debugging |
.yrox |
YAML | Human-readable, editing |
Planned Features
- Chart difficulty calculation
- Pattern analysis utilities
- Timing section helpers
- Batch conversion CLI tool
- WebAssembly support
Development
Prerequisites
- Rust 1.85+ (2024 edition)
- Cargo
Building
Running Tests
Running Specific Tests
Project Structure
rhythm-open-exchange/
├── src/
│ ├── lib.rs # Library entry point and re-exports
│ ├── error.rs # Error types (RoxError, RoxResult)
│ ├── codec/
│ │ ├── mod.rs # Codec module
│ │ ├── traits.rs # Encoder/Decoder traits
│ │ ├── rox.rs # RoxCodec (with zstd + delta encoding)
│ │ └── formats/ # Format converters
│ │ └── osu/ # osu!mania (.osu) converter
│ └── model/
│ ├── chart.rs # RoxChart struct
│ ├── metadata.rs # Metadata struct
│ ├── note.rs # Note and NoteType
│ ├── timing.rs # TimingPoint
│ └── hitsound.rs # Hitsound
├── tests/
│ ├── common/ # Test utilities
│ ├── codec/formats/osu/ # osu format tests
│ ├── codec_tests.rs
│ ├── model_tests.rs
│ └── integration_tests.rs
├── examples/ # Usage examples
├── assets/ # Test assets (.osu files)
├── output/ # Generated files (gitignored)
├── .wiki/ # Documentation wiki
└── README.md
Contributing
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Code Style
- Follow Rust standard formatting (
cargo fmt) - Ensure tests pass (
cargo test) - Add tests for new functionality
- Update documentation as needed
License
This project is licensed under the MIT License. See the LICENSE file for details.
See Also
- Wiki Documentation — Detailed format specification
- osu!mania — Popular VSRG
- Quaver — Competitive VSRG
- Etterna — Advanced VSRG