-
-
Save m4saka/a89594a17dc9422d75e01998bcfd2722 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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