sonolus-pjsekai-js 1.1.4 → 1.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/EngineWatchData +0 -0
- package/dist/index.cjs +29 -29
- package/dist/index.d.cts +4 -4
- package/dist/sus/analyze.cjs +25 -23
- package/dist/sus/analyze.d.ts +29 -0
- package/dist/sus/analyze.js +262 -0
- package/dist/sus/convert.cjs +22 -19
- package/dist/sus/convert.d.cts +1 -1
- package/dist/sus/convert.d.ts +5 -0
- package/dist/sus/convert.js +301 -0
- package/dist/usc/convert.cjs +74 -68
- package/dist/usc/convert.d.cts +2 -2
- package/dist/usc/convert.d.ts +3 -0
- package/dist/usc/convert.js +542 -0
- package/dist/usc/index.d.cts +15 -15
- package/dist/usc/index.d.ts +91 -0
- package/dist/usc/index.js +15 -0
- package/package.json +13 -5
package/dist/EngineWatchData
CHANGED
Binary file
|
package/dist/index.cjs
CHANGED
@@ -20,47 +20,47 @@ Object.defineProperty(exports, "susToUSC", { enumerable: true, get: function ()
|
|
20
20
|
var convert_cjs_2 = require("./usc/convert.cjs");
|
21
21
|
Object.defineProperty(exports, "uscToLevelData", { enumerable: true, get: function () { return convert_cjs_2.uscToLevelData; } });
|
22
22
|
__exportStar(require("./usc/index.cjs"), exports);
|
23
|
-
exports.version =
|
23
|
+
exports.version = "1.1.5";
|
24
24
|
exports.databaseEngineItem = {
|
25
|
-
name:
|
25
|
+
name: "prosekaR",
|
26
26
|
version: 13,
|
27
27
|
title: {
|
28
|
-
en:
|
29
|
-
ja:
|
30
|
-
ko:
|
31
|
-
zhs:
|
32
|
-
zht:
|
28
|
+
en: "ProSeka R",
|
29
|
+
ja: "プロセカ R",
|
30
|
+
ko: "프로세카 R",
|
31
|
+
zhs: "世界计划 R",
|
32
|
+
zht: "世界計劃 R",
|
33
33
|
},
|
34
34
|
subtitle: {
|
35
|
-
en:
|
36
|
-
ja:
|
37
|
-
ko:
|
38
|
-
zhs:
|
39
|
-
zht:
|
35
|
+
en: "ProSeka Rush",
|
36
|
+
ja: "プロセカ ラッシュ",
|
37
|
+
ko: "프로세카 러쉬",
|
38
|
+
zhs: "世界计划 匆忙",
|
39
|
+
zht: "世界計劃 匆忙",
|
40
40
|
},
|
41
41
|
author: {
|
42
|
-
en:
|
42
|
+
en: "Hyeon2#7895",
|
43
43
|
},
|
44
44
|
description: {
|
45
45
|
en: [
|
46
|
-
|
46
|
+
"A recreation of Project Sekai: Colorful Stage! engine in Sonolus.",
|
47
47
|
`Version: ${exports.version}`,
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
].join(
|
48
|
+
"",
|
49
|
+
"Forked from the pjsekai engine by Burrito#1000.",
|
50
|
+
"https://github.com/NonSpicyBurrito/sonolus-pjsekai-engine",
|
51
|
+
"",
|
52
|
+
"Github:",
|
53
|
+
"https://github.com/hyeon2006/sonolus-pjsekai-js",
|
54
|
+
].join("\n"),
|
55
55
|
ko: [
|
56
|
-
|
56
|
+
"프로젝트 세카이: 컬러풀 스테이지! 엔진을 Sonolus로 재현했습니다.",
|
57
57
|
`버전: ${exports.version}`,
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
].join(
|
58
|
+
"",
|
59
|
+
"Burrito#1000의 pjsekai 엔진에서 포크되었습니다.",
|
60
|
+
"https://github.com/NonSpicyBurrito/sonolus-pjsekai-engine",
|
61
|
+
"",
|
62
|
+
"깃허브:",
|
63
|
+
"https://github.com/hyeon2006/sonolus-pjsekai-js",
|
64
|
+
].join("\n"),
|
65
65
|
},
|
66
66
|
};
|
package/dist/index.d.cts
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
export { susToUSC } from
|
2
|
-
export { uscToLevelData } from
|
3
|
-
export * from
|
4
|
-
export declare const version = "1.1.
|
1
|
+
export { susToUSC } from "./sus/convert.cjs";
|
2
|
+
export { uscToLevelData } from "./usc/convert.cjs";
|
3
|
+
export * from "./usc/index.cjs";
|
4
|
+
export declare const version = "1.1.5";
|
5
5
|
export declare const databaseEngineItem: {
|
6
6
|
readonly name: "prosekaR";
|
7
7
|
readonly version: 13;
|
package/dist/sus/analyze.cjs
CHANGED
@@ -4,12 +4,12 @@ exports.analyze = void 0;
|
|
4
4
|
const analyze = (sus) => {
|
5
5
|
const { lines, measureChanges, meta } = parse(sus);
|
6
6
|
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
7
|
-
const offset = -+(meta.get(
|
7
|
+
const offset = -+(meta.get("WAVEOFFSET") || "0");
|
8
8
|
if (Number.isNaN(offset))
|
9
|
-
throw new Error(
|
9
|
+
throw new Error("Unexpected offset");
|
10
10
|
const ticksPerBeat = getTicksPerBeat(meta);
|
11
11
|
if (!ticksPerBeat)
|
12
|
-
throw new Error(
|
12
|
+
throw new Error("Missing or unexpected ticks per beat");
|
13
13
|
const barLengths = getBarLengths(lines, measureChanges);
|
14
14
|
const toTick = getToTick(barLengths, ticksPerBeat);
|
15
15
|
const bpms = new Map();
|
@@ -22,27 +22,27 @@ const analyze = (sus) => {
|
|
22
22
|
const [header, data] = line;
|
23
23
|
const measureOffset = measureChanges.find(([changeIndex]) => changeIndex <= index)?.[1] ?? 0;
|
24
24
|
// Time Scale Changes
|
25
|
-
if (header.length === 5 && header.startsWith(
|
25
|
+
if (header.length === 5 && header.startsWith("TIL")) {
|
26
26
|
timeScaleChanges.push(...toTimeScaleChanges(line, toTick));
|
27
27
|
continue;
|
28
28
|
}
|
29
29
|
// BPM
|
30
|
-
if (header.length === 5 && header.startsWith(
|
30
|
+
if (header.length === 5 && header.startsWith("BPM")) {
|
31
31
|
bpms.set(header.substring(3), +data);
|
32
32
|
continue;
|
33
33
|
}
|
34
34
|
// BPM Changes
|
35
|
-
if (header.length === 5 && header.endsWith(
|
35
|
+
if (header.length === 5 && header.endsWith("08")) {
|
36
36
|
bpmChanges.push(...toBpmChanges(line, measureOffset, bpms, toTick));
|
37
37
|
continue;
|
38
38
|
}
|
39
39
|
// Tap Notes
|
40
|
-
if (header.length === 5 && header[3] ===
|
40
|
+
if (header.length === 5 && header[3] === "1") {
|
41
41
|
tapNotes.push(...toNotes(line, measureOffset, toTick));
|
42
42
|
continue;
|
43
43
|
}
|
44
44
|
// Streams
|
45
|
-
if (header.length === 6 && (header[3] ===
|
45
|
+
if (header.length === 6 && (header[3] === "3" || header[3] === "9")) {
|
46
46
|
const key = `${header[5]}-${header[3]}`;
|
47
47
|
const stream = streams.get(key);
|
48
48
|
if (stream) {
|
@@ -57,7 +57,7 @@ const analyze = (sus) => {
|
|
57
57
|
continue;
|
58
58
|
}
|
59
59
|
// Directional Notes
|
60
|
-
if (header.length === 5 && header[3] ===
|
60
|
+
if (header.length === 5 && header[3] === "5") {
|
61
61
|
directionalNotes.push(...toNotes(line, measureOffset, toTick));
|
62
62
|
continue;
|
63
63
|
}
|
@@ -79,11 +79,11 @@ const parse = (sus) => {
|
|
79
79
|
const measureChanges = [];
|
80
80
|
const meta = new Map();
|
81
81
|
for (const line of sus
|
82
|
-
.split(
|
82
|
+
.split("\n")
|
83
83
|
.map((line) => line.trim())
|
84
|
-
.filter((line) => line.startsWith(
|
85
|
-
const isLine = line.includes(
|
86
|
-
const index = line.indexOf(isLine ?
|
84
|
+
.filter((line) => line.startsWith("#"))) {
|
85
|
+
const isLine = line.includes(":");
|
86
|
+
const index = line.indexOf(isLine ? ":" : " ");
|
87
87
|
if (index === -1)
|
88
88
|
continue;
|
89
89
|
const left = line.substring(1, index).trim();
|
@@ -91,7 +91,7 @@ const parse = (sus) => {
|
|
91
91
|
if (isLine) {
|
92
92
|
lines.push([left, right]);
|
93
93
|
}
|
94
|
-
else if (left ===
|
94
|
+
else if (left === "MEASUREBS") {
|
95
95
|
measureChanges.unshift([lines.length, +right]);
|
96
96
|
}
|
97
97
|
else {
|
@@ -105,7 +105,7 @@ const parse = (sus) => {
|
|
105
105
|
};
|
106
106
|
};
|
107
107
|
const getTicksPerBeat = (meta) => {
|
108
|
-
const request = meta.get(
|
108
|
+
const request = meta.get("REQUEST");
|
109
109
|
if (!request)
|
110
110
|
return;
|
111
111
|
if (!request.startsWith('"ticks_per_beat ') || !request.endsWith('"'))
|
@@ -118,7 +118,7 @@ const getBarLengths = (lines, measureChanges) => {
|
|
118
118
|
const [header, data] = line;
|
119
119
|
if (header.length !== 5)
|
120
120
|
continue;
|
121
|
-
if (!header.endsWith(
|
121
|
+
if (!header.endsWith("02"))
|
122
122
|
continue;
|
123
123
|
const measure = +header.substring(0, 3) +
|
124
124
|
(measureChanges.find(([changeIndex]) => changeIndex <= index)?.[1] ?? 0);
|
@@ -143,7 +143,7 @@ const getToTick = (barLengths, ticksPerBeat) => {
|
|
143
143
|
return (measure, p, q) => {
|
144
144
|
const bar = bars.find((bar) => measure >= bar.measure);
|
145
145
|
if (!bar)
|
146
|
-
throw new Error(
|
146
|
+
throw new Error("Unexpected missing bar");
|
147
147
|
return (bar.ticks +
|
148
148
|
(measure - bar.measure) * bar.ticksPerMeasure +
|
149
149
|
(p * bar.ticksPerMeasure) / q);
|
@@ -155,20 +155,22 @@ const toBpmChanges = (line, measureOffset, bpms, toTick) => toRaws(line, measure
|
|
155
155
|
}));
|
156
156
|
const toTimeScaleChanges = ([, data], toTick) => {
|
157
157
|
if (!data.startsWith('"') || !data.endsWith('"'))
|
158
|
-
throw new Error(
|
158
|
+
throw new Error("Unexpected time scale changes");
|
159
159
|
return data
|
160
160
|
.slice(1, -1)
|
161
|
-
.split(
|
161
|
+
.split(",")
|
162
162
|
.map((segment) => segment.trim())
|
163
163
|
.filter((segment) => !!segment)
|
164
164
|
.map((segment) => {
|
165
165
|
const [l, rest] = segment.split("'");
|
166
|
-
const [m, r] = rest.split(
|
166
|
+
const [m, r] = rest.split(":");
|
167
167
|
const measure = +l;
|
168
168
|
const tick = +m;
|
169
169
|
const timeScale = +r;
|
170
|
-
if (Number.isNaN(measure) ||
|
171
|
-
|
170
|
+
if (Number.isNaN(measure) ||
|
171
|
+
Number.isNaN(tick) ||
|
172
|
+
Number.isNaN(timeScale))
|
173
|
+
throw new Error("Unexpected time scale change");
|
172
174
|
return {
|
173
175
|
tick: toTick(measure, 0, 1) + tick,
|
174
176
|
timeScale,
|
@@ -210,7 +212,7 @@ const toSlides = (stream) => {
|
|
210
212
|
const toRaws = ([header, data], measureOffset, toTick) => {
|
211
213
|
const measure = +header.substring(0, 3) + measureOffset;
|
212
214
|
return (data.match(/.{2}/g) ?? [])
|
213
|
-
.map((value, i, values) => value !==
|
215
|
+
.map((value, i, values) => value !== "00" && {
|
214
216
|
tick: toTick(measure, i, values.length),
|
215
217
|
value,
|
216
218
|
})
|
@@ -0,0 +1,29 @@
|
|
1
|
+
type Meta = Map<string, string[]>;
|
2
|
+
export type TimeScaleChangeObject = {
|
3
|
+
tick: number;
|
4
|
+
timeScale: number;
|
5
|
+
};
|
6
|
+
export type BpmChangeObject = {
|
7
|
+
tick: number;
|
8
|
+
bpm: number;
|
9
|
+
};
|
10
|
+
export type NoteObject = {
|
11
|
+
tick: number;
|
12
|
+
lane: number;
|
13
|
+
width: number;
|
14
|
+
type: number;
|
15
|
+
timeScaleGroup: number;
|
16
|
+
};
|
17
|
+
export type Score = {
|
18
|
+
offset: number;
|
19
|
+
ticksPerBeat: number;
|
20
|
+
timeScaleChanges: TimeScaleChangeObject[][];
|
21
|
+
bpmChanges: BpmChangeObject[];
|
22
|
+
tapNotes: NoteObject[];
|
23
|
+
directionalNotes: NoteObject[];
|
24
|
+
slides: NoteObject[][];
|
25
|
+
guides: NoteObject[][];
|
26
|
+
meta: Meta;
|
27
|
+
};
|
28
|
+
export declare const analyze: (sus: string) => Score;
|
29
|
+
export {};
|
@@ -0,0 +1,262 @@
|
|
1
|
+
export const analyze = (sus) => {
|
2
|
+
const { lines, measureChanges, timeScaleGroupChanges, meta } = parse(sus);
|
3
|
+
const offset = -+(meta.get("WAVEOFFSET")?.[0] ?? "0");
|
4
|
+
if (Number.isNaN(offset))
|
5
|
+
throw "Unexpected offset";
|
6
|
+
const ticksPerBeat = getTicksPerBeat(meta) ?? 480;
|
7
|
+
if (!ticksPerBeat)
|
8
|
+
throw "Missing or unexpected ticks per beat";
|
9
|
+
const barLengths = getBarLengths(lines, measureChanges);
|
10
|
+
const toTick = getToTick(barLengths, ticksPerBeat);
|
11
|
+
const bpms = new Map();
|
12
|
+
const bpmChanges = [];
|
13
|
+
const timeScaleGroups = new Map();
|
14
|
+
const timeScaleChanges = [];
|
15
|
+
const tapNotes = [];
|
16
|
+
const directionalNotes = [];
|
17
|
+
const streams = new Map();
|
18
|
+
const guideStreams = new Map();
|
19
|
+
for (const [, timeScaleGroup] of timeScaleGroupChanges) {
|
20
|
+
if (timeScaleGroups.has(timeScaleGroup))
|
21
|
+
continue;
|
22
|
+
timeScaleGroups.set(timeScaleGroup, timeScaleGroups.size);
|
23
|
+
timeScaleChanges.push([]);
|
24
|
+
}
|
25
|
+
// Time Scale Changes
|
26
|
+
for (const line of lines) {
|
27
|
+
const [header] = line;
|
28
|
+
if (header.length === 5 && header.startsWith("TIL")) {
|
29
|
+
const timeScaleGroup = header.substring(3, 5);
|
30
|
+
const timeScaleIndex = timeScaleGroups.get(timeScaleGroup);
|
31
|
+
if (timeScaleIndex === undefined) {
|
32
|
+
continue;
|
33
|
+
}
|
34
|
+
timeScaleChanges[timeScaleIndex].push(...toTimeScaleChanges(line, toTick));
|
35
|
+
}
|
36
|
+
}
|
37
|
+
lines.forEach((line, index) => {
|
38
|
+
const [header, data] = line;
|
39
|
+
const measureOffset = measureChanges.find(([changeIndex]) => changeIndex <= index)?.[1] ?? 0;
|
40
|
+
const timeScaleGroupName = timeScaleGroupChanges.find(([changeIndex]) => changeIndex <= index)?.[1] ?? "00";
|
41
|
+
let timeScaleGroup = timeScaleGroups.get(timeScaleGroupName);
|
42
|
+
if (timeScaleGroup === undefined) {
|
43
|
+
timeScaleGroup = timeScaleGroups.size;
|
44
|
+
timeScaleGroups.set(timeScaleGroupName, timeScaleGroups.size);
|
45
|
+
timeScaleChanges.push([]);
|
46
|
+
}
|
47
|
+
// Hispeed definitions
|
48
|
+
if (header.length === 5 && header.startsWith("TIL")) {
|
49
|
+
return;
|
50
|
+
}
|
51
|
+
// BPM
|
52
|
+
if (header.length === 5 && header.startsWith("BPM")) {
|
53
|
+
bpms.set(header.substring(3), +data);
|
54
|
+
return;
|
55
|
+
}
|
56
|
+
// BPM Changes
|
57
|
+
if (header.length === 5 && header.endsWith("08")) {
|
58
|
+
bpmChanges.push(...toBpmChanges(line, measureOffset, bpms, toTick));
|
59
|
+
return;
|
60
|
+
}
|
61
|
+
// Tap Notes
|
62
|
+
if (header.length === 5 && header[3] === "1") {
|
63
|
+
tapNotes.push(...toNotes(line, measureOffset, timeScaleGroup, toTick));
|
64
|
+
return;
|
65
|
+
}
|
66
|
+
// Streams
|
67
|
+
if (header.length === 6 && header[3] === "3") {
|
68
|
+
const channel = header[5];
|
69
|
+
const stream = streams.get(channel);
|
70
|
+
if (stream) {
|
71
|
+
stream.push(...toNotes(line, measureOffset, timeScaleGroup, toTick));
|
72
|
+
}
|
73
|
+
else {
|
74
|
+
streams.set(channel, toNotes(line, measureOffset, timeScaleGroup, toTick));
|
75
|
+
}
|
76
|
+
return;
|
77
|
+
}
|
78
|
+
// Guides
|
79
|
+
if (header.length === 6 && header[3] === "9") {
|
80
|
+
const channel = header[5];
|
81
|
+
const stream = guideStreams.get(channel);
|
82
|
+
if (stream) {
|
83
|
+
stream.push(...toNotes(line, measureOffset, timeScaleGroup, toTick));
|
84
|
+
}
|
85
|
+
else {
|
86
|
+
guideStreams.set(channel, toNotes(line, measureOffset, timeScaleGroup, toTick));
|
87
|
+
}
|
88
|
+
return;
|
89
|
+
}
|
90
|
+
// Directional Notes
|
91
|
+
if (header.length === 5 && header[3] === "5") {
|
92
|
+
directionalNotes.push(...toNotes(line, measureOffset, timeScaleGroup, toTick));
|
93
|
+
return;
|
94
|
+
}
|
95
|
+
});
|
96
|
+
const slides = [...streams.values()].map(toSlides).flat();
|
97
|
+
const guides = [...guideStreams.values()].map(toSlides).flat();
|
98
|
+
return {
|
99
|
+
offset,
|
100
|
+
ticksPerBeat,
|
101
|
+
timeScaleChanges,
|
102
|
+
bpmChanges,
|
103
|
+
tapNotes,
|
104
|
+
directionalNotes,
|
105
|
+
slides,
|
106
|
+
guides,
|
107
|
+
meta,
|
108
|
+
};
|
109
|
+
};
|
110
|
+
const parse = (sus) => {
|
111
|
+
const lines = [];
|
112
|
+
const measureChanges = [];
|
113
|
+
const timeScaleGroupChanges = [];
|
114
|
+
const meta = new Map();
|
115
|
+
sus
|
116
|
+
.split("\n")
|
117
|
+
.map((line) => line.trim())
|
118
|
+
.filter((line) => line.startsWith("#"))
|
119
|
+
.forEach((line) => {
|
120
|
+
const isLine = line.includes(":");
|
121
|
+
const index = line.indexOf(isLine ? ":" : " ");
|
122
|
+
if (index === -1)
|
123
|
+
return;
|
124
|
+
const left = line.substring(1, index).trim();
|
125
|
+
const right = line.substring(index + 1).trim();
|
126
|
+
if (isLine) {
|
127
|
+
lines.push([left, right]);
|
128
|
+
}
|
129
|
+
else if (left === "MEASUREBS") {
|
130
|
+
measureChanges.unshift([lines.length, +right]);
|
131
|
+
}
|
132
|
+
else if (left === "HISPEED") {
|
133
|
+
timeScaleGroupChanges.unshift([lines.length, right]);
|
134
|
+
}
|
135
|
+
else {
|
136
|
+
if (!meta.has(left))
|
137
|
+
meta.set(left, []);
|
138
|
+
meta.get(left)?.push(right);
|
139
|
+
}
|
140
|
+
});
|
141
|
+
return {
|
142
|
+
lines,
|
143
|
+
measureChanges,
|
144
|
+
timeScaleGroupChanges,
|
145
|
+
meta,
|
146
|
+
};
|
147
|
+
};
|
148
|
+
const getTicksPerBeat = (meta) => {
|
149
|
+
const request = meta.get("REQUEST");
|
150
|
+
if (!request)
|
151
|
+
return;
|
152
|
+
const tpbRequest = request.find((r) => JSON.parse(r).startsWith("ticks_per_beat"));
|
153
|
+
if (!tpbRequest)
|
154
|
+
return;
|
155
|
+
return +JSON.parse(tpbRequest).split(" ")[1];
|
156
|
+
};
|
157
|
+
const getBarLengths = (lines, measureChanges) => {
|
158
|
+
const barLengths = [];
|
159
|
+
lines.forEach((line, index) => {
|
160
|
+
const [header, data] = line;
|
161
|
+
if (header.length !== 5)
|
162
|
+
return;
|
163
|
+
if (!header.endsWith("02"))
|
164
|
+
return;
|
165
|
+
const measure = +header.substring(0, 3) +
|
166
|
+
(measureChanges.find(([changeIndex]) => changeIndex <= index)?.[1] ?? 0);
|
167
|
+
if (Number.isNaN(measure))
|
168
|
+
return;
|
169
|
+
barLengths.push({ measure, length: +data });
|
170
|
+
});
|
171
|
+
return barLengths;
|
172
|
+
};
|
173
|
+
const getToTick = (barLengths, ticksPerBeat) => {
|
174
|
+
let ticks = 0;
|
175
|
+
const bars = barLengths
|
176
|
+
.sort((a, b) => a.measure - b.measure)
|
177
|
+
.map(({ measure, length }, i, values) => {
|
178
|
+
if (i) {
|
179
|
+
const prev = values[i - 1];
|
180
|
+
ticks += (measure - prev.measure) * prev.length * ticksPerBeat;
|
181
|
+
}
|
182
|
+
return { measure, ticksPerMeasure: length * ticksPerBeat, ticks };
|
183
|
+
})
|
184
|
+
.reverse();
|
185
|
+
return (measure, p, q) => {
|
186
|
+
const bar = bars.find((bar) => measure >= bar.measure);
|
187
|
+
if (!bar)
|
188
|
+
throw new Error("Unexpected missing bar");
|
189
|
+
return (bar.ticks +
|
190
|
+
(measure - bar.measure) * bar.ticksPerMeasure +
|
191
|
+
(p * bar.ticksPerMeasure) / q);
|
192
|
+
};
|
193
|
+
};
|
194
|
+
const toBpmChanges = (line, measureOffset, bpms, toTick) => toRaws(line, measureOffset, toTick).map(({ tick, value }) => ({
|
195
|
+
tick,
|
196
|
+
bpm: bpms.get(value) ?? 0,
|
197
|
+
}));
|
198
|
+
const toTimeScaleChanges = ([, data], toTick) => {
|
199
|
+
if (!data.startsWith('"') || !data.endsWith('"'))
|
200
|
+
throw new Error("Unexpected time scale changes");
|
201
|
+
return data
|
202
|
+
.slice(1, -1)
|
203
|
+
.split(",")
|
204
|
+
.map((segment) => segment.trim())
|
205
|
+
.filter((segment) => !!segment)
|
206
|
+
.map((segment) => {
|
207
|
+
const [l, rest] = segment.split("'");
|
208
|
+
const [m, r] = rest.split(":");
|
209
|
+
const measure = +l;
|
210
|
+
const tick = +m;
|
211
|
+
const timeScale = +r;
|
212
|
+
if (Number.isNaN(measure) ||
|
213
|
+
Number.isNaN(tick) ||
|
214
|
+
Number.isNaN(timeScale))
|
215
|
+
throw new Error("Unexpected time scale change");
|
216
|
+
return {
|
217
|
+
tick: toTick(measure, 0, 1) + tick,
|
218
|
+
timeScale,
|
219
|
+
};
|
220
|
+
})
|
221
|
+
.sort((a, b) => a.tick - b.tick);
|
222
|
+
};
|
223
|
+
const toNotes = (line, measureOffset, timeScaleGroup, toTick) => {
|
224
|
+
const [header] = line;
|
225
|
+
const lane = parseInt(header[4], 36);
|
226
|
+
return toRaws(line, measureOffset, toTick).map(({ tick, value }) => {
|
227
|
+
const width = parseInt(value[1], 36);
|
228
|
+
return {
|
229
|
+
tick,
|
230
|
+
lane,
|
231
|
+
width,
|
232
|
+
type: parseInt(value[0], 36),
|
233
|
+
timeScaleGroup,
|
234
|
+
};
|
235
|
+
});
|
236
|
+
};
|
237
|
+
const toSlides = (stream) => {
|
238
|
+
const slides = [];
|
239
|
+
let current;
|
240
|
+
stream
|
241
|
+
.sort((a, b) => a.tick - b.tick)
|
242
|
+
.forEach((note) => {
|
243
|
+
if (!current) {
|
244
|
+
current = [];
|
245
|
+
slides.push(current);
|
246
|
+
}
|
247
|
+
current.push(note);
|
248
|
+
if (note.type === 2) {
|
249
|
+
current = undefined;
|
250
|
+
}
|
251
|
+
});
|
252
|
+
return slides;
|
253
|
+
};
|
254
|
+
const toRaws = ([header, data], measureOffset, toTick) => {
|
255
|
+
const measure = +header.substring(0, 3) + measureOffset;
|
256
|
+
return (data.match(/.{2}/g) ?? [])
|
257
|
+
.map((value, i, values) => value !== "00" && {
|
258
|
+
tick: toTick(measure, i, values.length),
|
259
|
+
value,
|
260
|
+
})
|
261
|
+
.filter((object) => !!object);
|
262
|
+
};
|
package/dist/sus/convert.cjs
CHANGED
@@ -32,20 +32,20 @@ const susToUSC = (sus) => {
|
|
32
32
|
const key = getKey(note);
|
33
33
|
switch (note.type) {
|
34
34
|
case 1:
|
35
|
-
flickMods.set(key,
|
35
|
+
flickMods.set(key, "up");
|
36
36
|
break;
|
37
37
|
case 3:
|
38
|
-
flickMods.set(key,
|
38
|
+
flickMods.set(key, "left");
|
39
39
|
break;
|
40
40
|
case 4:
|
41
|
-
flickMods.set(key,
|
41
|
+
flickMods.set(key, "right");
|
42
42
|
break;
|
43
43
|
case 2:
|
44
|
-
easeMods.set(key,
|
44
|
+
easeMods.set(key, "in");
|
45
45
|
break;
|
46
46
|
case 5:
|
47
47
|
case 6:
|
48
|
-
easeMods.set(key,
|
48
|
+
easeMods.set(key, "out");
|
49
49
|
break;
|
50
50
|
}
|
51
51
|
}
|
@@ -77,14 +77,14 @@ const susToUSC = (sus) => {
|
|
77
77
|
const objects = [];
|
78
78
|
for (const timeScaleChange of score.timeScaleChanges) {
|
79
79
|
objects.push({
|
80
|
-
type:
|
80
|
+
type: "timeScale",
|
81
81
|
beat: timeScaleChange.tick / score.ticksPerBeat,
|
82
82
|
timeScale: timeScaleChange.timeScale,
|
83
83
|
});
|
84
84
|
}
|
85
85
|
for (const bpmChange of score.bpmChanges) {
|
86
86
|
objects.push({
|
87
|
-
type:
|
87
|
+
type: "bpm",
|
88
88
|
beat: bpmChange.tick / score.ticksPerBeat,
|
89
89
|
bpm: bpmChange.bpm,
|
90
90
|
});
|
@@ -92,7 +92,10 @@ const susToUSC = (sus) => {
|
|
92
92
|
for (const note of score.tapNotes) {
|
93
93
|
if (note.lane <= 1 || note.lane >= 14)
|
94
94
|
continue;
|
95
|
-
if (note.type !== 1 &&
|
95
|
+
if (note.type !== 1 &&
|
96
|
+
note.type !== 2 &&
|
97
|
+
note.type !== 5 &&
|
98
|
+
note.type !== 6)
|
96
99
|
continue;
|
97
100
|
const key = getKey(note);
|
98
101
|
if (preventSingles.has(key))
|
@@ -101,7 +104,7 @@ const susToUSC = (sus) => {
|
|
101
104
|
continue;
|
102
105
|
dedupeSingles.add(key);
|
103
106
|
const object = {
|
104
|
-
type:
|
107
|
+
type: "single",
|
105
108
|
beat: note.tick / score.ticksPerBeat,
|
106
109
|
lane: note.lane - 8 + note.width / 2,
|
107
110
|
size: note.width / 2,
|
@@ -118,7 +121,7 @@ const susToUSC = (sus) => {
|
|
118
121
|
if (!startNote)
|
119
122
|
continue;
|
120
123
|
const object = {
|
121
|
-
type:
|
124
|
+
type: "slide",
|
122
125
|
active: slide.type === 3,
|
123
126
|
critical: criticalMods.has(getKey(startNote)),
|
124
127
|
connections: [],
|
@@ -130,12 +133,12 @@ const susToUSC = (sus) => {
|
|
130
133
|
const size = note.width / 2;
|
131
134
|
const trace = traceMods.has(key);
|
132
135
|
const critical = object.critical || criticalMods.has(key);
|
133
|
-
const ease = easeMods.get(key) ??
|
136
|
+
const ease = easeMods.get(key) ?? "linear";
|
134
137
|
switch (note.type) {
|
135
138
|
case 1: {
|
136
139
|
if (!object.active || slideStartEndRemoveMods.has(key)) {
|
137
140
|
const connection = {
|
138
|
-
type:
|
141
|
+
type: "ignore",
|
139
142
|
beat,
|
140
143
|
lane,
|
141
144
|
size,
|
@@ -145,13 +148,13 @@ const susToUSC = (sus) => {
|
|
145
148
|
}
|
146
149
|
else {
|
147
150
|
const connection = {
|
148
|
-
type:
|
151
|
+
type: "start",
|
149
152
|
beat,
|
150
153
|
lane,
|
151
154
|
size,
|
152
155
|
trace,
|
153
156
|
critical,
|
154
|
-
ease: easeMods.get(key) ??
|
157
|
+
ease: easeMods.get(key) ?? "linear",
|
155
158
|
};
|
156
159
|
object.connections.push(connection);
|
157
160
|
}
|
@@ -160,7 +163,7 @@ const susToUSC = (sus) => {
|
|
160
163
|
case 2: {
|
161
164
|
if (!object.active || slideStartEndRemoveMods.has(key)) {
|
162
165
|
const connection = {
|
163
|
-
type:
|
166
|
+
type: "ignore",
|
164
167
|
beat,
|
165
168
|
lane,
|
166
169
|
size,
|
@@ -170,7 +173,7 @@ const susToUSC = (sus) => {
|
|
170
173
|
}
|
171
174
|
else {
|
172
175
|
const connection = {
|
173
|
-
type:
|
176
|
+
type: "end",
|
174
177
|
beat,
|
175
178
|
lane,
|
176
179
|
size,
|
@@ -187,7 +190,7 @@ const susToUSC = (sus) => {
|
|
187
190
|
case 3: {
|
188
191
|
if (tickRemoveMods.has(key)) {
|
189
192
|
const connection = {
|
190
|
-
type:
|
193
|
+
type: "attach",
|
191
194
|
beat,
|
192
195
|
critical,
|
193
196
|
};
|
@@ -195,7 +198,7 @@ const susToUSC = (sus) => {
|
|
195
198
|
}
|
196
199
|
else {
|
197
200
|
const connection = {
|
198
|
-
type:
|
201
|
+
type: "tick",
|
199
202
|
beat,
|
200
203
|
lane,
|
201
204
|
size,
|
@@ -211,7 +214,7 @@ const susToUSC = (sus) => {
|
|
211
214
|
if (tickRemoveMods.has(key))
|
212
215
|
break;
|
213
216
|
const connection = {
|
214
|
-
type:
|
217
|
+
type: "ignore",
|
215
218
|
beat,
|
216
219
|
lane,
|
217
220
|
size,
|
package/dist/sus/convert.d.cts
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
import { USC } from
|
1
|
+
import { USC } from "../usc/index.cjs";
|
2
2
|
export declare const susToUSC: (sus: string) => USC;
|