Skip to content

Commit 5222e43

Browse files
committed
feat(parser): 增强 ABC 解析器以支持小节级别的歌词处理
- 新增 SNMeasureLyric 接口,定义小节级别的歌词信息,包括歌词段号和音节数组。 - 更新 SNMeasureMeta 接口,添加 lyrics 字段以支持多段歌词的存储。 - 优化 AbcParser 和 AbcMeasureParser,确保小节的歌词信息能够正确解析和组织。 - 更新歌词解析逻辑,移除歌词行和注释行,提升解析准确性。 该变更提升了 ABC 解析器对小节级别歌词的处理能力,确保乐谱信息的准确解析和存储。
1 parent a823485 commit 5222e43

File tree

4 files changed

+51
-3
lines changed

4 files changed

+51
-3
lines changed

packages/simple-notation/src/data/model/parser.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,21 @@ export interface SNVoiceMeta {
7373

7474
export type SNVoiceMetaClef = 'treble' | 'bass' | 'alto' | 'tenor';
7575

76+
/** 小节级别的歌词信息 */
77+
export interface SNMeasureLyric {
78+
/** 歌词段号(0 = w:, 1+ = W:) */
79+
verse: number;
80+
/** 该小节的所有歌词音节 */
81+
syllables: string[];
82+
}
83+
7684
export interface SNMeasureMeta {
7785
annotations?: SNAnnotation[];
7886
chords?: SNParserChord[];
7987
barline?: SNBarline[];
8088
/** 行内声部标记 [V:数字],表示从该小节开始属于指定声部 */
8189
voiceId?: string;
90+
/** 小节级别的歌词(支持多段歌词) */
91+
lyrics?: SNMeasureLyric[];
8292
[key: string]: unknown;
8393
}

packages/simple-notation/src/data/parser/abc-parser.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,10 +294,11 @@ export class AbcParser extends BaseParser<SNAbcInput> {
294294
// 提取歌词
295295
const lyricLines = this.lyricParser.extractLyricLines(measuresContent);
296296

297-
// 移除声部标记和歌词行
297+
// 移除声部标记、歌词行和注释行
298298
const musicContent = measuresContent
299299
.replace(/\[\s*V:\s*\d+\s*\]/g, '')
300300
.replace(/^\s*[wW]:\s*.*$/gim, '')
301+
.replace(/^\s*%.*$/gim, '') // 移除注释行
301302
.trim();
302303

303304
// 分割小节

packages/simple-notation/src/data/parser/abc/parsers/lyric-parser.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -231,10 +231,11 @@ export class AbcLyricParser {
231231
let measureCountBefore = 0;
232232
let musicLineIndex = lineIndex - 1;
233233

234-
// 向前查找最近的音乐行
234+
// 向前查找最近的音乐行(跳过歌词行、注释行和空行)
235235
while (
236236
musicLineIndex >= 0 &&
237237
(/^\s*[wW]:/i.test(lines[musicLineIndex]) ||
238+
/^\s*%/.test(lines[musicLineIndex]) ||
238239
!lines[musicLineIndex].trim())
239240
) {
240241
musicLineIndex--;
@@ -243,7 +244,12 @@ export class AbcLyricParser {
243244
// 统计之前所有音乐行的小节数
244245
for (let i = 0; i < musicLineIndex; i++) {
245246
const prevLine = lines[i];
246-
if (!/^\s*[wW]:/i.test(prevLine) && prevLine.trim()) {
247+
// 跳过歌词行、注释行和空行
248+
if (
249+
!/^\s*[wW]:/i.test(prevLine) &&
250+
!/^\s*%/.test(prevLine) &&
251+
prevLine.trim()
252+
) {
247253
const lineWithoutRepeats = prevLine
248254
.replace(/\|:/g, '')
249255
.replace(/:\|/g, '');

packages/simple-notation/src/data/parser/abc/parsers/measure-parser.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,11 @@ export class AbcMeasureParser {
101101
measureMeta.voiceId = measureVoiceId;
102102
}
103103

104+
// 将该小节的歌词信息添加到 meta 中(支持多段歌词)
105+
if (lyricsForMeasure && lyricsForMeasure.length > 0) {
106+
measureMeta.lyrics = this.organizeLyricsByVerse(lyricsForMeasure);
107+
}
108+
104109
// 如果小节数据中包含行内调号标记,将其存储到小节的 props 中
105110
if (keySignature) {
106111
measure.props = {
@@ -218,6 +223,32 @@ export class AbcMeasureParser {
218223
return elements;
219224
}
220225

226+
/**
227+
* 将歌词按 verse 组织(用于存储在小节 meta 中)
228+
*
229+
* @param lyricsForMeasure - 该小节的所有歌词信息
230+
* @returns 按 verse 分组的歌词数组
231+
*/
232+
private organizeLyricsByVerse(lyricsForMeasure: LyricInfo[]): Array<{
233+
verse: number;
234+
syllables: string[];
235+
}> {
236+
// 按 verse 分组
237+
const verseMap = new Map<number, string[]>();
238+
239+
for (const lyric of lyricsForMeasure) {
240+
if (!verseMap.has(lyric.verse)) {
241+
verseMap.set(lyric.verse, []);
242+
}
243+
verseMap.get(lyric.verse)!.push(lyric.syllable);
244+
}
245+
246+
// 转换为数组并排序
247+
return Array.from(verseMap.entries())
248+
.sort((a, b) => a[0] - b[0])
249+
.map(([verse, syllables]) => ({ verse, syllables }));
250+
}
251+
221252
/**
222253
* 将歌词附加到元素
223254
*/

0 commit comments

Comments
 (0)