Hey all,
I am trying to use a third-party MIDI source library and files and I have a few questions on it. I did contact the guy who wrote the source files but have not had a reply and was wondering if someone could quickly answer a few queries on it so i can get it working as soon as i can as my hand-in date is looming fast..
I am trying to use CraigSapp MidiFile from here:
https://github.com/craigsapp/midifile
I am currently writing a C++ console-based application for a music sequencer for my degree and wanted to utilise saving the info to a MIDI file..
Below is the code I adapted from his code at
https://github.com/craigsapp/midifile/blob/master/src-programs/createmidifile.cpp
Not included in the code here (and to give you a basic background on the program and any variable shown):
• The user enters note values and duration (in quarter notes or fractions thereof (1 bar, beat, 16th of a bar etc) but is also expressed in milliseconds in another variable which may be easier to use)..
• These note values (C8 or G#7) are converted to MIDI numbers..
• The MIDI numbers are added to an array of vectors (NOTE_MIDINUM[]) – one vector for each track (melody)..
• Likewise for the durations – the ms values are in the vectors NOTE_DURATION_MS..
• NUMBER_OF_MELODIES is simply an integer value for the number of tracks..
• FULL_MIDI_PATH is simply a string value for the path and filename of the .mid file..
• The variable counter i = 0 – counter is a typedef for unsigned ints used in loops..
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
|
// FUNCTION: CREATE MIDI DATA..
/* CODE SUPPLIED (BUT EDITED TO SUIT) FROM CRAIGSAPP MIDIFILE: https://github.com/craigsapp/midifile */
void CREATE_MIDI()
{
MidiFile outputfile; // CREATE AN EMPTY MIDI FILE WITH ONE TRACK..
outputfile.absoluteTicks(); // TIME INFO STORED AS ABSOLUTE TIME..
outputfile.addTrack(NUMBER_OF_MELODIES -1); // ADD ALL CURRENT MELODIES (-1 AS WE ALREADY HAVE ONE TRACK)..
vector<uchar> midievent; // TEMP STORAGE FOR MIDI EVENTS..
midievent.resize(3); // SET THE ARRAY SIZE TO 3 BYTES..
int tpq = 120; // default value in MIDI file is 48
outputfile.setTicksPerQuarterNote(tpq);
// store a melody line in track 1 (track 0 left empty for conductor info)
int i = 0;
int actiontime = 0; // temporary storage for MIDI event time
midievent[2] = 64; // store attack/release velocity for note command..
// FOR: LOOP AROUND NUMBER OF MELODIES..
for (counter i = 0; i < NUMBER_OF_MELODIES; ++i)
{
// FOR: LOOP ROUND NUMBER OF NOTES IN EACH MELODY..
for (counter j = 0; j < NOTE_MIDINUM[i].size(); ++j)
{
midievent[i] = 0x90; // STORE 'NOTE-ON' COMMAND (ON MIDI CHANNEL 1)..
midievent[i+1] = NOTE_MIDINUM[i][j]; // ADD MELODY MIDI NUMBER INFO..
outputfile.addEvent(1, actiontime, midievent); // APPEND THE MIDI EVENT TO THE FILE..
actiontime += tpq * NOTE_DURATION_MS[i][j]; // CALCULATE TIMINGS AND APPEND FOR EACH NOTE..
midievent[i] = 0x80; // STORE 'NOTE-OFF' COMMAND (ON MIDI CHANNEL 1)..
outputfile.addEvent(1, actiontime, midievent); // APPEND THE MIDI EVENT TO THE FILE..
actiontime = 0; //RESET ACTIONTIME..
}
// END FOR..
}
// END FOR..
outputfile.sortTracks(); // ORGANISE DATA INTO CORRECT ORDER..
outputfile.write(FULL_MIDI_PATH); // WRITE STANDARD MIDI FILE..
}
// END FUNCTION..
|
The questions are as follows:
1: Firstly, in the original code he shows, he has:
1 2
|
int melody[50] = { 72,72,79,79,81,81,79,77,77,76,76,74,74,72,-1 };
int mrhythm[50] = { 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2,-1 };
|
I was wondering what does the -1 mean at the end of these arrays and why?
For the mrhythm, what are these values expressed in? What units? Seconds? Quarter notes?
If I wanted to use milliseconds, what would I need to change in the code above?
2: Do I need to include the MIDI file header / command byte etc? Or is the code as above sufficient? In one area he shows how to create the header but in his code example its not there.
If I do, what does the following mean? (from the page
http://midifile.sapp.org/class/MidiFile/):
1 2 3 4 5
|
// 1. The characters "MThd"
ch = 'M'; out << ch;
ch = 'T'; out << ch;
ch = 'h'; out << ch;
ch = 'd'; out << ch;
|
3: Even though I have all the header files in my program directory, I have only included #include “MidiFile.h” – do I need to include them all?
I did check all the header files and they are include guarded with usual #ifndef macro. When compiling, I get the following errors:
1 2 3 4
|
Severity Code Description Project File Line
Error LNK1120 8 unresolved externals with:
Error LNK2019 unresolved external symbol "public: int __thiscall MidiFile::addEvent(int,int,class std::vector<unsigned char,class std::allocator<unsigned char> > &)" (?addEvent@MidiFile@@QAEHHHAAV?$vector@EV?$allocator@E@std@@@std@@@Z) referenced in function "void __cdecl CREATE_MIDI(void)" (?CREATE_MIDI@@YAXXZ) SPMA - Assignment 1 - 4591930 EPM C:\Users\Paul\Desktop\Uni Stuff - YEAR 2\SOFTWARE PROGRAMMING\Assignments\Assignment 1\SPMA - Assignment 1 - 4591930 EPM\Main.obj 1
|
Many thanks,
Paul..