Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -474,7 +474,7 @@ private static void RunConvertChuSingleFile(string filePath, string inputKind)
var destNote = _outputSpec.Kind == OutputSinkKind.Stdout ? "(标准输出)" : outPath;
Console.Error.WriteLine($"{inputKind.ToUpperInvariant()} → {targetFormat.ToUpperInvariant()}: {full} → {destNote}");

IChuChart chart;
ChuChart chart;
List<Alert> parseAlerts;
switch (inputKind)
{
Expand Down
14 changes: 4 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,13 +160,13 @@ return maidataText; // maidataText即为转谱结果
var (c2sChart, alerts) = new C2sParser().Parse(c2sText); // 解析 C2S 谱面字符串
var (ugcChart, alerts) = new UgcParser().Parse(ugcText); // 解析 UGC 谱面字符串
var (susChart, alerts) = new SusParser().Parse(susText); // 解析 SUS 谱面字符串
// 以上得到的c2sChart、ugcChart、susChart,都是IChuChart类型的谱面表示对象
// 以上得到的c2sChart、ugcChart、susChart,都是ChuChart类型的谱面表示对象
// alerts是解析过程中可能产生的警告信息等,建议打印出来。

var (c2sText, alerts) = new C2sGenerator().Generate(ugcChart); // UGC -> C2S
var (ugcText, alerts) = new UgcGenerator().Generate(c2sChart); // C2S -> UGC
var (susText, alerts) = new SusGenerator().Generate(c2sChart); // C2S -> SUS
// 各种Generator的Generate方法,均接受任意的IChuChart对象
// 各种Generator的Generate方法,均接受 ChuChart(可将任一 Parser 产出的 ChuChart 互相传入)
// 同上,alerts是生成过程中可能产生的警告信息等,建议打印出来。
```

Expand Down Expand Up @@ -215,13 +215,7 @@ finally
- **parser(解析器)**:把“源格式文本”解析成中间表示
- `SimaiParser.Parse(string)` → `MaiChart`
- `MA2Parser.Parse(string)` → `MaiChart`
- CHUNITHM的三种Parser(`C2sParser`、`UgcParser`、`SusParser`):`Parse(string)` → `IChuChart`
> <details>
> <summary>关于IChuChart</summary>
> 当前实现IChuChart是一个通用的接口而非具体的类型,这是因为目前不同Parser解析出的谱面的IR尚未能够完全统一,所以只能都各自继承自IChuChart。
> 不过不用担心,任意的Generator都接受任意IChuChart对象,因此你可以不在意它们之间的差异,直接拿来用就行了。
> 未来如果有机会的话,我们会把它们进一步统一成同一个具体类型的IR,以进一步提升代码的可维护性和可读性。
> </details>
- CHUNITHM的三种Parser(`C2sParser`、`UgcParser`、`SusParser`):`Parse(string)` → `ChuChart`
Comment thread
cubic-dev-ai[bot] marked this conversation as resolved.
- 解析成功时,**返回值会同时带有 `List<Alert>`**,这是转谱过程中可能遇到的警告等信息,建议打印出来(直接对`Alert`对象`ToString()`即可)。
- 如果解析失败,会抛出 `ConversionException`;该异常对象中同样含有一个 `List<Alert>`,是导致转谱失败的错误信息,可以同上打印出来。

Expand All @@ -232,7 +226,7 @@ finally
- **generator(生成器)**:把中间表示转回“目标格式文本”
- `SimaiGenerator.Generate(MaiChart)` → Simai 单谱文本(可写入 `maidata.txt` 的 `&inote_*`)
- `MA2Generator.Generate(MaiChart)` → MA2 文本
- CHUNITHM的三种Generator(`C2sGenerator`、`UgcGenerator`、`SusGenerator`):`Generate(IChuChart)` → 目标格式的谱面文本
- CHUNITHM的三种Generator(`C2sGenerator`、`UgcGenerator`、`SusGenerator`):`Generate(ChuChart)` → 目标格式的谱面文本
- 与parser类似,成功生成时,**返回值会同时带有 `List<Alert>`**,这是转谱过程中可能遇到的警告等信息,建议打印出来(直接对`Alert`对象`ToString()`即可)。
- 如果生成失败,会抛出 `ConversionException`;该异常对象中同样含有一个 `List<Alert>`,是导致转谱失败的错误信息,可以同上打印出来。

Expand Down
9 changes: 9 additions & 0 deletions chart/BPMList.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,15 @@ internal Rational ConvertTime(Rational startTime, Rational value, decimal? srcBp
return result.CanonicalForm;
}
}

internal (decimal, decimal, decimal, decimal) BPM_DEF()
{
var bpms = this.Select(x => x.Bpm).ToList();
var max = bpms.Max();
var min = bpms.Min();
var modes = bpms.GroupBy(x => x).OrderByDescending(g => g.Count()).First().Key; // 众数
return (this.First().Bpm, modes, max, min);
}
Comment thread
Starrah marked this conversation as resolved.
}

public record BPM(Rational Time, decimal Bpm);
Expand Down
24 changes: 0 additions & 24 deletions chart/chu/C2sChart.cs

This file was deleted.

16 changes: 16 additions & 0 deletions chart/chu/ChuChart.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using MuConvert.chart;
using Rationals;

namespace MuConvert.chu;

public class ChuChart : BaseChart<ChuNote>
{
public string Title { get; set; } = "";
public string Artist { get; set; } = "";
public string Designer { get; set; } = ""; // 谱师
public int Difficulty { get; set; } = 3; // 难度,0-basic, 1-advanced, ...。大多数情况下都是数字字符串。不直接存成数字是为了,万一自制谱这里写的不是数字、保留鲁棒性
Comment thread
Starrah marked this conversation as resolved.
public string DisplayLevel { get; set; } = ""; // 显示等级,字符串
public decimal Level { get; set; } // 定数,小数
public string MusicId { get; set; } = "0";
public List<(Rational Time, Rational Duration, decimal Multiplier)> SflList = []; // 所有变速声明构成的列表。
}
61 changes: 39 additions & 22 deletions chart/chu/ChuNote.cs
Original file line number Diff line number Diff line change
@@ -1,38 +1,55 @@
using MuConvert.chart;
using Rationals;

namespace MuConvert.chu;

/**
* CHUNITHM 通用音符,C2S / UGC / SUS 共用此结构。
*/
public class ChuNote
public class ChuNote: BaseNote
{
/** 音符类型 (TAP, CHR, HLD, SLD, AIR, AHD 等) */
public string Type { get; set; } = "TAP";
/** 小节号 */
public int Measure { get; set; }
/** 小节内偏移 (C2S: 0–383, UGC/SUS: 0–1919) */
public int Offset { get; set; }
/** 起始列 (0–15) */
public int Cell { get; set; }
/** 宽度 (1–16) */
public int Width { get; set; } = 1;
/** HLD 持续时长 */
public int HoldDuration { get; set; }
/** SLD 持续时长 */
public int SlideDuration { get; set; }
/** HLD/SLD/AHD/ASD等的 持续时长 */
public Rational Duration { get; set => field = value.CanonicalForm; } = 0;
Comment thread
sourcery-ai[bot] marked this conversation as resolved.

/** SLD 终点列 */
public int EndCell { get; set; }
public int EndCell
{
get => _endCell ?? Cell;
set => _endCell = value;
}
/** SLD 终点宽度 */
public int EndWidth { get; set; } = 1;
/** CHR/FLK 附加数据(方向等) */
public int EndWidth
{
get => _endWidth ?? Width;
set => _endWidth = value;
}

/**
* 当前音符的”前驱“。对不同类型的音符,其定义不同:
* - 对 Slide(SLD/SLC),是该slide对应的前一段slide。(对首段slide,该值为null)
* - 对 Air(AIR/AUR/AUL/ADW/ADR/ADL),是它所依附的音符(可以是tap\hold等任何类型,应该只要不是air系列和aircrush(ALD)都行)
* - 对 Air Slide(ASD/ASC):对首段slide,同Air的情况、是它所依附的音符;对第二段及之后的slide,同Slide的情况,是该slide对应的前一段slide。
*
* 不难分析出,在完成整个chart之后,这个属性其实可以根据完整chart的列表动态推断的。
* 因此,在BaseChuParser类中提供了FillAllPrevious方法,该方法应该在所有Note被正常解析完成后调用,填充所有上述类型的音符的targetNote信息。这样就不用每个Parser都写一段相似的逻辑。
*/
public ChuNote? Previous;

/** CHR/FLK/Air系列音符可能会具有的标记(如UP、L、DEF等) */
public string Tag { get; set; } = "";
/** AIR/AHD 关联的目标音符类型 */
public string TargetNote { get; set; } = "";
/** AHD 持续时长 */
public int AirHoldDuration { get; set; }
/** Air Crush 起始高度 */
public int StartHeight { get; set; }
/** Air Crush 目标高度 */
public int TargetHeight { get; set; }
/** Air Crush 颜色 */
public string NoteColor { get; set; } = "";
/** ASD/ASC/ALD上具有的、目前含义还不明确的字段,统一收集到这个里面。 */
public List<int> ExtraData = [];

public override Rational EndTime => (Time + Duration).CanonicalForm;
/** Air系列音符/Slide系列音符的 关联的目标音符类型。仅供向前兼容使用。 */
public string TargetNote => Previous?.Type ?? "N";

private int? _endCell;
private int? _endWidth;
}
8 changes: 0 additions & 8 deletions chart/chu/IChuChart.cs

This file was deleted.

20 changes: 0 additions & 20 deletions chart/chu/SusChart.cs

This file was deleted.

27 changes: 0 additions & 27 deletions chart/chu/UgcChart.cs

This file was deleted.

Loading