From d0a5d5159b5fdd647b58f252fe038089e9127de3 Mon Sep 17 00:00:00 2001 From: Ignacio Conde Date: Tue, 24 Oct 2023 19:59:43 -0300 Subject: [PATCH 1/2] Update README and misc --- .gitignore | 3 +- Makefile | 384 ++++++++++++++++++------------------ README.md | 18 +- conf.py | 570 ++++++++++++++++++++++++++--------------------------- 4 files changed, 487 insertions(+), 488 deletions(-) diff --git a/.gitignore b/.gitignore index ed8ba77..bbef3e5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1 @@ -_* -.vscode/settings.json +_* diff --git a/Makefile b/Makefile index 05941a1..68c6b74 100644 --- a/Makefile +++ b/Makefile @@ -1,192 +1,192 @@ -# Makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -PAPER = -BUILDDIR = _build - -# User-friendly check for sphinx-build -ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) -$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) -endif - -# Internal variables. -PAPEROPT_a4 = -D latex_paper_size=a4 -PAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . -# the i18n builder cannot share the environment and doctrees with the others -I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . - -.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext - -help: - @echo "Please use \`make ' where is one of" - @echo " html to make standalone HTML files" - @echo " dirhtml to make HTML files named index.html in directories" - @echo " singlehtml to make a single large HTML file" - @echo " pickle to make pickle files" - @echo " json to make JSON files" - @echo " htmlhelp to make HTML files and a HTML help project" - @echo " qthelp to make HTML files and a qthelp project" - @echo " applehelp to make an Apple Help Book" - @echo " devhelp to make HTML files and a Devhelp project" - @echo " epub to make an epub" - @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" - @echo " latexpdf to make LaTeX files and run them through pdflatex" - @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" - @echo " text to make text files" - @echo " man to make manual pages" - @echo " texinfo to make Texinfo files" - @echo " info to make Texinfo files and run them through makeinfo" - @echo " gettext to make PO message catalogs" - @echo " changes to make an overview of all changed/added/deprecated items" - @echo " xml to make Docutils-native XML files" - @echo " pseudoxml to make pseudoxml-XML files for display purposes" - @echo " linkcheck to check all external links for integrity" - @echo " doctest to run all doctests embedded in the documentation (if enabled)" - @echo " coverage to run coverage check of the documentation (if enabled)" - -clean: - rm -rf $(BUILDDIR)/* - -html: - $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." - -dirhtml: - $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." - -singlehtml: - $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml - @echo - @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." - -pickle: - $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle - @echo - @echo "Build finished; now you can process the pickle files." - -json: - $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json - @echo - @echo "Build finished; now you can process the JSON files." - -htmlhelp: - $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp - @echo - @echo "Build finished; now you can run HTML Help Workshop with the" \ - ".hhp project file in $(BUILDDIR)/htmlhelp." - -qthelp: - $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp - @echo - @echo "Build finished; now you can run "qcollectiongenerator" with the" \ - ".qhcp project file in $(BUILDDIR)/qthelp, like this:" - @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/bmson-spec.qhcp" - @echo "To view the help file:" - @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/bmson-spec.qhc" - -applehelp: - $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp - @echo - @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." - @echo "N.B. You won't be able to view it unless you put it in" \ - "~/Library/Documentation/Help or install it in your application" \ - "bundle." - -devhelp: - $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp - @echo - @echo "Build finished." - @echo "To view the help file:" - @echo "# mkdir -p $$HOME/.local/share/devhelp/bmson-spec" - @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/bmson-spec" - @echo "# devhelp" - -epub: - $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub - @echo - @echo "Build finished. The epub file is in $(BUILDDIR)/epub." - -latex: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo - @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." - @echo "Run \`make' in that directory to run these through (pdf)latex" \ - "(use \`make latexpdf' here to do that automatically)." - -latexpdf: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through pdflatex..." - $(MAKE) -C $(BUILDDIR)/latex all-pdf - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." - -latexpdfja: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through platex and dvipdfmx..." - $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." - -text: - $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text - @echo - @echo "Build finished. The text files are in $(BUILDDIR)/text." - -man: - $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man - @echo - @echo "Build finished. The manual pages are in $(BUILDDIR)/man." - -texinfo: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo - @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." - @echo "Run \`make' in that directory to run these through makeinfo" \ - "(use \`make info' here to do that automatically)." - -info: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo "Running Texinfo files through makeinfo..." - make -C $(BUILDDIR)/texinfo info - @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." - -gettext: - $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale - @echo - @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." - -changes: - $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes - @echo - @echo "The overview file is in $(BUILDDIR)/changes." - -linkcheck: - $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck - @echo - @echo "Link check complete; look for any errors in the above output " \ - "or in $(BUILDDIR)/linkcheck/output.txt." - -doctest: - $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest - @echo "Testing of doctests in the sources finished, look at the " \ - "results in $(BUILDDIR)/doctest/output.txt." - -coverage: - $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage - @echo "Testing of coverage in the sources finished, look at the " \ - "results in $(BUILDDIR)/coverage/python.txt." - -xml: - $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml - @echo - @echo "Build finished. The XML files are in $(BUILDDIR)/xml." - -pseudoxml: - $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml - @echo - @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = _build + +# User-friendly check for sphinx-build +ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) +$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) +endif + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " applehelp to make an Apple Help Book" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " xml to make Docutils-native XML files" + @echo " pseudoxml to make pseudoxml-XML files for display purposes" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + @echo " coverage to run coverage check of the documentation (if enabled)" + +clean: + rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/bmson-spec.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/bmson-spec.qhc" + +applehelp: + $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp + @echo + @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." + @echo "N.B. You won't be able to view it unless you put it in" \ + "~/Library/Documentation/Help or install it in your application" \ + "bundle." + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/bmson-spec" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/bmson-spec" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +latexpdfja: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through platex and dvipdfmx..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +coverage: + $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage + @echo "Testing of coverage in the sources finished, look at the " \ + "results in $(BUILDDIR)/coverage/python.txt." + +xml: + $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml + @echo + @echo "Build finished. The XML files are in $(BUILDDIR)/xml." + +pseudoxml: + $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml + @echo + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." diff --git a/README.md b/README.md index a4481b8..3dd7048 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ -# bmson-spec - -[![Documentation Status](https://readthedocs.org/projects/bmson-spec/badge/?version=master)](http://bmson-spec.readthedocs.org/en/master/?badge=master) - -This is a technical specification document for bmson format. - -The compiled document is here: http://bmson-spec.readthedocs.org/ - -Pull requests are welcome. +# bmson-spec + +[![Documentation Status](https://readthedocs.org/projects/bmson-spec-fork/badge/?version=master)](http://bmson-spec-fork.readthedocs.org/en/master/?badge=master) + +This is a technical specification document for bmson format. + +The compiled document is here: http://bmson-spec-fork.readthedocs.org/ + +Pull requests are welcome. diff --git a/conf.py b/conf.py index 4dcce4e..7eb9f28 100644 --- a/conf.py +++ b/conf.py @@ -1,285 +1,285 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -# -# bmson-spec documentation build configuration file, created by -# sphinx-quickstart on Sat Dec 26 09:59:57 2015. -# -# This file is execfile()d with the current directory set to its -# containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -import sys -import os -import shlex - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.insert(0, os.path.abspath('.')) - -# -- General configuration ------------------------------------------------ - -# If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = [] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix(es) of source filenames. -# You can specify multiple suffix as a list of string: -# source_suffix = ['.rst', '.md'] -source_suffix = '.rst' - -# The encoding of source files. -#source_encoding = 'utf-8-sig' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = 'bmson-spec' -copyright = '2015, bmson team' -author = 'bmson team' - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -# The short X.Y version. -version = '1.0.0' -# The full version, including alpha/beta/rc tags. -release = '1.0.0-beta' - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -# -# This is also used if you do content translation via gettext catalogs. -# Usually you set "language" from the command line for these cases. -language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -#today = '' -# Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -exclude_patterns = ['_build'] - -# The reST default role (used for this markup: `text`) to use for all -# documents. -#default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -#add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -#show_authors = False - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] - -# If true, keep warnings as "system message" paragraphs in the built documents. -#keep_warnings = False - -# If true, `todo` and `todoList` produce output, else they produce nothing. -todo_include_todos = False - - -# -- Options for HTML output ---------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -html_theme = 'default' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -#html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -#html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -#html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -#html_favicon = None - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -# Add any extra paths that contain custom files (such as robots.txt or -# .htaccess) here, relative to this directory. These files are copied -# directly to the root of the documentation. -#html_extra_path = [] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -#html_last_updated_fmt = '%b %d, %Y' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -#html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -#html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -#html_additional_pages = {} - -# If false, no module index is generated. -#html_domain_indices = True - -# If false, no index is generated. -#html_use_index = True - -# If true, the index is split into individual pages for each letter. -#html_split_index = False - -# If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -#html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None - -# Language to be used for generating the HTML full-text search index. -# Sphinx supports the following languages: -# 'da', 'de', 'en', 'es', 'fi', 'fr', 'h', 'it', 'ja' -# 'nl', 'no', 'pt', 'ro', 'r', 'sv', 'tr' -#html_search_language = 'en' - -# A dictionary with options for the search language support, empty by default. -# Now only 'ja' uses this config value -#html_search_options = {'type': 'default'} - -# The name of a javascript file (relative to the configuration directory) that -# implements a search results scorer. If empty, the default will be used. -#html_search_scorer = 'scorer.js' - -# Output file base name for HTML help builder. -htmlhelp_basename = 'bmson-specdoc' - -# -- Options for LaTeX output --------------------------------------------- - -latex_elements = { -# The paper size ('letterpaper' or 'a4paper'). -#'papersize': 'letterpaper', - -# The font size ('10pt', '11pt' or '12pt'). -#'pointsize': '10pt', - -# Additional stuff for the LaTeX preamble. -#'preamble': '', - -# Latex figure (float) alignment -#'figure_align': 'htbp', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto, manual, or own class]). -latex_documents = [ - (master_doc, 'bmson-spec.tex', 'bmson-spec Documentation', - 'bmson team', 'manual'), -] - -# The name of an image file (relative to this directory) to place at the top of -# the title page. -#latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -#latex_use_parts = False - -# If true, show page references after internal links. -#latex_show_pagerefs = False - -# If true, show URL addresses after external links. -#latex_show_urls = False - -# Documents to append as an appendix to all manuals. -#latex_appendices = [] - -# If false, no module index is generated. -#latex_domain_indices = True - - -# -- Options for manual page output --------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - (master_doc, 'bmson-spec', 'bmson-spec Documentation', - [author], 1) -] - -# If true, show URL addresses after external links. -#man_show_urls = False - - -# -- Options for Texinfo output ------------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - (master_doc, 'bmson-spec', 'bmson-spec Documentation', - author, 'bmson-spec', 'One line description of project.', - 'Miscellaneous'), -] - -# Documents to append as an appendix to all manuals. -#texinfo_appendices = [] - -# If false, no module index is generated. -#texinfo_domain_indices = True - -# How to display URL addresses: 'footnote', 'no', or 'inline'. -#texinfo_show_urls = 'footnote' - -# If true, do not generate a @detailmenu in the "Top" node's menu. -#texinfo_no_detailmenu = False +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# bmson-spec documentation build configuration file, created by +# sphinx-quickstart on Sat Dec 26 09:59:57 2015. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys +import os +import shlex + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = 'bmson-spec' +copyright = '2015, bmson team' +author = 'bmson team' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '1.0.0' +# The full version, including alpha/beta/rc tags. +release = '1.0.0-beta' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +#keep_warnings = False + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = False + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'default' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +#html_extra_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Language to be used for generating the HTML full-text search index. +# Sphinx supports the following languages: +# 'da', 'de', 'en', 'es', 'fi', 'fr', 'h', 'it', 'ja' +# 'nl', 'no', 'pt', 'ro', 'r', 'sv', 'tr' +#html_search_language = 'en' + +# A dictionary with options for the search language support, empty by default. +# Now only 'ja' uses this config value +#html_search_options = {'type': 'default'} + +# The name of a javascript file (relative to the configuration directory) that +# implements a search results scorer. If empty, the default will be used. +#html_search_scorer = 'scorer.js' + +# Output file base name for HTML help builder. +htmlhelp_basename = 'bmson-specdoc' + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', + +# Latex figure (float) alignment +#'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'bmson-spec.tex', 'bmson-spec Documentation', + 'bmson team', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'bmson-spec', 'bmson-spec Documentation', + [author], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'bmson-spec', 'bmson-spec Documentation', + author, 'bmson-spec', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +#texinfo_no_detailmenu = False From 27778b9b0673bbd959c01818825cd9b2502f35bd Mon Sep 17 00:00:00 2001 From: Ignacio Conde Date: Tue, 24 Oct 2023 20:11:48 -0300 Subject: [PATCH 2/2] Added DJ.NEXT extension TODO: Add documentation details --- doc/index.rst | 2077 +++++++++++++++++++++++++------------------------ index.rst | 42 +- 2 files changed, 1080 insertions(+), 1039 deletions(-) diff --git a/doc/index.rst b/doc/index.rst index f5de5da..0864e81 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -1,1018 +1,1059 @@ -========================== -bmson format specification -========================== - -Version 1.1.0-beta (2022/07/05) - -Links -===== - -- Official Site: - https://bmson.nekokan.dyndns.info/ -- how_to_bmson (Japanese): - http://www40.atwiki.jp/laser_bm/pages/110.html -- #bmson Creaion Notes (English): - https://docs.google.com/document/d/1gQKPWApeL03aO09-II7slxTeuvm3HO_FmY1D4chRvOQ - -General -======= - -bmson is a file format based on JSON. - -Compared to BMS, it is a much easier format to handle on both artist and developer ends, as the format expects games to slice the sound stems during play rather than artists having to do all this work beforehand. This also removes the limit of keysounds you can have in a single chart, as well as it lets chart creators to use any part of any sound they want. - -For developers, it is easier to implement than BMS due to it being based on JSON, thus a JSON parser can make implementation of the format much quicker. - -.. admonition:: Notes - - - While this format is based on JSON, some bmson examples shown here are written in `YAML notation`_ instead, for conciseness and readability. - -.. _`YAML notation`: http://www.yaml.org/spec/1.2/spec.html - -Format Overview -=============== - -The format follows `Web IDL (Second Edition)`_ - -.. code-block:: c - - // top-level object - dictionary Bmson { - DOMString version; // bmson version - SongInfo song_info; // bmson information (title, artist, …) - ChartInfo chart_info; // chart information (level, chart_name, …) - ChartData chart_data; // chart data - } - - // header information - dictionary SongInfo { - DOMString title; // self-explanatory - DOMString artist; // self-explanatory - DOMString genre; // self-explanatory - } - - // chart info - dictionary ChartInfo { - DOMString subtitle = ""; // self-explanatory - DOMString[]? subartists = []; // ["key:value"] - DOMString chart_name; // e.g. "HYPER", "FOUR DIMENSIONS" - unsigned long level; // self-explanatory - DOMString? eyecatch_image; // eyecatch image filename - DOMString? banner_image; // banner image filename - DOMString? back_image; // background image filename - DOMString? preview_music; // preview music filename - BGA bga; // bga data - } - - // chart data - dictionary ChartData { - DOMString mode_hint = "beat-7k"; // layout hints, e.g. "beat-7k", "popn-5k", "generic-nkeys", "ez2-5k" - DOMString ln_type_hint = "ln"; // long note hints, e.g. "ln", "cn" - DOMString ln_judge_hint = "normal"; // long note judge hint, e.g. "normal", "tick" - DOMString ln_life_hint = "normal"; // long note life hint, e.g. "normal", "tick" - double init_bpm; // self-explanatory - double judge_multiplier = 1.00; // relative judge width - double life_multiplier = 1.00; // relative lifebar gain - unsigned long resolution = 240; // pulses per quarter note - BarLine[]? lines; // location of bar-lines in pulses - BpmEvent[]? bpm_events; // bpm changes - StopEvent[]? stop_events; // stop events - SoundChannel[] sound_channels; // note data - } - - // bar-line event - dictionary BarLine { - unsigned long y; // pulse number - } - // sound channel - dictionary SoundChannel { - DOMString name; // sound file name - NoteEvent[] note_events; // notes using this sound - } - - // sound note - dictionary NoteEvent { - any x; // lane - unsigned long y; // pulse number - unsigned long l; // length (0: normal note; greater than zero (length in pulses): long note) - boolean c; // continuation flag - - //Optional variables: - boolean up; - DOMString ln_type_hint; // long note hints, e.g. "ln", "cn" - DOMString ln_judge_hint; // long note judge hint, e.g. "normal", "tick" - DOMString ln_life_hint; // long note life hint, e.g. "normal", "tick" - } - - // bpm note - dictionary BpmEvent { - unsigned long y; // pulse number - double bpm; // bpm - } - - // stop note - dictionary StopEvent { - unsigned long y; // pulse number - unsigned long duration; // stop duration (pulses to stop) - } - - // for any custom classes of timing, - // follow format as bpmevent or stopevent. - // bga - dictionary BGA { - BGAHeader[] bga_header; // picture id and filename - BGAEvent[] bga_events; // picture sequence - BGAEvent[] layer_events; // picture sequence overlays bga_notes - BGAEvent[] poor_events; // picture sequence when missed - } - - // picture file - dictionary BGAHeader { - unsigned long id; // self-explanatory - DOMString name; // picture file name - } - - // bga note - dictionary BGAEvent { - unsigned long y; // pulse number - unsigned long id; // corresponds to BGAHeader.id - } - -.. _`Web IDL (Second Edition)`: https://heycam.github.io/webidl/ - -Changelog -========= - -1.0.1 (from 1.0.0) ------------------- - -Breaking Changes -~~~~~~~~~~~~~~~~ - -- Separate ``Bmson`` into ``Bmson`` and ``ChartData`` - - - ``Bmson.lines`` is now ``ChartData.lines`` - - ``Bmson.bpm_events`` is now ``ChartData.bpm_events`` - - ``Bmson.stop_events`` is now ``ChartData.stop_events`` - - ``Bmson.sound_channels`` is now ``ChartData.sound_channels`` - - ``Bmson.bga`` is now ``ChartInfo.bga`` - -- Separate ``BmsonInfo`` into ``SongInfo`` and ``ChartData`` - - - ``BmsonInfo.judge_rank`` is now ``ChartData.judge_multiplier`` - - ``BmsonInfo.total`` is now ``ChartData.life_multiplier`` - -- Separate ``BmsonInfo`` into ``SongInfo`` and ``ChartInfo`` - - - ``BmsonInfo.subtitle`` is now ``ChartInfo.subtitle`` - - ``BmsonInfo.subartists`` is now ``ChartInfo.subartists`` - - ``BmsonInfo.mode_hint`` is now ``ChartInfo.mode_hint`` - - ``BmsonInfo.chart_name`` is now ``ChartInfo.chart_name`` - - ``BmsonInfo.level`` is now ``ChartInfo.level`` - - ``BmsonInfo.back_image`` is now ``ChartInfo.back_image`` - - ``BmsonInfo.eyecatch_image`` is now ``ChartInfo.eyecatch_image`` - - ``BmsonInfo.banner_image`` is now ``ChartInfo.banner_image`` - - ``BmsonInfo.preview_music`` is now ``ChartInfo.preview_music`` - -- Rename objects - - - ``Note`` → ``NoteEvent`` - -- Rename fields - - - ``Bmson.info`` → ``Bmson.song_info`` - - ``SoundChannel.notes`` → ``SoundChannel.note_events`` - -- ``ChartData.life_multiplier`` and ``ChartData.judge_multiplier`` are now multiplier based instead of percentage based. - -Non Breaking Changes -~~~~~~~~~~~~~~~~~~~~ - -- Add fields - - - ``Bmson.chart_info`` - - ``Bmson.chart_data`` - - ``ChartData.ln_type_hint`` - - ``ChartData.ln_judge_hint`` - - ``ChartData.ln_life_hint`` - -- Add optional fields - - - ``NoteEvent.up`` - - ``NoteEvent.ln_type_hint`` - - ``NoteEvent.ln_judge_hint`` - - ``NoteEvent.ln_life_hint`` - -1.0.0 (from 0.21) ------------------ - -Breaking Changes -~~~~~~~~~~~~~~~~ - -- Change all *camelCased* fields to *snake_case*. - - - ``soundChannel`` - - ``judgeRank`` - - ``initBPM`` - - ``bgaHeader`` - - ``bgaNotes`` - - ``layerNotes`` - - ``poorNotes`` - - ``ID`` - -- Rename fields - - - ``bpmNotes`` → ``bpm_events`` - - ``stopEvents`` → ``stop_events`` - -- Remove fields - - - ``BarLine.k`` - - - It is unnecessary for common bmson format - -- Separate ``EventNote`` into ``BpmEvent`` and ``StopEvent`` - - - ``bpmNotes.v`` is now ``BpmEvent.bpm`` - - ``stopNotes.v`` is now ``StopEvent.duration`` - -- Time unit has been changed to *pulse* -- ``BMSInfo.total`` is changed to relative value - -Non Breaking Changes -~~~~~~~~~~~~~~~~~~~~ - -- Add fields - - - ``version`` - - ``BMSInfo.subtitle`` - - ``BMSInfo.subartists`` - - ``BMSInfo.mode_hint`` - - ``BMSInfo.chart_name`` - - ``BMSInfo.back_image`` - - ``BMSInfo.eyecatch_image`` - - ``BMSInfo.banner_image`` - - ``BMSInfo.preview_music`` - - ``BMSInfo.resolution`` - -Terminologies -============= - -Time Units ----------- - -There are three types of time unit: - -metric time (SI time): t - Measured in *second*. - -musical time: b - Measured in *beats*. The duration of a beat depends on BPM and stop notes. 1 beat = 1 quarter note in 4/4 measure. - -clock time (MIDI clock): y - Measured in *pulses*. A beat is split into discrete, equally-spaced pulses. The number of pulses in a beat depends on the beat resolution. Also known as *ticks* (programmer term) or *rows* (StepMania_ term). - -.. _StepMania: http://www.stepmania.com/ - -Beat Resolution ---------------- - -This is the number of pulses per one quarter note in a 4/4 measure. By default, this value is ``240``, which means that 1 quarter note is split into 240 pulses [#]_. - -.. figure:: images/time_units.png - - Example between beat, pulse, and metric time. - -.. admonition:: Notes - - In this document, we assume that resolution is always ``240``. - -.. [#] Many music games commonly use 48 pulses per quarter note (which means 192 pulses per 4/4 measure). It can handle up to 64th, 96th, and 192nd note, but fails to accommodate quintuplet notes (where a beat is divided into 5 equal intervals). 240 is the lowest common denominator of 48 and 5, and can represent up to 80th, 120th, and 240th note. - -Dimensions (what is *x* and *y*) --------------------------------- - -bmson is designed to be adaptable to multiple types of music games. For most music-based games, these are usually 2 common dimensions: - -- **Time**: When to activate? -- **Player channel**: How to activate? (For instance, in IIDX-style games, there are 8 playable channels: 1 turntable and 7 buttons). - -Given these two common dimensions, we can represent a note using an (x, y) coordinate like a piano roll, where x-coordinate represents the player channel, and y-coordinate represents the musical time. - -y: pulse number - We use *y* instead of *t*, because notes are specified in *pulse number*, as opposed to *metric time*. - -x: column / lane / button - It represents the player channel which the note is activated. - - In mode hint of ``beat-7k``, x = 1 through 7 are the keys, and 8 is the turntable. - - For the list of x value in conventional mode hints, see `Appendices/Canonical List of Mode Hints`_. - - .. _`Appendices/Canonical List of Mode Hints`: `Canonical List of Mode Hints`_ - -Top Level Object (Bmson) -======================== - -version :: DOMString - Specifies the version of this bmson. - - Currently possible value is ``1.0.0``. - -- Version numbers should be compared using the `Semantic Versioning 2.0.0`_ algorithm. -- bmson file without version field is a legacy bmson file. The implementor should either: - - - reject to process this file (the old format must be converted to new format), or - - process this file as bmson v0.21 (out of the scope of this specification). - -- If ``version`` is ``null``, the player should display an error message. - -.. _`Semantic Versioning 2.0.0`: http://semver.org/spec/v2.0.0.html - -Song Information Object (SongInfo) -============================== - -title :: DOMString - This is the title of song that will be displayed. - -- The implementor *need not* slice title string by delimiters (such as ``()``, ``--``) - -artist :: DOMString - This is the primary artist that will be displayed. - -- Usually, this is the music author. -- It may be contain multiple names in this string, for example: - - - ``Artist1 vs Artist2`` - - ``Artist1 feat. Vocalist`` - -genre :: DOMString - This is the genre of the song. - -Chart Information Object (ChartInfo) -==================================== - -subtitle :: DOMString - This is the subtitle of song that will be displayed. - - Default value is an empty string. - -- It is usually shown as a smaller text than ``title``. -- Multiple line subtitle may be possible by including a newline character ``\n`` - -subartists :: DOMString[] - Other artists that help authored this bmson file. - - Default value is an empty array. - -- This is useful for indexing and searching. For example, BMserver_. -- It is an array of strings, where each string is in form of ``key:value``. - - - ``key`` may be ``music``, ``vocal``, ``chart``, ``image``, ``movie``, ``other`` - - If ``key`` is omitted, default is ``other`` - - Others should only include a single name for each element. - - Implementers should trim the spaces before and after ``key`` and ``value``. - -- Example: ``"subartists": ["music:5argon", "music:encX", "chart:flicknote", "movie:5argon", "image:5argon"]`` - -.. _BMserver: http://bms.main.jp/ - -chart\_name :: DOMString - This is the chart name. - - Default value is an empty string. - -- Examples: ``BEGINNER``, ``NORMAL``, ``HYPER``, ``ANOTHER``, ``INSANE``, ``7keys Beginner`` - -level :: unsigned long - A value that shows the level of the note chart. - -- It is usually determined by subjective evaluation of the creator. It is recommended that the level number is based on the level scale of the base game. - -- For example, in ``beat`` mode, the level should be considered based on scale of 1~12. - -- ``level`` must be ≥0. Negative values may be regarded as invalid by a player. - -eyecatch\_image :: DOMString - The path to an image that may be displayed during song loading. - -- If eyecatch\_image is undefined, null or empty, player uses default eyecatch image. - -title\_image :: DOMString - The path to an image that will be displayed before song starts. - -- This is equivalent to `#BACKBMP in OADX+ skin`_. -- If ``title_image`` is undefined, null or empty, player will show title with default font. - -.. _`#BACKBMP in OADX+ skin`: http://www.geocities.jp/red_without_right_stick/backbmp/index.html - -banner\_image :: DOMString - The path to an image that may be displayed in song selection or result screen. - -- The image size should be 15:4, normally 600x160. Other sizes following this ratio (such as 900x240) are allowed for some high-resolution displays. - -back\_image :: DOMString - The path to a static background image that may be displayed during gameplay. - -- If ``back_image`` is undefined, null or empty, player uses default background image. -- Example: `Toy Musical 2`_ - -.. _`Toy Musical 2`: https://www.youtube.com/watch?v=8mDNzrQBlBY - -preview\_music :: DOMString - The path to an short audio file which preview the music. - -- If ``preview_music`` is not specified, player can create preview from ``sound_channels``. - -Chart Data Object (ChartData) -============================== - -mode\_hint :: DOMString - Specifies the game mode. - - Default value is ``beat-7k``. - -- Implementors should look at ``mode_hint`` to check if the note is designed for that particular kind of game mode. For example, 8-key games are different from IIDX-style games, even though they use exactly the same channel numbers. -- A layout for a generic symmetrical keyboard layout should use ``generic-nkeys`` where ``n`` is the number of keys. It should be ordered left to right. - -.. admonition:: Extension tip: On adding a mode that is not listed in this document - - A player may judge whether the format is supported by the player through ``version`` and ``mode_hint``. Therefore if you create an extension format, you should use a different ``mode_hint`` so that a player can judge what to do with the chart. You should not modify ``version``, because it represents underlying bmson format version. - -ln\_type\_hint :: DOMString - Specifies the long note type. - - Default value is ``ln``. - -- Implementors should look at ``ln_type_hint`` to check how to judge long notes **by default**. -- Implementors should note that **this may be optionally overridden** at each ``NoteEvent``. - -.. admonition:: Possible values - - - ``ln`` means that only the initial press is judged. - - ``cn`` means that both the initial press and the release are judged separately. - -ln\_judge\_hint :: DOMString - Specifies the long note judge type. - - Default value is ``normal``. - -- Implementors should look at ``ln_judge_hint`` to check how to handle long note judge **by default**. -- Implementors should note that **this may be optionally overridden** at each ``NoteEvent``. - -.. admonition:: Possible values - - - ``normal`` means that only the corresponding notes are judged, depending on ``ln_type_hint``. - - ``ticks`` means that additionally during the long note, extra 'ticks' are going to be judged. - -ln\_life\_hint :: DOMString - Specifies the long note life type. - - Default value is ``normal``. - -- Implementors should look at ``ln_life_hint`` to check how to handle long note life **by default**. -- Implementors should note that **this may be optionally overridden** at each ``NoteEvent``. - -.. admonition:: Possible values - - - ``normal`` means that only the corresponding notes replenish life, depending on ``ln_type_hint``. - - ``ticks`` means that additionally during the long note, extra 'ticks' are going to be judged. - -init\_bpm :: double - A value that shows the tempo at the start of the song. - -- It is a fatal error if ``init_bpm`` is unspecified. - -judge\_multiplier :: double - Specifies the width of judgment window. - - Default value is ``1.00``. - -- If ``judge_multiplier`` is larger than ``1.00``, judgment window is wider than player’s default. -- If ``judge_multiplier`` is smaller than ``1.00``, judgment window is narrower than player’s default. -- The implementation depends of each player. - -.. admonition:: A possible interpretation - - This section is provided as information only and is non-normative. - - - The ``judge_multiplier`` may be interpreted as a multiplier of judgment window. - - For example, to get a PERFECT judgment normally, you must hit the key within 20 millisecond window. - - If ``judge_multiplier`` is 2.50, then this judgement window is 2.5x the normal size, which is equal to 50 milliseconds. This make this chart easier. - - If ``judge_multiplier`` is 0.50, then judgement window is 0.5x the normal size (2x smaller). You must hit the key within 10 millisecond window. - -Here are the default judgment windows of some popular players. - -============= ======== ========== ======== -LunaticRave2_ [#]_ Bemuse_ -====================== =================== -Perfect GREAT ≤ 18 ms METICULOUS ≤ 20 ms -GREAT ≤ 40 ms PRECISE ≤ 50 ms -GOOD ≤ 100 ms GOOD ≤ 100 ms -BAD ≤ 200 ms OFFBEAT ≤ 200 ms -POOR > 200 ms MISSED > 200 ms -============= ======== ========== ======== - -.. _LunaticRave2: http://www.lr2.sakura.ne.jp/index2.html -.. _Bemuse: http://bemuse.ninja/ - -.. [#] #RANK 2 (NORMAL) - -life\_multiplier :: double - Default value is ``1.00``. - -- ``life_multiplier`` must be ≥ 0. - - - If 0, the lifebar doesn’t increase. - - If negative, take the absolute value. - -- It defines how much lifebar (also known as *groove gauge*) increases in number compared with default rate. - - - Default rate depends on each player. - - If ``life_multiplier`` is larger than ``1.00``, lifebar increases more when a note is played with high accuracy. - - If ``life_multiplier`` is smaller than ``1.00``, lifebar increases less when a note is played with high accuracy. - - It can also be a reference to how much lifebar decreases when a game player missed a note. - - - This behavior may also be different by each player. - -.. admonition:: Reference - - IIDX’s default rate approximation: - If player played all notes perfectly, the groove gauge increases by ``7.605 * n / (0.01 * n + 6.5)`` percent. - -resolution :: unsigned long - This is the number of pulses per one quarter note in a 4/4 measure. - - Default value is ``240``. - -- ``resolution`` must be > 0. - - - If 0, ``null`` or ``undefined``, use the default value. - - If negative, take the absolute value. - -- For detailed information, see `Terminologies/Beat Resolution`_. - -.. _`Terminologies/Beat Resolution`: `Beat Resolution`_ - -Time Signatures -=============== - -- **bmson does not have a native notion of ‘measures’ or ‘time signatures’**, but has a concept of *bar lines* instead. -- In BMS, notes are based on ‘measure number’ and ‘fraction of measure.’ The actual time of an event is also dependent on the time signature. -- In bmson, everything is based on a ‘pulse number,’ and is independent from any time signature or measure. A pulse is always a fraction of a quarter note in a 4/4 measure. - -lines :: BarLine[] - \ - -- Each BarLine object contains the y-position of each bar line to be displayed onscreen. - - - This can be used to simulate a notion of time signature. - -- The first bar line at ``y: 0`` can be omitted. - - - If it is present or omitted, it is up to the player whether to display this bar line or not. - -- If this is a blank array, then a chart will not have any barline, resulting in an effect as in \ `100% minimoo-G`_. -- If this is not specified (``null`` or ``undefined``), then a 4/4 time signature is assumed, and a bar line will be generated every 4 quarter notes. - -- Using the default resolution, a bar line will be generated every 960 pulses. - -.. _`100% minimoo-G`: https://www.youtube.com/watch?v=f1VBBNrSdgk - -+--------------------------------------+--------------------------------------+ -| **4/4 time signature** | .. code-block:: yaml | -| | | -| (common time) | lines: | -| | - y: 960 | -| | - y: 1920 | -| | - y: 2880 | -| | - y: 3840 | -| | # ... | -+--------------------------------------+--------------------------------------+ -| **3/4 time signature** | .. code-block:: yaml | -| | | -| (tempus perfectum) | lines: | -| | - y: 720 | -| | - y: 1440 | -| | - y: 2160 | -| | - y: 2880 | -| | # ... | -+--------------------------------------+--------------------------------------+ -| **Mapping from BMS** | .. code-block:: yaml | -| | | -| .. code:: | lines: | -| | - y: 960 # 000~001: 960 | -| #00102:0.75 | - y: 1680 # 001~002: 720 | -| #00302:1.25 | - y: 2640 # 002~003: 960 | -| | - y: 3840 # 003~004: 1200 | -| | # ... | -+--------------------------------------+--------------------------------------+ - -Timing -====== - -bpm\_events :: BpmEvent[] -- Tempo Changes - At the start of the song, the music will progress at a tempo specified in ``info.init_bpm``. - -- It is a fatal error if ``info.init_bpm`` is unspecified. -- When a ``BpmEvent`` is encountered, the tempo is changed to the value specified in the ``bpm`` field. -- If there are many ``BpmEvent`` at the same time, the BPM will change to the last one. -- Example: ``[ { y: 240, bpm: 100 }, { y: 240, bpm: 120 } ]`` → Tempo is changed to 120 BPM. - -stop\_events :: StopEvent[] -- Stops - When a ``StopEvent`` is encountered, the music will pause for a duration equivalent to a number of pulses specified in ``duration`` field. - -- If there are many ``StopEvent`` at the same time, these stop events add up. - -- Example: ``[ { y: 240, duration: 240 }, { y: 240, duration: 960 } ]`` → Scrolling stops for 1200 pulses. - -Order of Processing -------------------- - -- In case multiple events occur in the same pulse, events are processed in this order: - - - ``NoteEvent``, ``BGAEvent`` - - ``BpmEvent`` - - ``StopEvent`` - -- This is consistent with how BMS players interpret these events. -- If a ``StopEvent`` and a ``BpmEvent`` appear on the same pulse, the tempo will change first, then the music pauses. In other words, use the tempo at the pulse of the ``BpmEvent`` for calculating the duration of the stop in seconds, as well as any timing class similar to ``StopEvent``. -- If a ``StopEvent`` and a NoteEvent appear on the same pulse: - - - If it is a BGM note, the sound slice is played first, then the music pauses. - - If it is a playable note, the player must hit the note when the music pauses (not when the music resumes). - - For example, consider the following notes and stops: - - .. code-block:: yaml - - stop: { y: 240, duration: 240 } - note: { y: 240 } - - - This means the position ``y: 240`` covers a range of time, rather than a precise point in time (because speed is zero during the pause). - - When the current bpm value is 60, the correspondence of *y (pulse number)* and *t (metric time)* is as follows: - - ========== ============= - y (pulses) t (second) - ========== ============= - 0 0.0 - 120 0.5 - 239 239 / 240 - 240 1.0 ≤ t ≤ 2.0 - 241 481 / 240 - ========== ============= - - At ``y: 240`` the time is ambiguous. - - Therefore, this specification defines that the note at ``y: 240`` must be activated at ``t = 1.0`` (beginning of the pause). - -.. admonition:: Extension tip: On adding a timing class - - As written above, any accumulative timing class should follow the format of ``StopEvent``, and use a duration in pulses. A fixed-amount timing class should use the unit corresponding to its class, like ``BpmEvent`` does. - -Sound Channels -============== - -**bmson is sound channel based.** Notes from the same sound channel are -grouped together in the same array. - -sound\_channels :: SoundChannel[] - A sound channel represents an audio track. - - .. image:: images/sound_channels.png - -Slicing and Restarting ----------------------- - -The notes inside this sound channel determines how to slice and when to -restart. - -.. figure:: images/slicing_1.png - - Notes at different times caused sounds to be sliced at different time. - -.. figure:: images/slicing_2.png - - The highlighted ``SoundChannel`` represents a kick sound. Instead of repeating a kick sound many time, leading to a redundant audio file, the ``SoundChannel`` is restarted instead. - -name :: DOMString - This represents the filename of the audio track. - -- A file extension may be omitted. - - - If file extension is omitted, then the implementation should search for compatible sound file with that name. - - Example: ``{ name: “piano” }`` → Try ``piano.wav``, ``piano.ogg``, ``piano.m4a``, … - -- If file extension is provided but the file is not found or cannot be played, then the implementation should treat the file name as if its extension is removed. - - - Example: ``{ name: "piano.wav" }`` → ``piano.wav`` not found → Treat as ``"piano"`` → Try ``piano.wav``, ``piano.ogg``, … - - Example: ``{ name: "piano.ogg" }`` → ogg not supported → Treat as ``"piano"`` → Try ``piano.wav``, ``piano.ogg``, ``piano.m4a``… - -- The sound files may live in subdirectories relative to bmson file. - - - Path may be separated using backslash (``\``) or forward slash (``/``), the implementation should normalize them. - - The implementation must protect from malicious paths: - - - Absolute path: ``C:\password.txt`` or ``/etc/passwd`` - - Reference to parent directory: ``../../../var/www/html/config.php`` - - Null characters (``\0``) - - - Example: ``{ name: "intro\\drum" }`` - -Sound File Format Recommendation -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Players are expected to support these file formats: - -- Microsoft WAV file (.wav). -- Either OGG Vorbis (.ogg) or MP4 AAC (.m4a). - -OGG Vorbis is a free file format, and can be used freely, and is very easy to create. Unfortunately, not every platform supports decoding OGG files natively (with hardware acceleration). - -MP4 is the most common multimedia file format used in mobile phones with native support for Android and iOS, but it’s harder to create an MP4 file. - -.. warning:: - - MP3 file format is discouraged. - - Both MP3 encoder and decoders add silence to the beginning and end of file [#]_. - - This causes sounds to be shifted, sometimes as much as 20 milliseconds. This could change a Perfect GREAT into a GREAT. - -.. [#] http://lame.sourceforge.net/tech-FAQ.txt - -note_events :: NoteEvent[] - \ - -- ``x`` is the player channel for this note. - - - ``0`` or ``null`` → this is not a playable note (BGM note) - - ``1``, ``2``, ``3``, … → this is a playable note - -- ``y`` is the time (the pulse number) that this note must be activated -- ``l`` is the length of note - - - ``0`` → this is a short note - - ``> 0`` → this is a long note, starting at pulse ``y``, ending at ``y + l``. - -- ``c`` is the continuation flag - - - ``true`` → continue — don’t restart - - ``false`` → don’t continue — restart the audio - -.. admonition:: Optional variables - - - ``up`` is the up keysound flag, used for CN, BSS and MSS (Charge Note, BackSpin and MultiSpin Scratch). - - - For release keysound or BSS, a normal note with ``true`` must be layered on top of the end of the long note. - - For MSS a long note with ``true`` must be layered on top of the end of the long note. - - - This note can use the long note hint overrides detailed below to alter long note behaviour. - - ``ln_type_hint`` is the long note type hint override. Refer to ``ChartData`` documentation for more info. - - ``ln_judge_hint`` is the long note judge hint override. Refer to ``ChartData`` documentation for more info. - - ``ln_life_hint`` is the long note life hint override. Refer to ``ChartData`` documentation for more info. - -Slicing Algorithm (Roughly) ---------------------------- - -The high-level algorithm to slice is as follows. - -#. Gather all the pulse numbers in this ``SoundChannel``’s notes. Discard the duplicates. -#. Convert these pulse numbers into metric time (in seconds). -#. Restart the audio whenever a note without a continuation flag is encountered. -#. Slice the resulting audio, using the time values from step 2. as slicing points. -#. Each note is assigned a slice that starts at the same time as the note. - -Slicing Example -~~~~~~~~~~~~~~~ - -Given this ``SoundChannel`` object: - -.. code-block:: yaml - - sound_channels: - - name: vox.wav - note_events: - - { x: 1, y: 240, c: false } # 1 - - { x: 3, y: 360, c: true } # 2 - - { x: 7, y: 360, c: true } # 3 - - { x: 2, y: 720, c: false } # 4 - - { x: 3, y: 720, c: false } # 5 - - { x: 4, y: 840, c: true } # 6 - - { x: 6, y: 840, c: true } # 7 - - { x: 3, y: 1200, c: true } # 8 - - { x: 0, y: 1680, c: true } # 9 - -We obtain these information (given BPM=120): - -============ ==== ======= ======== ===== ======= -Pulse Number Beat Seconds Restart? Notes Slice # -============ ==== ======= ======== ===== ======= -240 1 0.5 true 1 1 -360 1.5 0.75 false 2, 3 2 -720 3 1.5 true 4, 5 3 -840 3.5 1.75 false 6, 7 4 -1200 5 2.5 false 8 5 -1680 7 3.5 false 9 6 -============ ==== ======= ======== ===== ======= - -Slicing based on these slicing points, we obtain these slices: - -======= ================ ============== ================== -Slice # Audio Start Time Audio End Time Slice Duration (s) -======= ================ ============== ================== -1 0 0.25 0.25 -2 0.25 1 0.75 -3 1 1.25 0.25 -4 1.25 2 0.75 -5 2 3 1 -6 3 (end of file) -======= ================ ============== ================== - -Sliced sound looks like this: - -.. image:: images/slicing_3.png - -Finally, these slices become associated with the notes. - -From the table above, **multiple notes may be assigned the same slice**. - -Edge Cases -~~~~~~~~~~ - -- If a same slice is assigned to both playable and BGM note, then the BGM note must be discarded. - - Example: - - .. code-block:: yaml - - sound_channels: - - file: kick.wav - notes: - - { x: 0, y: 960 } # (x) - - { x: 1, y: 960 } - - { x: 3, y: 960 } - - Here, the note marked (x) must be discarded. - -- If multiple notes are on the same pulse, and some have continuation flag set, but not all, the implementation should consider that the continuation flag is not set. - -Playback Behavior -~~~~~~~~~~~~~~~~~ - -- Each slice only has a polyphony of 1. - - This means that if a slice has been assigned to two or more notes (obviously, at the same pulse) and they are triggered simultaneously, this slice should not sound louder than normal. - - However, if different slices from the same sound channel are played, they should play simultaneously. - -- You may treat each slice like a #WAV channel in BMS files. -- Note that multiple sound channel may refer to the same file. - - - This is a different sound channel, so they can play simultaneously. This is matching with `multiplex WAV definitions`_. - -.. _`multiplex WAV definitions`: http://hitkey.nekokan.dyndns.info/cmds.htm#WAVXX-MULTIPLEX-DEFINITION - -.. admonition:: Recommendation for Implementations - - *This section is non-normative.* - - You may join consecutive slices if these slices are only used by BGM notes. This can reduce the number of slices and may improve sound smoothness and performance. - - A rough algorithm: - - .. code:: - - for each pair of consecutive slice s1 and s2 - if either slice is used by non-BGM note - don’t join - else if s2 is not continuing (c: false) - don’t join - else - join them together - -Layered Notes -------------- - -- In the case that notes from different sound channel exist on same (x, y) position, - - - The notes from these sound channels are “fusioned” and become a single note. When this note is played, the sound slice from each original sound channel is played. - - It is an error if length is unequal (player may issue a warning). - -bga :: BGA -========== - -Currently, BGA specification is just compatible with BMS. - -bga\_header :: BGAHeader[] - \ - -- ``id`` is picture file identifier. - - - If there is the same value in one file, player may issue a warning, taking posterior one. - -- ``name`` is the path to the picture file. - -- Recommended picture size is 1280x720. 1920x1080 is also acceptable. - - - In game with different aspect ratio, the background image may be cropped in the center. Therefore, make sure that the key elements are near the center of the image. - -- Players are expected to support these file formats: - - - Pictures: PNG - - Video: WebM - - - Audio channels may be ignored. - - -bga\_events, layer\_events, poor\_events :: BGAEvent[] - ``bga_events`` represent image/video files that will be displayed as the song’s background animation [#]_. - - ``layer_events`` represent image/video files that will be *layered* on top of the BGA. - -- ``id`` specifies picture declared at ``bga_header``. - -- ``y`` is pulse number when the picture is shown. - -- Unlike \ `BMS Layer Channel #xxx07`_, black pixels will not be made transparent. If you want transparency, use a file format that support transparency, such as PNG [#]_. - -.. _`BMS Layer Channel #xxx07`: http://hitkey.nekokan.dyndns.info/cmds.htm#BMPXX-LAYER - -.. [#] Some game may choose to display the BGA as the background, and overlay notes on top of it. Example commercial games that use this approach are DJ MAX series, DDR, and `Pump It Up`_. Other games may display the BGA in a dedicated space. Examples are beatmaniaIIDX and `LunaticRave2`_. - -.. [#] By extension, this means that a converter should convert a BMP files into PNG in a way that a perfect black pixel is turned into a transparent pixel. Note that a same image file may be used both as BGA and LAYER, so a single BMP file may have to be converted into two different PNG files. - -.. _`Pump It Up`: http://www.piugame.com/ -.. _`LunaticRave2`: http://www.lr2.sakura.ne.jp/index2.html - - -Appendices -========== - -Canonical List of Mode Hints ----------------------------- - -Left-most values are ``mode_hint``. - -Beat: ------ -============ == == == == == == == == == == == == == == == == -**x** 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 -============ == == == == == == == == == == == == == == == == -mode_hint Player 1 Player 2 ------------- ----------------------- ----------------------- -**beat-5k** 1 2 3 4 5 SC -**beat-7k** 1 2 3 4 5 6 7 SC -**beat-10k** 1 2 3 4 5 SC 1 2 3 4 5 SC -**beat-14k** 1 2 3 4 5 6 7 SC 1 2 3 4 5 6 7 SC -============ == == == == == == == == == == == == == == == == - -SC: Scratch (Turntable) - -Popn: ------ -=========== = = = = = = = = = -**x** 1 2 3 4 5 6 7 8 9 -=========== = = = = = = = = = -mode_hint Buttons ------------ ----------------- -**popn-5k** 1 2 3 4 5 -**popn-9k** 1 2 3 4 5 6 7 8 9 -=========== = = = = = = = = = - -EZ2: ----- -Player 1 side: - -================= == == == == == == == == == == == == == == == == == == -**x** 1 11 12 13 14 15 10 31 32 33 34 20 21 22 23 24 25 2 -================= == == == == == == == == == == == == == == == == == == -mode_hint Buttons side 1 Effectors Buttons side 2 ------------------ -------------------- ----------- -------------------- -**ez2-5k-only** 1 2 3 4 5 -**ez2-ruby** SC 1 2 3 4 5 PD -**ez2-5k** SC 1 2 3 4 5 PD -**ez2-7k** SC 1 2 3 4 5 PD E1 E2 -**ez2-10k** SC 1 2 3 4 5 PD 6 7 8 9 10 SC -**ez2-14k** SC 1 2 3 4 5 E1 E2 E3 E4 6 7 8 9 10 SC -**ez2-andromeda** SC 1 2 3 4 5 PD E1 E2 E3 E4 PD 6 7 8 9 10 SC -================= == == == == == == == == == == == == == == == == == == - -Player 2 side: - -================= == == == == == == == == == == == == == == == == == == -**x** 2 25 24 23 22 21 20 34 33 32 31 10 15 14 13 12 11 1 -================= == == == == == == == == == == == == == == == == == == -mode_hint Buttons side 1 Effectors Buttons side 2 ------------------ -------------------- ----------- -------------------- -**ez2-5k-only** 6 7 8 9 10 -**ez2-ruby** PD 6 7 8 9 10 SC -**ez2-5k** PD 6 7 8 9 10 SC -**ez2-7k** E3 E4 PD 6 7 8 9 10 SC -**ez2-10k** SC 1 2 3 4 5 PD 6 7 8 9 10 SC -**ez2-14k** SC 1 2 3 4 5 E1 E2 E3 E4 6 7 8 9 10 SC -**ez2-andromeda** SC 1 2 3 4 5 PD E1 E2 E3 E4 PD 6 7 8 9 10 SC -================= == == == == == == == == == == == == == == == == == == - -SC: Scratch (Turntable) - -PD: Pedal +========================== +bmson format specification +========================== + +Version 2.0.0 (2023/10/24) + +Links +===== + +- Official Site: + https://bmson.nekokan.dyndns.info/ +- how_to_bmson (Japanese): + http://www40.atwiki.jp/laser_bm/pages/110.html +- #bmson Creaion Notes (English): + https://docs.google.com/document/d/1gQKPWApeL03aO09-II7slxTeuvm3HO_FmY1D4chRvOQ + +General +======= + +bmson is a file format based on JSON. + +Compared to BMS, it is a much easier format to handle on both artist and developer ends, as the format expects games to slice the sound stems during play rather than artists having to do all this work beforehand. This also removes the limit of keysounds you can have in a single chart, as well as it lets chart creators to use any part of any sound they want. + +For developers, it is easier to implement than BMS due to it being based on JSON, thus a JSON parser can make implementation of the format much quicker. + +.. admonition:: Notes + + - While this format is based on JSON, some bmson examples shown here are written in `YAML notation`_ instead, for conciseness and readability. + +.. _`YAML notation`: http://www.yaml.org/spec/1.2/spec.html + +Format Overview +=============== + +The format follows `Web IDL (Second Edition)`_ + +.. code-block:: c + + // top-level object + dictionary Bmson { + DOMString version; // bmson version + SongInfo song_info; // bmson information (title, artist, …) + ChartInfo chart_info; // chart information (level, chart_name, …) + ChartData chart_data; // chart data + } + + // header information + dictionary SongInfo { + DOMString title; // self-explanatory + DOMString artist; // self-explanatory + DOMString genre; // self-explanatory + } + + // chart info + dictionary ChartInfo { + DOMString subtitle = ""; // self-explanatory + DOMString[]? subartists = []; // ["key:value"] + DOMString chart_name; // e.g. "HYPER", "FOUR DIMENSIONS" + unsigned long level; // self-explanatory + DOMString? eyecatch_image; // eyecatch image filename + DOMString? banner_image; // banner image filename + DOMString? back_image; // background image filename + DOMString? preview_music; // preview music filename + BGA bga; // bga data + } + + // chart data + dictionary ChartData { + DOMString mode_hint = "beat-7k"; // layout hints, e.g. "beat-7k", "popn-5k", "generic-nkeys", "ez2-5k" + DOMString ln_type_hint = "ln"; // long note hints, e.g. "ln", "cn" + DOMString ln_judge_hint = "normal"; // long note judge hint, e.g. "normal", "tick" + DOMString ln_life_hint = "normal"; // long note life hint, e.g. "normal", "tick" + double init_bpm; // self-explanatory + double judge_multiplier = 1.00; // relative judge width + double life_multiplier = 1.00; // relative lifebar gain + unsigned long resolution = 240; // pulses per quarter note + BarLine[]? lines; // location of bar-lines in pulses + BpmEvent[]? bpm_events; // bpm changes + StopEvent[]? stop_events; // stop events + SoundChannel[] sound_channels; // note data + + // DJ.NEXT Extension: + JudgementDeltas judge_deltas; // custom judgement window deltas in ms + LifeDeltas life_deltas; // custom life increments/decrements in percentage + } + + // bar-line event + dictionary BarLine { + unsigned long y; // pulse number + } + + // sound channel + dictionary SoundChannel { + DOMString name; // sound file name + NoteEvent[] note_events; // notes using this sound + } + + // sound note + dictionary NoteEvent { + any x; // lane + unsigned long y; // pulse number + unsigned long l; // length (0: normal note; greater than zero (length in pulses): long note) + boolean c; // continuation flag + + // Optional variables: + boolean up; + DOMString ln_type_hint; // long note hints, e.g. "ln", "cn" + DOMString ln_judge_hint; // long note judge hint, e.g. "normal", "tick" + DOMString ln_life_hint; // long note life hint, e.g. "normal", "tick" + + // DJ.NEXT Extension: + signed byte vol; // sound volume in percentage + signed byte pan; // sound panning + } + + // bpm note + dictionary BpmEvent { + unsigned long y; // pulse number + double bpm; // bpm + } + + // stop note + dictionary StopEvent { + unsigned long y; // pulse number + unsigned long duration; // stop duration (pulses to stop) + } + + // for any custom classes of timing, + // follow format as bpmevent or stopevent. + // bga + dictionary BGA { + BGAHeader[] bga_header; // picture id and filename + BGAEvent[] bga_events; // picture sequence + BGAEvent[] layer_events; // picture sequence overlays bga_notes + BGAEvent[] poor_events; // picture sequence when missed + } + + // picture file + dictionary BGAHeader { + unsigned long id; // self-explanatory + DOMString name; // picture file name + } + + // bga note + dictionary BGAEvent { + unsigned long y; // pulse number + unsigned long id; // corresponds to BGAHeader.id + } + + + // DJ.NEXT Extension: + // ------------------ + + // judgement delta values + dictionary JudgementDeltas { + unsigned long perfect; // perfect window delta in ms + unsigned long great; // great window delta in ms + unsigned long good; // good window delta in ms + unsigned long miss; // miss window delta in ms + } + + // life delta values + dictionary LifeDeltas { + signed float perfect; // perfect life delta in percent + signed float great; // great life delta in percent + signed float good; // good life delta in percent + signed float miss; // miss life delta in percent + } + +.. _`Web IDL (Second Edition)`: https://heycam.github.io/webidl/ + +Changelog +========= + +2.0.0 (from 1.0.0) +------------------ + +Breaking Changes +~~~~~~~~~~~~~~~~ + +- Separate ``Bmson`` into ``Bmson`` and ``ChartData`` + + - ``Bmson.lines`` is now ``ChartData.lines`` + - ``Bmson.bpm_events`` is now ``ChartData.bpm_events`` + - ``Bmson.stop_events`` is now ``ChartData.stop_events`` + - ``Bmson.sound_channels`` is now ``ChartData.sound_channels`` + - ``Bmson.bga`` is now ``ChartInfo.bga`` + +- Separate ``BmsonInfo`` into ``SongInfo`` and ``ChartData`` + + - ``BmsonInfo.judge_rank`` is now ``ChartData.judge_multiplier`` + - ``BmsonInfo.total`` is now ``ChartData.life_multiplier`` + +- Separate ``BmsonInfo`` into ``SongInfo`` and ``ChartInfo`` + + - ``BmsonInfo.subtitle`` is now ``ChartInfo.subtitle`` + - ``BmsonInfo.subartists`` is now ``ChartInfo.subartists`` + - ``BmsonInfo.mode_hint`` is now ``ChartInfo.mode_hint`` + - ``BmsonInfo.chart_name`` is now ``ChartInfo.chart_name`` + - ``BmsonInfo.level`` is now ``ChartInfo.level`` + - ``BmsonInfo.back_image`` is now ``ChartInfo.back_image`` + - ``BmsonInfo.eyecatch_image`` is now ``ChartInfo.eyecatch_image`` + - ``BmsonInfo.banner_image`` is now ``ChartInfo.banner_image`` + - ``BmsonInfo.preview_music`` is now ``ChartInfo.preview_music`` + +- Rename objects + + - ``Note`` → ``NoteEvent`` + +- Rename fields + + - ``Bmson.info`` → ``Bmson.song_info`` + - ``SoundChannel.notes`` → ``SoundChannel.note_events`` + +- ``ChartData.life_multiplier`` and ``ChartData.judge_multiplier`` are now multiplier based instead of percentage based. + +Non Breaking Changes +~~~~~~~~~~~~~~~~~~~~ + +- Add fields + + - ``Bmson.chart_info`` + - ``Bmson.chart_data`` + - ``ChartData.ln_type_hint`` + - ``ChartData.ln_judge_hint`` + - ``ChartData.ln_life_hint`` + +- Add optional fields + + - ``NoteEvent.up`` + - ``NoteEvent.ln_type_hint`` + - ``NoteEvent.ln_judge_hint`` + - ``NoteEvent.ln_life_hint`` + +- Add objects (DJ.NEXT extension) + + - ``JudgementDeltas`` + - ``LifeDeltas`` + +- Add fields (DJ.NEXT extension) + + - ``ChartData.judge_deltas`` + - ``ChartData.life_deltas`` + - ``NoteEvent.vol`` + - ``NoteEvent.pan`` + +1.0.0 (from 0.21) +----------------- + +Breaking Changes +~~~~~~~~~~~~~~~~ + +- Change all *camelCased* fields to *snake_case*. + + - ``soundChannel`` + - ``judgeRank`` + - ``initBPM`` + - ``bgaHeader`` + - ``bgaNotes`` + - ``layerNotes`` + - ``poorNotes`` + - ``ID`` + +- Rename fields + + - ``bpmNotes`` → ``bpm_events`` + - ``stopEvents`` → ``stop_events`` + +- Remove fields + + - ``BarLine.k`` + + - It is unnecessary for common bmson format + +- Separate ``EventNote`` into ``BpmEvent`` and ``StopEvent`` + + - ``bpmNotes.v`` is now ``BpmEvent.bpm`` + - ``stopNotes.v`` is now ``StopEvent.duration`` + +- Time unit has been changed to *pulse* +- ``BMSInfo.total`` is changed to relative value + +Non Breaking Changes +~~~~~~~~~~~~~~~~~~~~ + +- Add fields + + - ``version`` + - ``BMSInfo.subtitle`` + - ``BMSInfo.subartists`` + - ``BMSInfo.mode_hint`` + - ``BMSInfo.chart_name`` + - ``BMSInfo.back_image`` + - ``BMSInfo.eyecatch_image`` + - ``BMSInfo.banner_image`` + - ``BMSInfo.preview_music`` + - ``BMSInfo.resolution`` + +Terminologies +============= + +Time Units +---------- + +There are three types of time unit: + +metric time (SI time): t + Measured in *second*. + +musical time: b + Measured in *beats*. The duration of a beat depends on BPM and stop notes. 1 beat = 1 quarter note in 4/4 measure. + +clock time (MIDI clock): y + Measured in *pulses*. A beat is split into discrete, equally-spaced pulses. The number of pulses in a beat depends on the beat resolution. Also known as *ticks* (programmer term) or *rows* (StepMania_ term). + +.. _StepMania: http://www.stepmania.com/ + +Beat Resolution +--------------- + +This is the number of pulses per one quarter note in a 4/4 measure. By default, this value is ``240``, which means that 1 quarter note is split into 240 pulses [#]_. + +.. figure:: images/time_units.png + + Example between beat, pulse, and metric time. + +.. admonition:: Notes + + In this document, we assume that resolution is always ``240``. + +.. [#] Many music games commonly use 48 pulses per quarter note (which means 192 pulses per 4/4 measure). It can handle up to 64th, 96th, and 192nd note, but fails to accommodate quintuplet notes (where a beat is divided into 5 equal intervals). 240 is the lowest common denominator of 48 and 5, and can represent up to 80th, 120th, and 240th note. + +Dimensions (what is *x* and *y*) +-------------------------------- + +bmson is designed to be adaptable to multiple types of music games. For most music-based games, these are usually 2 common dimensions: + +- **Time**: When to activate? +- **Player channel**: How to activate? (For instance, in IIDX-style games, there are 8 playable channels: 1 turntable and 7 buttons). + +Given these two common dimensions, we can represent a note using an (x, y) coordinate like a piano roll, where x-coordinate represents the player channel, and y-coordinate represents the musical time. + +y: pulse number + We use *y* instead of *t*, because notes are specified in *pulse number*, as opposed to *metric time*. + +x: column / lane / button + It represents the player channel which the note is activated. + + In mode hint of ``beat-7k``, x = 1 through 7 are the keys, and 8 is the turntable. + + For the list of x value in conventional mode hints, see `Appendices/Canonical List of Mode Hints`_. + + .. _`Appendices/Canonical List of Mode Hints`: `Canonical List of Mode Hints`_ + +Top Level Object (Bmson) +======================== + +version :: DOMString + Specifies the version of this bmson. + + Currently possible value is ``2.0.0``. + +- Version numbers should be compared using the `Semantic Versioning 2.0.0`_ algorithm. +- bmson file without version field is a legacy bmson file. The implementor should either: + + - reject to process this file (the old format must be converted to new format), or + - process this file as bmson v0.21 (out of the scope of this specification). + +- If ``version`` is ``null``, the player should display an error message. + +.. _`Semantic Versioning 2.0.0`: http://semver.org/spec/v2.0.0.html + +Song Information Object (SongInfo) +============================== + +title :: DOMString + This is the title of song that will be displayed. + +- The implementor *need not* slice title string by delimiters (such as ``()``, ``--``) + +artist :: DOMString + This is the primary artist that will be displayed. + +- Usually, this is the music author. +- It may be contain multiple names in this string, for example: + + - ``Artist1 vs Artist2`` + - ``Artist1 feat. Vocalist`` + +genre :: DOMString + This is the genre of the song. + +Chart Information Object (ChartInfo) +==================================== + +subtitle :: DOMString + This is the subtitle of song that will be displayed. + + Default value is an empty string. + +- It is usually shown as a smaller text than ``title``. +- Multiple line subtitle may be possible by including a newline character ``\n`` + +subartists :: DOMString[] + Other artists that help authored this bmson file. + + Default value is an empty array. + +- This is useful for indexing and searching. For example, BMserver_. +- It is an array of strings, where each string is in form of ``key:value``. + + - ``key`` may be ``music``, ``vocal``, ``chart``, ``image``, ``movie``, ``other`` + - If ``key`` is omitted, default is ``other`` + - Others should only include a single name for each element. + - Implementers should trim the spaces before and after ``key`` and ``value``. + +- Example: ``"subartists": ["music:5argon", "music:encX", "chart:flicknote", "movie:5argon", "image:5argon"]`` + +.. _BMserver: http://bms.main.jp/ + +chart\_name :: DOMString + This is the chart name. + + Default value is an empty string. + +- Examples: ``BEGINNER``, ``NORMAL``, ``HYPER``, ``ANOTHER``, ``INSANE``, ``7keys Beginner`` + +level :: unsigned long + A value that shows the level of the note chart. + +- It is usually determined by subjective evaluation of the creator. It is recommended that the level number is based on the level scale of the base game. + +- For example, in ``beat`` mode, the level should be considered based on scale of 1~12. + +- ``level`` must be ≥0. Negative values may be regarded as invalid by a player. + +eyecatch\_image :: DOMString + The path to an image that may be displayed during song loading. + +- If eyecatch\_image is undefined, null or empty, player uses default eyecatch image. + +title\_image :: DOMString + The path to an image that will be displayed before song starts. + +- This is equivalent to `#BACKBMP in OADX+ skin`_. +- If ``title_image`` is undefined, null or empty, player will show title with default font. + +.. _`#BACKBMP in OADX+ skin`: http://www.geocities.jp/red_without_right_stick/backbmp/index.html + +banner\_image :: DOMString + The path to an image that may be displayed in song selection or result screen. + +- The image size should be 15:4, normally 600x160. Other sizes following this ratio (such as 900x240) are allowed for some high-resolution displays. + +back\_image :: DOMString + The path to a static background image that may be displayed during gameplay. + +- If ``back_image`` is undefined, null or empty, player uses default background image. +- Example: `Toy Musical 2`_ + +.. _`Toy Musical 2`: https://www.youtube.com/watch?v=8mDNzrQBlBY + +preview\_music :: DOMString + The path to an short audio file which preview the music. + +- If ``preview_music`` is not specified, player can create preview from ``sound_channels``. + +Chart Data Object (ChartData) +============================== + +mode\_hint :: DOMString + Specifies the game mode. + + Default value is ``beat-7k``. + +- Implementors should look at ``mode_hint`` to check if the note is designed for that particular kind of game mode. For example, 8-key games are different from IIDX-style games, even though they use exactly the same channel numbers. +- A layout for a generic symmetrical keyboard layout should use ``generic-nkeys`` where ``n`` is the number of keys. It should be ordered left to right. + +.. admonition:: Extension tip: On adding a mode that is not listed in this document + + A player may judge whether the format is supported by the player through ``version`` and ``mode_hint``. Therefore if you create an extension format, you should use a different ``mode_hint`` so that a player can judge what to do with the chart. You should not modify ``version``, because it represents underlying bmson format version. + +ln\_type\_hint :: DOMString + Specifies the long note type. + + Default value is ``ln``. + +- Implementors should look at ``ln_type_hint`` to check how to judge long notes **by default**. +- Implementors should note that **this may be optionally overridden** at each ``NoteEvent``. + +.. admonition:: Possible values + + - ``ln`` means that only the initial press is judged. + - ``cn`` means that both the initial press and the release are judged separately. + +ln\_judge\_hint :: DOMString + Specifies the long note judge type. + + Default value is ``normal``. + +- Implementors should look at ``ln_judge_hint`` to check how to handle long note judge **by default**. +- Implementors should note that **this may be optionally overridden** at each ``NoteEvent``. + +.. admonition:: Possible values + + - ``normal`` means that only the corresponding notes are judged, depending on ``ln_type_hint``. + - ``ticks`` means that additionally during the long note, extra 'ticks' are going to be judged. + +ln\_life\_hint :: DOMString + Specifies the long note life type. + + Default value is ``normal``. + +- Implementors should look at ``ln_life_hint`` to check how to handle long note life **by default**. +- Implementors should note that **this may be optionally overridden** at each ``NoteEvent``. + +.. admonition:: Possible values + + - ``normal`` means that only the corresponding notes replenish life, depending on ``ln_type_hint``. + - ``ticks`` means that additionally during the long note, extra 'ticks' are going to be judged. + +init\_bpm :: double + A value that shows the tempo at the start of the song. + +- It is a fatal error if ``init_bpm`` is unspecified. + +judge\_multiplier :: double + Specifies the width of judgment window. + + Default value is ``1.00``. + +- If ``judge_multiplier`` is larger than ``1.00``, judgment window is wider than player’s default. +- If ``judge_multiplier`` is smaller than ``1.00``, judgment window is narrower than player’s default. +- The implementation depends of each player. + +.. admonition:: A possible interpretation + + This section is provided as information only and is non-normative. + + - The ``judge_multiplier`` may be interpreted as a multiplier of judgment window. + - For example, to get a PERFECT judgment normally, you must hit the key within 20 millisecond window. + - If ``judge_multiplier`` is 2.50, then this judgement window is 2.5x the normal size, which is equal to 50 milliseconds. This make this chart easier. + - If ``judge_multiplier`` is 0.50, then judgement window is 0.5x the normal size (2x smaller). You must hit the key within 10 millisecond window. + +Here are the default judgment windows of some popular players. + +============= ======== ========== ======== +LunaticRave2_ [#]_ Bemuse_ +====================== =================== +Perfect GREAT ≤ 18 ms METICULOUS ≤ 20 ms +GREAT ≤ 40 ms PRECISE ≤ 50 ms +GOOD ≤ 100 ms GOOD ≤ 100 ms +BAD ≤ 200 ms OFFBEAT ≤ 200 ms +POOR > 200 ms MISSED > 200 ms +============= ======== ========== ======== + +.. _LunaticRave2: http://www.lr2.sakura.ne.jp/index2.html +.. _Bemuse: http://bemuse.ninja/ + +.. [#] #RANK 2 (NORMAL) + +life\_multiplier :: double + Default value is ``1.00``. + +- ``life_multiplier`` must be ≥ 0. + + - If 0, the lifebar doesn’t increase. + - If negative, take the absolute value. + +- It defines how much lifebar (also known as *groove gauge*) increases in number compared with default rate. + + - Default rate depends on each player. + - If ``life_multiplier`` is larger than ``1.00``, lifebar increases more when a note is played with high accuracy. + - If ``life_multiplier`` is smaller than ``1.00``, lifebar increases less when a note is played with high accuracy. + - It can also be a reference to how much lifebar decreases when a game player missed a note. + + - This behavior may also be different by each player. + +.. admonition:: Reference + + IIDX’s default rate approximation: + If player played all notes perfectly, the groove gauge increases by ``7.605 * n / (0.01 * n + 6.5)`` percent. + +resolution :: unsigned long + This is the number of pulses per one quarter note in a 4/4 measure. + + Default value is ``240``. + +- ``resolution`` must be > 0. + + - If 0, ``null`` or ``undefined``, use the default value. + - If negative, take the absolute value. + +- For detailed information, see `Terminologies/Beat Resolution`_. + +.. _`Terminologies/Beat Resolution`: `Beat Resolution`_ + +Time Signatures +=============== + +- **bmson does not have a native notion of ‘measures’ or ‘time signatures’**, but has a concept of *bar lines* instead. +- In BMS, notes are based on ‘measure number’ and ‘fraction of measure.’ The actual time of an event is also dependent on the time signature. +- In bmson, everything is based on a ‘pulse number,’ and is independent from any time signature or measure. A pulse is always a fraction of a quarter note in a 4/4 measure. + +lines :: BarLine[] + \ + +- Each BarLine object contains the y-position of each bar line to be displayed onscreen. + + - This can be used to simulate a notion of time signature. + +- The first bar line at ``y: 0`` can be omitted. + + - If it is present or omitted, it is up to the player whether to display this bar line or not. + +- If this is a blank array, then a chart will not have any barline, resulting in an effect as in \ `100% minimoo-G`_. +- If this is not specified (``null`` or ``undefined``), then a 4/4 time signature is assumed, and a bar line will be generated every 4 quarter notes. + +- Using the default resolution, a bar line will be generated every 960 pulses. + +.. _`100% minimoo-G`: https://www.youtube.com/watch?v=f1VBBNrSdgk + ++--------------------------------------+--------------------------------------+ +| **4/4 time signature** | .. code-block:: yaml | +| | | +| (common time) | lines: | +| | - y: 960 | +| | - y: 1920 | +| | - y: 2880 | +| | - y: 3840 | +| | # ... | ++--------------------------------------+--------------------------------------+ +| **3/4 time signature** | .. code-block:: yaml | +| | | +| (tempus perfectum) | lines: | +| | - y: 720 | +| | - y: 1440 | +| | - y: 2160 | +| | - y: 2880 | +| | # ... | ++--------------------------------------+--------------------------------------+ +| **Mapping from BMS** | .. code-block:: yaml | +| | | +| .. code:: | lines: | +| | - y: 960 # 000~001: 960 | +| #00102:0.75 | - y: 1680 # 001~002: 720 | +| #00302:1.25 | - y: 2640 # 002~003: 960 | +| | - y: 3840 # 003~004: 1200 | +| | # ... | ++--------------------------------------+--------------------------------------+ + +Timing +====== + +bpm\_events :: BpmEvent[] -- Tempo Changes + At the start of the song, the music will progress at a tempo specified in ``info.init_bpm``. + +- It is a fatal error if ``info.init_bpm`` is unspecified. +- When a ``BpmEvent`` is encountered, the tempo is changed to the value specified in the ``bpm`` field. +- If there are many ``BpmEvent`` at the same time, the BPM will change to the last one. +- Example: ``[ { y: 240, bpm: 100 }, { y: 240, bpm: 120 } ]`` → Tempo is changed to 120 BPM. + +stop\_events :: StopEvent[] -- Stops + When a ``StopEvent`` is encountered, the music will pause for a duration equivalent to a number of pulses specified in ``duration`` field. + +- If there are many ``StopEvent`` at the same time, these stop events add up. + +- Example: ``[ { y: 240, duration: 240 }, { y: 240, duration: 960 } ]`` → Scrolling stops for 1200 pulses. + +Order of Processing +------------------- + +- In case multiple events occur in the same pulse, events are processed in this order: + + - ``NoteEvent``, ``BGAEvent`` + - ``BpmEvent`` + - ``StopEvent`` + +- This is consistent with how BMS players interpret these events. +- If a ``StopEvent`` and a ``BpmEvent`` appear on the same pulse, the tempo will change first, then the music pauses. In other words, use the tempo at the pulse of the ``BpmEvent`` for calculating the duration of the stop in seconds, as well as any timing class similar to ``StopEvent``. +- If a ``StopEvent`` and a NoteEvent appear on the same pulse: + + - If it is a BGM note, the sound slice is played first, then the music pauses. + - If it is a playable note, the player must hit the note when the music pauses (not when the music resumes). + - For example, consider the following notes and stops: + + .. code-block:: yaml + + stop: { y: 240, duration: 240 } + note: { y: 240 } + + - This means the position ``y: 240`` covers a range of time, rather than a precise point in time (because speed is zero during the pause). + - When the current bpm value is 60, the correspondence of *y (pulse number)* and *t (metric time)* is as follows: + + ========== ============= + y (pulses) t (second) + ========== ============= + 0 0.0 + 120 0.5 + 239 239 / 240 + 240 1.0 ≤ t ≤ 2.0 + 241 481 / 240 + ========== ============= + + At ``y: 240`` the time is ambiguous. + + Therefore, this specification defines that the note at ``y: 240`` must be activated at ``t = 1.0`` (beginning of the pause). + +.. admonition:: Extension tip: On adding a timing class + + As written above, any accumulative timing class should follow the format of ``StopEvent``, and use a duration in pulses. A fixed-amount timing class should use the unit corresponding to its class, like ``BpmEvent`` does. + +Sound Channels +============== + +**bmson is sound channel based.** Notes from the same sound channel are +grouped together in the same array. + +sound\_channels :: SoundChannel[] + A sound channel represents an audio track. + + .. image:: images/sound_channels.png + +Slicing and Restarting +---------------------- + +The notes inside this sound channel determines how to slice and when to +restart. + +.. figure:: images/slicing_1.png + + Notes at different times caused sounds to be sliced at different time. + +.. figure:: images/slicing_2.png + + The highlighted ``SoundChannel`` represents a kick sound. Instead of repeating a kick sound many time, leading to a redundant audio file, the ``SoundChannel`` is restarted instead. + +name :: DOMString + This represents the filename of the audio track. + +- A file extension may be omitted. + + - If file extension is omitted, then the implementation should search for compatible sound file with that name. + - Example: ``{ name: “piano” }`` → Try ``piano.wav``, ``piano.ogg``, ``piano.m4a``, … + +- If file extension is provided but the file is not found or cannot be played, then the implementation should treat the file name as if its extension is removed. + + - Example: ``{ name: "piano.wav" }`` → ``piano.wav`` not found → Treat as ``"piano"`` → Try ``piano.wav``, ``piano.ogg``, … + - Example: ``{ name: "piano.ogg" }`` → ogg not supported → Treat as ``"piano"`` → Try ``piano.wav``, ``piano.ogg``, ``piano.m4a``… + +- The sound files may live in subdirectories relative to bmson file. + + - Path may be separated using backslash (``\``) or forward slash (``/``), the implementation should normalize them. + - The implementation must protect from malicious paths: + + - Absolute path: ``C:\password.txt`` or ``/etc/passwd`` + - Reference to parent directory: ``../../../var/www/html/config.php`` + - Null characters (``\0``) + + - Example: ``{ name: "intro\\drum" }`` + +Sound File Format Recommendation +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Players are expected to support these file formats: + +- Microsoft WAV file (.wav). +- Either OGG Vorbis (.ogg) or MP4 AAC (.m4a). + +OGG Vorbis is a free file format, and can be used freely, and is very easy to create. Unfortunately, not every platform supports decoding OGG files natively (with hardware acceleration). + +MP4 is the most common multimedia file format used in mobile phones with native support for Android and iOS, but it’s harder to create an MP4 file. + +.. warning:: + + MP3 file format is discouraged. + + Both MP3 encoder and decoders add silence to the beginning and end of file [#]_. + + This causes sounds to be shifted, sometimes as much as 20 milliseconds. This could change a Perfect GREAT into a GREAT. + +.. [#] http://lame.sourceforge.net/tech-FAQ.txt + +note_events :: NoteEvent[] + \ + +- ``x`` is the player channel for this note. + + - ``0`` or ``null`` → this is not a playable note (BGM note) + - ``1``, ``2``, ``3``, … → this is a playable note + +- ``y`` is the time (the pulse number) that this note must be activated +- ``l`` is the length of note + + - ``0`` → this is a short note + - ``> 0`` → this is a long note, starting at pulse ``y``, ending at ``y + l``. + +- ``c`` is the continuation flag + + - ``true`` → continue — don’t restart + - ``false`` → don’t continue — restart the audio + +.. admonition:: Optional variables + + - ``up`` is the up keysound flag, used for CN, BSS and MSS (Charge Note, BackSpin and MultiSpin Scratch). + + - For release keysound or BSS, a normal note with ``true`` must be layered on top of the end of the long note. + - For MSS a long note with ``true`` must be layered on top of the end of the long note. + + - This note can use the long note hint overrides detailed below to alter long note behaviour. + - ``ln_type_hint`` is the long note type hint override. Refer to ``ChartData`` documentation for more info. + - ``ln_judge_hint`` is the long note judge hint override. Refer to ``ChartData`` documentation for more info. + - ``ln_life_hint`` is the long note life hint override. Refer to ``ChartData`` documentation for more info. + +Slicing Algorithm (Roughly) +--------------------------- + +The high-level algorithm to slice is as follows. + +#. Gather all the pulse numbers in this ``SoundChannel``’s notes. Discard the duplicates. +#. Convert these pulse numbers into metric time (in seconds). +#. Restart the audio whenever a note without a continuation flag is encountered. +#. Slice the resulting audio, using the time values from step 2. as slicing points. +#. Each note is assigned a slice that starts at the same time as the note. + +Slicing Example +~~~~~~~~~~~~~~~ + +Given this ``SoundChannel`` object: + +.. code-block:: yaml + + sound_channels: + - name: vox.wav + note_events: + - { x: 1, y: 240, c: false } # 1 + - { x: 3, y: 360, c: true } # 2 + - { x: 7, y: 360, c: true } # 3 + - { x: 2, y: 720, c: false } # 4 + - { x: 3, y: 720, c: false } # 5 + - { x: 4, y: 840, c: true } # 6 + - { x: 6, y: 840, c: true } # 7 + - { x: 3, y: 1200, c: true } # 8 + - { x: 0, y: 1680, c: true } # 9 + +We obtain these information (given BPM=120): + +============ ==== ======= ======== ===== ======= +Pulse Number Beat Seconds Restart? Notes Slice # +============ ==== ======= ======== ===== ======= +240 1 0.5 true 1 1 +360 1.5 0.75 false 2, 3 2 +720 3 1.5 true 4, 5 3 +840 3.5 1.75 false 6, 7 4 +1200 5 2.5 false 8 5 +1680 7 3.5 false 9 6 +============ ==== ======= ======== ===== ======= + +Slicing based on these slicing points, we obtain these slices: + +======= ================ ============== ================== +Slice # Audio Start Time Audio End Time Slice Duration (s) +======= ================ ============== ================== +1 0 0.25 0.25 +2 0.25 1 0.75 +3 1 1.25 0.25 +4 1.25 2 0.75 +5 2 3 1 +6 3 (end of file) +======= ================ ============== ================== + +Sliced sound looks like this: + +.. image:: images/slicing_3.png + +Finally, these slices become associated with the notes. + +From the table above, **multiple notes may be assigned the same slice**. + +Edge Cases +~~~~~~~~~~ + +- If a same slice is assigned to both playable and BGM note, then the BGM note must be discarded. + + Example: + + .. code-block:: yaml + + sound_channels: + - file: kick.wav + notes: + - { x: 0, y: 960 } # (x) + - { x: 1, y: 960 } + - { x: 3, y: 960 } + + Here, the note marked (x) must be discarded. + +- If multiple notes are on the same pulse, and some have continuation flag set, but not all, the implementation should consider that the continuation flag is not set. + +Playback Behavior +~~~~~~~~~~~~~~~~~ + +- Each slice only has a polyphony of 1. + + This means that if a slice has been assigned to two or more notes (obviously, at the same pulse) and they are triggered simultaneously, this slice should not sound louder than normal. + + However, if different slices from the same sound channel are played, they should play simultaneously. + +- You may treat each slice like a #WAV channel in BMS files. +- Note that multiple sound channel may refer to the same file. + + - This is a different sound channel, so they can play simultaneously. This is matching with `multiplex WAV definitions`_. + +.. _`multiplex WAV definitions`: http://hitkey.nekokan.dyndns.info/cmds.htm#WAVXX-MULTIPLEX-DEFINITION + +.. admonition:: Recommendation for Implementations + + *This section is non-normative.* + + You may join consecutive slices if these slices are only used by BGM notes. This can reduce the number of slices and may improve sound smoothness and performance. + + A rough algorithm: + + .. code:: + + for each pair of consecutive slice s1 and s2 + if either slice is used by non-BGM note + don’t join + else if s2 is not continuing (c: false) + don’t join + else + join them together + +Layered Notes +------------- + +- In the case that notes from different sound channel exist on same (x, y) position, + + - The notes from these sound channels are “fusioned” and become a single note. When this note is played, the sound slice from each original sound channel is played. + - It is an error if length is unequal (player may issue a warning). + +bga :: BGA +========== + +Currently, BGA specification is just compatible with BMS. + +bga\_header :: BGAHeader[] + \ + +- ``id`` is picture file identifier. + + - If there is the same value in one file, player may issue a warning, taking posterior one. + +- ``name`` is the path to the picture file. + +- Recommended picture size is 1280x720. 1920x1080 is also acceptable. + + - In game with different aspect ratio, the background image may be cropped in the center. Therefore, make sure that the key elements are near the center of the image. + +- Players are expected to support these file formats: + + - Pictures: PNG + - Video: WebM + + - Audio channels may be ignored. + + +bga\_events, layer\_events, poor\_events :: BGAEvent[] + ``bga_events`` represent image/video files that will be displayed as the song’s background animation [#]_. + + ``layer_events`` represent image/video files that will be *layered* on top of the BGA. + +- ``id`` specifies picture declared at ``bga_header``. + +- ``y`` is pulse number when the picture is shown. + +- Unlike \ `BMS Layer Channel #xxx07`_, black pixels will not be made transparent. If you want transparency, use a file format that support transparency, such as PNG [#]_. + +.. _`BMS Layer Channel #xxx07`: http://hitkey.nekokan.dyndns.info/cmds.htm#BMPXX-LAYER + +.. [#] Some game may choose to display the BGA as the background, and overlay notes on top of it. Example commercial games that use this approach are DJ MAX series, DDR, and `Pump It Up`_. Other games may display the BGA in a dedicated space. Examples are beatmaniaIIDX and `LunaticRave2`_. + +.. [#] By extension, this means that a converter should convert a BMP files into PNG in a way that a perfect black pixel is turned into a transparent pixel. Note that a same image file may be used both as BGA and LAYER, so a single BMP file may have to be converted into two different PNG files. + +.. _`Pump It Up`: http://www.piugame.com/ +.. _`LunaticRave2`: http://www.lr2.sakura.ne.jp/index2.html + + +Appendices +========== + +Canonical List of Mode Hints +---------------------------- + +Left-most values are ``mode_hint``. + +Beat: +----- +============ == == == == == == == == == == == == == == == == +**x** 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 +============ == == == == == == == == == == == == == == == == +mode_hint Player 1 Player 2 +------------ ----------------------- ----------------------- +**beat-5k** 1 2 3 4 5 SC +**beat-7k** 1 2 3 4 5 6 7 SC +**beat-10k** 1 2 3 4 5 SC 1 2 3 4 5 SC +**beat-14k** 1 2 3 4 5 6 7 SC 1 2 3 4 5 6 7 SC +============ == == == == == == == == == == == == == == == == + +SC: Scratch (Turntable) + +Popn: +----- +=========== = = = = = = = = = +**x** 1 2 3 4 5 6 7 8 9 +=========== = = = = = = = = = +mode_hint Buttons +----------- ----------------- +**popn-5k** 1 2 3 4 5 +**popn-9k** 1 2 3 4 5 6 7 8 9 +=========== = = = = = = = = = + +DJ.NEXT: +---- +Player 1 side: + +================= == == == == == == == == == == == == == == == == == == +**x** 1 11 12 13 14 15 10 31 32 33 34 20 21 22 23 24 25 2 +================= == == == == == == == == == == == == == == == == == == +mode_hint Buttons side 1 Effectors Buttons side 2 +----------------- -------------------- ----------- -------------------- +**dj-5k-only** 1 2 3 4 5 +**dj-ruby** TT 1 2 3 4 5 PD +**dj-5k** TT 1 2 3 4 5 PD +**dj-7k** TT 1 2 3 4 5 PD E1 E2 +**dj-10k** TT 1 2 3 4 5 PD 6 7 8 9 10 TT +**dj-14k** TT 1 2 3 4 5 E1 E2 E3 E4 6 7 8 9 10 TT +**dj-andromeda** TT 1 2 3 4 5 PD E1 E2 E3 E4 PD 6 7 8 9 10 TT +================= == == == == == == == == == == == == == == == == == == + +Player 2 side: + +================= == == == == == == == == == == == == == == == == == == +**x** 2 25 24 23 22 21 20 34 33 32 31 10 15 14 13 12 11 1 +================= == == == == == == == == == == == == == == == == == == +mode_hint Buttons side 1 Effectors Buttons side 2 +----------------- -------------------- ----------- -------------------- +**dj-5k-only** 6 7 8 9 10 +**dj-ruby** PD 6 7 8 9 10 TT +**dj-5k** PD 6 7 8 9 10 TT +**dj-7k** E3 E4 PD 6 7 8 9 10 TT +**dj-10k** TT 1 2 3 4 5 PD 6 7 8 9 10 TT +**dj-14k** TT 1 2 3 4 5 E1 E2 E3 E4 6 7 8 9 10 TT +**dj-andromeda** TT 1 2 3 4 5 PD E1 E2 E3 E4 PD 6 7 8 9 10 TT +================= == == == == == == == == == == == == == == == == == == + +TT: Turntable + +PD: Pedal diff --git a/index.rst b/index.rst index 173a1ad..eec391b 100644 --- a/index.rst +++ b/index.rst @@ -1,21 +1,21 @@ -.. bmson-spec documentation master file, created by - sphinx-quickstart on Sat Dec 26 09:59:57 2015. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -Welcome to bmson-spec's documentation! -====================================== - -Contents: - -.. toctree:: - :maxdepth: 2 - - doc/index.rst - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` +.. bmson-spec documentation master file, created by + sphinx-quickstart on Sat Dec 26 09:59:57 2015. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to bmson-spec's documentation! +====================================== + +Contents: + +.. toctree:: + :maxdepth: 2 + + doc/index.rst + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search`