---
title: "用 R 写音乐"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{用 R 写音乐}
  %\VignetteEncoding{UTF-8}
  %\VignetteEngine{knitr::rmarkdown}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>",
  eval = identical(Sys.getenv("gm_vignette"), "true")
)
```

本文要介绍 R 包 [gm](https://github.com/flujoo/gm)，你可以用它来写音乐。

具体来说，gm 有两大特点：

第一，它提供了一套简单高阶的语言，你可以用这个语言来描述音乐，它会将你的描述转化成乐谱和音频。这个过程中，你不需要考虑无关的技术细节。

第二，gm 可以在 R Markdown 文档和 R Jupyter 笔记本中使用，它会自动将生成的音乐嵌入在生成的文本之中。

先来看一个简单的例子。


## 小例子

```{r message = FALSE}
# 加载 gm
library(gm)

# 创建 Music 对象
m <- 
  # 初始化 Music 对象
  Music() +
  # 加上 4/4 拍号
  Meter(4, 4) +
  # 加上一条包含四个音的声部
  Line(list("C5", "D5", "E5", "F5"), list(1, 1, 1, 1))

# 转化成乐谱和音频
show(m, c("score", "audio"))
```

相信这个例子足够让你感受 gm 的简单和直观。深入之前，先来看看如何下载。


## 下载

从 CRAN 上下载：

``` {.r}
install.packages("gm")
```

从 Github 上下载开发版：

``` {.r}
# 请先下载 devtools 如果没有的话
# install.packages("devtools")

devtools::install_github("flujoo/gm")
```

你还需要[下载 MuseScore](https://musescore.org/)，它是一款开源免费的打谱软件。


## 设置

MuseScore 有[默认的安装路径](https://musescore.org/en/handbook/3/revert-factory-settings)，如果你安装到其它路径，请在 .Renviron 文件中设置：

第一，打开 .Renviron 文件。可以用命令：

```r
usethis::edit_r_environ()
```

第二，在其中加入：

```
MUSESCORE_PATH=<MuseScore 可执行文件的路径>
```

比如：

```
MUSESCORE_PATH="C:/Program Files (x86)/MuseScore 3/bin/MuseScore3.exe"
```

第三，重启 R 以激活更改。


## 深入一点

使用 gm 时，我们通常需要初始化一个 `Music` 对象：

```{r}
m <- Music()
```

在这个空的 `Music` 对象之上，我们可以加上其它的成分，比如加上拍号：

```{r}
m <- m + Meter(4, 4)
```

加上声部：

```{r}
m <- m + Line(pitches = list("C5"), durations = list("whole"))
```

我们可以直接打印 `m` 来查看其结构：

```{r}
m
```

当然，更直观的方式是将其转化成乐谱查看：

```{r}
show(m)
```

gm 的语法有点像 ggplot2，你可以不断添加成分，然后查看，然后再添加，不断反复。

我们还可以加上拍速记号：

```{r}
m <- m + Tempo(120)
show(m)
```

加上新的声部：

```{r}
m <- m + Line(
  pitches = list("C3", "G3"),
  durations = list("half", "half")
)

show(m)
```

这个过程可以继续，但我们在此打住。


## 算法作曲

gm 的一个有趣应用是算法作曲，也就是用算法来生成音乐。下面是一个例子：

```{r}
pitches <- as.list(c(64, 65, 69, 71, 72, 76))
durations <- rep(list(1), length(pitches))

m <- Music() + Meter(4, 4) + Tempo(120)

for (i in 0:8) {
  m <- m + Line(pitches, durations, offset = 0.5 * i)
}

show(m, to = c("score", "audio"))
```

上面的代码生成了九条声部，所有声部的音符都是相同的，区别是每条声部加入的时间都比前一条声部慢一点，因此形成了有趣的回音效果。


## 更多内容

你可以查看[完整的文档](https://flujoo.github.io/gm/articles/gm.html)了解更多功能。
