如何在 C++ 中使用十六进制信息创建 MIDI 文件

How to create MIDI file using hexadecimal information in C++

我正在尝试用 C++ 从头开始​​创建 MIDI 文件。 我将此网站用作资源:https://intuitive-theory.com/midi-from-scratch/ .

由于 MIDI 要求它以十六进制编码,我编写了一个程序来创建一个 MIDI 文件并将十六进制代码粘贴到其中,如下所示:

#include <cstdlib>
#include <iostream>
#include <fstream>
#include <iomanip>
#include <stdio.h>

using namespace std; 

int main(){
    ofstream myfile;
    myfile.open ("output.mid",ios::binary);
    char buffer[44] = {static_cast<char>(0x4D,0x54,0x68,0x64,0x00,0x00,0x00,0x06,0x00,0x01,0x00,0x01,0x00,0x80,0x4D,0x54,0x72,0x6B,0x00,0x00,0x00,0x16,0x80,0x00,0x90,0x3C,0x60,0x81,0x00,0x3E,0x60,0x81,0x00,0x40,0x60,0x81,0x00,0xB0,0x7B,0x00,0x00,0xFF,0x2F,0x00)};
    myfile.write(buffer,44);
    myfile.close();

}

然而,这甚至无法在任何 MIDI 播放器上打开,因为“文件已损坏”。我不明白为什么会这样。

谢谢

char buffer[] = {static_cast<char>(0x4D,0x54,0x68,0x64,0x00,0x00,0x00,0x06,0x00,0x01,0x00,0x01,0x00,0x80,0x4D,0x54,0x72,0x6B,0x00,0x00,0x00,0x16,0x80,0x00,0x90,0x3C,0x60,0x81,0x00,0x3E,0x60,0x81,0x00,0x40,0x60,0x81,0x00,0xB0,0x7B,0x00,0x00,0xFF,0x2F,0x00)};

不会将所有逗号分隔值转换为 char。相反,因为 staic_cast 一次只能处理一个值,它会调用 comma operator ,这将使您保留最后一个值并丢弃其余值。

相反,让 buffer 成为正确的“形状”然后在将其传递给 write 时将其转换为 char 会更好。

int main(){
    ofstream myfile;
    myfile.open ("output.mid",ios::binary);
    unsigned char buffer[] = {0x4D,0x54,0x68,0x64,0x00,0x00,0x00,0x06,0x00,0x01,0x00,0x01,0x00,0x80,0x4D,0x54,0x72,0x6B,0x00,0x00,0x00,0x16,0x80,0x00,0x90,0x3C,0x60,0x81,0x00,0x3E,0x60,0x81,0x00,0x40,0x60,0x81,0x00,0xB0,0x7B,0x00,0x00,0xFF,0x2F,0x00};
    // unsigned char can fit any of the given values
    // Removed the 44. The compiler can figure the number of elements out from the 
    // number of initializers. Usually this is safer. Now you can add or remove 
    // a few bytes without also having to change the element count

    myfile.write(reinterpret_cast<char *>(buffer), //casting here
                 sizeof(buffer)); // Letting compiler figure out how many bytes to write
    myfile.close();

}

注意:reinterpret_cast 真的非常小心。它告诉编译器关闭它的大脑并相信你。如果你错了,程序将 break 并且你不会从编译器那里得到警告,并且运行时结果可能完全无法解释,直到你弄清楚发生了什么。