Skip to content

Instantly share code, notes, and snippets.

@hezi
Created August 2, 2020 09:02
Show Gist options
  • Save hezi/08387cda0649a7e01ff3e682b2a86eaa to your computer and use it in GitHub Desktop.
Save hezi/08387cda0649a7e01ff3e682b2a86eaa to your computer and use it in GitHub Desktop.
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#pragma pack(push, 1)
typedef struct {
char magic[6];
unsigned short iInstrumentBlockOffset;
unsigned short iMusicOffset;
unsigned short iTicksPerQuarterNote;
unsigned short iTicksPerSecond;
unsigned short iTagOffsetTitle;
unsigned short iTagOffsetComposer;
unsigned short iTagOffsetRemarks;
char iChannelsInUse[16];
unsigned short iNumInstruments;
unsigned short iTempo;
} CMFHEADER;
#define MIDI_SINGLE 0
#define MIDI_MULTIPLE 1
#define MIDI_PATTERN 2
typedef struct
{
char m_magic[4];
unsigned int m_seclen;
short m_format;
short m_ntracks;
short m_tickdiv;
} MidiHeader;
#pragma pack(pop)
int fsize(FILE *fp) {
int prev = ftell(fp);
fseek(fp, 0L, SEEK_END);
int sz = ftell(fp);
fseek(fp, prev, SEEK_SET);
return sz;
}
int main(int argc, char *argv[]) {
if (argc != 2) {
printf("Usage: convcmf <file>\n\n");
return 1;
}
CMFHEADER cmf;
char buffer[1024*1024];
FILE *fcmf;
fcmf = fopen(argv[1], "rb");
int cmf_size = fsize(fcmf);
// get header
fread(&cmf, sizeof(CMFHEADER), 1, fcmf);
// get music
fseek(fcmf, cmf.iMusicOffset, SEEK_SET);
fread(&buffer, 1, cmf_size - cmf.iMusicOffset, fcmf);
fclose(fcmf);
// write midi
FILE *f = fopen("output.mid", "wb");
MidiHeader header;
memcpy(header.m_magic, "MThd", 4);
header.m_seclen = ntohl(6);
header.m_format = MIDI_SINGLE;
header.m_ntracks = ntohs(1); // always one track in cmf
header.m_tickdiv = ntohs(cmf.iTicksPerQuarterNote);
fwrite(&header, sizeof(MidiHeader), 1, f);
// track
fwrite("MTrk", 4, 1, f);
char tempo_message[7] = {0x00, 0xFF, 0x51, 0x03, 0x00, 0x00, 0x00};
int usecPerQuarterNote = ntohl((60.0/cmf.iTempo) * 1000000.0); // Quarter note = 60 / BPM
memcpy(&tempo_message[4], (char*)&usecPerQuarterNote+1, 3); // why?
int track_len = ntohl(cmf_size - cmf.iMusicOffset + sizeof(tempo_message) + 1);
fwrite(&track_len, sizeof(int), 1, f);
fwrite(&tempo_message, sizeof(tempo_message), 1, f);
fwrite(&buffer, 1, cmf_size - cmf.iMusicOffset+1, f);
fclose(f);
printf("wrote output.mid. done.\n");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment