!!! This is a temporary documentation for bms parser package v2.0.0 !!!
- require('bms')
- require('bms/bms/chart')
- require('bms/bms/headers')
- require('bms/bms/objects')
- require('bms/compiler')
- require('bms/keysounds')
- require('bms/positioning')
- require('bms/reader')
- require('bms/song-info')
- require('bms/spacing')
- require('bms/speedcore')
- require('bms/time-signatures')
- require('bms/timing')
- class BMSChart
- class BMSHeaders
- data BMSObject
- class BMSObjects
- class Keysounds
- class Positioning
- class SongInfo
- class Spacing
- class Speedcore
- class TimeSignatures
- class Timing
- compile(text, options)
- read(buffer)
- readAsync(buffer, callback)
Public: The bms
package is a library for working with rhythm game data.
Although this library’s name suggests that it is for BMS file format, almost every part can be used standalone.
This package contains:
-
Modules that reads and parses BMS files:
- {Reader} reads the BMS file from a {Buffer}, detects the character set and decodes the buffer using that character set into a {String}.
- {Compiler} reads the BMS source from a {String}, and converts into BMSChart, an internal representation of a BMS notechart.
-
Classes for representing a BMS notechart. These module stores the data as close to the BMS file format as possible.
Almost no musical interpretation is made. For example, a BPM change is simply represented using a BMSObject with
channel
=03
or08
.- BMSChart is composed of BMSHeaders, BMSObjects, and TimeSignatures.
- BMSHeaders represents the header sentences in a BMS file.
- BMSObjects represents the objects in a BMS file.
- {BMSObject} represents a single object.
-
Classes that represent different aspects of a notechart. Instance of these classes may be created from a BMSChart, but they can be used in a standalone manner as well.
This makes this library very flexible, and able to accomodate different formats of notechart. For example, see the bmson package.
It’s also possible to use these classes in context other than music gaming, for example, you can use these classes to help building a music player that requires precise synchronization between beats.
- TimeSignatures represents a collection of time signatures in a musical score, and lets you convert the measure number and fraction into beat number.
- Timing represents the timing information in a musical score, and provides methods to convert between musical time (beats) and metric time (seconds).
- SongInfo represents the basic song information, such as title, artist, and genre.
- Notes represents the sound objects inside your notechart.
- Keysounds represents a mapping between keysound ID and filename.
- Positioning represents a mapping between beat and in-game position. Some rhythm game lets chart author control the amount of scrolling per beat. In StepMania 5, this is called the scroll segments.
- Spacing represents a mapping between beat and note spacing. Some rhythm game lets chart author change the note spacing (HI-SPEED) dynamically. In StepMania 5, this is called the speed segments.
-
Low-level utility classes:
- Speedcore represents a linear animation.
Public: A module that exposes BMSChart.
class BMSChart
Public: A BMSChart holds information about a particular BMS notechart. Note that a BMSChart does not contain any information about
#RANDOM
, as they are already processed after compilation.There is not many useful things you can do with a BMSChart other than accessing the header fields and objects inside it.
To extract information from a BMSChart, please look at the documentation of higher-level classes, such as Keysounds, Notes, and Timing.
Public: BMSHeaders representing the BMS-specific headers of this notechart
Public: BMSObjects representing all objects of this notechart
Public: TimeSignatures representing the time signature information in this chart
Public: Converts measure number and fraction into beat. A single beat is equivalent to a quarter note in common time signature.
measure
{Number} representing the measure number, starting from 0fraction
{Number} representing the fraction inside that measure, from 0 to 1
Returns the {Number} representing the beat number, starting from 0
Public: A module that exposes BMSHeaders.
class BMSHeaders
Public: A BMSHeader holds the header information in a BMS file, such as
#TITLE
,#ARTIST
, or#BPM
.You get retrieve a header using the
get()
method:chart.headers.get('title')For some header fields that may contain multiple values, such as
#SUBTITLE
, you can get them all usinggetAll()
:chart.headers.getAll()
Public: Iterates through each header field using a callback function.
callback
A {Function} that will be called for each header fieldkey
{String} representing the field’s namevalue
{String} representing the field’s value
Public: Retrieves the header field’s latest value.
name
A {String} representing field’s name
Returns a {String} representing the field’s value
Public: Retrieves the header field’s value. This is useful when a header field is specified multiple times.
name
A {String} representing field’s name
Returns an {Array} of {String} values
Public: Sets the header field’s value.
name
A {String} representing field’s namevalue
A {String} representing field’s value
Public: A module that exposes BMSObjects.
class BMSObjects
Public: A BMSObjects holds a collection of objects inside a BMS notechart.
Public: Adds a new object to this collection.
If an object already exists on the same channel and position, the object is replaced (except for autokeysound tracks).
object
{BMSObject} to add
data BMSObject
Public: A BMSObject data structure represents an object inside a BMSChart.
It is a plain object with the following fields:
channel
A {String} representing the raw two-character BMS channel of this objectmeasure
A {Number} representing the measure number, starting at 0 (corresponds to#000
)fraction
A {Number} representing the fractional position inside the measure, ranging from 0 (inclusive) to 1 (exclusive). 0 means that the object is at the start of the measure, whereas 1 means that the object is at the end of the measure.value
A {String} representing the raw value of the BMS object.
Public: A module that takes a string representing the BMS notechart, parses it, and compiles into a BMSChart.
exports.compile(text, options)
Public: Reads the string representing the BMS notechart, parses it, and compiles into a {BMSChart}.
text
{String} representing the BMS notechartoptions
(optional) {Object} representing additional parser optionsrng
(option) {Function} that generates a random number. It is used when processing#RANDOM n
directive. This function should return an integer number between 1 andn
.max
{Number} representing the maximum value.
Returns an {Object} with these keys:
chart
{BMSChart} representing the resulting chartwarnings
{Array} of warnings. Each warning is an {Object} with these keys:lineNumber
{Number} representing the line number where this warning occurredmessage
{String} representing the warning message
Public: A module that exposes Keysounds
class Keysounds
Public: A Keysounds is a simple mapping between keysounds ID and the file name.
If you have a BMS like this:
#WAVAA cat.wav
Having parsed it using a {Compiler} into a BMSChart, you can create a Keysounds using
fromBMSChart()
:var keysounds = Keysounds.fromBMSChart(bmsChart)Then you can retrieve the filename using
.get()
:keysounds.get('aa') // => 'cat.wav'
Public: Constructs an empty Keysounds object.
Public: Returns the keysound file at the specified ID.
id
{String} representing the two-character keysound ID
Returns {String} representing the filename Returns undefined if not found
Public: Constructs a new Keysounds object from a BMSChart.
Returns a Keysounds object
Public: A module that exposes Positioning
class Positioning
- new Positioning(segments)
- Positioning#speed(beat)
- Positioning#position(beat)
- Positioning.fromBMSChart(chart)
Public: A Positioning represents the relation between song beats and display position, and provides a way to convert between them.
In some rhythm games, the amount of scrolling per beat may be different. StepMania’s
#SCROLL
segments is an example.
Public: Constructs a Positioning from the given segments
.
segments
An {Array} of segment objects. Each segment {Object} contains:t
{Number} representing the beat numberx
{Number} representing the total elapsed amount of scrolling at beatt
dx
{Number} representing the amount of scrolling per beatinclusive
{Boolean} representing whether or not to include the starting beatt
as part of the segment
Public: Returns the scrolling speed at specified beat.
beat
{Number} representing the beat number
Returns a {Number} representing the amount of scrolling per beat
Public: Returns the total elapsed scrolling amount at specified beat.
beat
{Number} representing the beat number
Returns a {Number} representing the total elapsed scrolling amount
Public: Creates a Positioning object from the BMSChart.
chart
A BMSChart to construct a Positioning from
Returns a Positioning object
Public: A module that takes a buffer, detects the character set, and returns the decoded string.
The Reader follows ruv-it!’s algorithm for detecting the character set.
exports.read(buffer)
Public: Reads the buffer, detect the character set, and returns the decoded string synchronously.
buffer
{Buffer} representing the BMS file
Returns a {String} representing the decoded text
exports.readAsync(buffer, callback)
Public: Like read(buffer)
, but this is the asynchronous version.
buffer
{Buffer} representing the BMS filecallback
{Function} that will be called when finishederror
{Error} in case of failurevalue
{String} representing the decoded text
Public: A module that exposes SongInfo
class SongInfo
- new SongInfo(info)
- SongInfo#title
- SongInfo#artist
- SongInfo#genre
- SongInfo#subtitles
- SongInfo#subartists
- SongInfo#difficulty
- SongInfo#level
- SongInfo.fromBMSChart(chart)
Public: A SongInfo represents the song info, such as title, artist, genre.
If you have a BMS like this:
#TITLE Exargon [HYPER]
Having parsed it using a {Compiler} into a BMSChart, you can create a SongInfo using
fromBMSChart()
:var info = SongInfo.fromBMSChart(bmsChart)Then you can query the song information by accessing its properties.
info.title // => 'Exargon' info.subtitles // => ['HYPER']
Public: Constructs a SongInfo with information given by info
parameter.
info
{Object} representing the properties to set on this new instance
Public: {String} representing the song title
Public: {String} representing the song artist
Public: {String} representing the song genre
Public: {Array} representing the song's subtitles, one line per element. The subtitle may be used to represent the difficulty name, such as NORMAL, HYPER, ANOTHER.
Public: {Array} representing the song's other artists, one artist per element.
Public: {Number} representing the difficulty.
Meaning of the number is same as BMS's #DIFFICULTY
header.
difficulty | meaning |
---|---|
1 | BEGINNER |
2 | NORMAL |
3 | HYPER |
4 | ANOTHER |
5 | INSANE |
Public: {Number} representing the level of the song.
When converted from a BMS chart, this is the value of #PLAYLEVEL
header.
Public: Constructs a new SongInfo object from a BMSChart.
Returns a SongInfo object
Public: A module that exposes Spacing
class Spacing
Public: A Spacing represents the relation between song beats and notes spacing.
In some rhythm games, such as Pump It Up!, the speed (note spacing factor) may be adjusted by the notechart. StepMania’s
#SPEED
segments is an example.
Public: Constructs a Spacing from the given segments
.
segments
An {Array} of segment objects. Each segment {Object} contains:t
{Number} representing the beat numberx
{Number} representing the spacing at beatt
dx
{Number} representing the amount spacing factor change per beat, in order to create a continuous speed changeinclusive
{Boolean} representing whether or not to include the starting beatt
as part of the segment
Public: Returns a spacing factor at the specified beat.
beat
{Number} representing the beat
Returns the note spacing factor at the specified beat
Public: Creates a Spacing object from the BMSChart.
Speed is defined as keyframes. These keyframes will be linearly interpolated.
#SPEED01 1.0
#SPEED02 2.0
#001SP:01010202
In this example, the note spacing factor will gradually change from 1.0x at beat 1 to 2.0x at beat 2.
Returns a Spacing object
Public: A module that exposes Speedcore
class Speedcore
Speedcore is a small internally-used library. A Speedcore represents a single dimensional keyframed linear motion (as in equation x = f(t)), and is useful when working with BPM changes (Timing), note spacing factor (Spacing), or scrolling segments (Positioning). A Speedcore is constructed from an array of Segments.
A {Segment} is defined as
{ t, x, dx }
, such that:
- speedcore.x(segment.t) = segment.x
- speedcore.t(segment.x) = segment.t
- speedcore.x(segment.t + dt) = segment.x + (segment.dx / dt)
One way to think of these segments is to think about tempo changes, where:
t
is the elapsed time (in seconds) since song start.x
is the elapsed beat since song start.dx
is the amount ofx
increase pert
. In this case, it has the unit of beats per second.For example, consider a song that starts at 140 BPM. 32 beats later, the tempo changes to 160 BPM. 128 beats later (at beat 160), the tempo reverts to 140 BPM.
We can derive three segments:
- At time 0, we are at beat 0, and moving at 2.333 beats per second.
- At 13.714s, we are at beat 32, moving at 2.667 beats per second.
- At 61.714s, we are at beat 160, moving at 2.333 beats per second.
This maps out to this data structure:
[ /* [0] */ { t: 0.000, x: 0, dx: 2.333, inclusive: true }, /* [1] */ { t: 13.714, x: 32, dx: 2.667, inclusive: true }, /* [2] */ { t: 61.714, x: 160, dx: 2.333, inclusive: true } ]With this data, it is possible to find out the value of
x
at any givent
.For example, to answer the question, “what is the beat number at 30s?” First, we find the segment with maximum value of
t < 30
, and we get the segment[1]
.We calculate
segment.x + (t - segment.t) * segment.dx
. The result beat number is (32 + (30 - 13.714) * 2.667) = 75.435.We can also perform the reverse calculation in a similar way, by reversing the equation.
Interestingly, we can use these segments to represent the effect of both BPM changes and STOP segments in the same array. For example, a 150-BPM song with a 2-beat stop in the 32nd beat can be represented like this:
[ /* [0] */ { t: 0.0, x: 0, dx: 2.5, inclusive: true }, /* [1] */ { t: 12.8, x: 32, dx: 0, inclusive: true }, /* [2] */ { t: 13.6, x: 32, dx: 2.5, inclusive: false } ]
Public: Constructs a new Speedcore
from given segments.
segments
{Array} of {Segment} objects
Public: Calculates the t, given x.
x
{Number} representing the value of x
Returns {Number} t
Public: Calculates the x, given t.
t
{Number} representing the value of t
Returns {Number} x
Public: Finds the dx, given t.
t
{Number} representing the value of t
Returns {Number} dx
Public: A module that exposes TimeSignatures
class TimeSignatures
- TimeSignatures#set(measure, value)
- TimeSignatures#get(measure)
- TimeSignatures#getBeats(measure)
- TimeSignatures#measureToBeat(measure, fraction)
Public: A TimeSignatures is a collection of time signature values index by measure number.
The measure number starts from 0. By default, each measure has a measure size of 1 (which represents the common 4/4 time signature)
If you have a BMS like this:
#00102:0.75 #00103:1.25
Having parsed it using a {Compiler} into a BMSChart, you can access the TimeSignatures object:
var timeSignatures = bmsChart.timeSignaturesNote that you can also use the constructor to create a TimeSignatures from scratch.
One of the most useful use case of this class is to convert the measure and fraction into beat number.
timeSignatures.measureToBeat(0, 0.000) // => 0.0 timeSignatures.measureToBeat(0, 0.500) // => 2.0 timeSignatures.measureToBeat(1, 0.000) // => 4.0 timeSignatures.measureToBeat(1, 0.500) // => 5.5 timeSignatures.measureToBeat(2, 0.000) // => 7.0 timeSignatures.measureToBeat(2, 0.500) // => 9.5 timeSignatures.measureToBeat(3, 0.000) // => 12.0
Public: Sets the size of a specified measure.
measure
{Number} representing the measure number, starting from 0value
{Number} representing the measure size. For example, a size of 1.0 represents a common 4/4 time signature, whereas a size of 0.75 represents the 3/4 or 6/8 time signature.
Public: Retrieves the size of a specified measure.
measure
{Number} representing the measure number.
Returns a {Number} representing the size of the measure. By default, a measure has a size of 1.
Public: Retrieves the number of beats in a specified measure.
Since one beat is equivalent to a quarter note in 4/4 time signature,
this is equivalent to (timeSignatures.get(measure) * 4)
.
measure
{Number} representing the measure number.
Returns a {Number} representing the size of the measure in beats.
Public: Converts a measure number and a fraction inside that measure into the beat number.
measure
{Number} representing the measure number.fraction
{Number} representing the fraction of a measure, ranging from 0 (inclusive) to 1 (exclusive).
Returns a {Number} representing the number of beats since measure 0.
Public: A module that exposes Timing.
class Timing
- new Timing(initialBPM, actions)
- Timing#beatToSeconds(beat)
- Timing#secondsToBeat(seconds)
- Timing#bpmAtBeat(beat)
- Timing#getEventBeats(beat)
- Timing.fromBMSChart(chart)
Public: A Timing represents the timing information of a musical score. A Timing object provides facilities to synchronize between metric time (seconds) and musical time (beats).
A Timing are created from a series of actions:
- BPM changes.
- STOP action.
Public: Constructs a Timing from a specified actions.
Generally, you would use Timing.fromBMSChart
to create an instance
from a BMSChart, but the constructor may also be used in other situations
unrelated to the BMS file format.
initialBPM
{Number} The initial BPM of this songactions
An {Array} of actions objects. Each action object has these properties:type
{String} representing action type.bpm
for BPM change, andstop
for stopbeat
{Number} representing beat where this action occursbpm
{Number} representing BPM to change to (only forbpm
type)stopBeats
{Number} of beats to stop (only forstop
type)
Public: Convert the given beat into seconds.
Public: Convert the given second into beats.
Public: Returns the BPM at the specified beat.
Public: Returns an array representing the beats where there are events.
Public: Creates a Timing instance from a BMSChart.