From 048b631bd6405c0188f2226f4d19b8e7f5d9db28 Mon Sep 17 00:00:00 2001 From: EillesWan Date: Fri, 11 Apr 2025 16:58:11 +0800 Subject: [PATCH] =?UTF-8?q?=E5=BC=BA=E5=8C=96=E6=96=87=E6=A1=A3=E5=86=85?= =?UTF-8?q?=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Musicreater/utils.py | 24 ++++++- docs/API.md | 2 +- docs/FSQ文件格式.md | 37 ----------- docs/库的生成与功能文档.md | 2 +- docs/生成文件的使用说明.md | 2 +- docs/转换乐器对照表.md | 10 +-- docs/{MSQ文件格式.md => 音乐序列文件格式.md} | 66 ++++++++++++++++---- example_fsq_opera.py | 2 +- 8 files changed, 85 insertions(+), 60 deletions(-) delete mode 100644 docs/FSQ文件格式.md rename docs/{MSQ文件格式.md => 音乐序列文件格式.md} (72%) diff --git a/Musicreater/utils.py b/Musicreater/utils.py index cdeb600..b317f75 100644 --- a/Musicreater/utils.py +++ b/Musicreater/utils.py @@ -434,7 +434,29 @@ def load_decode_fsq_flush_release( starter_index: int, high_quantity_note: bool, ) -> Generator[MineNote, Any, None]: - """ """ + """ + 以流的方式解码FSQ音乐序列的音符序列并流式返回 + + Parameters + ---------- + buffer_in : BytesIO + 输入的MSQ格式二进制字节流 + starter_index : int + 字节流中,音符序列的起始索引 + high_quantity_note : bool + 是否启用高精度音符解析 + + Returns + ------- + Generator[MineNote, Any, None] + 以流的方式返回解码后的音符序列,每次返回一个元组 + 元组中包含两个元素,第一个元素为音符所在通道的索引,第二个元素为音符对象 + + Raises + ------ + MusicSequenceDecodeError + 当解码过程中出现错误,抛出异常 + """ if buffer_in.tell() != starter_index: buffer_in.seek(starter_index, 0) diff --git a/docs/API.md b/docs/API.md index 203d26b..dfd1abf 100644 --- a/docs/API.md +++ b/docs/API.md @@ -1,7 +1,7 @@

音·创 Musicreater

- +

**此为开发相关文档,内容包括:库的简单调用、所生成文件结构的详细说明、特殊参数的详细解释** diff --git a/docs/FSQ文件格式.md b/docs/FSQ文件格式.md deleted file mode 100644 index 16738da..0000000 --- a/docs/FSQ文件格式.md +++ /dev/null @@ -1,37 +0,0 @@ -# FSQ 文件格式 - -FSQ 文件是 音·创 库存储音符序列的一种格式,取自 **F**lowing Music **S**e**q**uence 之名。 - -现在 音·创 库及其上游软件使用的是在 MSQ 第三版 的基础上进行流式的兼容性变动。 - -## FSQ 第一版 - -第一版的码头是 `FSQ!` ,这一版中,所有的**字符串**皆以 _**GB18030**_ 编码进行编解码,**数值**皆是以 _**大端字节序**_ 存储的无符号整数。 - -码头是文件前四个字节的内容,这一部分内容是可读的 ASCII 字串。因此,这一版的文件前四个字节的内容必为 `FSQ!`。 - -因为这一版本是在 MSQ 第三版的基础上演变而来的,因此取自 MSQ 码头的 `MSQ!` 而改作 `FSQ!`。 - -### 文件头 - -FSQ 第一版的文件头是在 MSQ 第三版的文件头的基础上增加了一个占 5 字节的全曲音符总数。 - -也就是说,与 MSQ 第三版一致的,在这一元信息中,**音乐名称长度**和**最小音量**合计共 2 字节;**高精度音符时间控制启用**和**总音调偏移**合计共 2 字节;因此,除**音乐名称**为任意长度,前四字节内容均为固定。而最后增加 5 字节作为全曲音符总数。 - -### 音符序列 - -FSQ 格式不包含音符的通道信息,在读取处理时默认将同一乐器的音符视为同一通道。也就是说,仅存在一个序列。其中每个音符的信息存储方式与 MSQ 第三版一致。 - -音符序列的存储顺序是按照音符的**开始时间**进行排序的。 - -但是注意!有可能一个较长的音符的开始到结束时间内还包含有音符,此时如有要适配的读取器,还请继续读取直到下一个音符的开始时间大于此较长音符的结束时间。 - -在每 100 个音符后,插入一段 32 位的 XXHASH32 校验码,其所校验的内容为这一百个音符中每个音符的第 6 个字节彼此异或之结果,种子值为这一百个音符中每个音符的第 2 个字节的彼此异或结果。 - -若最后不满足 100 个音符,则不插入上述校验码。 - -### 文件校验 - -在所有有效数据之后,包含一个 128 位的校验值,用以标识整个文件结束的同时,验证整个文件的完整性。 - -该 128 位的校验值是 包括码头在内的元信息的 XXHASH64 校验值(种子值是全曲音符数) 对于前述所有 XXHASH32 校验值彼此异或的异或 所得值之 XXHASH128 校验值,以 全曲音符总数 作为种子值。 diff --git a/docs/库的生成与功能文档.md b/docs/库的生成与功能文档.md index 68298b2..443a942 100644 --- a/docs/库的生成与功能文档.md +++ b/docs/库的生成与功能文档.md @@ -1,7 +1,7 @@

