适用于音乐应用程序的灵活的 Direct2D pianoroll





5.00/5 (11投票s)
轻松创作音乐
- 在 Github 下载代码:包含 pianoroll 和一个 Visual Studio 2019 示例项目
- 包含:我的 XML 库
- 包含:我的多线程工具
- 用于:我的 VSTX 商业库及其他专业音乐项目
引言
这是我最古老的项目之一,现在开源了。钢琴卷帘是一种无需了解乐谱元素即可轻松创作音乐的方式。
特色
- 音符支持通道 (0-15),力度 (0-127),层 (无限)
- 带有吸附控制的移动、缩放
- 支持通过指定的调式和调性 (大调/小调) 进行音阶内移动
- 无限撤销/重做
- 无限层
- 钢琴侧边 (左/右/下/无)
- 回调
- 工具 - 自动、橡皮擦、单击输入、量化器
- 序列化/反序列化到 XML
- 每小节一个调
- 每小节一个速度
- 每小节一个拍号
- MIDI 导出
- 部分 MIDI 导入 (进行中)
- 非音符 MIDI 音符
- 元事件 (原始十六进制和特定项目)
- 触后事件
- 音高偏移事件
- 音符量化
- 标记
- 长文本显示
- 半音/音阶转位
- 从 MIDI 输入设备录制
- 流式回调
- 可配置颜色
- 乐段模式
示例项目演示
- 控件
- 保存/加载 XML
- 保存 MIDI
- 运行时通过 MIDI 输出播放
- 从 MIDI 输入录制
您还可以查看我在 VSTX 中的钢琴卷帘示例,了解一个使用此钢琴卷帘通过 VST 乐器创作音乐的工具。
使用钢琴卷帘
您只需要将 "pianoroll.hpp" 包含到您的项目中,然后
// Instantiate
PR::PIANOROLL prx;
// Pass messages WM_KEYDOWN, WM_LBUTTONDBLCLK, WM_LBUTTONDOWN,
// WM_RBUTTONDOWN, WM_MOUSEMOVE,WM_LBUTTONUP, WM_SYSKEYDOWN
switch(uMessage)
{
case WM_KEYDOWN:
prx.Message(uMessage,wParam,lParam);
}
回调
class PIANOROLLCALLBACK
{
public:
virtual HRESULT NoteAdded(PIANOROLL* pr, NOTE*) = 0;
virtual HRESULT NoteRemoved(PIANOROLL* pr, NOTE*) = 0;
virtual void RedrawRequest(PIANOROLL* pr, unsigned long long param) = 0;
virtual HRESULT OnNoteChange(PIANOROLL* pr, NOTE* oldn, NOTE* newn) = 0;
virtual HRESULT OnNoteSelect(PIANOROLL* pr, NOTE* oldn, bool) = 0;
virtual void OnPianoOn(PIANOROLL*, int n) = 0;
virtual void OnPianoOff(PIANOROLL*, int off) = 0;
};
prx.AddCallback(myPrc);
必不可少的回调是 `RedrawRequest`。当调用此函数时,调用 `PIANOROLL::Paint()`,传入您的 `ID2D1RenderTarget`,以便控件重绘自身。
小节、调和拍子
调设置用于允许控件在特定音阶内移动音符 (如果您按住 **Shift** 移动,音符将以半音方式移动)。例如,如果当前调是 D 大调,您在 D 音符上按下减号键,它将移动到 C#。
拍子允许一个乐节有不同数量的拍 (默认为 4)。
调和拍子是每小节的设置。调中最有趣的是音阶创建函数,它使用已知的 `MMmMMMm` 或 `MmMMm3m` 格式来根据调创建大调/小调音阶。
void CreateScale()
{
Scale.clear();
unsigned int fi = 0x48; // C
if (k > 0)
fi = (7 * k) % 12;
if (m == 1)
fi -= 3;
fi = fi % 12;
if (m == 1)
{
Scale.push_back(fi);
Scale.push_back(fi + 2);
Scale.push_back(fi + 3);
Scale.push_back(fi + 5);
Scale.push_back(fi + 7);
Scale.push_back(fi + 8);
Scale.push_back(fi + 11);
}
else
if (m == 0)
{
Scale.push_back(fi);
Scale.push_back(fi + 2);
Scale.push_back(fi + 4);
Scale.push_back(fi + 5);
Scale.push_back(fi + 7);
Scale.push_back(fi + 9);
Scale.push_back(fi + 11);
}
for (auto& e : Scale)
e = e % 12;
}
图层
音符可以属于某个层 (默认为层 1)。在处理层时,不属于当前层的音符不能被修改,除非通过更改层的命令。
注释
音符具有可配置的力度、通道和层。音符具有起始位置 (小节 + 拍) 和持续时间。
class NOTE
{
public:
int midi = 0;
int Selected = 0;
POSITION p;
FRACTION d;
int vel = 127;
int ch = 0;
int layer = 0;
}
此外,音符可以包含非音符事件,如乐器音色、音高弯音、系统独占事件或控制器消息。当使用不包含音符信息的事件时,您可以将它们放在任何位置 (使用 Ctrl+双击)。
钢琴
控件创建一个简单的钢琴,允许您测试音符。钢琴可以放在侧边 (左/右) 或底部。控件还提供纯钢琴绘图 (在我的 VSTX 库中用于 VST 乐器测试)。
绘图技术
控件使用您自己的 Direct2D 渲染目标,因此您可以随意绘制它 (作为 `HWND`,甚至作为屏幕截图的一部分,或在打印机的 `HDC` 中)。
在我的旧文**文章**中了解更多关于 `Direct2D` 的信息。
当控件需要重绘时,它会通知您。
缩放、移动、吸附和滚动
控件提供在小节之间无限移动和无限缩放的能力。控件还允许将音符移动吸附到拍子上。这可以配置为允许使用拍子的分数来更精确地移动。如果您想在移动时不吸附,请按住 **Shift** 移动音符。您可以使用箭头键或顶部的滚动条滚动。
流式传输
控件可以输出一个流式音符向量 (具有绝对时间格式),供您的 MIDI 序列器使用。
分数
所有内部库操作都使用分数完成,因此在浮点运算中不会丢失任何信息。
class FRACTION
{
public:
ssize_t n = 0;
ssize_t d = 1;
... operators to multiply, add, compare etc
}
转位
半音转位很简单,我们给音符加一或减一 MIDI 音符。音阶转位更复杂,我们需要考虑当前的调和调式,然后检查音符是否属于新的音阶。
序列化
控件使用我的 XML 库进行序列化。然后您可以根据需要重新加载控件。
MIDI
`pianoroll` 提供了一个简单的 MIDI 类,可以写入 MIDI 文件数据。MIDI 写入采用可变长度格式。
void WriteVarLen(long value, vector<unsigned char>& b)
{
unsigned long long buffer = value & 0x7f;
while ((value >>= 7) > 0)
{
buffer <<= 8;
buffer |= 0x80;
buffer += (value & 0x7f);
}
for (;;)
{
b.push_back((char)buffer);
if (buffer & 0x80)
buffer >>= 8;
else
break;
}
}
`pianoroll` 创建一个多轨 MIDI 文件 (每个层变成一个轨道)。调、文本、标记、拍号和速度变化都包含在文件中。
键盘
- A : 自动工具
- E : 橡皮擦工具
- I : 单击输入工具
- Q : 量化工具
- 1,2,3,4 (上一行) : 选择下一个音符的拍子持续时间
- Shift+1,2,3,4 (上一行) : 拍子持续时间 1/8, 1/16, 1/32, 1/64
- < 和 > : 更改所选项目的力度
- Ctrl+ < 和 > : 力度关闭/全开
- < 和 > (音高偏移时): 上/下音高偏移 (与 Ctrl/Shift/Alt 组合)
- +/- : 按音阶更改所选项目的音符位置
- Shift +/- : 按半音更改所选项目的音符位置
- 小键盘 +/-/* : 放大、缩小、全部显示
- Shift + 向上/向下箭头 : 更改通道
- Alt + 向上/向下箭头 : 更改层
- / 和 \ : 放大/缩小音符
- D,H,': 加倍/减半/+1/2 音符
- Ctrl+Q : 量化音符
- Ctrl+G : 转到小节
- J : 连接音符
- Ctrl+1...6 : 吸附分辨率
- Alt+1-9 小键盘 : 切换层
- 1-9 小键盘 : 下一个层
- Ctrl+A : 全选
- Ctrl+C : 复制
- Ctrl+T : 音阶转位
- Ctrl+Shift+T : 半音转位
- Ctrl+V : 粘贴到最后点击的小节
- Ctrl+Z : 撤销
- Ctrl+Y : 重做
- [,] : 下一个/上一个标记
- 右/左箭头 : 移动钢琴卷帘
- Del : 删除所选音符
- Ctrl+Home : 滚动到开始
- X,Z : 向左、向右移动
- P : 切换乐段模式
- Alt+P : 下一个乐段
鼠标
- 双击 : 插入音符 (自动工具)
- Ctrl + 双击 : 插入非音符事件
- Ctrl + Shift + 双击 : 插入触后事件
- 双击音符 : 移除音符
- 单击音符 : 选择/取消选择 (量化工具中的量化)
- 拖动音符外部: 选择 (插入工具中的插入,橡皮擦工具中的删除,量化工具中的量化)
- 拖动/调整音符大小
历史
- 2019/9/5: 更多控件,量化
- 2019/5/5: 键盘快捷键,标记,音高弯音,触后,音色和其他新功能。
- 2019/5/1: 首次发布