GUIDE.md 13 KB

简谱渲染引擎 - 用户使用指南

版本: 2.0
最后更新: 2026-01-30
状态: ✅ 已完成


📖 目录

  1. 快速开始
  2. 基础用法
  3. 新特性使用
  4. 绘制器API
  5. 配置选项
  6. 高级用法
  7. 常见问题

🚀 快速开始

安装

// 导入渲染器
import { JianpuRenderer, createJianpuRenderer } from '@/jianpu-renderer';

基本使用

// 1. 创建渲染器
const renderer = createJianpuRenderer('container-id', {
  systemWidth: 800,
  noteFontSize: 24,
  debug: false,
});

// 2. 加载乐谱数据(来自OSMD解析)
await renderer.load(osmdInstance);

// 3. 渲染
renderer.render();

📝 基础用法

创建渲染器

import { JianpuRenderer } from '@/jianpu-renderer';

// 方式1:使用容器ID
const renderer1 = new JianpuRenderer('my-container');

// 方式2:使用DOM元素
const container = document.getElementById('my-container');
const renderer2 = new JianpuRenderer(container);

// 方式3:使用工厂函数(推荐)
const renderer3 = createJianpuRenderer('my-container', {
  systemWidth: 800,
  drawLyrics: true,
});

加载和渲染

// 加载OSMD实例
await renderer.load(osmd);

// 渲染到容器
renderer.render();

// 获取渲染统计
const stats = renderer.getStats();
console.log(`渲染耗时: ${stats.totalTime}ms`);
console.log(`音符数: ${stats.noteCount}`);

更新配置

// 更新配置会自动重新渲染
renderer.updateConfig({
  noteColor: '#0000ff',
  noteFontSize: 28,
});

✨ 新特性使用

简谱渲染引擎 v2.0 新增了12个专业绘制器,支持丰富的乐谱特性。

特性概览

特性分类 包含内容 绘制器
连线系统 延音线、圆滑线 SlurTieDrawer
连音符 三连音、五连音等 TupletDrawer
反复记号 反复线、跳房子、D.C./D.S. RepeatDrawer
力度记号 pp~fff、渐强渐弱 DynamicsDrawer
演奏技法 顿音、重音、延长等 ArticulationDrawer
和弦 多音符垂直堆叠 ChordDrawer
装饰音 倚音、颤音、波音、回音 OrnamentDrawer
速度标记 BPM、速度术语、rit./accel. TempoDrawer
八度记号 8va、8vb、15ma、15mb OctaveShiftDrawer
踏板 Ped.、释放、换踩 PedalDrawer
字符谱 指法、弦号、技法 TablatureDrawer
打击乐 鼓组符号、音头类型 PercussionDrawer

使用数据模型自动渲染

当音符包含相应的修饰符时,渲染器会自动绘制:

// 音符数据中包含演奏技法
const note: JianpuNote = {
  id: 'note-1',
  pitch: 1,
  duration: 1,
  x: 100,
  y: 60,
  modifiers: {
    articulations: ['staccato', 'accent'],  // 自动绘制顿音和重音
    ornaments: ['trill'],                   // 自动绘制颤音
    graceNotes: {                           // 自动绘制倚音
      notes: [{ pitch: 5, octave: 0, duration: 0.25 }],
      slash: true,
    },
  },
};

// 小节数据中包含反复记号
const measure: JianpuMeasure = {
  // ...基础属性
  volta: { number: 1, text: '1.', type: 'start' },  // 自动绘制跳房子
  repeatMark: { type: 'dc', text: 'D.C.' },         // 自动绘制反复标记
};

🎨 绘制器API

每个绘制器都可以通过渲染器实例获取,用于自定义绘制。

获取绘制器

const renderer = createJianpuRenderer(container);

// 获取各种绘制器
const slurTieDrawer = renderer.getSlurTieDrawer();
const tupletDrawer = renderer.getTupletDrawer();
const repeatDrawer = renderer.getRepeatDrawer();
const dynamicsDrawer = renderer.getDynamicsDrawer();
const articulationDrawer = renderer.getArticulationDrawer();
const chordDrawer = renderer.getChordDrawer();
const ornamentDrawer = renderer.getOrnamentDrawer();
const tempoDrawer = renderer.getTempoDrawer();
const octaveShiftDrawer = renderer.getOctaveShiftDrawer();
const pedalDrawer = renderer.getPedalDrawer();
const tablatureDrawer = renderer.getTablatureDrawer();
const percussionDrawer = renderer.getPercussionDrawer();

连线绘制器 (SlurTieDrawer)

const slurTieDrawer = renderer.getSlurTieDrawer();

// 绘制延音线
const tieGroup = slurTieDrawer.drawTie(
  { x: 100, y: 60 },  // 起始位置
  { x: 150, y: 60 },  // 结束位置
  'above'             // 曲线位置: 'above' | 'below'
);

