您知道什么比学钢琴更难吗?在没有钢琴,也没有任何音乐理论知识的情况下学习钢琴。对我来说,买一架真正的钢琴是不可能的。我没有资金,大学的小公寓也没有空间放钢琴。很自然地,看起来我必须自己构建一个钢琴——当然是数字化的。幸运的是,我有Mathematica、Unity和几个小时的空闲时间。因为使用Wolfram 语言 (https://wolfr.am/10mTqMAq6) 和UnityLink (https://wolfr.am/10mTnjzOC)在 Unity 中工作非常快速和高效,所以我创建了一个可演奏的钢琴部分,甚至在这个过程中学习了一些音乐理论。 首先,我确定建造钢琴需要以下条件:
- 每个音符的音频
- 钢琴键的几何形状
- 便携式、交互式、实时渲染音频和 3D 物理引擎
前两个可以在 Wolfram 语言中轻松完成。至于最后一个,我选择使用新引入的 UnityLink — Wolfram 语言和实时开发平台 Unity 之间的强大链接。使用 UnityLink,现在可以结合Wolfram语言在渲染、音频和物理方面令人印象深刻的模拟优势与 Unity 将这三者有效地打包到 Web、桌面、移动和控制台平台的独立应用程序中相结合。
什么是钢琴?
在深入研究代码之前,让我们先了解一下钢琴和它演奏的音符的一些背景知识。了解实体钢琴背后的理论将帮助我们更好地在 Unity 中以数字方式重新创建它。
钢琴的起源可以追溯到 18 世纪早期的意大利,它是由Bartolomeo Cristofori发明的。从那时起,它经历了许多设计更改,最终形成了(大部分)标准化的按键配置。
现代钢琴共有 88 个键,其中 52 个是白色的,用于演奏自然音符(A、B、C、D、E、F 和 G)。剩余的36个键是黑色的,用于演奏所述记号(A♯/ B♭,C♯/ d♭,D♯/ E♭,F♯/ G♭和G♯/ A♭)。♯ 和 ♭ 符号分别代表尖锐和平坦。在这里您可以看到所有 88 个键,并标有相应的音符:
音符可以进一步分为八度,每个八度包含 12 个键。具有相同音符但处于不同八度的两个键将具有不同的音高。钢琴的八度在此图中用颜色编码:
钢琴包含七个完整的八度音程,末端有四个额外的键。这些额外的键允许在所有七个八度音阶中演奏 A 小调和 C 大调的音阶。
在这篇博文中,为简单起见,我将专注于单个音阶(按顺序排列的音符),但您可以应用此方法来创建整个钢琴。让我们使用最常见的音阶之一——C大调音阶。此音阶仅包含按 C、D、E、F、G、A 和 B 顺序排列的自然音符。可以选择任何 C 音符作为音阶的开始。在这里,我将使用第四个八度音阶中的 C 音符(也称为 C4 或中间 C):
如果您仔细观察,您会发现我们钢琴的这一小节包含所有七个自然音符和所有五个临时音符。请注意,我还在音阶中包含了下一个八度音阶 (C5) 的 C 键,因为这有助于“四舍五入”音阶:
制作音乐
哇!有了背景,我终于可以进入代码了。为了获得钢琴键的声音,我使用符号SoundNote,它可以从大量乐器中生成任何音符。对于单个音符,您只需为其指定音符名称、持续时间和乐器。当包裹在Audio 中时,它会创建一个可以直接在笔记本中播放的音频对象:
要获得特定八度的音符,您只需将八度数字连接到音符名称的末尾。例如,我可以使用此处显示的代码获得第四个八度音阶中的所有自然音符:
生成几何
钢琴键的确切形状和尺寸因制造商而异。我选择通过将每个键近似为棱镜来保持简单。使用棱镜的好处是我只需要指定基础多边形并向上挤压。但是,确保没有键重叠需要五个基本多边形变体:
剩下的就是将基本多边形转换为 3D 棱镜。这可以使用RegionProduct将多边形乘以具有给定高度的线段轻松完成:
准备项目
现在我有了音频和几何图形,是时候在 Unity 中将它们组合起来制作一架工作的钢琴了。正如我之前提到的,这可以通过 UnityLink 实现。
安装 Unity 后,加载 UnityLink 就像单个函数调用一样简单:
我首先打开一个新的 Unity 项目,我将其命名为“ MyPiano ”:
项目打开后,我现在可以从 Unity 发送和接收数据。我最终希望在Scene中创建我的钢琴——一个 3D 环境,可以充当菜单、游戏关卡或 Unity 应用程序的任何其他不同部分。但是在我创建我的Scene之前,我必须首先将我之前创建的音频和几何内容传输到 Unity。添加后,我将可以在我的 Scene 中自由使用它。
虽然不是必需的,但最好使用项目资产目录中的子目录来组织您的 Unity 项目。该 Assets 目录包含所有在项目中使用的资产(纹理,音频剪辑,网格等)。在此处显示的行中,我使用CreateUnityAssetDirectory在Assets目录中创建了五个目录:
现在我开始传输音频。为此,我将每个音符的音频传递给函数CreateUnityAudioClip,该函数会自动将其转换为 Unity 的 AudioClip 对象并将其存储在Assets目录中。这些AudioClip对象在 Wolfram 语言中表示为UnityAudioClip表达式:
接下来,我转移了钢琴键的几何形状。然而,这一次,我使用CreateUnityMesh自动将我的MeshRegions转换为 Unity 的Mesh对象,在 Wolfram 语言中表示为UnityMesh表达式。
我做了一些类似的事情来创建一个黑白材料,以及一个脚本组件来控制用户与钢琴键的交互。为简洁起见,我省略了这些,但可以在这篇文章的可下载笔记本中找到完整的代码。
设置场景
转移所有资产后,我终于可以为我的钢琴制作场景了。我首先创建一个新的默认场景:
如果您不熟悉 Unity,这里是Scenes的简要说明。Scenes包含游戏对象,而游戏对象又充当组件的容器。您可以将场景视为环境,将游戏对象视为该环境中的事物,将组件视为这些事物的行为。
在我的钢琴场景中,我将为每个键制作一个游戏对象。然后,我会将我之前创建的脚本组件附加到这些游戏对象中的每一个,以便在用户与它们交互时它们会发出声音并移动。
我可以一次添加一个键;然而,这将被证明是乏味的,并且在未来难以扩展。相反,我在两个列表中定义了有关每个白键和每个黑键的信息。然后我可以遍历这些列表以自动创建每个键。对于每个键,我指定了它对应的计算机键盘键、它应该播放的音符以及它应该使用的网格索引。请注意,黑键的网格索引被隐式假定为 5:
为了保持我的场景井井有条,我还将我的所有键分组到一个名为 “Piano Scale” 的主游戏对象下:
我首先遍历所有的白键:
接下来是黑键:
对于每个键,我使用CreateUnityGameObject创建一个具有适当网格的游戏对象。设置这个游戏对象的位置后,我通过将游戏对象和脚本名称传递给CreateUnityComponent来附加我之前创建的自定义脚本。我通过指定该键的键码和音频剪辑来完成。
就像那样,我有一架可以工作的(部分)钢琴。然而,它看起来并不像它想象的那么好。为了解决这个问题,我调整了物体材质以及照明和相机(可下载笔记本中的完整代码)。有了这个,我们得到了最终的结果:
现在看起来好多了!在继续之前,我还想通过调用SaveUnityScene来保存我刚刚对场景所做的所有更改:
弹钢琴
为了在 Unity 编辑器中测试钢琴,我可以使用UnityPlay和UnityStop在Play和Edit模式之间切换。当我对结果感到满意时,我可以使用 UnityBuild (https://reference.wolfram.com/language/UnityLink/ref/UnityBuild.html) 将项目构建为独立应用程序。
以下命令将自动将项目构建到我当前平台 (macOS) 的项目目录中的文件中:
构建成功后,我可以立即打开并弹奏我的钢琴应用程序:
在 Unity 中工作的优势之一是它能够构建到众多平台而无需更改您的代码。如果您可以在某个平台上玩游戏,那么 Unity 很可能可以为其构建内容。
它甚至可以构建为在 Web 浏览器中运行。尝试一下!
轮到您了!
钢琴的这一小部分可以轻松扩展为完整的钢琴键盘。SoundNote (https://reference.wolfram.com/language/ref/SoundNote.html.zh?source=wechat) 中提供了 160 多种风格和打击乐器,您还可以构建其他乐器,甚至将它们组合成一个合成器。
要开始使用 Wolfram 语言中的 UnityLink,请访问在线文档页面 (https://reference.wolfram.com/language/UnityLink/guide/UnityLink.html?source=wechat) 或尝试示例项目 (https://reference.wolfram.com/language/UnityLink/guide/SampleProjects.html?source=wechat) 之一。您可以使用内置界面 (https://www.wolfram.com/language/12/built-in-interface-to-unity-game-engine/index.html.zh?source=wechat) 做很多事情,我期待看到您在 Wolfram 社区 (https://community.wolfram.com/)上提出的项目!
版本 12 ( (https://www.wolfram.com/language/new-in-12/index.html.zh?source=wechat)) 为 Wolfram 语言带来了许多主要的新领域,包括与 Unity 游戏引擎的无缝接口。立即在桌面或 Wolfram Cloud 中使用Wolfram|One 或 Mathematica 开始编码。
本文译自博客:https://blog.wolfram.com/2019/06/06/how-i-built-a-virtual-piano-with-the-wolfram-language-and-the-unity-game-engine/