|
|
@@ -573,13 +573,132 @@ const tickSpace = Math.max(
|
|
|
| **Bug修复: 小节宽度不一致** | ✅ 已完成 | 1h | 0.5h | 修改宽度计算源头(2025-11-23) |
|
|
|
| **Bug修复: 五线谱休止符拆分** | ✅ 已完成 | 0.5h | 0.3h | 限制为简谱专用(2025-11-23) |
|
|
|
| **优化: 增时线按时值占空间** | ✅ 已完成 | 1h | 0.5h | 增时线与音符对齐(2025-11-23) |
|
|
|
+| **Bug修复: 增时线渲染位置** | ✅ 已完成 | 0.5h | 0.2h | formatter配置保存(2025-11-27) |
|
|
|
+| **Bug修复: 小节宽度包含padding** | ✅ 已完成 | 0.5h | 0.3h | 小节宽度计算修复(2025-12-01) |
|
|
|
+| **Bug修复: 音符边界限制** | ✅ 已完成 | 1h | 0.5h | 音符不超出小节边界(2025-12-01) |
|
|
|
| 测试与调优 | ⏳ 待测试 | 2h | - | 需用户测试 |
|
|
|
-| **总计** | **8/9 完成** | **10h** | **4.4h** | **核心功能完全实现** |
|
|
|
+| **总计** | **11/12 完成** | **12h** | **5.4h** | **核心功能完全实现** |
|
|
|
|
|
|
---
|
|
|
|
|
|
## 📝 变更日志
|
|
|
|
|
|
+### 2025-12-01
|
|
|
+
|
|
|
+**第八次修复 - 音符边界限制修复(用户反馈 - 音符溢出到下一小节)**:
|
|
|
+- 🐛 **问题**: P1轨第4小节的部分音符(如"6 6-")渲染到了第5小节的区域
|
|
|
+- 🔍 **根本原因分析**:
|
|
|
+ - **formatToStave中end_x计算问题**:VexFlow的`stave.format()`方法中,`end_x`会被`endModifiers`减小(stave.js第727行)
|
|
|
+ - 导致`getNoteEndX() - getNoteStartX()`返回的可用空间比实际小节宽度小
|
|
|
+ - 音符位置按tick计算后可能超出小节边界
|
|
|
+- ⭐ **修复方案**:
|
|
|
+ 1. **修复formatToStave宽度计算**:使用`stave.x + stave.width - noteStartX - 10`代替`getNoteEndX() - getNoteStartX()`
|
|
|
+ 2. **添加边界限制机制**:
|
|
|
+ - 计算右边界:`rightBoundary = justifyWidth - measurePadding - 5`
|
|
|
+ - 预估检查:如果最后一个音符会超出边界,自动调整`pxPerTick`按比例压缩
|
|
|
+ - 最终边界检查:设置每个音符位置时确保不超过右边界
|
|
|
+- 🎯 **效果**:
|
|
|
+ - 音符被强制限制在小节边界内(两条小节线之间)
|
|
|
+ - 如果空间不够,音符会按比例压缩而不是溢出
|
|
|
+ - 增时线使用调整后的pxPerTick,保持一致性
|
|
|
+- ✅ **实现内容**:
|
|
|
+ - 修改 `osmd-extended/src/VexFlowPatch/src/formatter.js` 的 `formatToStave` 方法
|
|
|
+ - 修改 `osmd-extended/src/VexFlowPatch/src/formatter.js` 的 `preFormat` 方法,添加边界限制逻辑
|
|
|
+- 📁 **修改文件**:
|
|
|
+ - `osmd-extended/src/VexFlowPatch/src/formatter.js` ⭐⭐ **关键修复**
|
|
|
+
|
|
|
+**第七次修复 - 小节宽度包含padding修复(用户反馈 - P1轨第4小节音符溢出)**:
|
|
|
+- 🐛 **问题**: P1轨第4小节的部分音符渲染到了第5小节,应该显示"0 6 6-"四个元素,但后面的"6-"跑到下一小节了
|
|
|
+- 🔍 **根本原因分析**:
|
|
|
+ - **计算小节宽度时没有包含padding**
|
|
|
+ - 在 `VexFlowMusicSheetCalculator.ts` 第228行:
|
|
|
+ ```typescript
|
|
|
+ minStaffEntriesWidth = measureDuration * 4 * quarterNoteSpacing / unitInPixels;
|
|
|
+ // 4/4拍:1.0 × 4 × 50 ÷ 10 = 20单位 = 200px
|
|
|
+ ```
|
|
|
+ - 这个200px传递给formatter后,formatter会减去左右padding(各20px):
|
|
|
+ ```javascript
|
|
|
+ const availableWidth = justifyWidth - (measurePadding * 2); // 200 - 40 = 160px
|
|
|
+ ```
|
|
|
+ - 导致实际用于音符的空间只有160px,而不是应有的200px
|
|
|
+ - 音符被压缩,最后的音符溢出到下一小节
|
|
|
+- ⭐ **修复方案**: 在计算小节宽度时包含padding
|
|
|
+ - 修改 `VexFlowMusicSheetCalculator.ts` 第215-231行
|
|
|
+ - 新公式:`totalWidth = (measureDuration × 4 × quarterNoteSpacing) + (measurePadding × 2)`
|
|
|
+ - 4/4拍示例:
|
|
|
+ - 内容宽度 = 1.0 × 4 × 50 = 200px
|
|
|
+ - 总宽度 = 200 + 20 + 20 = 240px
|
|
|
+ - 单位 = 240 ÷ 10 = 24单位
|
|
|
+ - 这样传递给formatter的宽度是240px,减去padding后剩余200px,正好够4个四分音符使用
|
|
|
+- 🎯 **效果**:
|
|
|
+ - 小节宽度正确包含padding空间
|
|
|
+ - 音符不会溢出到下一小节
|
|
|
+ - P1轨第4小节正确显示"0 6 6-"(休止符、八分音符、带增时线的二分音符)
|
|
|
+ - 音符间距保持固定时间比例
|
|
|
+- ✅ **实现内容**:
|
|
|
+ - 修改 `osmd-extended/src/MusicalScore/Graphical/VexFlow/VexFlowMusicSheetCalculator.ts` 第215-231行
|
|
|
+ - 重新构建 osmd-extended 模块
|
|
|
+- 📁 **修改文件**:
|
|
|
+ - `osmd-extended/src/MusicalScore/Graphical/VexFlow/VexFlowMusicSheetCalculator.ts` ⭐⭐ **关键修复**
|
|
|
+
|
|
|
+### 2025-11-27
|
|
|
+
|
|
|
+**第六次修复 - 增时线渲染入口修正(用户反馈 - 真正的根因)**:
|
|
|
+- 🐛 **问题**: 增时线仍然紧贴在音符后面,没有按照时值正确分布
|
|
|
+- 🔍 **深度根因分析**:
|
|
|
+ - **问题1**: `formatter.js` 的配置没有保存到对象(第一次修复已解决)
|
|
|
+ - **问题2(真正根因)**: 增时线有两个绘制方法:
|
|
|
+ - `drawLongDurationLines(ctx)` - 第758行,传统模式的对齐逻辑
|
|
|
+ - `drawLongDurationLinesDefault(ctx)` - 第823行,包含固定时间比例逻辑
|
|
|
+ - 渲染流程调用 `drawLongDurationLines` 方法
|
|
|
+ - 当满足条件(`long_duration_lines > 0` 且有拍号信息)时
|
|
|
+ - `drawLongDurationLines` 直接绘制增时线并 `return`(第809行)
|
|
|
+ - **永远不会调用** `drawLongDurationLinesDefault` 方法
|
|
|
+ - 所以我之前的修改根本没有被执行!
|
|
|
+- ⭐ **修复方案**: 在入口方法中添加固定时间比例判断
|
|
|
+ - 修改 `numbered_note.js` 的 `drawLongDurationLines` 方法(第758行)
|
|
|
+ - 在方法开始处检查是否启用了固定时间比例
|
|
|
+ - 如果启用,直接调用 `drawLongDurationLinesDefault` 并返回
|
|
|
+ - 否则使用传统的对齐逻辑
|
|
|
+ ```javascript
|
|
|
+ drawLongDurationLines(ctx) {
|
|
|
+ // 🔧 固定时间比例模式:统一使用 drawLongDurationLinesDefault
|
|
|
+ const stave = this.stave;
|
|
|
+ const formatter = stave ? stave.formatter : null;
|
|
|
+ const fixedTemporalSpacing = formatter ? formatter.fixedTemporalSpacing :
|
|
|
+ (stave ? stave.fixedTemporalSpacing : false);
|
|
|
+
|
|
|
+ if (fixedTemporalSpacing) {
|
|
|
+ this.drawLongDurationLinesDefault(ctx);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 传统模式:原有的对齐逻辑
|
|
|
+ // ...
|
|
|
+ }
|
|
|
+ ```
|
|
|
+- 🎯 **效果**:
|
|
|
+ - 增时线绘制入口现在会正确路由到固定时间比例逻辑
|
|
|
+ - 增时线按照时值均匀分布在小节中
|
|
|
+ - 二分音符的增时线在第2拍位置,全音符的3条增时线在第2、3、4拍位置
|
|
|
+ - 多声部总谱中,增时线与其他声部音符在相同时间点垂直对齐
|
|
|
+- ✅ **实现内容**:
|
|
|
+ - 修改 `osmd-extended/src/VexFlowPatch/src/formatter.js` 第507-519行(配置保存)
|
|
|
+ - 修改 `osmd-extended/src/VexFlowPatch/src/numbered_note.js` 第758行(入口路由)
|
|
|
+ - 重新构建 osmd-extended 模块
|
|
|
+- 📁 **修改文件**:
|
|
|
+ - `osmd-extended/src/VexFlowPatch/src/formatter.js`(配置保存)
|
|
|
+ - `osmd-extended/src/VexFlowPatch/src/numbered_note.js`(入口修复)⭐⭐ **关键修复**
|
|
|
+- 🧪 **验证方法**:
|
|
|
+ - 启动项目:`npm run dev`
|
|
|
+ - 打开浏览器:`http://localhost:3001/?fixedTempo=1`
|
|
|
+ - **强制刷新**:按 `Ctrl+Shift+R`(Windows)或 `Cmd+Shift+R`(Mac)清除缓存
|
|
|
+ - 打开控制台(F12)查看日志:`[FixedTempo-DurationLine]`
|
|
|
+ - **视觉验证**:
|
|
|
+ - 二分音符(如P1第5小节的6·):增时线应在第2个四分音符的位置
|
|
|
+ - 不应该紧贴在音符后面
|
|
|
+ - 应该与其他声部的第2拍音符垂直对齐
|
|
|
+
|
|
|
### 2025-11-23
|
|
|
|
|
|
**第五次优化 - 增时线按时值占据空间(用户反馈)**:
|
|
|
@@ -854,13 +973,24 @@ osmd = new OpenSheetMusicDisplay(container, {
|
|
|
1. `osmd-extended/src/OpenSheetMusicDisplay/OSMDOptions.ts` - 添加配置选项
|
|
|
2. `osmd-extended/src/MusicalScore/Graphical/EngravingRules.ts` - 添加规则属性
|
|
|
3. `osmd-extended/src/OpenSheetMusicDisplay/OpenSheetMusicDisplay.ts` - 连接配置
|
|
|
-4. `osmd-extended/src/VexFlowPatch/src/formatter.js` - ⭐ 核心逻辑(音符间距按时值比例分配)
|
|
|
+4. `osmd-extended/src/VexFlowPatch/src/formatter.js` - ⭐⭐ **核心逻辑**(音符间距按时值比例分配 + 配置保存)
|
|
|
5. `osmd-extended/src/MusicalScore/Graphical/VexFlow/VexFlowMeasure.ts` - 小节格式化逻辑
|
|
|
6. `osmd-extended/src/MusicalScore/Graphical/VexFlow/VexFlowMusicSheetCalculator.ts` - ⭐⭐ **最关键修复**(小节宽度计算源头,限制为简谱专用)
|
|
|
7. `osmd-extended/src/VexFlowPatch/src/numbered_note.js` - ⭐ **增时线优化**(增时线按时值占据空间)
|
|
|
8. `src/view/music-score/index.tsx` - URL 参数集成
|
|
|
|
|
|
-**关键修复点**(2025-11-23):
|
|
|
+**关键修复点 #1**(2025-11-27):
|
|
|
+- **文件**: `formatter.js` 第507-519行
|
|
|
+- **问题**: 增时线无法获取固定时间比例配置,导致仍然紧挤在一起
|
|
|
+- **修改**: 添加配置保存到 formatter 对象
|
|
|
+ ```javascript
|
|
|
+ this.fixedTemporalSpacing = fixedTemporalSpacing;
|
|
|
+ this.quarterNoteSpacing = quarterNoteSpacing;
|
|
|
+ this.measurePadding = measurePadding;
|
|
|
+ ```
|
|
|
+- **效果**: 增时线现在能正确按照时值均匀分布
|
|
|
+
|
|
|
+**关键修复点 #2**(2025-11-23):
|
|
|
- **文件**: `VexFlowMusicSheetCalculator.ts` 第214-228行
|
|
|
- **修改前**: `minStaffEntriesWidth = formatter.preCalculateMinTotalWidth(...)`(基于音符内容)
|
|
|
- **修改后**: 固定时间比例模式下,`minStaffEntriesWidth = measureDuration × 4 × quarterNoteSpacing`(基于时值)
|
|
|
@@ -869,6 +999,54 @@ osmd = new OpenSheetMusicDisplay(container, {
|
|
|
- 简谱:同拍号小节宽度完全一致
|
|
|
- 五线谱:保持传统渲染,避免休止符被错误拆分
|
|
|
|
|
|
+**关键修复点 #3**(2025-12-01):
|
|
|
+- **文件**: `VexFlowMusicSheetCalculator.ts` 第215-231行
|
|
|
+- **问题**: 音符溢出到下一小节(P1轨第4小节问题)
|
|
|
+- **根本原因**: 计算小节宽度时没有包含padding,导致实际空间不足
|
|
|
+- **修改前**:
|
|
|
+ ```typescript
|
|
|
+ minStaffEntriesWidth = measureDuration * 4 * quarterNoteSpacing / unitInPixels;
|
|
|
+ // 4/4拍:1.0 × 4 × 50 ÷ 10 = 20单位 = 200px
|
|
|
+ ```
|
|
|
+- **修改后**:
|
|
|
+ ```typescript
|
|
|
+ const contentWidth = measureDuration * 4 * quarterNoteSpacing;
|
|
|
+ const totalWidth = contentWidth + (measurePadding * 2);
|
|
|
+ minStaffEntriesWidth = totalWidth / unitInPixels;
|
|
|
+ // 4/4拍:(200 + 40) ÷ 10 = 24单位 = 240px
|
|
|
+ ```
|
|
|
+- **效果**:
|
|
|
+ - 小节宽度正确包含padding(左右各20px)
|
|
|
+ - 传递给formatter的宽度是240px,减去padding后剩余200px
|
|
|
+
|
|
|
+**关键修复点 #4**(2025-12-01):
|
|
|
+- **文件**: `formatter.js` 的 `formatToStave` 和 `preFormat` 方法
|
|
|
+- **问题**: 音符仍然溢出到下一小节
|
|
|
+- **根本原因**:
|
|
|
+ 1. VexFlow的`stave.format()`中`end_x`会被`endModifiers`减小
|
|
|
+ 2. `getNoteEndX() - getNoteStartX()`返回的可用空间比实际小
|
|
|
+- **修复方案**:
|
|
|
+ 1. **formatToStave**: 使用`stave.x + stave.width - noteStartX - 10`计算宽度
|
|
|
+ 2. **preFormat**: 添加边界限制机制
|
|
|
+ ```javascript
|
|
|
+ // 计算右边界
|
|
|
+ const rightBoundary = justifyWidth - measurePadding - 5;
|
|
|
+
|
|
|
+ // 如果会超出边界,自动压缩pxPerTick
|
|
|
+ if (estimatedLastX > rightBoundary && lastTick > 0) {
|
|
|
+ adjustedPxPerTick = (rightBoundary - startX) / lastTick;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 最终边界检查
|
|
|
+ if (noteX > rightBoundary) {
|
|
|
+ noteX = rightBoundary;
|
|
|
+ }
|
|
|
+ ```
|
|
|
+- **效果**:
|
|
|
+ - 音符被强制限制在小节边界内
|
|
|
+ - 如果空间不够,按比例压缩而不是溢出
|
|
|
+ - 完美解决P1轨第4小节音符溢出问题
|
|
|
+
|
|
|
---
|
|
|
|
|
|
## 🧪 快速测试步骤(2025-11-23修复验证)
|