// 绘制圆滑线
const slurGroup = slurTieDrawer.drawSlur(
  { x: 100, y: 60 },
  { x: 200, y: 70 },
  'below'
);

连音符绘制器 (TupletDrawer)

const tupletDrawer = renderer.getTupletDrawer();

// 绘制三连音
const tupletGroup = tupletDrawer.drawTuplet({
  notes: [note1, note2, note3],
  actualNotes: 3,
  normalNotes: 2,
  showBracket: true,
  showNumber: true,
  position: 'above',
});

力度绘制器 (DynamicsDrawer)

const dynamicsDrawer = renderer.getDynamicsDrawer();

// 绘制力度文字
const dynGroup = dynamicsDrawer.drawDynamic('f', 100, 80);  // type: 'ppp'|'pp'|'p'|'mp'|'mf'|'f'|'ff'|'fff'|'sfz'|'fp'

// 绘制渐强楔形
const crescGroup = dynamicsDrawer.drawHairpin('crescendo', 100, 200, 80);

// 绘制渐弱楔形
const dimGroup = dynamicsDrawer.drawHairpin('diminuendo', 100, 200, 80);

和弦绘制器 (ChordDrawer)

const chordDrawer = renderer.getChordDrawer();

// 从音符数组创建和弦
const chordGroup = chordDrawer.drawChordFromNotes(
  [note1, note2, note3],  // JianpuNote数组
  100,                     // X坐标
  60                       // Y坐标
);

// 使用ChordInfo对象
const chordGroup2 = chordDrawer.drawChord({
  notes: [
    { pitch: 1, octave: 0 },
    { pitch: 3, octave: 0 },
    { pitch: 5, octave: 0 },
  ],
  x: 100,
  y: 60,
  duration: 1,
});

装饰音绘制器 (OrnamentDrawer)

const ornamentDrawer = renderer.getOrnamentDrawer();

// 绘制装饰音
const trillGroup = ornamentDrawer.drawTrill(100, 60, 50);  // x, y, 波浪线宽度
const mordentGroup = ornamentDrawer.drawMordent(100, 60);
const turnGroup = ornamentDrawer.drawTurn(100, 60);
const tremoloGroup = ornamentDrawer.drawTremolo(100, 60, 3);  // 3条线

// 绘制倚音
const graceGroup = ornamentDrawer.drawGraceNotes(
  [{ pitch: 5, octave: 0 }, { pitch: 6, octave: 0 }],  // 倚音音符
  100,  // 主音符X
  60,   // 主音符Y
  true  // 是否有斜杠(短倚音)
);

速度绘制器 (TempoDrawer)

const tempoDrawer = renderer.getTempoDrawer();

// 绘制BPM标记
const bpmGroup = tempoDrawer.drawSimpleBpmMark(120, 50, 30);

// 绘制完整BPM标记(指定音符时值)
const bpmGroup2 = tempoDrawer.drawBpmMark(
  { noteValue: 'quarter', bpm: 120 },
  50, 30
);

// 绘制速度术语
const tempoWord = tempoDrawer.drawTempoWord('Allegro', 50, 30, true);  // 显示BPM参考

// 绘制渐变速度
const ritGroup = tempoDrawer.drawRitardando(100, 60, 80);  // rit.
const accelGroup = tempoDrawer.drawAccelerando(100, 60, 80);  // accel.

八度记号绘制器 (OctaveShiftDrawer)

const octaveDrawer = renderer.getOctaveShiftDrawer();

// 绘制8va(高八度)
const octave8va = octaveDrawer.draw8va(50, 200, 60);

// 绘制8vb(低八度)
const octave8vb = octaveDrawer.draw8vb(50, 200, 100);

// 绘制15ma(高两个八度)
const octave15ma = octaveDrawer.draw15ma(50, 200, 60);

// 绘制loco(恢复原位)
const locoGroup = octaveDrawer.drawLoco(200, 60);

踏板绘制器 (PedalDrawer)

const pedalDrawer = renderer.getPedalDrawer();

// 绘制踏板区间
const pedalGroup = pedalDrawer.drawPedalRange({
  type: 'sustain',     // 'sustain' | 'sostenuto' | 'soft'
  startX: 50,
  endX: 200,
  y: 120,
  changePoints: [100, 150],  // 换踩点
});

// 单独绘制踏板标记
const pedStart = pedalDrawer.drawPedalStart(50, 120);
const pedStop = pedalDrawer.drawPedalStop(200, 120);
const pedChange = pedalDrawer.drawPedalChange(125, 120);

字符谱绘制器 (TablatureDrawer)

const tablatureDrawer = renderer.getTablatureDrawer();

// 绘制指法
const fingerGroup = tablatureDrawer.drawLeftHandFingering(2, 100, 50);  // 左手2指
const rightGroup = tablatureDrawer.drawRightHandFingering('i', 100, 50);  // 右手i指

