Created
August 2, 2020 09:02
-
-
Save hezi/08387cda0649a7e01ff3e682b2a86eaa to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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