English|简体中文
An .osu ⟷ .tja converter, for Python 3.
.osu
(osu! Beatmap) is the single-difficulty chart format for the game osu!. .osz
(osu! Beatmap Archive) is the standard zipped form containing multiple .osu
files and resources for a song entry in osu!.
.tja
or TJA (unknown acronym, likely "Taiko (Tatsu)jin Another") is a Taiko chart format supported by many simulators, such as TaikoJiro, Taiko-san Daijiro, Malody, TJAPlayer3, OpenTaiko, and Project OutFox.
It contains 2 major tools: osz2tja & tja2osz.
For charts which aren't authored by you, the converted charts aren't yours either and are for personal use only.
If you want to distribute any converted charts not authored by you, please ask the chart author(s) for permission first. We don't support content stealing and do strictly condemn it.
- Python 3.10+
- ffmpeg (optional, for osz2tja)
If ffmpeg is installed or placed under the same directory as osz2tja.py
, osz2tja will automatically convert the audio file into .ogg
format.
Get ffmpeg here: https://www.ffmpeg.org/download.html
After downloading, unzip it and copy bin/ffmpeg.exe
into the same directory as osz2tja.py
, and the conversion should now work.
python osz2tja.py [input_folder] [output_folder]
Example:
python osz2tja.py a_folder b_folder
[input_folder]
is where your.osz
files are located. Defaults toSongs
if omitted.[output_folder]
is where the converted.tja
files and audio files will be saved. Defaults toOutput
if omitted.
osz2tja will create a folder in [output_folder]
for each generated .tja
file.
- Batch conversion of
.osz
files to.tja
files. (@MoshirMoshir) - Automatically maps osu! difficulties (up to 5 per
.tja
file) to TJA Edit (Taiko: Inner/Ura Oni or Extra Extreme), Oni (Taiko: Extreme), Hard, Normal, and Easy difficulties. (@MoshirMoshir; improved to 5) - Beatmaps with more than 5 difficulties are split into multiple
.tja
files (e.g.,title - 1
,title - 2
). (@MoshirMoshir; improved to suffix only when necessary) - Beatmaps with multiple song audio files (unrankable but seen in loved beatmaps) are also split into multiple
.tja
files. (new) - Automatically copy song audio files (@SamLangTen; automatic OGG conversion — @k2angel), (new) as well as background image and other files used by the chart.
- Input (
.osu
):- osu file format v4–14 (those tested; warns and continues to process for other versions) (improved)
- Encoding: UTF-8 (without BOM)
- taiko mode
- std, (improved) mania, & catch mode conversion
- time offsets in decimal (seen in beatmaps created in osu!lazer or converted by 3rd-party tools) (new)
- Output (
.tja
)- Encoding: Shift-JIS (if possible) or (new) UTF-8 (with BOM).
- Floating number precision: Python builtin
float
(IEEE 754 binary64) precision, (improved) output simpliest decimal without digit count limits.
- TJA Headers
- Metadata Headers
- osu2tja watermark (moved to the first line of the TJA file)
-
TitleUnicode:
/Title:
→TITLE:
-
Source:
AND/ORArtistUnicode:
/Artist:
→SUBTITLE:
(@k2angel) -
AudioFilename:
→WAVE:
, (@SamLangTen) with automatic file copy, (@k2angel) with OGG conversion -
PreviewTime:
→DEMOSTART:
, (new) with osu! music offset correction -
Creator:
→MAKER:
(@MoshirMoshir) -
Creator:
→AUTHOR:
(for Malody) (new) - timing point: hitsound volume (max) →
SEVOL:
÷SONGVOL:
(TODO)
- Decoration Headers
- First centered background event: filename →
PREIMAGE:
(new) -
First centered background event: filename →(not planned)BGIMAGE:
- First centered video event: filename →
BGMOVIE:
(new) - First centered video event: start time →
MOVIEOFFSET:
, with osu! music offset correction (new) - Storyboard event → TJAPlayer3-Extended OBJ commands (not planned)
- First centered background event: filename →
- Sync Headers
- initial BPM →
BPM:
(for display only), (new) for each difficulty, (new) output simpliest decimal without digit count limits. - initial beat time position →
OFFSET:
(improved), (new) for each difficulty, (new) with -15ms music offset correction (extra +24ms for format v4 and earlier)- The
OFFSET:
is set to the beginning time position of the last beat non-after the audio to mimic osu! behavior. It was the earliest of the first note or the timing point in delguoqing's version. - Ranked osu! beatmaps have roughly +15ms music offset than perfect sync due to the historical reasons. Ranked format v4 and earlier beatmaps have additional -24ms music offset (-9ms in total).
- The
- initial BPM →
- Difficulty Headers
-
Version:
&Mode:
→ TJA comment (for reference only) (new) -
Version:
→NOTEDESIGNER<n>:
(for difficulties by guest chart creators) (TODO) -
Creator:
→NOTEDESIGNER<n>:
(otherwise) (TODO) - Difficulties sorted by
OverallDifficulty:
→COURSE:
(@SamLangTen; automated — @MoshirMoshir; improved to includeCOURSE:Edit
) -
OverallDifficulty:
→LEVEL:
(@SamLangTen)- TODO: Use the actual osu! star rating.
- Spinner: Time length →
BALLOON:
(improved using the official formula to account forOverallDifficulty:
(might still off by 1 or 2 hits))
-
- Metadata Headers
- TJA Commands
- Uninherited timing point: BPM →
#BPMCHANGE
- Uninherited timing point: Beats per bar →
#MEASURE
- Incomplete bar →
#MEASURE
+ optional#DELAY
(crash fixed — @delguoqing; improved to ms-level accuracy) -
SliderMultiplier:
→ Base#SCROLL
multiplier for whole chart (new) - Inherited timing point: Slider velocity change →
#SCROLL
(uncapped range) - Timing point: Kiai time →
#GOGOSTART
&#GOGOEND
- Timing point: Omit first bar line →
#BARLINEOFF
&#BARLINEON
(TODO)
- Uninherited timing point: BPM →
- TJA Note Definition
- Timing
- relative time offset to bar start and end → beat division
- Mid-bar inter-note command insertion (improved, new)
- ms-level timing accuracy (TODO)
- Currently everything is pre-quantized to 1/96ths (1/24 beats).
- Note Symbols
- (std mode) short slider to circles (improved using the official algorithm)
- (mania mode) hold to circles (new)
- TODO: Hold to bar drumroll with note overlapping handling.
- (mania mode, > 1 keys) convert Don/Katsu by column position instead of hitsound (new)
- Layout: KD(D), KDDK, KKDD(DD)K, KKDDDDKK, KKKDDDD(DD)KK, KKKDDDDDDKKK, KKKKDDDDDD(DD)KKK, ...
- Empty →
0
(blank) - Circle, normal or Don column, non-finish hitsound →
1
(regular Don) - Circle, whistle/clap or Katsu column, non-finish hitsound →
2
(regular Katsu) - Circle, normal or Don column, finish hitsound →
3
(big Don) - Circle, whistle/clap or Katsu column, finish hitsound →
4
(big Katsu) - Slider, non-finish hitsound →
5
+8
(regular bar drumroll) - Slider, finish hitsound →
6
+8
(big bar drumroll) - Spinner, ANY hitsound →
7
+8
(regular balloon roll) - Spinner, finish hitsound →
9
+8
(special balloon roll) (TODO)
- Timing
python tja2osz.py [input_folder] [output_folder]
Example:
python tja2osz.py a_folder b_folder
[input_folder]
is where your.tja
files are located (can be in any inner directories). Defaults toSongs
if omitted.[output_folder]
is where the converted.osu
files and audio files will be saved. Defaults toOutput
if omitted.
tja2osz will create a folder in [output_folder]
for each processed .tja
file. This folder will contain converted .osu
files and audio file. tja2osz will also create an .osz
file in [output_folder]
for these .osu
files.
- Batch conversion of
.tja
files to.osz
files. (new) - Automatically split each TJA difficulty, player-side, and each main branch route as a separate
.osu
difficulty file. (fixed) - Automatically copy song audio, background image, and other files used by the chart (new)
- Output (
.osu
):- osu file format v14 (improved)
- Encoding: UTF-8 (without BOM)
- Floating number precision: Python builtin
float
(IEEE 754 binary64) precision, (improved) output simpliest decimal without digit count limits.
- Input (
.tja
) encoding: Guessed among UTF-8, GBK, Shift-JIS, & Big5 (improved) - TJA
//
comment ignoring, (fixed) including when when splitting TJAs - TJA Headers
- Metadata Headers
- osu2tja watermark (new)
-
TITLE:
→Title:
, (new) UTF-8 with(out) BOM support -
SUBTITLE:
→Artist:
(TODO) (Currently defaults tounknown
) -
MAKER:
/AUTHOR:
///created by
→Creator:
(new) (defaults tounknown
) -
SUBTITLE:
→Source:
(bug fixed), (new) UTF-8 with(out) BOM support - ? →
Tags:
(defaults totaiko jiro tja
) -
GENRE:
→Tags:
(TODO) -
NOTESDESIGNER<n>:
→Tags:
(for guest chart creators) (TODO) -
WAVE:
→AudioFilename:
, (new) with automatic file copy - ? →
AudioLeadIn:
(defaults to0
) (improved) -
DEMOSTART:
→PreviewTime:
(bug fixed), (new) with osu! offset correction - ? →
CountDown:
(defaults to0
(false)) - ? →
SampleSet:
(defaults toNormal
) -
StackLeniency:0.7
(no effects) - ? →
Mode:
(defaults to1
(Taiko)) - ? →
LetterboxInBreaks:
(defaults to0
(false)) (improved) -
SEVOL:
÷SONGVOL:
→ Timing point: hitsound volume (new)
- Decoration Headers
-
BGIMAGE:
/PREIMAGE:
→ Background event: filename, with automatic file copy (new) -
BGMOVIE:
→ Video event: filename, with automatic file copy (new) -
MOVIEOFFSET:
→ Video event: start time, with osu! offset correction (new) - TJAPlayer3-Extended OBJ commands → Storyboard event (not planned)
-
- Sync Headers
-
BPM:
→ initial uninherited timing point: BPM -
OFFSET:
→ initial uninherited timing point: time, (new) with +15ms music offset correction- Ranked osu! beatmaps have roughly +15ms music offset than perfect sync due to the historical reasons.
-
- Difficulty Headers
-
STYLE:
→Version:
(new) -
COURSE:
→Version:
(defaults toOni
) (improved) -
NOTESDESIGNER<n>:
→Version:<notesdesigner>'s <course>
when<notesdesigner>
isn't<maker>
/<author>
(TODO) -
COURSE:
+LEVEL:
→HPDrainRate:
(TODO) (defaults to7
(roughly Taiko Oni 10 full gauge) (improved)) -
CircleSize:5
(no effects) -
ApproachRate:5
(no effects) -
COURSE:
+LEVEL:
→OverallDifficulty:
(TODO) (defaults to8.333
(Taiko Hard & Oni GREAT/GOOD window) (improved)) - ? →
SliderMultiplier:
(defaults to1.44
(AC15– note spacing)) - (Mostly-used) beat division →
SliderTickRate:
(TODO) (defaults to4
(1/16th)) -
HEADSCROLL:
→ initial inherited timing point: Slider velocity change (TODO)
-
- Metadata Headers
- TJA Commands
-
#START
→ Uninherited timing point: Large beats per bar + omit first bar line + (optional) incomplete bar (TODO) -
#START P<n>
→#START
in player-side TJA (new) -
#END
/end-of-file → Uninherited timing point: Large beats per bar + omit first bar line (new) -
#BRANCHSTART
→ Begin branch-split section- TODO: detect and avoid impossible branch routes
-
#N
/#E
/#M
→ Split into branch TJA- FIXME: Omitting some branches causes missing bars.
-
#BRANCHEND
→ Begin branch-common section- FIXME:
#BRANCHEND
is recognized but ignored.
- FIXME:
-
#BPMCHANGE
, positive → Uninherited timing point: BPM -
#BPMCHANGE
, negative, with positive (bar length ÷ BPM) → Uninherited timing point: absolute-valued BPM (TODO) -
#MEASURE
, positive integer beats → Uninherited timing point: Beats per bar (improved), (new) float values -
#MEASURE
, positive fraction beats → Uninherited timing point: Beats per bar + incomplete bar (improved), (new) float values - Negative (bar length ÷ BPM) → Notechart events are not in completely increasing time order, re-sorted by time (TODO)
-
#DELAY
→ move time of definition cursor- FIXME: The bar line after
#DELAY
will be wrongly displayed until the next uninherited timing point generated. - FIXME: The generated events might not be in the correct increasing time order if large negative
#DELAY
s are used.
- FIXME: The bar line after
-
#SCROLL
, with positive (scroll × BPM) → Inherited timing point: Slider velocity change- FIXME: Use BPM changes to work around the slider velocity change being capped between 0.01x to 10x in osu!.
- Non-positive/complex-valued (scroll × BPM) → Inherited timing point: Absolute-valued slider velocity change (TODO)
-
#SUDDEN
, with positive stop duration → Inherited timing point: Scaled slider velocity change (TODO) -
#GOGOSTART
&#GOGOEND
→ Timing point: Kiai time -
#BARLINEOFF
&#BARLINEON
→ Timing point: Omit first bar line (new) -
#BARLINE
→ Split bars into (possibly) incomplete bars (TODO) -
#BARLINESCROLL
→ Inherited timing points: Slider velocity change for every bar line and every first note after bar line; split out a 1ms bar with omitted first bar line for notes on the original bar start (TODO)
-
- TJA Note Definition
- Timing
- Measure with no note symbols (
,
) → Full measure (new bug fix) - Mid-bar
#BPMCHANGE
s - Sum of (bar length ÷ beat division ÷ BPM at each division) → relative time offset to bar start (bug fixed for fractional-beat bars with
#SCROLL
) - ms-level timing accuracy (TODO)
- Currently everything is pre-quantized to 1/96ths (1/24 beats).
- Measure with no note symbols (
- Note Symbols
-
0
(blank) → Empty -
1
(regular Don) → Circle, default hitsound -
2
(regular Katsu) → Circle, clap hitsound -
F
(ad-lib) → = regular Don/Katsu? (TODO) -
C
(bomb/mine) → = regular Don/Katsu? empty? (TODO) -
3
(big Don) → Circle, finish hitsound -
A
(handed big Don) → Circle, finish hitsound (TODO) -
4
(big Katsu) → Circle, clap finish hitsound -
B
(handed big Katsu) → Circle, clap finish hitsound (TODO) -
G
(Kadon) → = big Don/Katsu? (TODO) -
5
(head of regular bar drumroll) → Slider, default hitsound -
I
(head of regular/Katsu? bar drumroll) → = head of regular bar drumroll? (TODO) -
6
(head of big bar drumroll) → Slider, finish hitsound -
H
(head of big/Don? bar drumroll) → = head of big bar drumroll? (TODO) -
7
(head of regular balloon roll) → Spinner, default hitsound -
9
(head of special balloon roll) → Spinner, default hitsound- TODO: use finish hitsound to mark difference
-
D
(head of fuze balloon roll) → = regular balloon roll? (TODO) - Head of any roll-type note, after unended roll-type notes → Empty (TODO)
-
8
(explicit end of rolls), after unended roll-type notes → End of last slider/spinner - Any hit-type note, after unended roll-type notes → Forced end of last slider/spinner (TODO)
-
#END
(command), after unended roll-type notes → Forced end of last slider/spinner (TODO) -
8
, straying → Empty (TODO) - Any roll-type note, non-positive time duration → Empty (TODO)
-
- Timing