Skip to content

Commit

Permalink
Add files via upload
Browse files Browse the repository at this point in the history
  • Loading branch information
qishipai authored Oct 21, 2021
1 parent 1b66954 commit 40368d0
Show file tree
Hide file tree
Showing 12 changed files with 1,109 additions and 0 deletions.
159 changes: 159 additions & 0 deletions MIDI.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
#include <cstdio>
#include "Utils.hxx"
#include "MIDI.hxx"
using namespace NV;

bool NVmidiFile::mid_open(const char *name)
{
FILE *midifp = fopen(name, "rb");
u32_t tmp = 0, size = 0;

if (!midifp)
{
error("MIDI", "%s: 不存在或无法访问。 \n", name);
return false;
}

fread(&tmp, 4, 1, midifp);

if (tmp != 0x6468544Du)
{
fclose(midifp);
error("MIDI", "%s: 不是标准MIDI文件。 \n", name);
return false;
}

fread(&size , 4, 1, midifp);
fread(&type , 2, 1, midifp);
fread(&tracks, 2, 1, midifp);
fread(&ppnq , 2, 1, midifp);
revU32(size ); revU16(type);
revU16(tracks); revU16(ppnq);
fseek(midifp, SEEK_SET, size + 8);

trk_over = new bool [tracks];
trk_data = new nv_byte* [tracks];
trk_ptr = new nv_byte* [tracks];
grp_code = new nv_byte [tracks];

for (u16_t i = 0; i < tracks; ++i)
{
fread(&tmp , 4, 1, midifp);
fread(&size, 4, 1, midifp);

if (tmp != 0x6B72544Du)
{
tracks = i; mid_close();
fclose(midifp);
error("MIDI", "异常数据!(track%hu)\n", i);
return false;
}

revU32(size); tmp = 0;
trk_over[i] = false;
grp_code[i] = 0x0Fu;
nv_byte *dat = new nv_byte [size];
fread(dat, size, 1, midifp);
trk_data[i] = trk_ptr[i] = dat;
}

fclose(midifp);
return true;
}

void NVmidiFile::mid_close()
{
for (u16_t trk = 0; trk < tracks; ++trk)
{
delete[] trk_data[trk];
}

delete[] trk_data; delete[] trk_ptr;
trk_data = nullptr; trk_ptr = nullptr;
delete[] trk_over; delete[] grp_code;
trk_over = nullptr; grp_code = nullptr;
}

static u32_t getVLi_U32(nv_byte **p)
{
u32_t VLi = **p & 0x7Fu;

while (*(*p)++ & 0x80u)
{
(VLi <<= 7) |= **p & 0x7Fu;
}

return VLi;
}

bool NVmidiEvent::get(u16_t track, NVmidiFile &midi)
{
if (midi.trk_over[track])
{
return false;
}

nv_byte code, **p = midi.trk_ptr + track;
tick = getVLi_U32(p);

if (**p & 0x80u)
{
code = *(*p)++;
midi.grp_code[track] = code;
}
else
{
code = midi.grp_code[track];
}

chan = code & 0x0Fu;

switch (type = (NV_METYPE)(code & 0xF0u))
{
case (NV_METYPE::NOTEOFF):
case (NV_METYPE::NOTEON):
case (NV_METYPE::KEY_AT):
case (NV_METYPE::CTROCH):

num = *(*p)++;

case (NV_METYPE::PROGCH):
case (NV_METYPE::CHAN_AT):

value = *(*p)++;
break;

case (NV_METYPE::PITCH):

value = *(*p)++;
value = value << 7 | *(*p)++;
break;

case (NV_METYPE::SYSCODE):

if (code == 0xFFu)
{
if ((num = *(*p)++) == 0x2Fu)
{
midi.trk_over[track] = true;
}

type = NV_METYPE::OTHER;
}
else
{
num = code & 0x0Fu;
}

datasz = getVLi_U32(p); data = *p;
*p = *p + datasz; chan = (nv_byte)-1;
break;

default:

warn("MIDI", "异常数据!(track=%hu) \n", track);
return false;
}

return true;
}
47 changes: 47 additions & 0 deletions MIDI.hxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// MIDI.hxx 2021-10-21 by 云中龙++
#ifndef __MIDI_H_
#define __MIDI_H_

enum class NV_METYPE // MIDI事件类型码
{
NOTEOFF = (nv_byte)0x80, // 音符停止发声
NOTEON = (nv_byte)0x90, // 音符开始发声
KEY_AT = (nv_byte)0xA0, // 触后音符(?
CTROCH = (nv_byte)0xB0, // ControlChange
PROGCH = (nv_byte)0xC0, // ProgramChange
CHAN_AT = (nv_byte)0xD0, // 触后通道(?
PITCH = (nv_byte)0xE0, // Pitchbend
SYSCODE = (nv_byte)0xF0, // 系统码数据包
OTHER = (nv_byte)0xFF, // Meta-Event
};

