在Haskell中创建MIDI文件

8
我想创建一个简单的程序来生成MIDI文件。不,我不想使用Haskore,因为它对于这个项目来说有点过度了。我认为像this library这样的东西就足够了。
我想要做到以下几点:
- 创建新的MIDI文件; - 往里面写入一些事件(我想控制音量、音高和时间位置); - 保存MIDI文件。
就是这么简单,我相信这并不难,但我找不到任何好的例子来做到这一点。
请提供一个基本的例子或指出在Haskell中如何创建MIDI文件的相关信息。
注意:我不是在问你如何选择一个好的库来完成它,我只是想知道如何在Haskell中实现它(使用你认为适合用于示例的任何库)。

3
我不懂 Haskell,但测试和示例文件夹中的内容看起来很有趣。 - CL.
1
你是否已经尝试过网上提供的更简单的程序(例如这个同一作者的其他程序)? - Aurélien Bénel
@Aurélien,我在谷歌搜索这个主题时看到了这个程序。不幸的是,我不知道这是否是一个体面的程序编写方式(它使用Codec.Midi,真的好吗?)。如果那段代码有详细的注释,它会更加有用。 - Mark Karpov
在SO上,“给我代码”这样的问题是不受欢迎的。你的问题太宽泛,无法适应SO的格式。 - Bakuriu
1
@Bakuriu,太宽泛了吗?实际上,请求的答案大约有16行代码,这些信息将对许多未来的读者有用,您可以想任何您想要的,但是没有好的文档示例说明如何做到这一点,至少不容易找到。“给我代码”这样的问题并不是要提供规范的示例。 - Mark Karpov
显示剩余2条评论
1个回答

7

前言

好的,我不确定这是一个好问题,但我已经等不及了,所以这里介绍如何使用Haskell编写一些MIDI。需要注意的是,这个主题几乎没有文档记录,除了一些看起来相当神秘的包描述。

最适合我们需求的最小化包是HCodecs,并且它似乎定期更新。我们感兴趣的是模块Codec.Midi

MIDI事件

在这个库中,事件被期望表示为元组:

(time-offset, message)

其中time-offset是上一个事件和新事件之间经过的滴答数(请参见下面如何设置每拍的滴答数)。message必须是Message类型,完整的构造函数列表可以在这里找到。这些构造函数对应于所有基本MIDI事件。

创建轨道

轨道是事件列表。因此,我们现在可以编写一些非常简单的内容:

track0 = [(0,  NoteOn 0 60 80),
          (24, NoteOff 0 60 0),
          (0,  TrackEnd)]

这里使用了中央C(60)作为音符,我们使用了NoteOnNoteOff事件(实际上NoteOff和速度为0NoteOn是一样的,所以实践中人们倾向于只使用NoteOn)。想要了解更多关于这方面可以搜索MIDI格式相关信息。

让我们再创建一个包含E的音轨:

track1 = [(0,  NoteOn 0 64 80),
          (24, NoteOn 0 64 0),
          (0,  TrackEnd)]

太好了!现在是把数据放入MIDI容器的时候了。

集合在一起!

让我们创建一个代表整个MIDI文件的对象。我们将使用Midi数据类型的构造函数。

myMidi = Midi { fileType = MultiTrack, 
                timeDiv  = TicksPerBeat 24, 
                tracks   = [track0, track1] }

这就是全部内容了!timeDiv 定义了轨道的量化,如果我们每拍有 24 个滴答声,我们的音符将恰好持续一拍(当然,您可以添加一些事件来设置节奏等等,请尝试!)。

保存内容

要保存一个 Midi 文件,我们应该使用exportFile(点击链接以获取更多信息…… 好吧,开玩笑的,甚至没有一行描述)。
exportFile "my-midi.mid" myMidi

完成。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接