packages/bms/src/time-signatures/index.ts
/**
* 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)
*
* ## Example
*
* 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:
*
* ```js
* var timeSignatures = bmsChart.timeSignatures
* ```
*
* Note 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.
*
* ```js
* 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
* ```
*/
export class TimeSignatures {
private _values: { [measure: number]: number }
constructor() {
this._values = {}
}
/**
* Sets the size of a specified measure.
* @param measure the measure number, starting from 0
* @param value 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.
*/
set(measure: number, value: number) {
this._values[measure] = value
}
/**
* Retrieves the size of a specified measure.
* @param measure representing the measure number.
* @returns the size of the measure.
* By default, a measure has a size of 1.
*/
get(measure: number): number {
return this._values[measure] || 1
}
/**
* 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)`.
* @param measure representing the measure number.
* @returns the size of the measure in beats.
*/
getBeats(measure: number): number {
return this.get(measure) * 4
}
/**
* Converts a measure number and a fraction inside that measure
* into the beat number.
*
* @param measure the measure number.
* @param fraction the fraction of a measure,
* @returns the number of beats since measure 0.
*/
measureToBeat(measure: number, fraction: number): number {
let sum = 0
for (let i = 0; i < measure; i++) sum += this.getBeats(i)
return sum + this.getBeats(measure) * fraction
}
}