struct NVmidiFile // MIDI文件类
{
/* 类型、轨道数、分辨率 */
u16_t type, tracks, ppnq;

bool *trk_over; // 轨道结束标志
nv_byte **trk_data; // 轨道数据
nv_byte **trk_ptr; // 读取位置
nv_byte *grp_code; // 事件组类型码

/* 打开MIDI文件 */
bool mid_open(const char *name);

/* 关闭MIDI文件 */
void mid_close();
};

struct NVmidiEvent // MIDI事件类
{
u32_t tick, datasz; // tick与元数据长度
NV_METYPE type; // 事件类型码
nv_byte chan, num; // 通道号 编号
u16_t value; // 事件值
const nv_byte *data; // 元数据指针

/* 从指定文件的指定轨道中获取事件 */
bool get(u16_t track, NVmidiFile &midi);
};

#endif
130 changes: 130 additions & 0 deletions Nlist.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
#include <cmath>
#include "Utils.hxx"
#include "MIDI.hxx"
#include "Sequ.hxx"
#include "Nlist.hxx"
using namespace NV;
using namespace std;

NVnote::NVnote(double T, const NVseq_event &E):
Tstart(T), Tend(114514191981.0), track(E.track),
channel(E.chan), key(E.num), vel(E.value) { }

NVnoteList::NVnoteList(const char *name):
Tread(0.0), abstick(0), keys(nullptr)
{
if ((err = !M.mid_open(name)))
{
return;
}

print(name, "类型码: %4hu\n", M.type);
print(name, "轨道数: %4hu\n", M.tracks);
print(name, "分辨率: %4hu\n", M.ppnq);

if ((err = M.type == 2))
{
error("Nlist", "%s: MIDI格式不支持!(type2)\n");
return;
}

S.seq_init(M); dT = 0.5 / M.ppnq;
keys = new rmPR<decltype(keys)>::t [M.tracks];
}

NVnoteList::~NVnoteList()
{
delete[] keys; keys = nullptr;
M.mid_close(); S.seq_destroy();
}

void NVnoteList::update_to(double T)
{
while (S.event().track < M.tracks && Tread < T)
{
const NVseq_event &E = S.event();

if (E.abstick != abstick)
{
Tread += dT * (E.abstick - abstick);
abstick = E.abstick;
}

switch (E.type)
{
case (NV_METYPE::OTHER):

if (E.num == 0x51u)
{
u32_t speed = *E.data;
(speed <<= 8) |= *(E.data + 1);
(speed <<= 8) |= *(E.data + 2);
dT = 1e-6 * speed / M.ppnq;
}

break;

case (NV_METYPE::NOTEON):

if (E.value > 0)
{
L[E.num].emplace_back(Tread, E);
auto p = L[E.num].end();
keys[E.track][E.num].push(--p);
break;
}

case (NV_METYPE::NOTEOFF):

if (!keys[E.track][E.num].empty())
{
keys[E.track][E.num].top()->Tend = Tread;
keys[E.track][E.num].pop();
}

default: break;
}

S.seq_next(M);
}
}

void NVnoteList::OR()
{
for (int i = 0; i < 128; ++i)
{
list<NVnote>::iterator p = L[i].end();
double T0 = 114514191981.0;
double T1 = 114514191981.0;

while (p-- != L[i].begin())
{
if (T0 < p->Tend && p->Tend < T1)
{
p->Tend = T0, T0 = p->Tstart;

if (p->Tend - p->Tstart < 1e-7)
{
p = L[i].erase(p);
}
}
else
{
T0 = p->Tstart, T1 = p->Tend;
}
}
}
}

void NVnoteList::remove_to(double T)
{
for (int i = 0; i < 128; ++i)
{
list<NVnote>::iterator p = L[i].begin();

while (p != L[i].end() && p->Tstart < T)
{
p->Tend < T? (p = L[i].erase(p)) : ++p;
}
}
}
47 changes: 47 additions & 0 deletions Nlist.hxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Nlist.hxx 2021-10-21 by 云中龙++
#ifndef __NLIST_H_
#define __NLIST_H_

#include <stack>
#include <list>

struct NVnote // 绘制用音符类
{
double Tstart, Tend; // 首尾时间
u16_t track; // 所属轨道
nv_byte channel, key, vel; // 音符属性

NVnote(double T, const NVseq_event &E);
};

class NVnoteList // 音符队列
{
public:

NVmidiFile M; // MIDI文件
bool err; // 错误标志
double Tread; // 当前读取位置(秒)
std::list<NVnote> L[128]; // 音符列表

/* 打开一个MIDI文件 */
NVnoteList(const char *name);

~NVnoteList();

/* 将第T秒前的音符放入列表 */
void update_to(double T);

void OR(); // 懂BM的都懂,不懂的用不到

/* 移除列表中第T秒前的音符 */
void remove_to(double T);

private:

NVsequencer S; // 事件排列器
double dT; // 速率
u32_t abstick; // 当前读取位置(tick)
std::stack<std::list<NVnote>::iterator> (*keys)[128];
};

#endif
Loading

0 comments on commit 40368d0

Please sign in to comment.