Midifile:C++ MIDI文件解析库完全指南

Midifile:C++ MIDI文件解析库完全指南

【免费下载链接】midifile C++ classes for reading/writing Standard MIDI Files 【免费下载链接】midifile 项目地址: https://gitcode.com/gh_mirrors/mi/midifile

项目概述

Midifile是一个用于读写标准MIDI文件的C++类库,提供强大的MIDI文件处理能力。该项目由六个精心设计的核心类组成,能够高效地解析、创建和修改MIDI文件。无论你是音乐软件开发者、音乐教育工作者还是音乐学研究者,这个开源库都能为你的项目提供可靠的技术支持。

核心技术架构

Midifile采用模块化设计,每个类都有明确的职责分工,共同构建了完整的MIDI文件处理解决方案:

MidiFile - 主控制器类

作为主要接口,MidiFile类负责MIDI文件的全面管理,包括读取、写入和时间分析。它表现为一个二维的MidiEvents数组,第一维度是轨道列表,第二维度是MIDI事件列表。这个类提供了对MIDI文件操作的所有基本功能。

MidiEventList - 事件列表管理器

这个数据结构负责管理MIDI文件轨道中的MidiEvents列表。每个轨道对应一个MidiEventList对象,确保事件的有序存储和高效访问。

MidiEvent - 单个事件处理器

作为MidiMessages在MidiFile中的主要存储单元。该类包含一个tick时间戳(delta或绝对时间)和一个表示MIDI消息字节的向量。

MidiMessage - MIDI消息解析器

作为MidiEvents的基类,这是一个STL无符号字节向量,代表MIDI(或元)消息。

Binasc - ASCII格式转换器

辅助MidiFile类的一个帮助类,允许以ASCII格式读写MIDI文件,描述二进制标准MIDI文件的字节。

Options - 配置选项处理器

一个可选便利类,用于示例程序中的命令行选项解析。这个类可以从库中移除,因为使用MidiFile类时并不需要它。

主要功能特性

多格式支持

Midifile支持标准MIDI文件的所有格式,包括二进制标准MIDI文件、十六进制字节码表示和广义的binasc语法文件。

时间分析能力

通过MidiFile::doTimeAnalysis()函数,可以将绝对tick时间戳转换为秒,根据文件中的任何速度元消息进行计算。

音符配对功能

MidiFile::linkNotePairs()函数可以匹配音符开启和音符关闭事件。完成后,可以通过MidiEvent::getDurationInSeconds()访问音符开启消息的持续时间。

安装与编译

下载项目

你可以通过以下命令下载项目源代码:

git clone https://gitcode.com/gh_mirrors/mi/midifile

编译库文件

使用GCC编译库:

make library

这将创建lib/libmidifile.a文件,可用于链接使用该库的程序。

编译示例程序

编译所有示例程序:

make programs

编译后的示例程序将存储在bin目录中。

编译单个程序

要仅编译单个程序,如createmidifile,键入:

make createmidifile

核心使用示例

MIDI文件读取示例

以下程序列出MIDI文件中的所有MidiEvents:

#include "MidiFile.h"
#include "Options.h"
#include <iostream>
#include <iomanip>

using namespace std;
using namespace smf;

int main(int argc, char** argv) {
   Options options;
   options.process(argc, argv);
   MidiFile midifile;
   if (options.getArgCount() == 0) midifile.read(cin);
   else midifile.read(options.getArg(1));
   midifile.doTimeAnalysis();
   midifile.linkNotePairs();

   int tracks = midifile.getTrackCount();
   cout << "TPQ: " << midifile.getTicksPerQuarterNote() << endl;
   if (tracks > 1) cout << "TRACKS: " << tracks << endl;
   for (int track=0; track<tracks; track++) {
      if (tracks > 1) cout << "\nTrack " << track << endl;
      cout << "Tick\tSeconds\tDur\tMessage" << endl;
      for (int event=0; event<midifile[track].size(); event++) {
         cout << dec << midifile[track][event].tick;
         cout << '\t' << dec << midifile[track][event].seconds;
         cout << '\t';
         if (midifile[track][event].isNoteOn())
            cout << midifile[track][event].getDurationInSeconds();
         cout << '\t' << hex;
         for (int i=0; i<midifile[track][event].size(); i++)
            cout << (int)midifile[track][event][i] << ' ';
         cout << endl;
      }
   }

   return 0;
}