// 绘制弦号
const stringGroup = tablatureDrawer.drawString({ x: 100, y: 50, string: 1 });

// 绘制把位
const posGroup = tablatureDrawer.drawPosition({ x: 50, y: 30, position: 5, endX: 200 });

// 绘制技法
const hammerOn = tablatureDrawer.drawHammerOn(100, 50, 150);
const pullOff = tablatureDrawer.drawPullOff(100, 50, 150);
const slide = tablatureDrawer.drawSlide(100, 50, 150);

打击乐绘制器 (PercussionDrawer)

const percussionDrawer = renderer.getPercussionDrawer();

// 绘制鼓组符号
const bassGroup = percussionDrawer.drawBassDrum(100, 60);
const snareGroup = percussionDrawer.drawSnare(150, 60);
const hihatGroup = percussionDrawer.drawHiHat(200, 40);

// 绘制音头
const xHead = percussionDrawer.drawNoteHead({ type: 'x', x: 100, y: 60 });
const diamondHead = percussionDrawer.drawNoteHead({ type: 'diamond', x: 150, y: 60 });

// 绘制技法
const openGroup = percussionDrawer.drawOpen(100, 40);
const closedGroup = percussionDrawer.drawClosed(150, 40);

// 绘制滚奏
const rollGroup = percussionDrawer.drawRoll({ startX: 100, endX: 150, y: 60 });

⚙️ 配置选项

渲染器选项

interface JianpuRendererOptions {
  // 布局配置
  quarterNoteSpacing?: number;  // 四分音符间距(默认: 50)
  measurePadding?: number;      // 小节内边距(默认: 20)
  systemWidth?: number;         // 行宽度(默认: 800)
  systemHeight?: number;        // 行高度(默认: 150)
  
  // 显示配置
  drawPartNames?: boolean;      // 是否绘制声部名称
  drawLyrics?: boolean;         // 是否绘制歌词(默认: true)
  musicColor?: string;          // 音符颜色
  
  // 字体配置
  noteFontSize?: number;        // 音符字体大小(默认: 24)
  fontFamily?: string;          // 字体
  
  // 调试配置
  debug?: boolean;              // 调试模式(默认: false)
}

配置示例

const renderer = createJianpuRenderer(container, {
  systemWidth: 1000,
  systemHeight: 180,
  noteFontSize: 28,
  musicColor: '#333333',
  drawLyrics: true,
  debug: false,
});

🔧 高级用法

自定义绘制流程

// 获取SVG元素进行自定义操作
const svg = renderer.getSVGElement();

// 获取所有音符
const notes = renderer.getAllNotes();

// 获取所有小节
const measures = renderer.getAllMeasures();

// 使用绘制器添加自定义元素
const dynamicsDrawer = renderer.getDynamicsDrawer();
const customDynamic = dynamicsDrawer.drawDynamic('ff', 200, 100);
svg?.appendChild(customDynamic);

绘制器统计

每个绘制器都提供统计信息:

const articulationDrawer = renderer.getArticulationDrawer();

// 执行一些绘制操作后...
const stats = articulationDrawer.getStats();
console.log(`绘制数量: ${stats.articulationsDrawn}`);
console.log(`绘制耗时: ${stats.drawTime}ms`);

// 重置统计
articulationDrawer.resetStats();

OSMD兼容接口

// 渲染器提供OSMD兼容接口
const cursor = renderer.cursor;           // 光标适配器
const graphicSheet = renderer.GraphicSheet;  // 图形表适配器
const sheet = renderer.Sheet;             // 乐谱信息
const rules = renderer.EngravingRules;    // 渲染规则

❓ 常见问题

Q1: 如何调试渲染问题?

// 启用调试模式
const renderer = createJianpuRenderer(container, {
  debug: true,  // 启用调试日志
});

Q2: 如何获取渲染性能数据?

const stats = renderer.getStats();
console.log(`解析时间: ${stats.parseTime}ms`);
console.log(`布局时间: ${stats.layoutTime}ms`);
console.log(`绘制时间: ${stats.drawTime}ms`);
console.log(`总时间: ${stats.totalTime}ms`);

Q3: 如何在已有SVG上添加新元素?

const svg = renderer.getSVGElement();
const dynamicsDrawer = renderer.getDynamicsDrawer();

// 创建新元素
const element = dynamicsDrawer.drawDynamic('f', 100, 80);

// 添加到SVG
svg?.appendChild(element);

Q4: 绘制器配置如何更新?

const articulationDrawer = renderer.getArticulationDrawer();

// 更新绘制器配置
articulationDrawer.updateConfig({
  color: '#0000ff',
});

📚 相关文档


文档版本: 2.0
最后更新: 2026-01-30
维护者: 开发团队