Skip to content

Instantly share code, notes, and snippets.

@m4saka
Forked from albshin/kshon
Last active May 5, 2022 14:06
Show Gist options
  • Save m4saka/a89594a17dc9422d75e01998bcfd2722 to your computer and use it in GitHub Desktop.
Save m4saka/a89594a17dc9422d75e01998bcfd2722 to your computer and use it in GitHub Desktop.
modified version of: https://bmson-spec.readthedocs.io/en/master/doc/index.html
Encoding: UTF-8 (without BOM), LF
// TODO List
// - full list of audio effect parameters
// top-level object
dictionary kson {
DOMString version; // kson version
MetaInfo meta; // meta data, e.g. title, artist, ...
BeatInfo beat; // beat-related data, e.g. bpm, time signature, ...
GaugeInfo? gauge; // gauge-related data
NoteInfo? note; // notes on each lane
AudioInfo? audio; // audio-related data
CameraInfo? camera; // camera-related data
BgInfo? bg; // background-related data
ClientList? impl; // Implementation-dependent options for each clients
}
/* ------------------------------------------------------------------ */
/* ----------------------------- COMMON ----------------------------- */
/* ------------------------------------------------------------------ */
// interval
dictionary Interval {
unsigned long y; // pulse number
unsigned long l = 0; // length
}
// event triggered by measure index
dictionary ByMeasureIndex<T> {
unsigned long idx; // measure index
T? v; // body
}
// event triggered by pulse
dictionary ByPulse<T> {
unsigned long y; // pulse number
T? v; // body
}
// events triggered by BT/FX/laser notes
dictionary ByNotes<T> {
ByBtnNote<T>[]? bt; // events triggered by BT notes
ByBtnNote<T>[]? fx; // events triggered by FX notes
ByLaserNote<T>[]? laser; // events triggered by laser notes
}
// event triggered by BT/FX note
dictionary ByBtnNote<T> {
unsigned long lane; // lane index (corresponds to the 1st index of NoteInfo.bt/fx)
unsigned long idx; // note index (corresponds to the 2nd index of NoteInfo.bt/fx)
T? v; // body
}
// event triggered by laser point
dictionary ByLaserNote<T> {
unsigned long lane; // lane index (corresponds to the 1st index of NoteInfo.laser)
unsigned long sec; // section index (corresponds to the 2nd index of NoteInfo.laser)
unsigned long idx; // point index (corresponds to the index of LaserSection.point)
T? v; // body
}
// graph (whole chart)
dictionary GraphPoint {
unsigned long y; // absolute pulse number
long v; // value (use 0 to stop)
long? vf; // second value (for an immediate change)
long a = 0; // x-coordinate (%) of the curve control point (0-100)
long b = 0; // y-coordinate (%) of the curve control point (0-100)
}
// graph point (for graph sections = ByPulse<GraphSectionPoint[]>)
dictionary GraphSectionPoint {
unsigned long ry; // relative pulse number
long v; // value (use 0 to stop)
long? vf; // second value (for an immediate change)
long a = 0; // x-coordinate (%) of the curve control point (0-100)
long b = 0; // y-coordinate (%) of the curve control point (0-100)
}
// definition
dictionary Def<T> {
T v; // changeable parameters (default values)
... // unchangeable parameters (e.g. filename, audio effect type)
}
dictionary DefList<T> {
Def<T>? ...(name is the key);
...
}
// invocation
dictionary InvokeList<T> {
T? ...(name is the key); // values which overwrites Def<T>.v
// (special rules are applied for overwriting v.l & v.scale & v.vol)
...
}
/* ------------------------------------------------------------------ */
/* ------------------------------ META ------------------------------ */
/* ------------------------------------------------------------------ */
// meta data
dictionary MetaInfo {
DOMString title; // self-explanatory
DOMString? title_translit; // transliterated title
DOMString? subtitle; // self-explanatory, can be a CD title or a music genre
DOMString artist; // self-explanatory
DOMString? artist_translit; // transliterated artist
DOMString chart_author; // self-explanatory
DifficultyInfo difficulty; // self-explanatory
unsigned int level; // self-explanatory, 1-20
DOMString? disp_bpm; // displayed bpm (allowed characters: 0-9, "-", ".")
// If not specified, the first value of BeatInfo.bpm will be used.
double? std_bpm; // standard bpm for hi-speed values (should be between minimum bpm and maximum bpm in the chart)
DOMString? jacket_filename; // self-explanatory (can have a preset image "nowprinting1"/"nowprinting2"/"nowprinting3")
DOMString? jacket_author; // self-explanatory
DOMString? information; // optional information shown in song selection
}
// chart difficulty (or custom chart name)
dictionary DifficultyInfo {
DOMString? name; // e.g. "Challenge", "Infinity", "Gravity", "Maximum", "FOUR DIMENSIONS"
DOMString? short_name; // e.g. "CH", "IN", "GRV", "MXM", "FD"
// (if not specified, it inherits the client defaults based on "index". e.g. 1=>"CH")
unsigned char idx; // 0-4 e.g. "CH"=>1, "IN"/"GRV"=>3, "MXM"/"FD"=>4
}
/* ------------------------------------------------------------------ */
/* ------------------------------ BEAT ------------------------------ */
/* ------------------------------------------------------------------ */
// beat-related data
dictionary BeatInfo {
ByPulse<double>[] bpm; // bpm changes
ByMeasureIndex<TimeSignature>[]? time_sig; // time signature changes
// this is used for drawing bar lines and
// calculating duration of length parameters for audio effects
ScrollSpeedPoint[]? scroll_speed; // scroll speed changes (e.g. stop events)
unsigned long resolution = 240; // pulses per quarter note
}
// time signature
dictionary TimeSignature {
unsigned long n; // numerator
unsigned long d; // denominator
}
/* ------------------------------------------------------------------ */
/* ----------------------------- GAUGE ------------------------------ */
/* ------------------------------------------------------------------ */
// gauge-related data
dictionary GaugeInfo {
unsigned int? total; // total ascension of gauge percentage in the entire chart (100-)
// set automatically if not specified
}
/* ------------------------------------------------------------------ */
/* ------------------------------ NOTE ------------------------------ */
/* ------------------------------------------------------------------ */
// notes on each lane
dictionary NoteInfo {
Interval[][]? bt; // BT notes (first index: lane) (l=0: chip note, l>0: long note)
Interval[][]? fx; // FX notes (first index: lane) (l=0: chip note, l>0: long note)
LaserSection[][]? laser; // laser notes (first index: lane (0: left knob, 1: right knob))
}
// laser section
dictionary LaserSection : ByPulse<GraphSectionPoint[]> {
unsigned long y; // pulse number
GraphSectionPoint[] v; // laser points (0-100)
unsigned char wide = 1; // 1-2, sets this section to be a 2x wide sections or not
}
/* ------------------------------------------------------------------- */
/* ------------------------------ AUDIO ------------------------------ */
/* ------------------------------------------------------------------- */
// audio-related data
dictionary AudioInfo {
BgmInfo? bgm; // bgm-related data
KeySoundInfo? key_sound; // key-sound-related data
AudioEffectInfo? audio_effect; // audio-effect-related data
}
/* ---------------------------- AUDIO.BGM ---------------------------- */
// bgm-related data
dictionary BgmInfo {
DOMString? filename; // self-explanatory
unsigned int vol = 100; // bgm volume (%)
long offset = 0; // offset in milliseconds (starting point of the audio file)
DOMString? preview_filename; // specified only if another audio file is used for preview
unsigned long preview_offset = 0; // preview offset in milliseconds (starting point of the audio file)
unsigned long preview_duration = 0; // preview duration in milliseconds
}
/* ------------------------- AUDIO.KEY_SOUND ------------------------- */
// key-sound-related data
dictionary KeySoundInfo {
DefList<KeySound>? def; // key sound definitions
InvokeList<ByPulse<KeySound>[]>? pulse_event; // key sound invocation by pulse
InvokeList<ByNotes<KeySound>>? note_event; // key sound invocation by notes
}
// key sound definition
dictionary Def<KeySound> {
// key sound filename (unchangeable in invocation)
DOMString filename;
// parameters (changeable in invocation, the default values are only used in Def)
KeySound v {
unsigned int vol = 100; // standard volume (%), this value is multiplied if specified in invocation
// vol[%] = Def<KeySound>.v.vol * invocation.v.vol / 100
};
}
/* ----------------------- AUDIO.AUDIO_EFFECT ------------------------ */
// audio-effect-related data
dictionary AudioEffectInfo {
DefList<AudioEffect>? def; // audio effect definitions
InvokeList<ByPulse<AudioEffect>[]>? pulse_event; // audio effect invocation (parameter changes) by pulse
InvokeList<ByNotes<AudioEffect>>? note_event; // audio effect invocation (parameter changes) by notes
}
// Note: In AudioEffectInfo.note_event.laser, the laser points inherit the audio effect type of the previous point.
// But this is not applied beyond a section.
// Note that the default audio effect (peaking filter) is set to the first point of every section as default.
// audio effect definition
dictionary Def<AudioEffect> {
DOMString type; // name of the audio effect to inherit (e.g. "Flanger")
AudioEffect v {
// Custom fields per FX
};
DOMString? filename; // can be specified only if type="SwitchAudio"
}
// Note: Preset audio effects ("", "Retrigger", "Gate", "Flanger"...) are implicitly defined in default.
// If an audio effect with the same name as a preset effect, implicitly defined presets will be overwritten.
//
// BT & FX & laser share the audio effect definition itself,
// but the instances of audio effects are created for each, and they work in parallel.
//
// Examples:
// ex1) "type=Flanger;delay=80samples;depth=30samples-60samples" in KSH
// {
// "type":"Flanger",
// "v":{
// "delay": ["80samples"],
// "depth": ["30samples", "30samples", "60samples"]
// }
// }
//
// ex2) "type=TapeStop;trigger=off>on;speed=20%" in KSH
// {
// "type":"TapeStop",
// "v":{
// "delay": ["off", "on"],
// "depth": ["20%"]
// }
// }
//
// ex3) "type=SwitchAudio;fileName=music.ogg" in KSH
// {
// "type":"SwitchAudio",
// "filename":"music.ogg" // not in "v" because "filename" is not changeable in invocation
// }
/* -------------------------------------------------------------------- */
/* ------------------------------ CAMERA ------------------------------ */
/* -------------------------------------------------------------------- */
// camera-related data
dictionary CameraInfo {
TiltInfo? tilt; // tilt-related data
CamInfo? cam; // cam-related data
}
/* --------------------------- CAMERA.TILT --------------------------- */
// tilt-related data
dictionary TiltInfo {
GraphSection[]? manual; // manual tilt (-100 - 100)
Interval[]? keep; // tilt keep
// (while a tilt keep event, the value is only updated to larger absolute values with the same sign)
}
// Note: the default value of "cam_assign" is
// {"rotation_z":[{"y":0, "v":7}], "jdgline_shift_x":[{"y":0, "v":?? (depends on clients) }]}
/* --------------------------- CAMERA.CAM ---------------------------- */
dictionary CamInfo {
CamGraphs body; // cam value changes
CamGraphs? tilt_assign; // tilt=>cam value translation scales (for NORMAL/BIGGER/BIGGEST tilt)
CamPatternInfo pattern; // cam pattern
}
// cam pattern
dictionary CamPatternInfo {
DefList<CamPattern>? def; // cam pattern definitions
InvokeList<ByPulse<CamPattern>[]>? pulse_event; // cam pattern invocation by pulse
InvokeList<ByNotes<CamPattern>>? note_event; // cam pattern invocation by notes
};
// cam value changes (whole chart)
dictionary CamGraphs {
GraphPoint[]? zoom; // zoom_bottom (affects both lane & jdgline relatively)
GraphPoint[]? shift_x; // zoom_side (affects both lane & jdgline relatively)
GraphPoint[]? rotation_x; // zoom_top (affects both lane & jdgline relatively)
GraphPoint[]? rotation_z; // rotation degree (affects both lane & jdgline relatively)
GraphPoint[]? lane_zoom; // zoom_bottom (lane only)
GraphPoint[]? lane_shift_x; // zoom_side (lane only)
GraphPoint[]? lane_rotation_x; // zoom_top (lane only)
GraphPoint[]? lane_rotation_z; // rotation degree (lane only)
GraphPoint[]? jdgline_zoom; // zoom_bottom (judgment line only)
GraphPoint[]? jdgline_shift_x; // judgment line x (judgment line only)
GraphPoint[]? jdgline_rotation_z; // rotation degree (judgment line only)
}
// cam pattern definition
dictionary Def<CamPattern> {
// name of the cam pattern (e.g. "spin")
DOMString name;
// body (unchangeable in invocation)
CamPatternGraphs body {
GraphSectionPoint[]? zoom; // zoom_bottom (affects both lane & jdgline relatively)
GraphSectionPoint[]? shift_x; // zoom_side (affects both lane & jdgline relatively)
GraphSectionPoint[]? rotation_x; // zoom_top (affects both lane & jdgline relatively)
GraphSectionPoint[]? rotation_z; // rotation degree (affects both lane & jdgline relatively)
GraphSectionPoint[]? lane_zoom; // zoom_bottom (lane only)
GraphSectionPoint[]? lane_shift_x; // zoom_side (lane only)
GraphSectionPoint[]? lane_rotation_x; // zoom_top (lane only)
GraphSectionPoint[]? lane_rotation_z; // rotation degree (lane only)
GraphSectionPoint[]? jdgline_zoom; // zoom_bottom (judgment line only)
GraphSectionPoint[]? jdgline_shift_x; // judgment line x (judgment line only)
GraphSectionPoint[]? jdgline_rotation_z; // rotation degree (judgment line only)
};
// parameters (changeable in invocation, the default values are only used in Def)
CamPattern v {
unsigned long l; // standard duration
// if a differrent value is set in invocation.v.l, Def<CamPattern>.body.ry will be scaled
// ry = Def<CamPattern>.body.ry * invocation.v.l / Def<CamPattern>.v.l
long scale = 100; // standard scale (normally only specified in invocation)
// scale[%] = 100 * invocation.v.scale / Def<CamPattern>.v.scale
// (set this value to -100 for right-to-left laser slams)
unsigned long repeat = 1; // number of repeat
long repeat_scale = 100; // rate (%) of the current "scale" to that of the previous repeat
// (set "-100" to generate a loop like a sine wave)
long decay_order = 0; // order of the decay that scales camera values
// - equation: `value * (1.0 - ((l - y) / l))^decay_order`
// - examples
// 0: no decay, 1: linear decay, 2: squared decay, negative: increasing
};
}
// Note: The pattern named "default" will be automatically invoked at the pulse 0.
//
// Note: "" (no change) & "laser_slam" & "spin" & "half_spin" & "swing" are predefined by kson clients.
//
// Predefined pattern example:
// {
// "name":"swing",
// "body":{
// "shift_x":[
// {"ry":0, "v":0, "a":100, "b":59}
// {"ry":480, "v":100, "a":0, "b":59}
// {"ry":960, "v":0}
// ]
// },
// "v":{
// "l":960,
// "repeat_scale":-100
// }
// }
/* -------------------------------------------------------------------- */
/* -------------------------------- BG -------------------------------- */
/* -------------------------------------------------------------------- */
// background-related data
dictionary BgInfo {
LayerInfo? layer; // layer-related data
MovieInfo? movie; // movie-related data
}
/* ----------------------------- BG.LAYER ------------------------------ */
// layer-related data
dictionary LayerInfo {
DefList<Layer>? def; // layer definitions
InvokeList<ByPulse<Layer>[]>? pulse_event; // layer invocation (parameter changes) by pulse
InvokeList<ByNotes<Layer>>? note_event; // layer invocation (parameter changes) by notes
}
// layer definition
dictionary Def<Layer> {
// name of the layer
DOMString name;
// image files
// one file: use one image regardless of the gauge
// two files: use second image when gauge >= 70%
ImageFile image[] {
// image filename
DOMString filename;
// size of one frame in pixels
// (if not specified, the entire image is regarded as one frame)
unsigned long? w;
unsigned long? h;
unsigned long frame; // number of frames
// offset position in pixels
unsigned long offset_x = 0;
unsigned long offset_y = 0;
// relative pixels of the next frame
unsigned long dx = w;
unsigned long dy = 0;
}
// parameters (changeable in invocation, the default values are only used in Def)
Layer v {
bool visible = true; // self-explanatory
long l = 0; // pulses for one loop of the animation
// (if the value is set to 0, the animation stops at the current frame)
long frame = 0; // frame index (this parameter means "frame offset" in Def and "seeking to a frame" in invocation)
// modulo value is used if the frame index is out of range
// (frame index) = frame % (number of frames) (if frame >= 0)
// (frame index) = frame % (number of frames) + (number of frames) (if frame < 0)
long x = 0; // x-axis position (0 = center, positive = right)
long y = 0; // y-axis position (0 = center, positive = up)
long z = 0; // order of drawing layers (smaller = higher priority)
// negative values: in front of the lane
// positive values: behind the lane
unsigned int opacity = 255; // self-explanatory (0-255)
int rotation = 0; // rotation in degrees
DOMString mode = "normal"; // blend mode ("normal"/"additive")
};
// layer pattern
LayerPatternInfo pattern;
}
// Note: KSM bg images (e.g. "desert") and KSM animation layers (e.g. "arrow") are predefined.
// KSM bg images: z = 200, mode = "normal"
// KSM animation layers: z = 100, mode = "additive"
// layer pattern
dictionary LayerPatternInfo {
DefList<LayerPattern> def; // layer pattern definitions
InvokeList<ByPulse<Layer>[]>? pulse_event; // layer pattern invocation by pulse
InvokeList<ByNotes<Layer>>? note_event; // layer pattern invocation by notes
}
// layer pattern definition
dictionary Def<LayerPattern> {
// name of the layer pattern
DOMString name;
// body (unchangeable in invocation)
LayerPatternGraphs body {
GraphSectionPoint[]? l;
GraphSectionPoint[]? frame;
GraphSectionPoint[]? x;
GraphSectionPoint[]? y;
GraphSectionPoint[]? z;
GraphSectionPoint[]? opacity;
GraphSectionPoint[]? rotation;
};
// parameters (changeable in invocation, the default values are only used in Def)
LayerPattern v {
unsigned long l; // standard duration
// if a differrent value is set in invocation.v.l, Def<LayerPattern>.body.ry will be scaled
// ry = Def<LayerPattern>.body.ry * invocation.v.l / Def<LayerPattern>.v.l
long scale = 100; // standard scale (normally only specified in invocation)
// scale[%] = 100 * invocation.v.scale / Def<LayerPattern>.v.scale
unsigned long repeat = 1; // number of repeat
long repeat_scale = 100; // rate (%) of the current "scale" to that of the previous repeat
// (set "-100" to generate a loop like a sine wave)
long decay_order = 0; // order of the decay that scales layer values
// - equation: `value * (1.0 - ((l - y) / l))^decay_order`
// - examples
// 0: no decay, 1: linear decay, 2: squared decay, negative: increasing
};
}
/* ----------------------------- BG.MOVIE ------------------------------ */
// movie-related data
dictionary MovieInfo {
DOMString? filename; // self-explanatory
long offset = 0; // offset in milliseconds (starting point of the video file)
}
/* -------------------------------------------------------------------- */
/* ------------------------------- IMPL ------------------------------- */
/* -------------------------------------------------------------------- */
// Client list using implementation-dependent options
dictionary ClientList {
ImplInfo? ksm2; // Just an example
...
}
// Implementation-dependent options
// - This allows using options undefined in kson spec
// - If known parameters in kson spec is set, these parameters are forked by clients.
// - The replacement affects each parameter
// - e.g. even if "note":{} is set, the notes will not be deleted
// - But an array is regarded as a parameter
// - e.g. if "note":{"bt":[]} is set, the BT notes will be deleted,
// and this will not affect the other lanes
dictionary ImplInfo {
any? meta; // meta data
any? beat; // beat-related data
any? gauge; // gauge-related data
any? note; // note-related data
any? audio; // audio-related data
any? camera; // camera-related data
any? bg; // background-related data
any? other; // others
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment