Skip to content

IepIweidieng/osu2tja

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

osu2tja

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.

⚠️ IMPORTANT NOTE ⚠️

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.

Requirements

  • Python 3.10+
  • ffmpeg (optional, for osz2tja)

ffmpeg

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.

osz2tja

Usage

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 to Songs if omitted.
  • [output_folder] is where the converted .tja files and audio files will be saved. Defaults to Output if omitted.

osz2tja will create a folder in [output_folder] for each generated .tja file.

Features

  • 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.

Conversion Details

  • 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/OR ArtistUnicode:/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 → BGIMAGE: (not planned)
      • 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)
    • 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).
    • 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 include COURSE:Edit)
      • OverallDifficulty:LEVEL: (@SamLangTen)
        • TODO: Use the actual osu! star rating.
      • Spinner: Time length → BALLOON: (improved using the official formula to account for OverallDifficulty: (might still off by 1 or 2 hits))
  • 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)
  • 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)

tja2osz

Usage

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 to Songs if omitted.
  • [output_folder] is where the converted .osu files and audio files will be saved. Defaults to Output 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.

Features

  • 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)

Conversion Details

  • 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 to unknown)
      • MAKER:/AUTHOR:///created by Creator: (new) (defaults to unknown)
      • SUBTITLE:Source: (bug fixed), (new) UTF-8 with(out) BOM support
      • ? → Tags: (defaults to taiko jiro tja)
      • GENRE:Tags: (TODO)
      • NOTESDESIGNER<n>:Tags: (for guest chart creators) (TODO)
      • WAVE:AudioFilename:, (new) with automatic file copy
      • ? → AudioLeadIn: (defaults to 0) (improved)
      • DEMOSTART:PreviewTime: (bug fixed), (new) with osu! offset correction
      • ? → CountDown: (defaults to 0 (false))
      • ? → SampleSet: (defaults to Normal)
      • StackLeniency:0.7 (no effects)
      • ? → Mode: (defaults to 1 (Taiko))
      • ? → LetterboxInBreaks: (defaults to 0 (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 to Oni) (improved)
      • NOTESDESIGNER<n>:Version:<notesdesigner>'s <course> when <notesdesigner> isn't <maker>/<author> (TODO)
      • COURSE: + LEVEL:HPDrainRate: (TODO) (defaults to 7 (roughly Taiko Oni 10 full gauge) (improved))
      • CircleSize:5 (no effects)
      • ApproachRate:5 (no effects)
      • COURSE: + LEVEL:OverallDifficulty: (TODO) (defaults to 8.333 (Taiko Hard & Oni GREAT/GOOD window) (improved))
      • ? → SliderMultiplier: (defaults to 1.44 (AC15– note spacing))
      • (Mostly-used) beat division → SliderTickRate: (TODO) (defaults to 4 (1/16th))
      • HEADSCROLL: → initial inherited timing point: Slider velocity change (TODO)
  • 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.
    • #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 #DELAYs are used.
    • #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 #BPMCHANGEs
      • 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).
    • 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)

Languages

  • Python 100.0%