使用 C 解析 MIDI 文件 - (分配内存的可能问题)

Posted

技术标签:

【中文标题】使用 C 解析 MIDI 文件 - (分配内存的可能问题)【英文标题】:Parsing MIDI Files using C - (Possible Problem Allocating Memory) 【发布时间】:2019-01-22 15:24:36 【问题描述】:

我一直在尝试使用 C 编写 MIDI 解析器。我进行了研究,并从多个来源中学到了很多关于 MIDI 文件结构的知识。这里有一些最有用的(对于那些有兴趣的人):

https://web.archive.org/web/20141227205754/http://www.sonicspot.com:80/guide/midifiles.html https://www.csie.ntu.edu.tw/~r92092/ref/midi/

使用上述来源的信息,我编写了一个非常未经优化的 MIDI 解析器。当前版本的目的是简单地打印它遇到的事件并将它们保存在一个文件中。我已经设法解析了 midi 文件 [虽然我遇到了一个不应该存在的元事件(元事件 0x09)] .


但是,在实现保存功能时,我发现如果我尝试保存某些 midi 文件会导致问题(只需解析它们就可以正常工作)(程序冻结一段时间并在完成执行之前返回非零值)。我认为问题可能与我分配内存或访问它的方式有关。 这是代码(正如我所说,它还不漂亮)):

_MtrkCD **MtrkDatas = (_MtrkCD **)(malloc(sizeof(_MtrkCD *)));
uint64_t i,j,k,p;
for (p=0;p<MthdData->tracks_count;p++)
    MtrkDatas[p] = (_MtrkCD *)(malloc(sizeof(_MtrkCD)));
    if(!_ReadMtrkChunk(midiFile,MtrkDatas[p],p,print))
        printf("Error reading MTrk Chunk. Bad MTrk.\n");
        return 0;
    

^分配内存的部分(因需要而发布)^

main.c 这是我使用的两个示例文件(一个工作正常,另一个导致问题):home.mid(This file doesn't cause problems)014-Theme03.mid(This is the one causing problems) 以下是我运行程序时的输出:home Parsed.txt(Expected Output)014-Theme03 Parsed.txt(What even is this?) 再次,我想指出一些我注意到的事情:

    程序解析两个 MIDI 文件没有任何问题 程序不仅无法将事件输出写入 .txt 文件,而且无法写入正确的字节数

感谢大家的宝贵时间。 (如果有人更好地格式化文本,我将不胜感激。如您所见,我不是很擅长。)

更新:

这是工作代码。我在为轨道分配内存时犯了一个非常简单的错误。感谢Paul R指出错误。

_MtrkCD **MtrkDatas = (malloc(sizeof(_MtrkCD *) * (MthdData->tracks_count)));
uint64_t i,j,k,p;
for (p=0;p<MthdData->tracks_count;p++)
    MtrkDatas[p] = (malloc(sizeof(_MtrkCD)));
    if(!_ReadMtrkChunk(midiFile,MtrkDatas[p],p,print))
        printf("Error reading MTrk Chunk. Bad MTrk.\n");
        return 0;
    

【问题讨论】:

元事件 0x09 是 RP-019 中的 specified。 您的代码似乎无法处理运行状态。有关示例,请参见 aplaymidi source。 【参考方案1】:

在这一行:

_MtrkCD **MtrkDatas = (_MtrkCD **)(malloc(sizeof(_MtrkCD *)));

你只是分配一个一个指针组成的数组。所以在这里你有未定义的行为:

MtrkDatas[p] = (_MtrkCD *)(malloc(sizeof(_MtrkCD)));

只要 p > 0(即如果 tracking_count > 1 那么你就有麻烦了)。

你可能应该改变:

_MtrkCD **MtrkDatas = (_MtrkCD **)(malloc(sizeof(_MtrkCD *)));

到:

_MtrkCD **MtrkDatas = malloc(MthdData->tracks_count * sizeof(_MtrkCD *));

(请注意,演员表已被删除,因为它是 redundant and potentially dangerous to cast the result of malloc and friends in C)。

【讨论】:

首先,感谢您抽出宝贵的时间。你是对的,问题在于我没有分配足够的内存。多么愚蠢的错误。但是,我仍然不明白它是如何与 3 首曲目一起工作的……这也有不止一个曲目。 @PlagueTR:一旦你进入了未定义的行为领域,那么实际上任何事情都可能发生,包括一些看起来可以正常工作的事情,即使你认为它们不应该。 我明白了。我可能应该添加更多错误检查以查看内存分配是否成功。 错误检查很好,断言很好。在 valgrind 下运行代码很好。

以上是关于使用 C 解析 MIDI 文件 - (分配内存的可能问题)的主要内容,如果未能解决你的问题,请参考以下文章

BLE MIDIMIDI 文件格式分析 ( MIDI 文件头解析 | MIDI 文件头标识 | MIDI 文件头长度 | MIDI 文件格式 | MIDI 轨道个数 | 基本时间 )

BLE MIDIMIDI 文件格式分析 ( MIDI 文件头解析 | MIDI 文件头标识 | MIDI 文件头长度 | MIDI 文件格式 | MIDI 轨道个数 | 基本时间 )(代码

C语言中内存分配

UnicodeDecodeError:解析 Midi 文件时出现 Utf-8 解码错误

C 语言内存四区原理 ( 内存四区建立流程 )

C语言中内存分配 (转)