So i have this code (dont judge the class instead of namespace and the namespace globals):
#include <iostream>
#include <fstream>
#include <windows.h>
#include <cmath>
namespace Global
{
int m_BPM = 0;
}
class Midi
{
public:
static void WriteVarLength(std::ofstream& file, int value)
{
int buffer[4];
int i = 0;
do {
buffer[i++] = value & 0x7F;
value >>= 7;
} while (value > 0);
for (int j = i - 1; j >= 0; j--) {
if (j > 0) {
buffer[j] |= 0x80;
}
file.put(static_cast<char>(buffer[j]));
}
}
static void WriteHChunk(std::ofstream& file, int format, int nTracks, int division)
{
file.write("MThd",4);
file.put(0x00);
file.put(0x00);
file.put(0x00);
file.put(0x06);
if (format == 0 || format == 1 || format == 2)
{
file.put(static_cast<char>(format >> 8));
file.put(static_cast<char>(format));
}
else {
MessageBox(
nullptr,
(LPCSTR)L"Invalid format number.",
(LPCSTR)L"MidiSaver",
MB_ICONERROR | MB_OK
);
exit(1);
}
file.put(static_cast<char>(nTracks >> 8));
file.put(static_cast<char>(nTracks));
file.put(static_cast<char>(division >> 8));
file.put(static_cast<char>(division));
}
static std::streampos WriteTrackChunk(std::ofstream& file)
{
file.write("MTrk", 4);
std::streampos pos = file.tellp();
std::cout << "TrackLengthpos: " << pos << std::endl;
file.put(0x00);
file.put(0x00);
file.put(0x00);
file.put(0x00);
return pos;
}
static void MetaEventBPM(std::ofstream& file, int m_BPM)
{
int tempo = 60000000 / m_BPM;
file.put(static_cast<char>(0xFF));
file.put(static_cast<char>(0x51));
file.put(static_cast<char>(0x03));
file.put(static_cast<char>(tempo >> 16));
file.put(static_cast<char>(tempo >> 8));
file.put(static_cast<char>(tempo));
}
static void MetaEndTrack(std::ofstream& file)
{
file.put(0x00);
file.put(static_cast<char>(0xFF));
file.put(0x2F);
file.put(0x00);
}
static void DeltaEvent(std::ofstream& file, int delta)
{
int size = 1;
for (int d = delta; d >= 128; d >>= 7) size++;
for (int i = size - 1; i >= 0; i--) {
int shift = i * 7;
int mask = (i == size - 1) ? 0x7F : 0xFF;
file.put(static_cast<char>(((delta >> shift) & mask) | (i > 0 ? 0x80 : 0x00)));
}
}
static void CalTHeaderLength(std::ofstream& file, std::streampos trackLengthPos) {
std::streampos currentPos = file.tellp();
file.seekp(0, std::ios::end);
uint32_t trackLength = file.tellp() - trackLengthPos - 8;
file.seekp(trackLengthPos);
file.put(static_cast<char>(trackLength >> 24));
file.put(static_cast<char>(trackLength >> 16));
file.put(static_cast<char>(trackLength >> 8));
file.put(static_cast<char>(trackLength));
file.seekp(currentPos);
}
static void EventNoteOn(std::ofstream& file, int delta_time, int note, int velocity, int channel)
{
DeltaEvent(file, delta_time);
int statusByte = 0x90 | (channel & 0x0F);
file.put(static_cast<char>(statusByte));
file.put(static_cast<char>(note));
file.put(static_cast<char>(velocity));
}
static void EventNoteOff(std::ofstream& file, int delta_time, int note, int channel)
{
DeltaEvent(file, delta_time);
int statusByte = 0x80 | (channel & 0x0F);
file.put(static_cast<char>(statusByte));
file.put(static_cast<char>(note));
file.put(0x00);
}
};
int main()
{
Global::m_BPM = 170;
std::string filename = "test.mid";
std::ofstream file(filename, std::ios::binary);
int format = 0;
int nTracks = 1;
int division = 96;
Midi::WriteHChunk(file, format, nTracks, division);
std::streampos trackLengthPos = Midi::WriteTrackChunk(file);
std::cout << "trackLengthPos value: " << trackLengthPos << std::endl;
Midi::MetaEventBPM(file, Global::m_BPM);
Midi::EventNoteOn(file, 0, 60, 127, 0);
Midi::EventNoteOff(file, 96, 60, 0);
Midi::MetaEndTrack(file);
Midi::CalTHeaderLength(file, trackLengthPos);
file.close();
}
The code is supposed to generate a .mid file that creates a C5 note at the beginning of the file, and last a quarter note (96ticks) However there is a weird issue i can't really fix for some reason The C5 note is starting at the half of the 56th bar and also is misaligned. I don't know what can cause this, but the BPM is also for some reason wrong. The intended BPM is 170, but on FL Studio 20, it's 140 BPM and on OpenMPT, it's a default BPM value, 120.
Here's the hex of the .mid file generated by my program, if it helps: 0x4D, 0x54, 0x68, 0x64, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x60, 0x4D, 0x54, 0x72, 0x6B, 0x00, 0x00, 0x00, 0x0E, 0xFF, 0x51, 0x03, 0x05, 0x62, 0xAD, 0x00, 0x90, 0x3C, 0x7F, 0x60, 0x80, 0x3C, 0x00, 0x00, 0xFF, 0x2F, 0x00
Thanks for any help.
I tried fixing it with this: changed how delta-time is being written on NoteOn and NoteOff functions, 3 variations i think, one made it generate on 1976th bar of the file changed the midi header function a bit