我有音符索引(每个八度有12个音符)与时间(以拍子为单位)数据。如何将这些数据转换为Midi文件?
Example Data:
time = [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 9.0, 9.0, 9.0, 10.0, 10.0, 10.0, 11.0, 11.0]
notes = [57.0, 59.0, 60.0, 62.0, 64.0, 65.0, 67.0, 57.0, 60.0, 64.0, 65.0, 62.0, 59.0, 64.0, 67.0]
乐器是钢琴。
另外,请注意同时存在多个音符。
谢谢。
答案 0 :(得分:0)
我创建了一个程序,可以在读取Python之前将您的数据转换为C ++的MIDI文件。无论如何,我更喜欢C ++和Qt,因此本示例将drumstick-file library用于作业。免责声明:我是鼓槌的作者,以防万一有人抱怨垃圾邮件或自我宣传。这是代码:
smfbuilder.pro
TEMPLATE = app
CONFIG += c++11 console link_pkgconfig
packagesExist(drumstick-file) {
message("using pkg-config")
PKGCONFIG += drumstick-file
} else {
message("using environment variables")
INCLUDEPATH += $$(DRUMSTICKINCLUDES)
LIBS += -L$$(DRUMSTICKLIBS) -ldrumstick-file
}
HEADERS += smfbuilder.h
SOURCES += smfbuilder.cpp
smfbuilder.h
#include <QObject>
#include <drumstick/qsmf.h>
class MidiEvent
{
public:
long absTime;
int status;
int data1;
int data2;
};
class Sequence : public QList<MidiEvent>
{
public:
virtual ~Sequence();
void sort();
};
class SMFBuilder : public QObject
{
Q_OBJECT
public:
SMFBuilder();
void run(QString fileName);
void generate();
public slots:
void errorHandler(const QString& errorStr);
void trackHandler(int track);
private:
drumstick::QSmf *m_engine;
Sequence m_sequence;
};
smfbuilder.cpp
#include <QCoreApplication>
#include <QDebug>
#include <QTextCodec>
#include <drumstick/qsmf.h>
#include "smfbuilder.h"
static inline bool eventLessThan(const MidiEvent& s1, const MidiEvent& s2)
{
return s1.absTime < s2.absTime;
}
void Sequence::sort()
{
std::stable_sort(begin(), end(), eventLessThan);
}
Sequence::~Sequence()
{
clear();
}
SMFBuilder::SMFBuilder() : QObject()
{
m_engine = new drumstick::QSmf(this);
m_engine->setTextCodec(QTextCodec::codecForName("UTF-8"));
connect(m_engine, SIGNAL(signalSMFError(const QString&)),
this, SLOT(errorHandler(const QString&)));
connect(m_engine, SIGNAL(signalSMFWriteTrack(int)),
this, SLOT(trackHandler(int)));
}
void SMFBuilder::errorHandler(const QString& errorStr)
{
qWarning() << errorStr;
exit(1);
}
void SMFBuilder::trackHandler(int )
{
// meta events
m_engine->writeBpmTempo(0, 100); // m.m.=100 (andante)
m_engine->writeTimeSignature(0, 4, 2, 18, 8); // ts = 4/4
m_engine->writeKeySignature(0, 0, major_mode); // C major
m_engine->writeMidiEvent(0, program_chng, 0, 0); // grand piano
// note events
long last_time = 0;
for(auto ev : m_sequence)
{
long delta = ev.absTime - last_time;
last_time = ev.absTime;
m_engine->writeMidiEvent(delta, ev.status, 0, ev.data1, ev.data2);
}
// final event
m_engine->writeMetaEvent(0, end_of_track);
}
void SMFBuilder::run(QString fileName)
{
m_engine->setDivision(120); // ticks per quarter note
m_engine->setFileFormat(0); // single track
m_engine->setTracks(1);
m_engine->writeToFile(fileName);
}
void SMFBuilder::generate()
{
QList<float> times = { 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 9.0, 9.0, 9.0, 10.0, 10.0, 10.0, 11.0, 11.0};
QList<float> notes = {57.0, 59.0, 60.0, 62.0, 64.0, 65.0, 67.0, 57.0, 60.0, 64.0, 65.0, 62.0, 59.0, 64.0, 67.0};
long quarter_length = 120; // quarter note duration in ticks
int velocityOn = 100; // forte
for ( int i=0; i<times.length(); ++i) {
long event_time = static_cast<long>(times[i] * quarter_length);
int midi_note = static_cast<int>(notes[i]);
// insert note on event
MidiEvent noteOn;
noteOn.absTime = event_time;
noteOn.status = note_on;
noteOn.data1 = midi_note;
noteOn.data2 = velocityOn;
m_sequence.append(noteOn);
// insert note off event
MidiEvent noteOff;
noteOff.absTime = event_time + quarter_length;
noteOff.status = note_off;
noteOff.data1 = midi_note;
noteOff.data2 = 0; // note off
m_sequence.append(noteOff);
}
m_sequence.sort();
}
int main(int argc, char **argv)
{
QCoreApplication app(argc, argv);
SMFBuilder builder;
builder.generate();
builder.run("output.mid");
return 0;
}
有关代码的一些注释:
您可以使用两种方式来配置鼓槌相关性。假设您使用的是Linux,请从Linux发行版中安装drumstick-devel软件包(或从源代码进行编译),并使用pkg-config管理依赖项,或者在QtCreator项目设置中定义环境变量DRUMSTICKINCLUDES和DRUMSTICKLIBS,或您的外壳。
MIDI文件就像一个乐谱。您的数据没有指定很多音乐参数,例如速度,音调,拍号...,我试图选择合理的值并提供适当的代码注释。
一般策略是在SMFBuilder :: generate()中生成一系列midi事件,然后将其写入文件。
生成文件“ output.mid”之后,这是Rosegarden的表示形式: