项目状态: 准备阶段
开始日期: 2026-01-29
预计完成: 8-10周
当前进度: 阶段0 - 准备工作(进行中)
src/jianpu-renderercore/parser - 解析器core/layout - 布局引擎core/drawer - 绘制引擎core/config - 配置models - 数据模型adapters - 兼容层utils - 工具函数__tests__ - 测试文件index.tsJianpuRenderer.tsREADME.md验收标准:
JianpuNote 音符模型
JianpuMeasure 小节模型
JianpuSystem 行模型JianpuScore 总谱模型RenderConfig 渲染配置验收标准:
basic.xml - 基础简谱(只有四分音符)mixed-durations.xml - 混合时值(八分、四分、二分音符)multi-voice.xml - 多声部简谱with-lyrics.xml - 带歌词简谱complex.xml - 复杂记号(装饰音、连音符等)__tests__/compare.htmlDEVELOPMENT.md 开发指南API.md API文档框架验收标准:
预计时间: 0.5天
OSMDDataParser.ts - 框架代码TimeCalculator.ts - 框架代码MeasureLayoutEngine.ts - 框架代码SystemLayoutEngine.ts - 框架代码NotePositionCalculator.ts - 框架代码MultiVoiceAligner.ts - 框架代码NoteDrawer.ts - 框架代码LineDrawer.ts - 框架代码LyricDrawer.ts - 框架代码ModifierDrawer.ts - 框架代码OSMDCompatibilityAdapter.ts - 框架代码DOMAdapter.ts - 框架代码SVGHelper.tsMathHelper.tsConstants.ts验收标准:
为什么需要这个阶段: 磨刀不误砍柴工!先定义清楚规范,开发时就不会反复讨论"应该怎么处理"
目标: 创建MusicXML标签到简谱的完整映射表
文件: docs/jianpu-renderer/04-MUSICXML_MAPPING.md
内容:
[ ] Divisions转换规则
[ ] 音高元素解析规则
<step> → 简谱数字(C=1, D=2, ... B=7)<octave> → 高低音点数量<alter> → 升降号(1=#, -1=♭, 0=♮)[ ] 时值元素解析规则
<type> → 音符基准类型<dot> → 附点时值计算(+50%, +75%)<duration> → 实际时值[ ] 特殊元素处理规则
<grace> → 装饰音(duration=0)<rest> → 休止符<chord> → 和弦(多个音符同时发声)<tuplet> → 连音符(3连音、5连音等)<tie> → 延音线
[ ] 修饰符处理规则
<accidental> → 临时升降号<articulations> → 演奏技法(staccato顿音等)<ornaments> → 装饰音记号<dynamics> → 力度记号验收标准:
预计时间: 2天
目标: 定义简谱各元素的精确渲染规则
文件: docs/jianpu-renderer/06-RENDER_SPEC.md
内容:
[ ] 增时线渲染规范 ⭐⭐⭐
Math.floor(realValue) - 1[ ] 减时线渲染规范
Math.log2(4 / realValue)[ ] 高低音点规范
[ ] 附点规范
[ ] 升降号规范
[ ] 视觉尺寸标准
验收标准:
预计时间: 1天
目标: 定义与VexFlow/OSMD的完整兼容规范
文件: docs/jianpu-renderer/05-VEXFLOW_COMPAT.md
内容:
[ ] DOM结构规范
vf-{noteId}vf-note, vf-numbered-note-head等[ ] state.times字段完整清单 ⭐⭐⭐
[ ] cursor接口规范
[ ] GraphicSheet接口规范
[ ] 其他兼容接口
验收标准:
预计时间: 1.5天
目标: 使用现有引擎生成测试基准,作为新引擎的对比标准
内容:
[ ] 选择5个测试曲谱
[ ] 使用旧引擎渲染,保存基准
[ ] 创建对比测试页面
验收标准:
预计时间: 1.5天
阶段0.5总结:
目标: 实现MusicXML divisions的正确处理(这是时值计算的基础!)
文件: src/jianpu-renderer/core/parser/DivisionsHandler.ts
内容:
[ ] 实现divisions缓存机制
[ ] 实现duration转换
realValue = duration / divisions; // 转换为四分音符为单位
duration为负数
[ ] 编写单元测试
测试不同divisions值(1, 256, 480, 960)
测试转换准确性
测试异常处理
验收标准:
预计时间: 0.5天
OSMDDataParser.parse() 主方法parseMeasures() 方法osmd.GraphicSheet.MeasureListparseNotes() 方法osmd.cursor.Iterator 遍历音符getPitchNumber() - 音名转简谱数字getOctaveOffset() - 计算八度偏移getKeyString() - 获取调号字符串验收标准:
测试用例: ```
✓ 应该正确解析4/4拍小节 ✓ 应该正确解析3/4拍小节 ✓ 应该正确解析音符音高 do re mi fa sol la si ✓ 应该正确识别休止符 ✓ 应该正确解析附点音符 ✓ 应该正确解析升降号 ✓ 应该正确解析多声部 ✓ 应该正确解析不同时值的音符 ✓ 应该保留OSMD数据引用 ✓ 应该正确解析调号变化
**预计时间:** 3天
---
### 任务1.2:实现时间计算器 ⏸️ 待开始
- [ ] 实现 `calculateTimes()` 主方法
- [ ] 根据BPM计算四分音符时长
- [ ] 按小节和时间戳排序音符
- [ ] 计算每个音符的绝对开始时间
- [ ] 计算每个音符的绝对结束时间
- [ ] 支持变速
- [ ] 识别小节内的速度变化
- [ ] 正确计算变速后的时间
- [ ] 处理反复记号
- [ ] 识别反复记号(暂时可以简化处理)
**验收标准:**
- [ ] 时间计算准确(误差<1ms)
- [ ] 支持不同速度(60-240 BPM)
- [ ] 支持变速
- [ ] 单元测试通过
**测试用例:**
✓ 120 BPM时四分音符应该是0.5秒 ✓ 60 BPM时四分音符应该是1秒 ✓ 应该正确计算连续音符的时间 ✓ 应该正确处理变速 ✓ 时间计算误差应该小于1ms
**预计时间:** 1天
---
### 任务1.3:集成测试解析器 ⏸️ 待开始
- [ ] 使用真实的MusicXML文件测试
- [ ] 验证解析结果的完整性
- [ ] 修复发现的bug
- [ ] 优化性能
**预计时间:** 0.5天
---
## 📐 阶段2:布局引擎(第3-4周)
### 任务2.1:实现小节布局计算器 ⏸️ 待开始
- [ ] 实现固定时间比例算法
- [ ] 根据拍号计算小节总时值
- [ ] 计算小节内容宽度
- [ ] 计算小节总宽度(包含padding)
- [ ] 实现 `calculateNotePositions()` 方法
- [ ] 计算每个音符的X坐标
- [ ] 应用固定时间比例公式
- [ ] 计算音符宽度
- [ ] 应用最小间距限制
- [ ] 实现 `layoutMeasures()` 批量布局方法
- [ ] 遍历所有小节
- [ ] 累计X坐标
**核心算法:**
```typescript
// 小节宽度 = (拍数 / 单位拍 × 4) × 四分音符间距 + 左右padding
measureWidth = (beats / beatType × 4) × quarterNoteSpacing + padding × 2
// 音符X坐标 = 小节起始X + 左padding + 时间戳 × 单位间距
noteX = measureX + measurePadding + timestamp × (beatType / 4) × quarterNoteSpacing
验收标准:
测试用例:
✓ 4/4拍所有小节宽度应该相同
✓ 3/4拍所有小节宽度应该相同
✓ 4/4拍宽度应该是3/4拍的4/3倍
✓ 二分音符间距应该是四分音符的2倍
✓ 八分音符间距应该是四分音符的0.5倍
✓ padding应该正确应用
预计时间: 3天
MultiVoiceAligner.alignVoices() 方法
验收标准:
测试用例:
✓ 相同时间点的音符应该X坐标相同
✓ 单声部不应该被影响
✓ 休止符应该正确对齐
✓ 不同时值的音符应该正确对齐
预计时间: 2天
SystemLayoutEngine.layoutSystems() 方法
验收标准:
预计时间: 2天
NotePositionCalculator.calculateNoteY() 方法
验收标准:
预计时间: 1天
NoteDrawer.drawNote() 主方法
vf-{noteId})vf-note)vf-numbered-note-head)验收标准:
预计时间: 3天
LineDrawer.drawDurationLines() 主方法
drawExtensionLines()
vf-{noteId}-lines)drawUnderlines()
核心算法:
// 增时线数量 = Math.floor(时值) - 1
// 二分音符(2.0):1条
// 全音符(4.0):3条
// 减时线数量 = Math.log2(4 / 时值)
// 八分音符(0.5):1条
// 十六分音符(0.25):2条
// 三十二分音符(0.125):3条
验收标准:
预计时间: 2天
LyricDrawer.drawLyric() 方法
vf-lyric, lyric{noteId})lyricIndex 属性(用于多遍歌词)验收标准:
预计时间: 1天
预计时间: 1天
预计时间: 1天
generateTimesArray() 方法
i, noteId, idtime, endtimeMeasureNumberXML, measureListIndexsvgElement (with attrs.id)noteElementbboxhalfTone, frequencyisRestFlag, realValuecreateCursorAdapter() 方法
createGraphicSheetAdapter() 方法
验收标准:
state.times数组结构100%兼容cursor接口功能完整GraphicSheet接口可用预计时间: 3天
src/view/music-score/index.tsx
useNewEngine=1)验收标准:
预计时间: 1天
.vf-custom-bg元素存在验收标准:
预计时间: 2天
预计时间: 1天
预计时间: 2天
预计时间: 2天
预计时间: 2天
预计时间: 1天
预计时间: 1天
[x]阶段N (0-5)任务N.M (如任务1.2)[任务N.M] 完成XXX功能当前优先级: 完成阶段0
下一个任务: 任务0.3 - 创建测试数据和环境
需要做的事情:
预计时间: 0.5天
文档版本: v1.0
最后更新: 2026-01-29
维护者: 开发团队