3

我正在开发一个 iOS 音乐应用程序(用 C++ 编写),我的模型看起来或多或少像这样:

--Song
----Track
----Track
------Pattern
------Pattern
--------Note
--------Note
--------Note

所以基本上 aSong有多个Tracks, aTrack可以有多个Patterns和 aPattern有多个Notes.这些东西中的每一个都由一个类表示,除了 Song 对象之外,它们都存储在向量中。

每个Note都有一个"frame"参数,以便我可以计算何时应该播放一个音符。例如,如果我有 44100 个样本/秒并且特定音符的帧是 132300,我知道在第三秒开始时我需要那个音符。

我的问题是我应该如何表示这些音符以获得最佳性能?现在我正在考虑将注释存储在每个模式的向量数据成员中,然后循环所有的Tracks,然后Song查看Patterns并循环Notes查看哪个具有大于 132300 且小于 176400 的帧数据成员(第 4 秒开始)。

如您所知,这是很多循环,一首歌可能长达 10 分钟。所以我想知道这是否足够快来计算所有帧并按时将它们发送到缓冲区。

4

4 回答 4

4

您应该记住的一件事是,为了提高性能,通常必须增加内存消耗。在这种情况下,它也是相关的(并且是合理的),因为我相信您想以不同的方式存储相同的数据两次

首先,你应该拥有一首歌曲的基本结构:

map<Track, vector<Pattern>> tracks;

它将每个映射TrackPatterns 的向量。地图很好,因为您不关心轨道的顺序。

遍历Tracks 和Patterns 应该很快,因为它们的数量不会很高(我假设)。主要的性能问题是循环数以千计的音符。以下是我建议的解决方法:

首先,对于每个Pattern对象,您应该有一个vector<Note>作为您的主要数据存储。您将首先将Pattern's 内容的所有更改写入此内容vector<Note>

vector<Note> notes;

出于性能考虑,您可以采用第二种存储笔记的方式:

map<int, vector<Notes>> measures;

这会将 a 中的每个度量(按其编号)映射到该度量中包含的 sPattern的向量。Note每次主notes存储中的数据更改时,您都会将相同的更改应用到measures. 您也可以每次在播放前,甚至播放时,在单独的线程中只执行一次。

当然,您只能将音符存储在小节中,而无需同步两个数据源。但是当您必须对一堆音符应用大量操作时,使用它可能不太方便。

在播放过程中,在下一个小节开始之前,将(大致)发生以下算法:

  1. 在每个音轨中,找到所有模式,其中pattern->startTime <= [current playback second] <= pattern->endTime.
  2. 对于每个模式,计算当前的度量值并从地图中获取vector<Notes>相应的度量值。measures
  3. 现在,直到下一个小节(第二个?)开始之前,您只需要循环浏览当前小节的音符。
于 2012-04-17T12:31:42.683 回答
3

Just keep those vectors sorted.

During playback, you can just keep a pointer (index) into each vector for the last note player. To search for new notes, you check have to check the following note in each vector, no looping through notes required.

于 2012-04-18T02:58:03.710 回答
1

Keep your vectors sorted, and try things out - that is more important and any answer you can receive here.

For all of your questions you should seek to answer then with tests and prototypes, then you will know if you even have a problem. And also while trying it out you will see things that you wouldn't normally see with just the theory alone.

于 2012-04-18T23:38:34.903 回答
0

我的模型看起来或多或少是这样的:

您的模型中缺少几个至关重要的概念:

  1. 速度。
  2. 动力学
  3. 踏板
  4. 乐器
  5. 时间签名
  6. (可选)音调。
  7. 效果(混响/合唱,音高轮)。
  8. 立体定位。
  9. 歌词。
  10. 和弦图。
  11. 作曲家信息/标题。

每个音符都有一个“帧”参数,以便我可以计算何时播放音符。

您的模型中缺少几个至关重要的概念:

  1. 关节。
  2. 触后。
  3. 注意持续时间。

我建议看看lilypond。它是排版软件,但它也是以人类可读的文本格式表示音乐的最精确方式之一。

我的问题是我应该如何表示这些音符以获得最佳性能?

将它们全部放入std::map<Timestamp, Note>并使用 lower_bound/upper_bound 找到您想要播放的片段。或者,只要对数据进行排序,您就可以在平面 std::vector 中对它们进行二进制搜索。

除非您想制作“蜂鸣器”,否则制作音乐应用程序比您想象的要困难得多。我强烈建议尝试另一个项目。

于 2012-04-12T04:14:33.357 回答