音·创 Musicreater

- +

**此为开发相关文档,内容包括:库的简单调用、所生成文件结构的详细说明、特殊参数的详细解释** diff --git a/docs/生成文件的使用说明.md b/docs/生成文件的使用说明.md index 96c423d..8a7522a 100644 --- a/docs/生成文件的使用说明.md +++ b/docs/生成文件的使用说明.md @@ -1,7 +1,7 @@

音·创 Musicreater

- +

# 生成文件的使用 diff --git a/docs/转换乐器对照表.md b/docs/转换乐器对照表.md index d6f747c..0fc1850 100644 --- a/docs/转换乐器对照表.md +++ b/docs/转换乐器对照表.md @@ -1,7 +1,7 @@

音·创 Musicreater

- +

# 转换乐器对照表 @@ -12,11 +12,11 @@ **_使用时请遵循协议规定_** -- 版权所有 © 2024 金羿 & 诸葛亮与八卦阵 -- Copyright © 2025 Eilles & bgArray +- 版权所有 © 2024 金羿 & 诸葛亮与八卦阵 +- Copyright © 2025 Eilles & bgArray -* 开源相关声明请见 仓库根目录下的 License.md -* Terms & Conditions: License.md in the root directory +* 开源相关声明请见 仓库根目录下的 License.md +* Terms & Conditions: License.md in the root directory 音·创 开发交流群 861684859\ Email TriM-Organization@hotmail.com\ diff --git a/docs/MSQ文件格式.md b/docs/音乐序列文件格式.md similarity index 72% rename from docs/MSQ文件格式.md rename to docs/音乐序列文件格式.md index 099eeb2..5ef4209 100644 --- a/docs/MSQ文件格式.md +++ b/docs/音乐序列文件格式.md @@ -1,22 +1,24 @@ -# MSQ 文件格式 +# 音乐序列文件格式 -MSQ 文件是 音·创 库存储音符序列的一种格式,取自 **M**usic**S**e**Q**uence 类之名。 +音·创 库的音符序列文件格式包含两种,一种是常规的音乐序列存储采用的 MSQ 格式,另一种是为了流式读取音符而采用的 FSQ 格式。 + +## MSQ 数据格式 + +MSQ 格式是 音·创 库存储音符序列的一种字节码格式,取自 **M**usic**S**e**Q**uence 类之名。 现在 音·创 库及其上游软件使用的是在 第二版 的基础上增设校验功能的 MSQ 第三版。 -## MSQ 第三版 +### MSQ 第三版 -第二版的码头是 `MSQ@` ,这一版中,所有的**字符串**皆以 _**GB18030**_ 编码进行编解码,**数值**皆是以 _**大端字节序**_ 存储的无符号整数。 +第三版 MSQ 格式的码头是 `MSQ!` ,这一版中,所有的**字符串**皆以 _**GB18030**_ 编码进行编解码,**数值**皆是以 _**大端字节序**_ 存储的无符号整数。 -MSQ 第三版的码头是 `MSQ!`。 +码头是字节码前四个字节的内容,这一部分内容是可读的 ASCII 字串。因此,第三版的字节码中前四个字节的内容必为 `MSQ!`。 -码头是文件前四个字节的内容,这一部分内容是可读的 ASCII 字串。因此,第三版的文件前四个字节的内容必为 `MSQ!`。 - -取 MSQ@ 是因为美式键盘上 @ 是 Shift+2 键 按下取得的,故代表 MSQ 第二版。 +第二版 MSQ 取 `MSQ@` 作为码头是因为美式键盘上 @ 是 Shift+2 键 按下取得的,故代表 MSQ 第二版。 你猜为什么第三版是 `MSQ!`。 -### 元信息 +#### 元信息 | 信息名称 | 西文代号 | 位长(多少个 0 或 1) | 支持说明 | | ------------------------------ | -------------------------- | --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | @@ -29,7 +31,7 @@ MSQ 第三版的码头是 `MSQ!`。 在这一元信息中,**音乐名称长度**和**最小音量**合计共 2 字节;**高精度音符时间控制启用**和**总音调偏移**合计共 2 字节;因此,除**音乐名称**为任意长度,前四字节内容均为固定。 -### 音符序列 +#### 音符序列 每个序列前 4 字节为一个用以表示当前通道中音符数量的值,也就是**通道音符数**(notes_count)。也即是说,一个通道内的音符可以是 0~4294967295 个。 @@ -48,7 +50,7 @@ MSQ 第三版的码头是 `MSQ!`。 | **乐器名称** | sound_name | 依据先前定义 | 最多可支持 31 个中文字符 或 63 个西文字符,其长度取决于先前获知的 “乐器名称长度” 的定义 | | **声像位移**(非必含) | position_displacement | 共三个值,每个值 16 位 共 48 位 | 若前述**是否启用声像位移**已启用,则此值启用;三个值分别代表 x、y、z 轴上的偏移,每个值支持数值 0~65535,注意,这里每个 1 代表最小音量的 0.001 个单位,即取值是此处表示数字的千分倍 | -### 序列校验 +#### 序列校验 _第三版新增_ @@ -56,11 +58,11 @@ _第三版新增_ 在这 128 位里,前 64 位是该通道音符数的 XXHASH64 校验值,以 3 作为种子值。 后 64 位是整个通道全部字节串的 XXHASH64 校验值(包括通道开头的音符数),以 该通道音符数 作为种子值。 -### 文件校验 +#### 总体校验 _第三版新增_ -在所有有效数据之后,包含一个 128 位的校验值,用以标识整个文件结束的同时,验证整个文件的完整性。 +在所有有效数据之后,包含一个 128 位的校验值,用以标识整个字节串结束的同时,验证整个字节码数据的完整性。 该 128 位的校验值是 包括码头在内的元信息的 XXHASH64 校验值(种子值是全曲音符数) 对于前述所有校验值彼此异或的异或 所得值之 XXHASH128 校验值,以 全曲音符总数 作为种子值。 @@ -107,3 +109,41 @@ ADD XXH128( note_count ) ``` + +## FSQ 数据格式 + +FSQ 格式是 音·创 库存储音符序列的一种字节码格式,取自 **F**lowing Music **S**e**q**uence 之名。 + +现在 音·创 库及其上游软件使用的是在 MSQ 第三版 的基础上进行流式的兼容性变动。 + +### FSQ 第一版 + +第一版的码头是 `FSQ!` ,这一版中,所有的**字符串**皆以 _**GB18030**_ 编码进行编解码,**数值**皆是以 _**大端字节序**_ 存储的无符号整数。 + +码头是字节串前四个字节的内容,这一部分内容是可读的 ASCII 字串。因此,这一版的文件前四个字节的内容必为 `FSQ!`。 + +因为这一版本是在 MSQ 第三版的基础上演变而来的,因此取自 MSQ 码头的 `MSQ!` 而改作 `FSQ!`。 + +#### 元信息 + +FSQ 第一版的元信息是在 MSQ 第三版的元信息的基础上增加了一个占 5 字节的全曲音符总数。 + +也就是说,与 MSQ 第三版一致的,在这一组信息中,**音乐名称长度**和**最小音量**合计共 2 字节;**高精度音符时间控制启用**和**总音调偏移**合计共 2 字节;因此,除**音乐名称**为任意长度,前四字节内容均为固定。而最后增加 5 字节作为全曲音符总数。 + +#### 音符序列 + +FSQ 格式不包含音符的通道信息,在读取处理时默认将同一乐器的音符视为同一通道。也就是说,仅存在一个序列。其中每个音符的信息存储方式与 MSQ 第三版一致。 + +音符序列的存储顺序是按照音符的**开始时间**进行排序的。 + +但是注意!有可能一个较长的音符的开始到结束时间内还包含有音符,此时如有要适配的读取器,还请继续读取直到下一个音符的开始时间大于此较长音符的结束时间。 + +在每 100 个音符后,插入一段 32 位的 XXHASH32 校验码,其所校验的内容为这一百个音符中每个音符的第 6 个字节彼此异或之结果,种子值为这一百个音符中每个音符的第 2 个字节的彼此异或结果。 + +若最后不满足 100 个音符,则不插入上述校验码。 + +#### 总体校验 + +在所有有效数据之后,包含一个 128 位的校验值,用以标识整个字节串结束的同时,验证整个字节码数据的完整性。 + +该 128 位的校验值是 包括码头在内的元信息的 XXHASH64 校验值(种子值是全曲音符数) 对于前述所有 XXHASH32 校验值彼此异或的异或 所得值之 XXHASH128 校验值,以 全曲音符总数 作为种子值。 diff --git a/example_fsq_opera.py b/example_fsq_opera.py index 16a8c0a..b56bcbc 100644 --- a/example_fsq_opera.py +++ b/example_fsq_opera.py @@ -8,7 +8,7 @@ from rich.pretty import pprint msc_seq = Musicreater.MusicSequence.from_mido( Musicreater.mido.MidiFile( - "./resource/测试片段.mid", + "./resources/测试片段.mid", ), "TEST-测试片段", )