parent
06d23501ca
commit
514c01dc3f
@ -54,11 +54,14 @@ Contains information that applies to the whole set of charts
|
||||
- string, optional
|
||||
- Relative path to the jacket / album cover / album art to be shown in music select for example. usually a square image.
|
||||
- **BPM**
|
||||
- number, required
|
||||
- number or string, required
|
||||
- Song tempo in Beats per Minute.
|
||||
- Striclty positive
|
||||
- Strings allowed for easier decimal representation preservation
|
||||
- **offset**
|
||||
- number, required
|
||||
- number or string, required
|
||||
- In seconds, opposite of the time position of the first beat in the music file. For instance, if the first beat occurs at 0.15 seconds in the audio file, `offset̀` should be -0.15
|
||||
- Strings allowed for easier decimal representation preservation
|
||||
- **preview**
|
||||
- object or string, optional
|
||||
- Contains either a {ref}`preview object <preview>` or a path to a bms-style preview file
|
||||
@ -76,11 +79,15 @@ Contains information that applies to the whole set of charts
|
||||
Describes the part of the music file that's meant to be played on loop when previewing this song at the music select screen
|
||||
|
||||
- **start**
|
||||
- number, required
|
||||
- number or string, required
|
||||
- In seconds, start of the loop
|
||||
- Positive
|
||||
- Strings allowed for easier decimal representation preservation
|
||||
- **duration**
|
||||
- number, required
|
||||
- number or string, required
|
||||
- In seconds, duration of the loop
|
||||
- Strictly positive
|
||||
- Strings allowed for easier decimal representation preservation
|
||||
|
||||
(data)=
|
||||
## Data
|
||||
@ -165,7 +172,7 @@ A classic note.
|
||||
|
||||
Ticks are fractions of the beat.
|
||||
The resolution defines how many ticks are in a beat for a given chart.
|
||||
In other words if the resolution is 420, a tick lasts for 1/420th of a beat
|
||||
In other words if the resolution is 420, a tick lasts for 1/420th oLike for the BPM, sf a beat
|
||||
|
||||
For more info about measuring time in ticks, see [bmson's docs](https://bmson-spec.readthedocs.io/en/master/doc/index.html#terminologies) (their docs refers to ticks as *pulses*).
|
||||
- as an array :
|
||||
|
@ -103,19 +103,13 @@ Since this is mostly an implicit rule that's not strictly followed by official c
|
||||
|
||||
## Decimal values
|
||||
|
||||
If possible, non-integer values like `BPM` or `offset` should be manipulated using a [Decimal Data Type](https://en.wikipedia.org/wiki/Decimal_data_type) to preserve their original decimal representation. I think no one likes to see the BPM they defined as a clean `195.3` in the editor be stored as a messy `195.3000030517578125` in the file.
|
||||
If possible, non-integer values like `BPM` or `offset` should be manipulated using a [Decimal Data Type](https://en.wikipedia.org/wiki/Decimal_data_type) to preserve their original decimal representation. I think no one likes to see the BPM they defined as a clean `195.3` in the editor be stored as a messy `195.3000030517578125` in the file. If doing this is too hard with your language / library of choice, keep in mind that `1.0.0` allows strings instead :
|
||||
|
||||
Be careful that the serialized values in the resulting file must still be *number litterals*, not strings.
|
||||
|
||||
- **Good**
|
||||
- **Valid**
|
||||
```json
|
||||
{ "BPM" : 195.3 }
|
||||
```
|
||||
- **Bad**
|
||||
- **Valid since 1.0.0**
|
||||
```json
|
||||
{ "BPM": "195.3" }
|
||||
```
|
||||
|
||||
This is not that easy. Python's standard module `json`, for instance, allows *deserializing* (reading) numbers in a json file as `decimal.Decimal` instances, but has no easy way of *serializing* (writing) `decimal.Decimal` instances as a json number litteral that respects the original representation.
|
||||
|
||||
A possible solution is to use the [simplejson](https://pypi.org/project/simplejson/) module as a near drop-in replacement for `json` and use the `use_decimal` options
|
||||
```
|
45
schema.json
45
schema.json
@ -30,12 +30,11 @@
|
||||
},
|
||||
"BPM": {
|
||||
"description": "Song tempo in Beats per Minute",
|
||||
"type": "number",
|
||||
"exclusiveMinimum": 0
|
||||
"$ref": "#/$defs/strictlyPositiveDecimal"
|
||||
},
|
||||
"offset": {
|
||||
"description": "In seconds, opposite of the time position of the first beat in the music file",
|
||||
"type": "number"
|
||||
"$ref": "#/$defs/decimal"
|
||||
},
|
||||
"preview": {
|
||||
"description": "Describes the part of the music file that's to be played on loop when previewing this song",
|
||||
@ -45,13 +44,11 @@
|
||||
"properties": {
|
||||
"start": {
|
||||
"description": "In seconds, Time at which preview should start",
|
||||
"type": "number",
|
||||
"minimum": 0
|
||||
"$ref": "#/$defs/positiveDecimal"
|
||||
},
|
||||
"duration": {
|
||||
"description": "In seconds, for how long should the preview be played past the starting point",
|
||||
"type": "number",
|
||||
"minimum": 0
|
||||
"$ref": "#/$defs/strictlyPositiveDecimal"
|
||||
}
|
||||
},
|
||||
"required": ["start", "duration"]
|
||||
@ -180,6 +177,40 @@
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"decimal": {
|
||||
"description": "a decimal number as either a number literal or a string",
|
||||
"oneOf": [{
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"pattern": "^-?\\d+(\\.\\d+)?$"
|
||||
}
|
||||
]
|
||||
},
|
||||
"positiveDecimal": {
|
||||
"description": "a decimal number as either a number literal or a string",
|
||||
"oneOf": [{
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"pattern": "^\\d+(\\.\\d+)?$"
|
||||
}
|
||||
]
|
||||
},
|
||||
"strictlyPositiveDecimal": {
|
||||
"description": "a strictly positive decimal number as either a number literal or a string",
|
||||
"oneOf": [{
|
||||
"type": "number",
|
||||
"exclusiveMinimum": 0
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"pattern": "^(0\\.\\d*[1-9]\\d*|\\d*[1-9]\\d*(\\.\\d+)?)$"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
@ -7,7 +7,7 @@
|
||||
"offset": 0,
|
||||
"preview": {
|
||||
"start": 0,
|
||||
"duration": 0
|
||||
"duration": 1
|
||||
}
|
||||
},
|
||||
"data": {}
|
||||
|
@ -0,0 +1,10 @@
|
||||
{
|
||||
"version": "1.0.0",
|
||||
"metadata": {
|
||||
"title": "",
|
||||
"artist": "",
|
||||
"BPM": -1,
|
||||
"offset": 0
|
||||
},
|
||||
"data": {}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
{
|
||||
"version": "1.0.0",
|
||||
"metadata": {
|
||||
"title": "",
|
||||
"artist": "",
|
||||
"BPM": "-1",
|
||||
"offset": 0
|
||||
},
|
||||
"data": {}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
{
|
||||
"version": "1.0.0",
|
||||
"metadata": {
|
||||
"title": "",
|
||||
"artist": "",
|
||||
"BPM": 1,
|
||||
"offset": 0,
|
||||
"preview": {
|
||||
"start": "0",
|
||||
"duration": "0.000"
|
||||
}
|
||||
},
|
||||
"data": {}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
{
|
||||
"version": "1.0.0",
|
||||
"metadata": {
|
||||
"title": "",
|
||||
"artist": "",
|
||||
"BPM": 1,
|
||||
"offset": 0,
|
||||
"preview": {
|
||||
"start": "0",
|
||||
"duration": "-10.000"
|
||||
}
|
||||
},
|
||||
"data": {}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
{
|
||||
"version": "1.0.0",
|
||||
"metadata": {
|
||||
"title": "",
|
||||
"artist": "",
|
||||
"BPM": 1,
|
||||
"offset": 0,
|
||||
"preview": {
|
||||
"start": "0",
|
||||
"duration": "0"
|
||||
}
|
||||
},
|
||||
"data": {}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
{
|
||||
"version": "1.0.0",
|
||||
"metadata": {
|
||||
"title": "",
|
||||
"artist": "",
|
||||
"BPM": "0.000",
|
||||
"offset": 0
|
||||
},
|
||||
"data": {}
|
||||
}
|
10
tests/data/06 - decimals as string/fail/zero BPM number.json
Normal file
10
tests/data/06 - decimals as string/fail/zero BPM number.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"version": "1.0.0",
|
||||
"metadata": {
|
||||
"title": "",
|
||||
"artist": "",
|
||||
"BPM": 0,
|
||||
"offset": 0
|
||||
},
|
||||
"data": {}
|
||||
}
|
10
tests/data/06 - decimals as string/fail/zero BPM string.json
Normal file
10
tests/data/06 - decimals as string/fail/zero BPM string.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"version": "1.0.0",
|
||||
"metadata": {
|
||||
"title": "",
|
||||
"artist": "",
|
||||
"BPM": "0",
|
||||
"offset": 0
|
||||
},
|
||||
"data": {}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
{
|
||||
"version": "1.0.0",
|
||||
"metadata": {
|
||||
"title": "",
|
||||
"artist": "",
|
||||
"BPM": "0.1",
|
||||
"offset": 0
|
||||
},
|
||||
"data": {}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
{
|
||||
"version": "1.0.0",
|
||||
"metadata": {
|
||||
"title": "",
|
||||
"artist": "",
|
||||
"BPM": "123.456",
|
||||
"offset": 0
|
||||
},
|
||||
"data": {}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
{
|
||||
"version": "1.0.0",
|
||||
"metadata": {
|
||||
"title": "",
|
||||
"artist": "",
|
||||
"BPM": 123.456,
|
||||
"offset": "-0.24"
|
||||
},
|
||||
"data": {}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
{
|
||||
"version": "1.0.0",
|
||||
"metadata": {
|
||||
"title": "",
|
||||
"artist": "",
|
||||
"BPM": 123.456,
|
||||
"offset": "12.34"
|
||||
},
|
||||
"data": {}
|
||||
}
|
10
tests/data/06 - decimals as string/pass/integer BPM.json
Normal file
10
tests/data/06 - decimals as string/pass/integer BPM.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"version": "1.0.0",
|
||||
"metadata": {
|
||||
"title": "",
|
||||
"artist": "",
|
||||
"BPM": 125,
|
||||
"offset": 0
|
||||
},
|
||||
"data": {}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
{
|
||||
"version": "1.0.0",
|
||||
"metadata": {
|
||||
"title": "",
|
||||
"artist": "",
|
||||
"BPM": "123",
|
||||
"offset": 0
|
||||
},
|
||||
"data": {}
|
||||
}
|
10
tests/data/06 - decimals as string/pass/number BPM.json
Normal file
10
tests/data/06 - decimals as string/pass/number BPM.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"version": "1.0.0",
|
||||
"metadata": {
|
||||
"title": "",
|
||||
"artist": "",
|
||||
"BPM": 123.456,
|
||||
"offset": 0
|
||||
},
|
||||
"data": {}
|
||||
}
|
14
tests/data/06 - decimals as string/pass/preview object.json
Normal file
14
tests/data/06 - decimals as string/pass/preview object.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"version": "1.0.0",
|
||||
"metadata": {
|
||||
"title": "",
|
||||
"artist": "",
|
||||
"BPM": 1,
|
||||
"offset": 0,
|
||||
"preview": {
|
||||
"start": "8346.9346",
|
||||
"duration": "35.936"
|
||||
}
|
||||
},
|
||||
"data": {}
|
||||
}
|
@ -7,7 +7,7 @@ from jschon.jsonschema import Scope
|
||||
from jschon import create_catalog, JSONSchema, JSON
|
||||
import pytest
|
||||
|
||||
_catalog = create_catalog('2020-12')
|
||||
_catalog = create_catalog("2020-12")
|
||||
SCHEMA = JSONSchema.loadf("schema.json", catalog=_catalog)
|
||||
|
||||
def prettify_path(json_path: str) -> str:
|
||||
|
Loading…
Reference in New Issue
Block a user