sonolus-pjsekai-js 1.2.19 → 1.3.0
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.d.cts → index.d.ts} +5 -5
- package/dist/index.js +48 -0
- package/dist/sus/{analyze.cjs → analyze.js} +1 -5
- package/dist/sus/{convert.d.cts → convert.d.ts} +1 -1
- package/dist/sus/{convert.cjs → convert.js} +3 -7
- package/dist/usc/ccIndex.js +15 -0
- package/dist/usc/{convert.d.cts → convert.d.ts} +1 -1
- package/dist/usc/{convert.cjs → convert.js} +18 -22
- package/dist/usc/index.js +1 -0
- package/dist/usc/{revert.d.cts → revert.d.ts} +2 -2
- package/dist/usc/{revert.cjs → revert.js} +1 -5
- package/package.json +9 -9
- package/dist/index.cjs +0 -68
- package/dist/sus/decode.cjs +0 -318
- package/dist/sus/decode.d.cts +0 -1
- package/dist/sus/index.cjs +0 -18
- package/dist/sus/revert.cjs +0 -339
- package/dist/sus/revert.d.cts +0 -1
- package/dist/usc/ccIndex.cjs +0 -18
- package/dist/usc/ccIndex.d.cts +0 -91
- package/dist/usc/index.cjs +0 -2
- /package/dist/sus/{analyze.d.cts → analyze.d.ts} +0 -0
- /package/dist/{sus/index.d.cts → usc/ccIndex.d.ts} +0 -0
- /package/dist/usc/{index.d.cts → index.d.ts} +0 -0
package/dist/EngineWatchData
CHANGED
Binary file
|
@@ -1,8 +1,8 @@
|
|
1
|
-
export { susToUSC } from "./sus/convert.
|
2
|
-
export { uscToLevelData } from "./usc/convert.
|
3
|
-
export * from "./usc/index.
|
4
|
-
export { uscToUSC } from "./usc/revert.
|
5
|
-
export declare const version = "1.
|
1
|
+
export { susToUSC } from "./sus/convert.js";
|
2
|
+
export { uscToLevelData } from "./usc/convert.js";
|
3
|
+
export * from "./usc/index.js";
|
4
|
+
export { uscToUSC } from "./usc/revert.js";
|
5
|
+
export declare const version = "1.3.0";
|
6
6
|
export declare const databaseEngineItem: {
|
7
7
|
readonly name: "prosekaR";
|
8
8
|
readonly version: 13;
|
package/dist/index.js
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
export { susToUSC } from "./sus/convert.js";
|
2
|
+
export { uscToLevelData } from "./usc/convert.js";
|
3
|
+
export * from "./usc/index.js";
|
4
|
+
export { uscToUSC } from "./usc/revert.js";
|
5
|
+
export const version = "1.3.0";
|
6
|
+
export const databaseEngineItem = {
|
7
|
+
name: "prosekaR",
|
8
|
+
version: 13,
|
9
|
+
title: {
|
10
|
+
en: "ProSeka R",
|
11
|
+
ja: "プロセカ R",
|
12
|
+
ko: "프로세카 R",
|
13
|
+
zhs: "世界计划 R",
|
14
|
+
zht: "世界計劃 R",
|
15
|
+
},
|
16
|
+
subtitle: {
|
17
|
+
en: "ProSeka Rush",
|
18
|
+
ja: "プロセカ ラッシュ",
|
19
|
+
ko: "프로세카 러쉬",
|
20
|
+
zhs: "世界计划 匆忙",
|
21
|
+
zht: "世界計劃 匆忙",
|
22
|
+
},
|
23
|
+
author: {
|
24
|
+
en: "Hyeon2#7895",
|
25
|
+
},
|
26
|
+
description: {
|
27
|
+
en: [
|
28
|
+
"A recreation of Project Sekai: Colorful Stage! engine in Sonolus.",
|
29
|
+
`Version: ${version}`,
|
30
|
+
"",
|
31
|
+
"Forked from the pjsekai engine by Burrito#1000.",
|
32
|
+
"https://github.com/NonSpicyBurrito/sonolus-pjsekai-engine",
|
33
|
+
"",
|
34
|
+
"Github:",
|
35
|
+
"https://github.com/hyeon2006/sonolus-pjsekai-js",
|
36
|
+
].join("\n"),
|
37
|
+
ko: [
|
38
|
+
"프로젝트 세카이: 컬러풀 스테이지! 엔진을 Sonolus로 재현했습니다.",
|
39
|
+
`버전: ${version}`,
|
40
|
+
"",
|
41
|
+
"Burrito#1000의 pjsekai 엔진에서 포크되었습니다.",
|
42
|
+
"https://github.com/NonSpicyBurrito/sonolus-pjsekai-engine",
|
43
|
+
"",
|
44
|
+
"깃허브:",
|
45
|
+
"https://github.com/hyeon2006/sonolus-pjsekai-js",
|
46
|
+
].join("\n"),
|
47
|
+
},
|
48
|
+
};
|
@@ -1,7 +1,4 @@
|
|
1
|
-
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.analyze = void 0;
|
4
|
-
const analyze = (sus) => {
|
1
|
+
export const analyze = (sus) => {
|
5
2
|
const { lines, measureChanges, meta } = parse(sus);
|
6
3
|
const offset = -+(meta.get("WAVEOFFSET") || "0");
|
7
4
|
if (Number.isNaN(offset))
|
@@ -73,7 +70,6 @@ const analyze = (sus) => {
|
|
73
70
|
slides,
|
74
71
|
};
|
75
72
|
};
|
76
|
-
exports.analyze = analyze;
|
77
73
|
const parse = (sus) => {
|
78
74
|
const lines = [];
|
79
75
|
const measureChanges = [];
|
@@ -1,2 +1,2 @@
|
|
1
|
-
import { USC } from '../usc/index.
|
1
|
+
import { USC } from '../usc/index.js';
|
2
2
|
export declare const susToUSC: (sus: string) => USC;
|
@@ -1,9 +1,6 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
const analyze_cjs_1 = require("./analyze.cjs");
|
5
|
-
const susToUSC = (sus) => {
|
6
|
-
const score = (0, analyze_cjs_1.analyze)(sus);
|
1
|
+
import { analyze } from './analyze.js';
|
2
|
+
export const susToUSC = (sus) => {
|
3
|
+
const score = analyze(sus);
|
7
4
|
const flickMods = new Map();
|
8
5
|
const traceMods = new Set();
|
9
6
|
const criticalMods = new Set();
|
@@ -236,5 +233,4 @@ const susToUSC = (sus) => {
|
|
236
233
|
objects,
|
237
234
|
};
|
238
235
|
};
|
239
|
-
exports.susToUSC = susToUSC;
|
240
236
|
const getKey = (note) => `${note.lane}-${note.tick}`;
|
@@ -1,8 +1,5 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
exports.uscToLevelData = void 0;
|
4
|
-
const core_1 = require("@sonolus/core");
|
5
|
-
const uscToLevelData = (usc, offset = 0) => {
|
1
|
+
import { EngineArchetypeDataName, EngineArchetypeName, } from '@sonolus/core';
|
2
|
+
export const uscToLevelData = (usc, offset = 0) => {
|
6
3
|
const entities = [];
|
7
4
|
const timeToIntermediates = new Map();
|
8
5
|
const intermediateToRef = new Map();
|
@@ -25,7 +22,7 @@ const uscToLevelData = (usc, offset = 0) => {
|
|
25
22
|
data: [],
|
26
23
|
};
|
27
24
|
if (intermediate.sim) {
|
28
|
-
const beat = intermediate.data[
|
25
|
+
const beat = intermediate.data[EngineArchetypeDataName.Beat];
|
29
26
|
if (typeof beat !== 'number')
|
30
27
|
throw new Error('Unexpected beat');
|
31
28
|
const intermediates = timeToIntermediates.get(beat);
|
@@ -88,7 +85,6 @@ const uscToLevelData = (usc, offset = 0) => {
|
|
88
85
|
entities,
|
89
86
|
};
|
90
87
|
};
|
91
|
-
exports.uscToLevelData = uscToLevelData;
|
92
88
|
const directions = {
|
93
89
|
left: -1,
|
94
90
|
up: 0,
|
@@ -103,20 +99,20 @@ const eases = {
|
|
103
99
|
};
|
104
100
|
const bpm = (object, append) => {
|
105
101
|
append({
|
106
|
-
archetype:
|
102
|
+
archetype: EngineArchetypeName.BpmChange,
|
107
103
|
data: {
|
108
|
-
[
|
109
|
-
[
|
104
|
+
[EngineArchetypeDataName.Beat]: object.beat,
|
105
|
+
[EngineArchetypeDataName.Bpm]: object.bpm,
|
110
106
|
},
|
111
107
|
sim: false,
|
112
108
|
});
|
113
109
|
};
|
114
110
|
const timeScale = (object, append) => {
|
115
111
|
append({
|
116
|
-
archetype:
|
112
|
+
archetype: EngineArchetypeName.TimeScaleChange,
|
117
113
|
data: {
|
118
|
-
[
|
119
|
-
[
|
114
|
+
[EngineArchetypeDataName.Beat]: object.beat,
|
115
|
+
[EngineArchetypeDataName.TimeScale]: object.timeScale,
|
120
116
|
},
|
121
117
|
sim: false,
|
122
118
|
});
|
@@ -139,7 +135,7 @@ const single = (object, append) => {
|
|
139
135
|
? 'CriticalTapNote'
|
140
136
|
: 'NormalTapNote',
|
141
137
|
data: {
|
142
|
-
[
|
138
|
+
[EngineArchetypeDataName.Beat]: object.beat,
|
143
139
|
lane: object.lane,
|
144
140
|
size: object.size,
|
145
141
|
direction: object.direction && directions[object.direction],
|
@@ -167,7 +163,7 @@ const slide = (object, append) => {
|
|
167
163
|
? 'CriticalSlideStartNote'
|
168
164
|
: 'NormalSlideStartNote',
|
169
165
|
data: {
|
170
|
-
[
|
166
|
+
[EngineArchetypeDataName.Beat]: connection.beat,
|
171
167
|
lane: connection.lane,
|
172
168
|
size: connection.size,
|
173
169
|
},
|
@@ -182,7 +178,7 @@ const slide = (object, append) => {
|
|
182
178
|
const ci = {
|
183
179
|
archetype: 'IgnoredSlideTickNote',
|
184
180
|
data: {
|
185
|
-
[
|
181
|
+
[EngineArchetypeDataName.Beat]: connection.beat,
|
186
182
|
lane: connection.lane,
|
187
183
|
size: connection.size,
|
188
184
|
},
|
@@ -217,7 +213,7 @@ const slide = (object, append) => {
|
|
217
213
|
? 'CriticalSlideEndNote'
|
218
214
|
: 'NormalSlideEndNote',
|
219
215
|
data: {
|
220
|
-
[
|
216
|
+
[EngineArchetypeDataName.Beat]: connection.beat,
|
221
217
|
lane: connection.lane,
|
222
218
|
size: connection.size,
|
223
219
|
direction: connection.direction && directions[connection.direction],
|
@@ -233,7 +229,7 @@ const slide = (object, append) => {
|
|
233
229
|
const ci = {
|
234
230
|
archetype: 'IgnoredSlideTickNote',
|
235
231
|
data: {
|
236
|
-
[
|
232
|
+
[EngineArchetypeDataName.Beat]: connection.beat,
|
237
233
|
lane: connection.lane,
|
238
234
|
size: connection.size,
|
239
235
|
},
|
@@ -253,7 +249,7 @@ const slide = (object, append) => {
|
|
253
249
|
const ci = {
|
254
250
|
archetype: 'IgnoredSlideTickNote',
|
255
251
|
data: {
|
256
|
-
[
|
252
|
+
[EngineArchetypeDataName.Beat]: connection.beat,
|
257
253
|
lane: connection.lane,
|
258
254
|
size: connection.size,
|
259
255
|
},
|
@@ -274,7 +270,7 @@ const slide = (object, append) => {
|
|
274
270
|
? 'CriticalSlideTickNote'
|
275
271
|
: 'NormalSlideTickNote',
|
276
272
|
data: {
|
277
|
-
[
|
273
|
+
[EngineArchetypeDataName.Beat]: connection.beat,
|
278
274
|
lane: connection.lane,
|
279
275
|
size: connection.size,
|
280
276
|
},
|
@@ -289,7 +285,7 @@ const slide = (object, append) => {
|
|
289
285
|
const ci = {
|
290
286
|
archetype: 'HiddenSlideTickNote',
|
291
287
|
data: {
|
292
|
-
[
|
288
|
+
[EngineArchetypeDataName.Beat]: connection.beat,
|
293
289
|
},
|
294
290
|
sim: false,
|
295
291
|
};
|
@@ -303,7 +299,7 @@ const slide = (object, append) => {
|
|
303
299
|
? 'CriticalAttachedSlideTickNote'
|
304
300
|
: 'NormalAttachedSlideTickNote',
|
305
301
|
data: {
|
306
|
-
[
|
302
|
+
[EngineArchetypeDataName.Beat]: connection.beat,
|
307
303
|
},
|
308
304
|
sim: false,
|
309
305
|
};
|
@@ -0,0 +1 @@
|
|
1
|
+
export {};
|
@@ -1,6 +1,3 @@
|
|
1
|
-
"use strict";
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.uscToUSC = void 0;
|
4
1
|
/**
|
5
2
|
* B 타입의 USC 슬라이드 연결 노드를 A 타입으로 변환합니다.
|
6
3
|
* @param connection B 타입의 연결 노트
|
@@ -94,7 +91,7 @@ const getBeatForSort = (obj) => {
|
|
94
91
|
* @param uscB B 타입 USC 객체
|
95
92
|
* @returns A 타입 USC 객체
|
96
93
|
*/
|
97
|
-
const uscToUSC = (uscB) => {
|
94
|
+
export const uscToUSC = (uscB) => {
|
98
95
|
const newObjects = [];
|
99
96
|
let timeScaleGroupConverted = false; // 첫 번째 timeScaleGroup만 변환하기 위한 플래그
|
100
97
|
for (const object of uscB.objects) {
|
@@ -168,4 +165,3 @@ const uscToUSC = (uscB) => {
|
|
168
165
|
objects: newObjects,
|
169
166
|
};
|
170
167
|
};
|
171
|
-
exports.uscToUSC = uscToUSC;
|
package/package.json
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
{
|
2
2
|
"name": "sonolus-pjsekai-js",
|
3
|
-
"version": "1.
|
3
|
+
"version": "1.3.0",
|
4
4
|
"description": "A recreation of Project Sekai: Colorful Stage! engine in Sonolus",
|
5
5
|
"type": "module",
|
6
6
|
"files": [
|
7
7
|
"dist"
|
8
8
|
],
|
9
9
|
"exports": {
|
10
|
-
".": "./dist/index.
|
10
|
+
".": "./dist/index.js",
|
11
11
|
"./EngineConfiguration": "./dist/EngineConfiguration",
|
12
12
|
"./EnginePlayData": "./dist/EnginePlayData",
|
13
13
|
"./EngineWatchData": "./dist/EngineWatchData",
|
@@ -16,22 +16,22 @@
|
|
16
16
|
"./EngineThumbnail": "./dist/thumbnail.png"
|
17
17
|
},
|
18
18
|
"scripts": {
|
19
|
-
"dev
|
20
|
-
"dev
|
21
|
-
"dev
|
22
|
-
"dev
|
19
|
+
"dev-play": "sonolus-cli --dev ./play",
|
20
|
+
"dev-watch": "sonolus-cli --dev ./watch",
|
21
|
+
"dev-preview": "sonolus-cli --dev ./preview",
|
22
|
+
"dev-tutorial": "sonolus-cli --dev ./tutorial",
|
23
23
|
"format": "biome format --write",
|
24
24
|
"lint": "biome lint",
|
25
25
|
"lint-fix": "biome lint --write",
|
26
26
|
"biome": "biome check",
|
27
|
-
"build": "tsc -p ./lib && sonolus-cli --build ./play && sonolus-cli --build ./watch && sonolus-cli --build ./preview && sonolus-cli --build ./tutorial && node ./lib/build.
|
27
|
+
"build": "tsc -p ./lib && sonolus-cli --build ./play && sonolus-cli --build ./watch && sonolus-cli --build ./preview && sonolus-cli --build ./tutorial && node ./lib/build.js"
|
28
28
|
},
|
29
29
|
"devDependencies": {
|
30
30
|
"@biomejs/biome": "2.0.6",
|
31
|
-
"@sonolus/sonolus.js": "~9.
|
31
|
+
"@sonolus/sonolus.js": "~9.6.0",
|
32
32
|
"typescript": "~5.8.3"
|
33
33
|
},
|
34
34
|
"dependencies": {
|
35
|
-
"@sonolus/core": "~7.
|
35
|
+
"@sonolus/core": "~7.14.0"
|
36
36
|
}
|
37
37
|
}
|
package/dist/index.cjs
DELETED
@@ -1,68 +0,0 @@
|
|
1
|
-
"use strict";
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
3
|
-
if (k2 === undefined) k2 = k;
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
7
|
-
}
|
8
|
-
Object.defineProperty(o, k2, desc);
|
9
|
-
}) : (function(o, m, k, k2) {
|
10
|
-
if (k2 === undefined) k2 = k;
|
11
|
-
o[k2] = m[k];
|
12
|
-
}));
|
13
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
14
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
15
|
-
};
|
16
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
17
|
-
exports.databaseEngineItem = exports.version = exports.uscToUSC = exports.uscToLevelData = exports.susToUSC = void 0;
|
18
|
-
var convert_cjs_1 = require("./sus/convert.cjs");
|
19
|
-
Object.defineProperty(exports, "susToUSC", { enumerable: true, get: function () { return convert_cjs_1.susToUSC; } });
|
20
|
-
var convert_cjs_2 = require("./usc/convert.cjs");
|
21
|
-
Object.defineProperty(exports, "uscToLevelData", { enumerable: true, get: function () { return convert_cjs_2.uscToLevelData; } });
|
22
|
-
__exportStar(require("./usc/index.cjs"), exports);
|
23
|
-
var revert_cjs_1 = require("./usc/revert.cjs");
|
24
|
-
Object.defineProperty(exports, "uscToUSC", { enumerable: true, get: function () { return revert_cjs_1.uscToUSC; } });
|
25
|
-
exports.version = "1.2.19";
|
26
|
-
exports.databaseEngineItem = {
|
27
|
-
name: "prosekaR",
|
28
|
-
version: 13,
|
29
|
-
title: {
|
30
|
-
en: "ProSeka R",
|
31
|
-
ja: "プロセカ R",
|
32
|
-
ko: "프로세카 R",
|
33
|
-
zhs: "世界计划 R",
|
34
|
-
zht: "世界計劃 R",
|
35
|
-
},
|
36
|
-
subtitle: {
|
37
|
-
en: "ProSeka Rush",
|
38
|
-
ja: "プロセカ ラッシュ",
|
39
|
-
ko: "프로세카 러쉬",
|
40
|
-
zhs: "世界计划 匆忙",
|
41
|
-
zht: "世界計劃 匆忙",
|
42
|
-
},
|
43
|
-
author: {
|
44
|
-
en: "Hyeon2#7895",
|
45
|
-
},
|
46
|
-
description: {
|
47
|
-
en: [
|
48
|
-
"A recreation of Project Sekai: Colorful Stage! engine in Sonolus.",
|
49
|
-
`Version: ${exports.version}`,
|
50
|
-
"",
|
51
|
-
"Forked from the pjsekai engine by Burrito#1000.",
|
52
|
-
"https://github.com/NonSpicyBurrito/sonolus-pjsekai-engine",
|
53
|
-
"",
|
54
|
-
"Github:",
|
55
|
-
"https://github.com/hyeon2006/sonolus-pjsekai-js",
|
56
|
-
].join("\n"),
|
57
|
-
ko: [
|
58
|
-
"프로젝트 세카이: 컬러풀 스테이지! 엔진을 Sonolus로 재현했습니다.",
|
59
|
-
`버전: ${exports.version}`,
|
60
|
-
"",
|
61
|
-
"Burrito#1000의 pjsekai 엔진에서 포크되었습니다.",
|
62
|
-
"https://github.com/NonSpicyBurrito/sonolus-pjsekai-engine",
|
63
|
-
"",
|
64
|
-
"깃허브:",
|
65
|
-
"https://github.com/hyeon2006/sonolus-pjsekai-js",
|
66
|
-
].join("\n"),
|
67
|
-
},
|
68
|
-
};
|
package/dist/sus/decode.cjs
DELETED
@@ -1,318 +0,0 @@
|
|
1
|
-
"use strict";
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.uscToSUS = void 0;
|
4
|
-
const TICKS_PER_BEAT = 480;
|
5
|
-
const uscToSUS = (uscData) => {
|
6
|
-
const usc = uscData.usc ? uscData.usc : uscData;
|
7
|
-
const susLines = [];
|
8
|
-
const noteData = new Map();
|
9
|
-
let slideChannelCounter = 0;
|
10
|
-
// (메타데이터 및 전역 정의 생성은 이전과 동일)
|
11
|
-
susLines.push(`#TITLE ""`, `#ARTIST ""`, `#DESIGNER ""`, `#WAVEOFFSET ${-usc.offset}`, `#REQUEST "ticks_per_beat ${TICKS_PER_BEAT}"`, ``);
|
12
|
-
const ticksPerMeasure = TICKS_PER_BEAT * 4;
|
13
|
-
const bpmObjects = usc.objects.filter((obj) => obj.type === "bpm");
|
14
|
-
const bpmDefinitions = new Map();
|
15
|
-
let bpmCounter = 1;
|
16
|
-
for (const bpmObject of bpmObjects) {
|
17
|
-
if (!bpmDefinitions.has(bpmObject.bpm)) {
|
18
|
-
const bpmId = bpmCounter.toString().padStart(2, "0");
|
19
|
-
bpmDefinitions.set(bpmObject.bpm, bpmId);
|
20
|
-
susLines.push(`#BPM${bpmId}: ${bpmObject.bpm}`);
|
21
|
-
bpmCounter++;
|
22
|
-
}
|
23
|
-
}
|
24
|
-
susLines.push(``);
|
25
|
-
const timeScaleGroups = usc.objects.filter((obj) => obj.type === "timeScaleGroup");
|
26
|
-
const tilIdMap = new Map();
|
27
|
-
timeScaleGroups.forEach((group, index) => {
|
28
|
-
const tilId = index.toString().padStart(2, "0");
|
29
|
-
tilIdMap.set(index, tilId);
|
30
|
-
const changesString = group.changes
|
31
|
-
.map(change => {
|
32
|
-
const totalTicks = change.beat * TICKS_PER_BEAT;
|
33
|
-
const measure = Math.floor(totalTicks / ticksPerMeasure);
|
34
|
-
const tickInMeasure = totalTicks % ticksPerMeasure;
|
35
|
-
return `${measure}'${tickInMeasure}:${change.timeScale}`;
|
36
|
-
})
|
37
|
-
.join(", ");
|
38
|
-
susLines.push(`#TIL${tilId}: "${changesString}"`);
|
39
|
-
});
|
40
|
-
susLines.push(``);
|
41
|
-
addNoteData(0, "00002", 0, "4", 0);
|
42
|
-
for (const bpmObject of bpmObjects) {
|
43
|
-
const tick = bpmObject.beat * TICKS_PER_BEAT;
|
44
|
-
const measure = Math.floor(tick / ticksPerMeasure);
|
45
|
-
const tickInMeasure = tick % ticksPerMeasure;
|
46
|
-
const bpmId = bpmDefinitions.get(bpmObject.bpm);
|
47
|
-
if (bpmId) {
|
48
|
-
addNoteData(measure, `${measure.toString().padStart(3, "0")}08`, tickInMeasure, bpmId, 0);
|
49
|
-
}
|
50
|
-
}
|
51
|
-
for (const obj of usc.objects) {
|
52
|
-
switch (obj.type) {
|
53
|
-
case "single":
|
54
|
-
case "damage":
|
55
|
-
processSingleOrDamage(obj);
|
56
|
-
break;
|
57
|
-
case "slide":
|
58
|
-
processSlide(obj);
|
59
|
-
slideChannelCounter++;
|
60
|
-
break;
|
61
|
-
case "guide":
|
62
|
-
processGuide(obj);
|
63
|
-
slideChannelCounter++;
|
64
|
-
break;
|
65
|
-
case "timeScaleGroup":
|
66
|
-
case "bpm":
|
67
|
-
break;
|
68
|
-
}
|
69
|
-
}
|
70
|
-
const sortedMeasures = Array.from(noteData.keys()).sort((a, b) => a - b);
|
71
|
-
let activeTimeScaleGroup = -1;
|
72
|
-
for (const measure of sortedMeasures) {
|
73
|
-
const headerMap = noteData.get(measure);
|
74
|
-
const sortedHeaders = Array.from(headerMap.keys()).sort();
|
75
|
-
for (const header of sortedHeaders) {
|
76
|
-
const notes = headerMap.get(header);
|
77
|
-
if (!notes || notes.length === 0)
|
78
|
-
continue;
|
79
|
-
const noteTimeScaleGroup = notes[0].timeScaleGroup;
|
80
|
-
const tilId = tilIdMap.get(noteTimeScaleGroup);
|
81
|
-
if (noteTimeScaleGroup !== activeTimeScaleGroup && tilId !== undefined) {
|
82
|
-
susLines.push(`#HISPEED ${tilId}`);
|
83
|
-
activeTimeScaleGroup = noteTimeScaleGroup;
|
84
|
-
}
|
85
|
-
if (header.endsWith("02") || header.endsWith("08")) {
|
86
|
-
susLines.push(`#${header}: ${notes[0].value}`);
|
87
|
-
continue;
|
88
|
-
}
|
89
|
-
const granularity = 1920;
|
90
|
-
const data = Array(granularity).fill("00");
|
91
|
-
for (const note of notes) {
|
92
|
-
const index = Math.floor((note.tick / ticksPerMeasure) * granularity);
|
93
|
-
if (index < granularity) {
|
94
|
-
data[index] = note.value;
|
95
|
-
}
|
96
|
-
}
|
97
|
-
susLines.push(`#${header}: ${data.join("")}`);
|
98
|
-
}
|
99
|
-
}
|
100
|
-
return susLines.join("\r\n");
|
101
|
-
// --- Helper Functions ---
|
102
|
-
function addNoteData(measure, header, tickInMeasure, value, timeScaleGroup) {
|
103
|
-
if (!noteData.has(measure))
|
104
|
-
noteData.set(measure, new Map());
|
105
|
-
const headerMap = noteData.get(measure);
|
106
|
-
if (!headerMap.has(header))
|
107
|
-
headerMap.set(header, []);
|
108
|
-
headerMap.get(header).push({ tick: tickInMeasure, value, timeScaleGroup });
|
109
|
-
}
|
110
|
-
function getSusLaneAndWidth(uscLane, uscSize) {
|
111
|
-
const susWidth = Math.round(uscSize * 2);
|
112
|
-
const susLane = Math.round(uscLane - uscSize + 8);
|
113
|
-
return [Math.max(0, susLane), Math.max(1, susWidth)];
|
114
|
-
}
|
115
|
-
function addTapNote(beat, lane, width, noteType, timeScaleGroup) {
|
116
|
-
const tick = beat * TICKS_PER_BEAT;
|
117
|
-
const measure = Math.floor(tick / ticksPerMeasure);
|
118
|
-
const tickInMeasure = tick % ticksPerMeasure;
|
119
|
-
const laneHex = lane.toString(36);
|
120
|
-
const widthHex = width.toString(36);
|
121
|
-
const header = `${measure.toString().padStart(3, "0")}1${laneHex}`;
|
122
|
-
const value = `${noteType}${widthHex}`;
|
123
|
-
addNoteData(measure, header, tickInMeasure, value, timeScaleGroup);
|
124
|
-
}
|
125
|
-
function processSingleOrDamage(note) {
|
126
|
-
if (note.type === 'damage') {
|
127
|
-
const [lane, width] = getSusLaneAndWidth(note.lane, note.size);
|
128
|
-
addTapNote(note.beat, lane, width, "4", note.timeScaleGroup);
|
129
|
-
return;
|
130
|
-
}
|
131
|
-
const [lane, width] = getSusLaneAndWidth(note.lane, note.size);
|
132
|
-
let susNoteType = "1";
|
133
|
-
if (note.critical && note.trace)
|
134
|
-
susNoteType = "6";
|
135
|
-
else if (note.critical)
|
136
|
-
susNoteType = "2";
|
137
|
-
else if (note.trace)
|
138
|
-
susNoteType = "5";
|
139
|
-
addTapNote(note.beat, lane, width, susNoteType, note.timeScaleGroup);
|
140
|
-
if (note.direction && note.direction !== "none") {
|
141
|
-
let directionalType;
|
142
|
-
switch (note.direction) {
|
143
|
-
case "up":
|
144
|
-
directionalType = "1";
|
145
|
-
break;
|
146
|
-
case "left":
|
147
|
-
directionalType = "3";
|
148
|
-
break;
|
149
|
-
case "right":
|
150
|
-
directionalType = "4";
|
151
|
-
break;
|
152
|
-
default: return;
|
153
|
-
}
|
154
|
-
const [dirLane, dirWidth] = getSusLaneAndWidth(note.lane, note.size);
|
155
|
-
const tick = note.beat * TICKS_PER_BEAT;
|
156
|
-
const measure = Math.floor(tick / ticksPerMeasure);
|
157
|
-
const tickInMeasure = tick % ticksPerMeasure;
|
158
|
-
const dirHeader = `${measure.toString().padStart(3, "0")}5${dirLane.toString(36)}`;
|
159
|
-
const dirValue = `${directionalType}${dirWidth.toString(36)}`;
|
160
|
-
addNoteData(measure, dirHeader, tickInMeasure, dirValue, note.timeScaleGroup);
|
161
|
-
}
|
162
|
-
}
|
163
|
-
// ▼▼▼ 'tick', 'hidden', 'skip' 개념을 최종적으로 수정한 `processSlide` 함수 ▼▼▼
|
164
|
-
function processSlide(slide) {
|
165
|
-
const channel = (slideChannelCounter % 36).toString(36);
|
166
|
-
const sortedConnections = [...slide.connections].sort((a, b) => a.beat - b.beat);
|
167
|
-
let lastKnownLane = 0;
|
168
|
-
let lastKnownWidth = 0;
|
169
|
-
for (const conn of sortedConnections) {
|
170
|
-
const tick = conn.beat * TICKS_PER_BEAT;
|
171
|
-
const measure = Math.floor(tick / ticksPerMeasure);
|
172
|
-
const tickInMeasure = tick % ticksPerMeasure;
|
173
|
-
const timeScaleGroup = conn.timeScaleGroup ?? 0;
|
174
|
-
// --- 3가지 규칙에 따른 분기 처리 ---
|
175
|
-
if (conn.type === "tick") {
|
176
|
-
// `critical` 속성 존재 여부로 '일반 Tick'과 'Hidden'을 구분합니다.
|
177
|
-
if (conn.critical !== undefined) {
|
178
|
-
// --- 일반 Tick 처리 ---
|
179
|
-
// 경로에 영향을 주는 보이는 경유점(타입 3)을 생성합니다.
|
180
|
-
const [lane, width] = getSusLaneAndWidth(conn.lane, conn.size);
|
181
|
-
lastKnownLane = lane;
|
182
|
-
lastKnownWidth = width;
|
183
|
-
const laneHex = lane.toString(36);
|
184
|
-
const header = `${measure.toString().padStart(3, "0")}3${laneHex}${channel}`;
|
185
|
-
const value = `3${width.toString(36)}`;
|
186
|
-
addNoteData(measure, header, tickInMeasure, value, timeScaleGroup);
|
187
|
-
}
|
188
|
-
else {
|
189
|
-
// --- Hidden 노트 처리 ---
|
190
|
-
// 경로에 영향을 주는 보이지 않는 경유점(타입 5)을 생성합니다.
|
191
|
-
// 위치는 직전 노트의 것을 그대로 사용합니다.
|
192
|
-
const laneHex = lastKnownLane.toString(36);
|
193
|
-
const widthHex = lastKnownWidth.toString(36);
|
194
|
-
const header = `${measure.toString().padStart(3, "0")}3${laneHex}${channel}`;
|
195
|
-
const value = `5${widthHex}`;
|
196
|
-
addNoteData(measure, header, tickInMeasure, value, timeScaleGroup);
|
197
|
-
}
|
198
|
-
}
|
199
|
-
else if (conn.type === "attach") {
|
200
|
-
// --- Skip 노트 처리 ---
|
201
|
-
// 경로에 영향을 주지 않으므로 아무것도 생성하지 않고 건너뜁니다.
|
202
|
-
continue;
|
203
|
-
}
|
204
|
-
else {
|
205
|
-
// --- Start, End 노트 처리 ---
|
206
|
-
const [lane, width] = getSusLaneAndWidth(conn.lane, conn.size);
|
207
|
-
lastKnownLane = lane;
|
208
|
-
lastKnownWidth = width;
|
209
|
-
const isCritical = slide.critical || conn.critical;
|
210
|
-
let markerType = null;
|
211
|
-
if ("judgeType" in conn) {
|
212
|
-
if (conn.judgeType === "none")
|
213
|
-
markerType = isCritical ? "8" : "7";
|
214
|
-
else if (conn.judgeType === "trace")
|
215
|
-
markerType = isCritical ? "6" : "5";
|
216
|
-
}
|
217
|
-
if (conn.type === "start" && isCritical && markerType === null) {
|
218
|
-
markerType = "2";
|
219
|
-
}
|
220
|
-
if (markerType) {
|
221
|
-
addTapNote(conn.beat, lane, width, markerType, timeScaleGroup);
|
222
|
-
}
|
223
|
-
if ("ease" in conn && conn.ease) {
|
224
|
-
let easeType = conn.ease;
|
225
|
-
if (easeType === 'inout')
|
226
|
-
easeType = 'in';
|
227
|
-
if (easeType === 'outin')
|
228
|
-
easeType = 'out';
|
229
|
-
let directionalType = null;
|
230
|
-
if (easeType === 'in')
|
231
|
-
directionalType = '2';
|
232
|
-
else if (easeType === 'out')
|
233
|
-
directionalType = '5';
|
234
|
-
if (directionalType) {
|
235
|
-
const laneHex = lane.toString(36);
|
236
|
-
const widthHex = width.toString(36);
|
237
|
-
const dirHeader = `${measure.toString().padStart(3, "0")}5${laneHex}`;
|
238
|
-
const dirValue = `${directionalType}${widthHex}`;
|
239
|
-
addNoteData(measure, dirHeader, tickInMeasure, dirValue, timeScaleGroup);
|
240
|
-
}
|
241
|
-
}
|
242
|
-
const noteType = conn.type === "start" ? "1" : "2";
|
243
|
-
const laneHex = lane.toString(36);
|
244
|
-
const header = `${measure.toString().padStart(3, "0")}3${laneHex}${channel}`;
|
245
|
-
const value = `${noteType}${width.toString(36)}`;
|
246
|
-
addNoteData(measure, header, tickInMeasure, value, timeScaleGroup);
|
247
|
-
if (conn.type === "end" && conn.direction) {
|
248
|
-
let directionalType;
|
249
|
-
switch (conn.direction) {
|
250
|
-
case "up":
|
251
|
-
directionalType = "1";
|
252
|
-
break;
|
253
|
-
case "left":
|
254
|
-
directionalType = "3";
|
255
|
-
break;
|
256
|
-
case "right":
|
257
|
-
directionalType = "4";
|
258
|
-
break;
|
259
|
-
default: continue;
|
260
|
-
}
|
261
|
-
const dirHeader = `${measure.toString().padStart(3, "0")}5${laneHex}`;
|
262
|
-
const dirValue = `${directionalType}${width.toString(36)}`;
|
263
|
-
addNoteData(measure, dirHeader, tickInMeasure, dirValue, timeScaleGroup);
|
264
|
-
}
|
265
|
-
}
|
266
|
-
}
|
267
|
-
}
|
268
|
-
function processGuide(guide) {
|
269
|
-
const channel = (slideChannelCounter % 36).toString(36);
|
270
|
-
const sortedMidpoints = [...guide.midpoints].sort((a, b) => a.beat - b.beat);
|
271
|
-
sortedMidpoints.forEach((midpoint, index) => {
|
272
|
-
const tick = midpoint.beat * TICKS_PER_BEAT;
|
273
|
-
const measure = Math.floor(tick / ticksPerMeasure);
|
274
|
-
const tickInMeasure = tick % ticksPerMeasure;
|
275
|
-
let noteType;
|
276
|
-
if (index === 0)
|
277
|
-
noteType = "1";
|
278
|
-
else if (index === sortedMidpoints.length - 1)
|
279
|
-
noteType = "2";
|
280
|
-
else
|
281
|
-
noteType = "3";
|
282
|
-
const [lane, width] = getSusLaneAndWidth(midpoint.lane, midpoint.size);
|
283
|
-
const laneHex = lane.toString(36);
|
284
|
-
const widthHex = width.toString(36);
|
285
|
-
if (guide.fade === "in" && index === 0) {
|
286
|
-
const dirHeader = `${measure.toString().padStart(3, "0")}5${laneHex}`;
|
287
|
-
const dirValue = `2${widthHex}`;
|
288
|
-
addNoteData(measure, dirHeader, tickInMeasure, dirValue, midpoint.timeScaleGroup);
|
289
|
-
}
|
290
|
-
if (guide.fade === "out" && index === sortedMidpoints.length - 1) {
|
291
|
-
const dirHeader = `${measure.toString().padStart(3, "0")}5${laneHex}`;
|
292
|
-
const dirValue = `5${widthHex}`;
|
293
|
-
addNoteData(measure, dirHeader, tickInMeasure, dirValue, midpoint.timeScaleGroup);
|
294
|
-
}
|
295
|
-
if (midpoint.ease) {
|
296
|
-
let easeType = midpoint.ease;
|
297
|
-
if (easeType === 'inout')
|
298
|
-
easeType = 'in';
|
299
|
-
if (easeType === 'outin')
|
300
|
-
easeType = 'out';
|
301
|
-
let directionalType = null;
|
302
|
-
if (easeType === 'in')
|
303
|
-
directionalType = '2';
|
304
|
-
else if (easeType === 'out')
|
305
|
-
directionalType = '5';
|
306
|
-
if (directionalType) {
|
307
|
-
const dirHeader = `${measure.toString().padStart(3, "0")}5${laneHex}`;
|
308
|
-
const dirValue = `${directionalType}${widthHex}`;
|
309
|
-
addNoteData(measure, dirHeader, tickInMeasure, dirValue, midpoint.timeScaleGroup);
|
310
|
-
}
|
311
|
-
}
|
312
|
-
const header = `${measure.toString().padStart(3, "0")}9${laneHex}${channel}`;
|
313
|
-
const value = `${noteType}${widthHex}`;
|
314
|
-
addNoteData(measure, header, tickInMeasure, value, midpoint.timeScaleGroup);
|
315
|
-
});
|
316
|
-
}
|
317
|
-
};
|
318
|
-
exports.uscToSUS = uscToSUS;
|
package/dist/sus/decode.d.cts
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
export declare const uscToSUS: (uscData: any) => string;
|
package/dist/sus/index.cjs
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
"use strict";
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.USCFade = exports.USCColor = void 0;
|
4
|
-
exports.USCColor = {
|
5
|
-
neutral: 0,
|
6
|
-
red: 1,
|
7
|
-
green: 2,
|
8
|
-
blue: 3,
|
9
|
-
yellow: 4,
|
10
|
-
purple: 5,
|
11
|
-
cyan: 6,
|
12
|
-
black: 7,
|
13
|
-
};
|
14
|
-
exports.USCFade = {
|
15
|
-
in: 2,
|
16
|
-
out: 0,
|
17
|
-
none: 1,
|
18
|
-
};
|
package/dist/sus/revert.cjs
DELETED
@@ -1,339 +0,0 @@
|
|
1
|
-
"use strict";
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.uscToSUS = void 0;
|
4
|
-
const TICKS_PER_BEAT = 480;
|
5
|
-
const uscToSUS = (uscData) => {
|
6
|
-
const usc = uscData.usc ? uscData.usc : uscData;
|
7
|
-
const susLines = [];
|
8
|
-
const noteData = new Map();
|
9
|
-
let slideChannelCounter = 0;
|
10
|
-
// (메타데이터 및 전역 정의 생성은 이전과 동일)
|
11
|
-
susLines.push(`#TITLE ""`, `#ARTIST ""`, `#DESIGNER ""`, `#WAVEOFFSET ${-usc.offset}`, `#REQUEST "ticks_per_beat ${TICKS_PER_BEAT}"`, ``);
|
12
|
-
const ticksPerMeasure = TICKS_PER_BEAT * 4;
|
13
|
-
const bpmObjects = usc.objects.filter((obj) => obj.type === 'bpm');
|
14
|
-
const bpmDefinitions = new Map();
|
15
|
-
let bpmCounter = 1;
|
16
|
-
for (const bpmObject of bpmObjects) {
|
17
|
-
if (!bpmDefinitions.has(bpmObject.bpm)) {
|
18
|
-
const bpmId = bpmCounter.toString().padStart(2, '0');
|
19
|
-
bpmDefinitions.set(bpmObject.bpm, bpmId);
|
20
|
-
susLines.push(`#BPM${bpmId}: ${bpmObject.bpm}`);
|
21
|
-
bpmCounter++;
|
22
|
-
}
|
23
|
-
}
|
24
|
-
susLines.push(``);
|
25
|
-
const timeScaleGroups = usc.objects.filter((obj) => obj.type === 'timeScaleGroup');
|
26
|
-
const tilIdMap = new Map();
|
27
|
-
timeScaleGroups.forEach((group, index) => {
|
28
|
-
const tilId = index.toString().padStart(2, '0');
|
29
|
-
tilIdMap.set(index, tilId);
|
30
|
-
const changesString = group.changes
|
31
|
-
.map((change) => {
|
32
|
-
const totalTicks = change.beat * TICKS_PER_BEAT;
|
33
|
-
const measure = Math.floor(totalTicks / ticksPerMeasure);
|
34
|
-
const tickInMeasure = totalTicks % ticksPerMeasure;
|
35
|
-
return `${measure}'${tickInMeasure}:${change.timeScale}`;
|
36
|
-
})
|
37
|
-
.join(', ');
|
38
|
-
susLines.push(`#TIL${tilId}: "${changesString}"`);
|
39
|
-
});
|
40
|
-
susLines.push(``);
|
41
|
-
addNoteData(0, '00002', 0, '4', 0);
|
42
|
-
for (const bpmObject of bpmObjects) {
|
43
|
-
const tick = bpmObject.beat * TICKS_PER_BEAT;
|
44
|
-
const measure = Math.floor(tick / ticksPerMeasure);
|
45
|
-
const tickInMeasure = tick % ticksPerMeasure;
|
46
|
-
const bpmId = bpmDefinitions.get(bpmObject.bpm);
|
47
|
-
if (bpmId) {
|
48
|
-
addNoteData(measure, `${measure.toString().padStart(3, '0')}08`, tickInMeasure, bpmId, 0);
|
49
|
-
}
|
50
|
-
}
|
51
|
-
for (const obj of usc.objects) {
|
52
|
-
switch (obj.type) {
|
53
|
-
case 'single':
|
54
|
-
case 'damage':
|
55
|
-
processSingleOrDamage(obj);
|
56
|
-
break;
|
57
|
-
case 'slide':
|
58
|
-
processSlide(obj);
|
59
|
-
slideChannelCounter++;
|
60
|
-
break;
|
61
|
-
case 'guide':
|
62
|
-
processGuide(obj);
|
63
|
-
slideChannelCounter++;
|
64
|
-
break;
|
65
|
-
case 'timeScaleGroup':
|
66
|
-
case 'bpm':
|
67
|
-
break;
|
68
|
-
}
|
69
|
-
}
|
70
|
-
// ▼▼▼ 노트 겹침 및 BPM 겹침 오류를 모두 해결한 최종 렌더링 로직 ▼▼▼
|
71
|
-
const sortedMeasures = Array.from(noteData.keys()).sort((a, b) => a - b);
|
72
|
-
let activeTimeScaleGroup = -1;
|
73
|
-
for (const measure of sortedMeasures) {
|
74
|
-
const headerMap = noteData.get(measure);
|
75
|
-
const sortedHeaders = Array.from(headerMap.keys()).sort();
|
76
|
-
for (const header of sortedHeaders) {
|
77
|
-
const notes = headerMap.get(header);
|
78
|
-
if (!notes || notes.length === 0)
|
79
|
-
continue;
|
80
|
-
const noteTimeScaleGroup = notes[0].timeScaleGroup;
|
81
|
-
const tilId = tilIdMap.get(noteTimeScaleGroup);
|
82
|
-
if (noteTimeScaleGroup !== activeTimeScaleGroup && tilId !== undefined) {
|
83
|
-
susLines.push(`#HISPEED ${tilId}`);
|
84
|
-
activeTimeScaleGroup = noteTimeScaleGroup;
|
85
|
-
}
|
86
|
-
if (header.endsWith('02')) {
|
87
|
-
susLines.push(`#${header}: ${notes[0].value}`);
|
88
|
-
continue;
|
89
|
-
}
|
90
|
-
const granularity = 1920;
|
91
|
-
const data = Array(granularity).fill('00');
|
92
|
-
const finalNotes = new Map();
|
93
|
-
const getPriority = (value) => {
|
94
|
-
const typeChar = value.charAt(0);
|
95
|
-
// Hidden 노트(타입 5)는 우선순위가 낮습니다.
|
96
|
-
if (typeChar === '5')
|
97
|
-
return 2;
|
98
|
-
// 그 외 모든 노트(BPM 변경 포함)는 우선순위가 높습니다.
|
99
|
-
return 1;
|
100
|
-
};
|
101
|
-
for (const note of notes) {
|
102
|
-
const index = Math.floor((note.tick / ticksPerMeasure) * granularity);
|
103
|
-
if (index >= granularity)
|
104
|
-
continue;
|
105
|
-
const existingNoteValue = finalNotes.get(index);
|
106
|
-
const newNoteValue = note.value;
|
107
|
-
if (!existingNoteValue ||
|
108
|
-
getPriority(newNoteValue) <= getPriority(existingNoteValue)) {
|
109
|
-
finalNotes.set(index, newNoteValue);
|
110
|
-
}
|
111
|
-
}
|
112
|
-
for (const [index, value] of finalNotes.entries()) {
|
113
|
-
data[index] = value;
|
114
|
-
}
|
115
|
-
susLines.push(`#${header}: ${data.join('')}`);
|
116
|
-
}
|
117
|
-
}
|
118
|
-
return susLines.join('\r\n');
|
119
|
-
// --- Helper Functions ---
|
120
|
-
function addNoteData(measure, header, tickInMeasure, value, timeScaleGroup) {
|
121
|
-
if (!noteData.has(measure))
|
122
|
-
noteData.set(measure, new Map());
|
123
|
-
const headerMap = noteData.get(measure);
|
124
|
-
if (!headerMap.has(header))
|
125
|
-
headerMap.set(header, []);
|
126
|
-
headerMap.get(header).push({ tick: tickInMeasure, value, timeScaleGroup });
|
127
|
-
}
|
128
|
-
function getSusLaneAndWidth(uscLane, uscSize) {
|
129
|
-
const susWidth = Math.round(uscSize * 2);
|
130
|
-
const susLane = Math.round(uscLane - uscSize + 8);
|
131
|
-
return [Math.max(0, susLane), Math.max(1, susWidth)];
|
132
|
-
}
|
133
|
-
function addTapNote(beat, lane, width, noteType, timeScaleGroup) {
|
134
|
-
const tick = beat * TICKS_PER_BEAT;
|
135
|
-
const measure = Math.floor(tick / ticksPerMeasure);
|
136
|
-
const tickInMeasure = tick % ticksPerMeasure;
|
137
|
-
const laneHex = lane.toString(36);
|
138
|
-
const widthHex = width.toString(36);
|
139
|
-
const header = `${measure.toString().padStart(3, '0')}1${laneHex}`;
|
140
|
-
const value = `${noteType}${widthHex}`;
|
141
|
-
addNoteData(measure, header, tickInMeasure, value, timeScaleGroup);
|
142
|
-
}
|
143
|
-
function processSingleOrDamage(note) {
|
144
|
-
if (note.type === 'damage') {
|
145
|
-
const [lane, width] = getSusLaneAndWidth(note.lane, note.size);
|
146
|
-
addTapNote(note.beat, lane, width, '4', note.timeScaleGroup);
|
147
|
-
return;
|
148
|
-
}
|
149
|
-
const [lane, width] = getSusLaneAndWidth(note.lane, note.size);
|
150
|
-
let susNoteType = '1';
|
151
|
-
if (note.critical && note.trace)
|
152
|
-
susNoteType = '6';
|
153
|
-
else if (note.critical)
|
154
|
-
susNoteType = '2';
|
155
|
-
else if (note.trace)
|
156
|
-
susNoteType = '5';
|
157
|
-
addTapNote(note.beat, lane, width, susNoteType, note.timeScaleGroup);
|
158
|
-
if (note.direction && note.direction !== 'none') {
|
159
|
-
let directionalType;
|
160
|
-
switch (note.direction) {
|
161
|
-
case 'up':
|
162
|
-
directionalType = '1';
|
163
|
-
break;
|
164
|
-
case 'left':
|
165
|
-
directionalType = '3';
|
166
|
-
break;
|
167
|
-
case 'right':
|
168
|
-
directionalType = '4';
|
169
|
-
break;
|
170
|
-
default:
|
171
|
-
return;
|
172
|
-
}
|
173
|
-
const [dirLane, dirWidth] = getSusLaneAndWidth(note.lane, note.size);
|
174
|
-
const tick = note.beat * TICKS_PER_BEAT;
|
175
|
-
const measure = Math.floor(tick / ticksPerMeasure);
|
176
|
-
const tickInMeasure = tick % ticksPerMeasure;
|
177
|
-
const dirHeader = `${measure.toString().padStart(3, '0')}5${dirLane.toString(36)}`;
|
178
|
-
const dirValue = `${directionalType}${dirWidth.toString(36)}`;
|
179
|
-
addNoteData(measure, dirHeader, tickInMeasure, dirValue, note.timeScaleGroup);
|
180
|
-
}
|
181
|
-
}
|
182
|
-
// ▼▼▼ `ease` 처리 로직을 최종 수정한 `processSlide` 함수 ▼▼▼
|
183
|
-
function processSlide(slide) {
|
184
|
-
const channel = (slideChannelCounter % 36).toString(36);
|
185
|
-
const sortedConnections = [...slide.connections].sort((a, b) => a.beat - b.beat);
|
186
|
-
let lastKnownLane = 0;
|
187
|
-
let lastKnownWidth = 0;
|
188
|
-
for (const conn of sortedConnections) {
|
189
|
-
const tick = conn.beat * TICKS_PER_BEAT;
|
190
|
-
const measure = Math.floor(tick / ticksPerMeasure);
|
191
|
-
const tickInMeasure = tick % ticksPerMeasure;
|
192
|
-
const timeScaleGroup = conn.timeScaleGroup ?? 0;
|
193
|
-
const isCritical = slide.critical || conn.critical;
|
194
|
-
let lane, width;
|
195
|
-
if (conn.type !== 'attach' && 'lane' in conn && 'size' in conn) {
|
196
|
-
;
|
197
|
-
[lane, width] = getSusLaneAndWidth(conn.lane, conn.size);
|
198
|
-
lastKnownLane = lane;
|
199
|
-
lastKnownWidth = width;
|
200
|
-
}
|
201
|
-
else {
|
202
|
-
lane = lastKnownLane;
|
203
|
-
width = lastKnownWidth;
|
204
|
-
}
|
205
|
-
const laneHex = lane.toString(36);
|
206
|
-
const widthHex = width.toString(36);
|
207
|
-
// --- 마커 및 방향성 노트 생성 로직 ---
|
208
|
-
// 1. Easing 마커 (start, end, tick 모두에 적용)
|
209
|
-
if ('ease' in conn && conn.ease) {
|
210
|
-
let easeType = conn.ease;
|
211
|
-
if (easeType === 'inout')
|
212
|
-
easeType = 'in';
|
213
|
-
if (easeType === 'outin')
|
214
|
-
easeType = 'out';
|
215
|
-
let directionalType = null;
|
216
|
-
if (easeType === 'in')
|
217
|
-
directionalType = '2';
|
218
|
-
else if (easeType === 'out')
|
219
|
-
directionalType = '5';
|
220
|
-
if (directionalType) {
|
221
|
-
const dirHeader = `${measure.toString().padStart(3, '0')}5${laneHex}`;
|
222
|
-
const dirValue = `${directionalType}${widthHex}`;
|
223
|
-
addNoteData(measure, dirHeader, tickInMeasure, dirValue, timeScaleGroup);
|
224
|
-
}
|
225
|
-
}
|
226
|
-
// 2. 기타 마커 및 Flick (start, end 에만 적용)
|
227
|
-
if (conn.type === 'start' || conn.type === 'end') {
|
228
|
-
let markerType = null;
|
229
|
-
if ('judgeType' in conn) {
|
230
|
-
if (conn.judgeType === 'none')
|
231
|
-
markerType = isCritical ? '8' : '7';
|
232
|
-
else if (conn.judgeType === 'trace')
|
233
|
-
markerType = isCritical ? '6' : '5';
|
234
|
-
}
|
235
|
-
if (conn.type === 'start' && isCritical && markerType === null) {
|
236
|
-
markerType = '2';
|
237
|
-
}
|
238
|
-
if (markerType) {
|
239
|
-
addTapNote(conn.beat, lane, width, markerType, timeScaleGroup);
|
240
|
-
}
|
241
|
-
if (conn.type === 'end' && conn.direction) {
|
242
|
-
let directionalType;
|
243
|
-
switch (conn.direction) {
|
244
|
-
case 'up':
|
245
|
-
directionalType = '1';
|
246
|
-
break;
|
247
|
-
case 'left':
|
248
|
-
directionalType = '3';
|
249
|
-
break;
|
250
|
-
case 'right':
|
251
|
-
directionalType = '4';
|
252
|
-
break;
|
253
|
-
default:
|
254
|
-
continue;
|
255
|
-
}
|
256
|
-
const dirHeader = `${measure.toString().padStart(3, '0')}5${laneHex}`;
|
257
|
-
const dirValue = `${directionalType}${widthHex}`;
|
258
|
-
addNoteData(measure, dirHeader, tickInMeasure, dirValue, timeScaleGroup);
|
259
|
-
}
|
260
|
-
}
|
261
|
-
// --- 실제 슬라이드 경로 노트 생성 로직 ---
|
262
|
-
let noteType = null;
|
263
|
-
switch (conn.type) {
|
264
|
-
case 'start':
|
265
|
-
noteType = '1';
|
266
|
-
break;
|
267
|
-
case 'end':
|
268
|
-
noteType = '2';
|
269
|
-
break;
|
270
|
-
case 'tick':
|
271
|
-
noteType = conn.critical !== undefined ? '3' : '5';
|
272
|
-
break;
|
273
|
-
case 'attach':
|
274
|
-
// `convert.ts` 원리: '보이는 경유점(타입 3)' + '틱 제거 마커(타입 3)' 조합으로 변환
|
275
|
-
const attachHeader = `${measure.toString().padStart(3, '0')}3${laneHex}${channel}`;
|
276
|
-
const attachValue = `3${widthHex}`; // 보이는 경유점
|
277
|
-
addNoteData(measure, attachHeader, tickInMeasure, attachValue, timeScaleGroup);
|
278
|
-
// 틱 제거용 마커(SUS 탭 타입 3)
|
279
|
-
addTapNote(conn.beat, lane, width, '3', timeScaleGroup);
|
280
|
-
continue;
|
281
|
-
}
|
282
|
-
if (noteType) {
|
283
|
-
const header = `${measure.toString().padStart(3, '0')}3${laneHex}${channel}`;
|
284
|
-
const value = `${noteType}${widthHex}`;
|
285
|
-
addNoteData(measure, header, tickInMeasure, value, timeScaleGroup);
|
286
|
-
}
|
287
|
-
}
|
288
|
-
}
|
289
|
-
function processGuide(guide) {
|
290
|
-
const channel = (slideChannelCounter % 36).toString(36);
|
291
|
-
const sortedMidpoints = [...guide.midpoints].sort((a, b) => a.beat - b.beat);
|
292
|
-
sortedMidpoints.forEach((midpoint, index) => {
|
293
|
-
const tick = midpoint.beat * TICKS_PER_BEAT;
|
294
|
-
const measure = Math.floor(tick / ticksPerMeasure);
|
295
|
-
const tickInMeasure = tick % ticksPerMeasure;
|
296
|
-
let noteType;
|
297
|
-
if (index === 0)
|
298
|
-
noteType = '1';
|
299
|
-
else if (index === sortedMidpoints.length - 1)
|
300
|
-
noteType = '2';
|
301
|
-
else
|
302
|
-
noteType = '3';
|
303
|
-
const [lane, width] = getSusLaneAndWidth(midpoint.lane, midpoint.size);
|
304
|
-
const laneHex = lane.toString(36);
|
305
|
-
const widthHex = width.toString(36);
|
306
|
-
if (guide.fade === 'in' && index === 0) {
|
307
|
-
const dirHeader = `${measure.toString().padStart(3, '0')}5${laneHex}`;
|
308
|
-
const dirValue = `2${widthHex}`;
|
309
|
-
addNoteData(measure, dirHeader, tickInMeasure, dirValue, midpoint.timeScaleGroup);
|
310
|
-
}
|
311
|
-
if (guide.fade === 'out' && index === sortedMidpoints.length - 1) {
|
312
|
-
const dirHeader = `${measure.toString().padStart(3, '0')}5${laneHex}`;
|
313
|
-
const dirValue = `5${widthHex}`;
|
314
|
-
addNoteData(measure, dirHeader, tickInMeasure, dirValue, midpoint.timeScaleGroup);
|
315
|
-
}
|
316
|
-
if (midpoint.ease) {
|
317
|
-
let easeType = midpoint.ease;
|
318
|
-
if (easeType === 'inout')
|
319
|
-
easeType = 'in';
|
320
|
-
if (easeType === 'outin')
|
321
|
-
easeType = 'out';
|
322
|
-
let directionalType = null;
|
323
|
-
if (easeType === 'in')
|
324
|
-
directionalType = '2';
|
325
|
-
else if (easeType === 'out')
|
326
|
-
directionalType = '5';
|
327
|
-
if (directionalType) {
|
328
|
-
const dirHeader = `${measure.toString().padStart(3, '0')}5${laneHex}`;
|
329
|
-
const dirValue = `${directionalType}${widthHex}`;
|
330
|
-
addNoteData(measure, dirHeader, tickInMeasure, dirValue, midpoint.timeScaleGroup);
|
331
|
-
}
|
332
|
-
}
|
333
|
-
const header = `${measure.toString().padStart(3, '0')}9${laneHex}${channel}`;
|
334
|
-
const value = `${noteType}${widthHex}`;
|
335
|
-
addNoteData(measure, header, tickInMeasure, value, midpoint.timeScaleGroup);
|
336
|
-
});
|
337
|
-
}
|
338
|
-
};
|
339
|
-
exports.uscToSUS = uscToSUS;
|
package/dist/sus/revert.d.cts
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
export declare const uscToSUS: (uscData: any) => string;
|
package/dist/usc/ccIndex.cjs
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
"use strict";
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.USCFade = exports.USCColor = void 0;
|
4
|
-
exports.USCColor = {
|
5
|
-
neutral: 0,
|
6
|
-
red: 1,
|
7
|
-
green: 2,
|
8
|
-
blue: 3,
|
9
|
-
yellow: 4,
|
10
|
-
purple: 5,
|
11
|
-
cyan: 6,
|
12
|
-
black: 7,
|
13
|
-
};
|
14
|
-
exports.USCFade = {
|
15
|
-
in: 2,
|
16
|
-
out: 0,
|
17
|
-
none: 1,
|
18
|
-
};
|
package/dist/usc/ccIndex.d.cts
DELETED
@@ -1,91 +0,0 @@
|
|
1
|
-
export type USC = {
|
2
|
-
offset: number;
|
3
|
-
objects: USCObject[];
|
4
|
-
};
|
5
|
-
export type USCObject = USCBpmChange | USCTimeScaleChange | USCSingleNote | USCSlideNote | USCGuideNote | USCDamageNote;
|
6
|
-
type BaseUSCObject = {
|
7
|
-
beat: number;
|
8
|
-
timeScaleGroup: number;
|
9
|
-
};
|
10
|
-
export type USCBpmChange = Omit<BaseUSCObject, 'timeScaleGroup'> & {
|
11
|
-
type: 'bpm';
|
12
|
-
bpm: number;
|
13
|
-
};
|
14
|
-
export type USCTimeScaleChange = {
|
15
|
-
type: 'timeScaleGroup';
|
16
|
-
changes: {
|
17
|
-
beat: number;
|
18
|
-
timeScale: number;
|
19
|
-
}[];
|
20
|
-
};
|
21
|
-
type BaseUSCNote = BaseUSCObject & {
|
22
|
-
lane: number;
|
23
|
-
size: number;
|
24
|
-
};
|
25
|
-
export type USCSingleNote = BaseUSCNote & {
|
26
|
-
type: 'single';
|
27
|
-
critical: boolean;
|
28
|
-
trace: boolean;
|
29
|
-
direction?: 'left' | 'up' | 'right' | 'none';
|
30
|
-
};
|
31
|
-
export type USCDamageNote = BaseUSCNote & {
|
32
|
-
type: 'damage';
|
33
|
-
};
|
34
|
-
export type USCConnectionStartNote = BaseUSCNote & {
|
35
|
-
type: 'start';
|
36
|
-
critical: boolean;
|
37
|
-
ease: 'out' | 'linear' | 'in' | 'inout' | 'outin';
|
38
|
-
judgeType: 'normal' | 'trace' | 'none';
|
39
|
-
};
|
40
|
-
export type USCConnectionTickNote = BaseUSCNote & {
|
41
|
-
type: 'tick';
|
42
|
-
critical?: boolean;
|
43
|
-
ease: 'out' | 'linear' | 'in' | 'inout' | 'outin';
|
44
|
-
};
|
45
|
-
export type USCConnectionAttachNote = Omit<BaseUSCObject, 'timeScaleGroup'> & {
|
46
|
-
type: 'attach';
|
47
|
-
critical?: boolean;
|
48
|
-
timeScaleGroup?: number;
|
49
|
-
};
|
50
|
-
export type USCConnectionEndNote = BaseUSCNote & {
|
51
|
-
type: 'end';
|
52
|
-
critical: boolean;
|
53
|
-
direction?: 'left' | 'up' | 'right';
|
54
|
-
judgeType: 'normal' | 'trace' | 'none';
|
55
|
-
};
|
56
|
-
export type USCSlideNote = {
|
57
|
-
type: 'slide';
|
58
|
-
critical: boolean;
|
59
|
-
connections: [
|
60
|
-
USCConnectionStartNote,
|
61
|
-
...(USCConnectionTickNote | USCConnectionAttachNote)[],
|
62
|
-
USCConnectionEndNote
|
63
|
-
];
|
64
|
-
};
|
65
|
-
export declare const USCColor: {
|
66
|
-
neutral: number;
|
67
|
-
red: number;
|
68
|
-
green: number;
|
69
|
-
blue: number;
|
70
|
-
yellow: number;
|
71
|
-
purple: number;
|
72
|
-
cyan: number;
|
73
|
-
black: number;
|
74
|
-
};
|
75
|
-
export type USCColor = keyof typeof USCColor;
|
76
|
-
export type USCGuideMidpointNote = BaseUSCNote & {
|
77
|
-
ease: 'out' | 'linear' | 'in' | 'inout' | 'outin';
|
78
|
-
};
|
79
|
-
export declare const USCFade: {
|
80
|
-
in: number;
|
81
|
-
out: number;
|
82
|
-
none: number;
|
83
|
-
};
|
84
|
-
export type USCFade = keyof typeof USCFade;
|
85
|
-
export type USCGuideNote = {
|
86
|
-
type: 'guide';
|
87
|
-
color: USCColor;
|
88
|
-
fade: USCFade;
|
89
|
-
midpoints: USCGuideMidpointNote[];
|
90
|
-
};
|
91
|
-
export {};
|
package/dist/usc/index.cjs
DELETED
File without changes
|
File without changes
|
File without changes
|