Archived
1
0
Fork 0

first and last commit

This commit is contained in:
Sen 2025-09-02 14:43:36 +02:00
commit c9e78fd810
Signed by: sen
GPG key ID: 3AC50A6F47D1B722
381 changed files with 37141 additions and 0 deletions

518
midi.h Normal file
View file

@ -0,0 +1,518 @@
void snd_logd(const char *fmt, ...);
void snd_loge(const char *fmt, ...);
void snd_logx(const char *fmt, ...);
void mid_dlog(const char *format, ...) {
if(sgt.log_debug)
snd_logd(format);
}
void mid_settempo(mid_handle *mid, uint tempo) {
mid->uspb = tempo;
mid->ticktime = mid->uspb / mid->tpqn;
}
uint mid_read_uint32(byte *data) {
uint value = 0;
for(int h = 0; h < 4; h++) {
value |= ((uint)data[h]);
value <<= h < 3 ? 8 : 0;
}
return value;
}
ushort mid_read_uint16(byte *data) {
ushort value = 0;
for(int h = 0; h < 2; h++) {
value |= ((ushort)data[h]);
value <<= h < 1 ? 8 : 0;
}
return value;
}
uint midt_read_uint32(mid_track *trk) {
uint value = 0;
for(int h = 0; h < 4; h++) {
if(trk->pos >= trk->size) {
break;
}
value |= ((uint)trk->buffer[trk->pos++]);
value <<= h < 3 ? 8 : 0;
}
return value;
}
uint midt_read_uint24(mid_track *trk) {
uint value = 0;
for(int h = 0; h < 3; h++) {
if(trk->pos >= trk->size) {
break;
}
value |= ((uint)trk->buffer[trk->pos++]);
value <<= h < 2 ? 8 : 0;
}
return value;
}
ushort midt_read_uint16(mid_track *trk) {
ushort value = 0;
for(int h = 0; h < 2; h++) {
if(trk->pos >= trk->size) {
break;
}
value |= ((ushort)trk->buffer[trk->pos++]);
value <<= h < 1 ? 8 : 0;
}
return value;
}
byte midt_read_uint8(mid_track *trk) {
byte value = 0;
if(trk->pos < trk->size) {
value = trk->buffer[trk->pos++];
}
return value;
}
void midt_read_var(mid_track *trk, uint len, byte *chars) {
memset(chars, 0, len);
for(int h = 0; h < len; h++) {
if(trk->pos >= trk->size) {
break;
}
chars[h] = trk->buffer[trk->pos++];
}
}
uint mid_read_vlen(mid_track *trk)
{
uint value;
byte bt;
if(trk->pos >= trk->size) {
return 0;
}
if((value = trk->buffer[trk->pos++]) & 0x80)
{
value &= 0x7f;
do {
if(trk->pos >= trk->size) {
break;
}
value = (value << 7) + ((bt = trk->buffer[trk->pos++]) & 0x7f);
}
while(bt & 0x80);
}
return value;
}
uint mid_read(mid_handle *mid, const char *filename) {
int err;
FILE *fd = fopen(filename, "rb");
if(fd == NULL) {
err = errno;
loge(LOG_IO, STR_MID_OPNERR, filename, strerror(err), err);
return 0;
}
if(fseek(fd, 0L, SEEK_END)) {
err = errno;
loge(LOG_IO, STR_MID_EGEN, filename, strerror(err), err);
fclose(fd);
return 0;
}
long size = ftell(fd);
if(size < 0L) {
err = errno;
loge(LOG_IO, STR_MID_EGEN, filename, strerror(err), err);
fclose(fd);
return 0;
}
if(fseek(fd, 0L, SEEK_SET)) {
err = errno;
loge(LOG_IO, STR_MID_EGEN, filename, strerror(err), err);
fclose(fd);
return 0;
}
if(size < 14) {
loge(LOG_IO, STR_MID_ESHORT, filename);
fclose(fd);
return 0;
}
byte header[14];
if(fread(header, 1, 14, fd) != 14) {
err = feof(fd);
loge(LOG_IO, err == 0 ? STR_MID_EIO : STR_MID_EEOF, filename);
fclose(fd);
return 0;
}
if(memcmp(header, mid_hdr, 4) != 0) {
loge(LOG_IO, STR_MID_EMFHDR, filename);
fclose(fd);
return 0;
}
if(mid_read_uint32(header+4) != 6) {
loge(LOG_IO, STR_MID_EHSIZE, filename);
fclose(fd);
return 0;
}
byte mtrack;
ushort type = mid_read_uint16(header+8);
if(type == 0) {
mtrack = 0;
}
else if((type == 1) || (type == 2)) {
mtrack = 1;
}
else {
loge(LOG_IO, STR_MID_ETKFMT, filename);
fclose(fd);
return 0;
}
mid->tracks = mid_read_uint16(header+10);
if(mid->tracks == 0) {
loge(LOG_IO, STR_MID_ENOTRK, filename);
fclose(fd);
return 0;
}
else if((mtrack ^ 1) && (mid->tracks > 1)) {
loge(LOG_IO, STR_MID_ESMULT, filename);
fclose(fd);
return 0;
}
mid->tpqn = mid_read_uint16(header+12);
if((mid->tpqn & 0x8000) > 0) {
loge(LOG_IO, STR_MID_ESMPTE, filename);
fclose(fd);
return 0;
}
if(mid->tpqn == 0) {
loge(LOG_IO, STR_MID_EDZERO, filename);
fclose(fd);
return 0;
}
uint esize = 0;
for(ushort trk = 0; trk < mid->tracks; trk++) {
if(fread(header, 1, 8, fd) != 8) {
err = feof(fd);
loge(LOG_IO, err == 0 ? STR_MID_EIO : STR_MID_EEOF, filename);
fclose(fd);
return 0;
}
if(memcmp(header, mid_trk, 4) != 0) {
loge(LOG_IO, STR_MID_ETKHDR, filename);
fclose(fd);
return 0;
}
uint trks = mid_read_uint32(header+4);
if((14 + esize + 8 + trks) > size) {
loge(LOG_IO, STR_MID_EOUTOF, filename, trk+1);
fclose(fd);
return 0;
}
if(fseek(fd, trks, SEEK_CUR)) {
err = errno;
loge(LOG_IO, STR_MID_EGEN, filename, strerror(err), err);
fclose(fd);
return 0;
}
esize += trks + 8;
}
if(fseek(fd, 14L, SEEK_SET)) {
err = errno;
loge(LOG_IO, STR_MID_EGEN, filename, strerror(err), err);
fclose(fd);
return 0;
}
esize -= (mid->tracks * 8);
byte *buf = mem_alloc((sizeof(mid_track) * mid->tracks) + esize, MEM_FILE);
mid->track = (mid_track*)buf;
buf += (sizeof(mid_track) * mid->tracks);
for(ushort trk = 0; trk < mid->tracks; trk++) {
memset((mid->track)+trk, 0, sizeof(mid_track));
if(fread(header, 1, 8, fd) != 8) {
err = feof(fd);
loge(LOG_IO, err == 0 ? STR_MID_EIO : STR_MID_EEOF, filename);
fclose(fd);
mem_free(mid->track);
return 0;
}
mid->track[trk].size = mid_read_uint32(header+4);
if(fread(buf, 1, mid->track[trk].size, fd) != mid->track[trk].size) {
err = feof(fd);
loge(LOG_IO, err == 0 ? STR_MID_EIO : STR_MID_EEOF, filename);
fclose(fd);
mem_free(mid->track);
return 0;
}
mid->track[trk].buffer = buf;
mid->track[trk].pos = 0;
mid->track[trk].wait = 0;
mid->track[trk].trknum = trk;
buf += mid->track[trk].size;
}
fclose(fd);
mid_settempo(mid, MID_DEFTEMPO);
return (sizeof(mid_track) * mid->tracks) + esize;
}
void mid_process_meta(mid_handle *mid, mid_track *trk) {
byte meta = midt_read_uint8(trk);
uint size = mid_read_vlen(trk);
switch(meta) {
case midmt_seqnum:
if(size == 0) {
mid_dlog(STR_MID_SEQNUMO, trk->trknum, trk->trknum);
return;
}
else if(size != 2) {
trk->pos += size;
snd_loge(STR_MID_METALEN, trk->trknum, meta, 2, size);
return;
}
mid_dlog(STR_MID_SEQNUM, trk->trknum, midt_read_uint16(trk));
return;
case midmt_text:
case midmt_copyright:
case midmt_trackname:
case midmt_instrname:
case midmt_lyric:
case midmt_marker:
case midmt_cuepoint: {
byte dt[size+1];
dt[size] = 0;
midt_read_var(trk, size, dt);
snd_logx("%d%s", meta, dt);
return;
}
case midmt_chnprefix:
if(size != 1) {
trk->pos += size;
snd_loge(STR_MID_METALEN, trk->trknum, meta, 1, size);
return;
}
mid_dlog(STR_MID_CHNPFX, trk->trknum, midt_read_uint8(trk));
return;
case midmt_endtrack:
trk->pos += size;
trk->ending = 1;
mid_dlog(STR_MID_END, trk->trknum);
return;
case midmt_tempo:
if(size != 3) {
trk->pos += size;
snd_loge(STR_MID_METALEN, trk->trknum, meta, 3, size);
return;
}
mid_settempo(mid, midt_read_uint24(trk));
mid_dlog(STR_MID_TEMPO, 60000000 / mid->uspb);
return;
case midmt_smpte:
if(size != 5) {
trk->pos += size;
snd_loge(STR_MID_METALEN, trk->trknum, meta, 5, size);
return;
}
trk->pos += 5;
mid_dlog(STR_MID_SMPTE);
return;
case midmt_timesig: {
if(size != 4) {
trk->pos += size;
snd_loge(STR_MID_METALEN, trk->trknum, meta, 4, size);
return;
}
byte n = midt_read_uint8(trk);
uint d = 1 << ((uint)midt_read_uint8(trk));
byte c = midt_read_uint8(trk);
byte b = midt_read_uint8(trk);
mid_dlog(STR_MID_TIMESIG, n, d, c, b);
return;
}
case midmt_keysig: {
if(size != 2) {
trk->pos += size;
snd_loge(STR_MID_METALEN, trk->trknum, meta, 2, size);
return;
}
int8_t s = midt_read_uint8(trk);
byte m = midt_read_uint8(trk);
mid_dlog(STR_MID_KEYSIG, s, (m == 0) ? "MAJOR" : ((m == 1) ? "MINOR" : "- ? -"));
return;
}
case midmt_seqspec: {
trk->pos += size;
mid_dlog(STR_MID_SEQDATA, trk->trknum, size);
return;
}
default:
trk->pos += size;
mid_dlog(STR_MID_UNKMETA, trk->trknum, meta, size);
return;
}
}
#ifndef MID_NOEVT
void mid_process(mid_handle *mid, mid_track *trk, bank_handle *bank, opl3_chip *chip) {
#else
void mid_process(mid_handle *mid, mid_track *trk) {
#endif
if(trk->pos >= trk->size) {
return;
}
byte status = trk->buffer[trk->pos++];
if((status & 0x80) == 0) {
status = trk->status;
trk->pos -= 1;
}
else {
trk->status = status;
}
if((status & 0xf0) != 0xf0) {
byte channel = status & 0x0f;
status &= 0xf0;
switch(status) {
case midev_noteoff: {
byte o_key = midt_read_uint8(trk);
byte o_velocity = midt_read_uint8(trk);
#ifndef MID_NOEVT
bank_noteoff(bank, chip, channel, o_key, o_velocity);
#endif
mid_dlog(STR_MID_NOTEOFF, channel+1, o_key, o_velocity);
break;
}
case midev_noteon: {
byte key = midt_read_uint8(trk);
byte velocity = midt_read_uint8(trk);
#ifndef MID_NOEVT
if(velocity == 0) {
bank_noteoff(bank, chip, channel, key, velocity);
}
else {
bank_noteon(bank, chip, channel, key, velocity);
}
#endif
mid_dlog(STR_MID_NOTEON, channel+1, key, velocity);
break;
}
case midev_aftertouch: {
byte pressure = midt_read_uint8(trk);
mid_dlog(STR_MID_PRESS, channel+1, pressure);
break;
}
case midev_control: {
byte control = midt_read_uint8(trk);
byte value = midt_read_uint8(trk);
#ifndef MID_NOEVT
bank_control(bank, chip, channel, control, value);
#endif
mid_dlog(STR_MID_CC, channel+1, control, value);
break;
}
case midev_progchg: {
byte program = midt_read_uint8(trk);
#ifndef MID_NOEVT
bank_progchange(bank, chip, channel, program);
#endif
mid_dlog(STR_MID_PROG, channel+1, program);
break;
}
case midev_chnpressure: {
byte cpressure = midt_read_uint8(trk);
mid_dlog(STR_MID_CPRESS, channel+1, cpressure);
break;
}
case midev_pitchbend: {
ushort pb = ((ushort)midt_read_uint8(trk)) | (((ushort)midt_read_uint8(trk)) << 7);
short pitch = ((short)pb) - 0x2000;
#ifndef MID_NOEVT
bank_pitchbend(bank, chip, channel, pitch);
#endif
mid_dlog(STR_MID_PITCH, channel+1, pitch);
break;
}
}
}
else {
switch(status) {
case midev_sysex: {
uint slen = mid_read_vlen(trk);
trk->pos += slen;
mid_dlog(STR_MID_SYSEX, slen);
break;
}
case midev_songpos:
mid_dlog(STR_MID_SONGPOS, ((ushort)midt_read_uint8(trk)) | (((ushort)midt_read_uint8(trk)) << 7));
break;
case midev_songsel:
mid_dlog(STR_MID_SONGSEL, midt_read_uint8(trk));
break;
case midev_tunereq:
mid_dlog(STR_MID_TUNE);
break;
case midev_endsysex: {
uint elen = mid_read_vlen(trk);
trk->pos += elen;
mid_dlog(STR_MID_ESYSEX, elen);
break;
}
case midev_clock:
case midev_start:
case midev_continue:
case midev_stop:
case midev_actsense:
mid_dlog(STR_MID_GENSTAT, status);
break;
case midev_meta:
mid_process_meta(mid, trk);
break;
default:
snd_loge(STR_MID_UNKSTAT, status);
break;
}
}
}
#ifndef MID_NOEVT
byte mid_tick(mid_handle *mid, bank_handle *bank, opl3_chip *chip) {
#else
byte mid_tick(mid_handle *mid) {
#endif
byte end = 1;
for(int trk = 0; trk < mid->tracks; trk++) {
mid_track *track = (mid->track)+trk;
if(track->ending) {
continue;
}
if(track->wait > 0) {
track->wait -= 1;
if(track->wait > 0) {
end = 0;
continue;
}
}
while(1) {
if(track->pos > 0) {
#ifndef MID_NOEVT
mid_process(mid, track, bank, chip);
#else
mid_process(mid, track);
#endif
if((track->ending ^ 1) && (track->pos >= track->size)) {
snd_loge(STR_MID_EEND, track->trknum);
track->ending = 1;
}
if(track->ending) {
break;
}
}
track->wait = mid_read_vlen(track);
if(track->wait > 0) {
break;
}
}
end &= track->ending;
}
return end ^ 1;
}