MIDI文件创建示例

以下程序创建一个MIDI文件并生成随机音符序列:

#include "MidiFile.h"
#include "Options.h"
#include <random>
#include <iostream>

using namespace std;
using namespace smf;

int main(int argc, char** argv) {
   Options options;
   options.define("n|note-count=i:10", "How many notes to randomly play");
   options.define("o|output-file=s",   "Output filename (stdout if none)");
   options.define("i|instrument=i:0",  "General MIDI instrument number");
   options.define("x|hex=b",           "Hex byte-code output");
   options.process(argc, argv);

   random_device rd;
   mt19937 mt(rd());
   uniform_int_distribution<int> starttime(0, 100);
   uniform_int_distribution<int> duration(1, 8);
   uniform_int_distribution<int> pitch(36, 84);
   uniform_int_distribution<int> velocity(40, 100);

   MidiFile midifile;
   int track   = 0;
   int channel = 0;
   int instr   = options.getInteger("instrument");
   midifile.addTimbre(track, 0, channel, instr);

   int tpq     = midifile.getTPQ();
   int count   = options.getInteger("note-count");
   for (int i=0; i<count; i++) {
      int starttick = int(starttime(mt) / 4.0 * tpq);
      int key       = pitch(mt);
      int endtick   = starttick + int(duration(mt) / 4.0 * tpq);
      midifile.addNoteOn (track, starttick, channel, key, velocity(mt));
      midifile.addNoteOff(track, endtick,   channel, key);
   }
   midifile.sortTracks();
   string filename = options.getString("output-file");
   if (filename.empty()) {
      if (options.getBoolean("hex")) midifile.writeHex(cout);
      else cout << midifile;
   } else
      midifile.write(filename);

   return 0;
}

工具程序集

Midifile项目提供了丰富的工具程序,涵盖各种MIDI文件处理需求:

基础转换工具

  • base642midi - Base64到MIDI转换器
  • midi2base64 - MIDI到Base64转换器
  • midi2text - MIDI到文本转换器
  • text2midi - 文本到MIDI转换器

分析工具

  • chaninfo - 通道信息分析器
  • deltatimes - 增量时间分析器
  • durations - 持续时间分析器

编辑工具

  • createmidifile - MIDI文件创建器
  • removenote - 音符移除工具
  • sortnotes - 音符排序工具

可视化工具

  • mid2svg - MIDI到SVG转换器,用于可视化MIDI数据

高级功能应用

时间管理

Midifile支持两种时间状态:绝对tick时间和delta tick时间。默认情况下,MidiFile类存储MIDI事件的绝对tick时间,可通过MidiEvent::tick访问。在标准MIDI文件中,tick存储为delta值,其中tick指示自轨道中先前消息以来的等待持续时间。

轨道操作

MidiFile::joinTracks()函数可用于将多轨道数据转换为单个时间序列。joinTrack()操作可以通过调用MidiFile::splitTracks()函数来反转。

元消息处理

库提供了对文本元消息的完整支持,包括歌词提取、轨道名称识别等功能。

集成到现有项目

在你的项目中使用midifile库的最简单方法是将include目录中的头文件和src目录中的源代码文件复制到自己的项目中。你不需要复制Options.h或Options.cpp,因为MidiFile类不依赖于它们。

项目优势

高效性能

通过优化的类结构,Midifile确保高效的文件操作和数据处理能力。

灵活集成

库设计允许轻松集成到现有的C++项目中,提供了灵活的使用方式。

全面兼容

支持所有标准MIDI特性和格式,包括多轨道、时间戳和各种MIDI消息。

开源免费

作为开源项目,用户可以自由使用、修改和分发,没有任何商业限制。

结语

Midifile库为C++开发者提供了强大而灵活的MIDI文件处理解决方案。无论你的项目规模大小,这个工具都能提供可靠的技术支持。通过其清晰的架构和丰富的功能,你可以轻松实现MIDI文件的读取、创建、编辑和分析,为音乐编程项目奠定坚实基础。

【免费下载链接】midifile C++ classes for reading/writing Standard MIDI Files 【免费下载链接】midifile 项目地址: https://gitcode.com/gh_mirrors/mi/midifile

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值