Further midi file support.

This commit is contained in:
jmsgrogan 2020-05-03 16:28:50 +01:00
parent 36826fa1d4
commit 4d5ca4d654
12 changed files with 739 additions and 200 deletions

View file

@ -6,12 +6,14 @@ list(APPEND audio_LIB_INCLUDES
midi/MidiTrack.cpp midi/MidiTrack.cpp
midi/MidiDocument.cpp midi/MidiDocument.cpp
midi/MidiEvent.cpp midi/MidiEvent.cpp
midi/MetaMidiEvent.cpp) midi/MetaMidiEvent.cpp
midi/MidiChannelEvent.cpp)
add_library(audio SHARED ${audio_LIB_INCLUDES}) add_library(audio SHARED ${audio_LIB_INCLUDES})
target_include_directories(audio PUBLIC target_include_directories(audio PUBLIC
"${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}"
"${PROJECT_SOURCE_DIR}/src/core/file_utilities"
"${PROJECT_SOURCE_DIR}/src/core/loggers" "${PROJECT_SOURCE_DIR}/src/core/loggers"
"${CMAKE_CURRENT_SOURCE_DIR}/audio_interfaces" "${CMAKE_CURRENT_SOURCE_DIR}/audio_interfaces"
"${CMAKE_CURRENT_SOURCE_DIR}/midi" "${CMAKE_CURRENT_SOURCE_DIR}/midi"

View file

@ -1,7 +1,55 @@
#include "MetaMidiEvent.h" #include "MetaMidiEvent.h"
MetaMidiEvent::MetaMidiEvent() MetaMidiEvent::MetaMidiEvent()
: MidiEvent() : MidiEvent(),
mType(Type::UNSET),
mLabel(),
mValue(0)
{ {
} }
std::shared_ptr<MetaMidiEvent> MetaMidiEvent::Create()
{
return std::make_shared<MetaMidiEvent>();
}
void MetaMidiEvent::SetValue(int value)
{
mValue = value;
}
bool MetaMidiEvent::IsTrackName(char c)
{
return (c & META_TRACK_NAME) == META_TRACK_NAME;
}
bool MetaMidiEvent::IsSetTempo(char c)
{
return (c & META_SET_TEMPO) == META_SET_TEMPO;
}
bool MetaMidiEvent::IsTimeSignature(char c)
{
return (c & META_TIME_SIG) == META_TIME_SIG;
}
void MetaMidiEvent::SetIsSetTempo()
{
mType = Type::SET_TEMPO;
}
void MetaMidiEvent::SetIsTrackName()
{
mType = Type::TRACK_NAME;
}
void MetaMidiEvent::SetIsTimeSignature()
{
mType = Type::TIME_SIGNATURE;
}
void MetaMidiEvent::SetLabel(const std::string& label)
{
mLabel = label;
}

View file

@ -1,8 +1,8 @@
#pragma once #pragma once
#include <string>
#include "MidiEvent.h" #include "MidiEvent.h"
#include <memory>
#include <string>
class MetaMidiEvent : public MidiEvent class MetaMidiEvent : public MidiEvent
{ {
@ -10,17 +10,40 @@ public:
enum class Type enum class Type
{ {
UNSET, UNSET,
TRACK_NAME TRACK_NAME,
SET_TEMPO,
TIME_SIGNATURE
}; };
Type mType = Type::UNSET; private:
std::string mLabel;
MetaMidiEvent();
static bool IsTrackName(char c)
{
return (c & META_TRACK_NAME) == META_TRACK_NAME;
}
static const int META_SET_TEMPO = 0x51; // 0101 0001
static const int META_TRACK_NAME = 0x3; // 0000 0011 static const int META_TRACK_NAME = 0x3; // 0000 0011
static const int META_TIME_SIG = 0x58; // 0101 1000
Type mType;
std::string mLabel;
int mValue;
public:
MetaMidiEvent();
static std::shared_ptr<MetaMidiEvent> Create();
void SetValue(int value);
void SetIsTrackName();
void SetIsSetTempo();
void SetIsTimeSignature();
void SetLabel(const std::string& label);
static bool IsTrackName(char c);
static bool IsSetTempo(char c);
static bool IsTimeSignature(char c);
}; };
using MetaMidiEventPtr = std::shared_ptr<MetaMidiEvent>;

View file

@ -0,0 +1,80 @@
#include "MidiChannelEvent.h"
MidiChannelEvent::MidiChannelEvent()
: MidiEvent(),
mType(Type::NONE),
mValue0(0),
mValue1(0)
{
}
std::shared_ptr<MidiChannelEvent> MidiChannelEvent::Create()
{
return std::make_shared<MidiChannelEvent>();
}
void MidiChannelEvent::SetType(Type type)
{
mType = type;
}
MidiChannelEvent::Type MidiChannelEvent::GetType()
{
return mType;
}
void MidiChannelEvent::SetValues(int value0, int value1)
{
mValue0 = value0;
mValue1 = value1;
}
int MidiChannelEvent::GetValue0()
{
return mValue0;
}
int MidiChannelEvent::GetValue1()
{
return mValue1;
}
bool MidiChannelEvent::IsControllerEvent(int c)
{
return (c & CONTROLLER) == CONTROLLER;
}
bool MidiChannelEvent::IsNoteOnEvent(int c)
{
return (c & NOTE_ON) == NOTE_ON;
}
bool MidiChannelEvent::IsNoteOffEvent(int c)
{
return (c & NOTE_OFF) == NOTE_OFF;
}
bool MidiChannelEvent::IsNoteAfterTouchEvent(int c)
{
return (c & NOTE_AFTERTOUCH) == NOTE_AFTERTOUCH;
}
bool MidiChannelEvent::IsProgramEvent(int c)
{
return (c & PROGRAM) == PROGRAM;
}
bool MidiChannelEvent::IsChannelAftertouchEvent(int c)
{
return (c & CHANNEL_AFTERTOUCH) == CHANNEL_AFTERTOUCH;
}
bool MidiChannelEvent::IsPitchbendEvent(int c)
{
return (c & PITCH_BEND) == PITCH_BEND;
}
bool MidiChannelEvent::IsStatusByte(int c)
{
return IsControllerEvent(c) || IsNoteOnEvent(c) ||
IsNoteOffEvent(c) || IsNoteAfterTouchEvent(c) ||
IsProgramEvent(c) || IsChannelAftertouchEvent(c) ||
IsPitchbendEvent(c);
}

View file

@ -0,0 +1,52 @@
#pragma once
#include "MidiEvent.h"
class MidiChannelEvent : public MidiEvent
{
public:
enum class Type{
NONE, NOTE_OFF, NOTE_ON, NOTE_AFTERTOUCH, CONTROLLER,
PROGRAM, CHANNEL_AFTERTOUCH, PITCH_BEND
};
private:
static const int NOTE_OFF = 0x8;
static const int NOTE_ON = 0x9;
static const int NOTE_AFTERTOUCH = 0xA;
static const int CONTROLLER = 0xB;
static const int PROGRAM = 0xC;
static const int CHANNEL_AFTERTOUCH = 0xD;
static const int PITCH_BEND = 0xE;
Type mType;
int mValue0;
int mValue1;
public:
MidiChannelEvent();
static std::shared_ptr<MidiChannelEvent> Create();
void SetType(Type type);
Type GetType();
void SetValues(int value0, int value1);
int GetValue0();
int GetValue1();
static bool IsControllerEvent(int c);
static bool IsNoteOnEvent(int c);
static bool IsNoteOffEvent(int c);
static bool IsNoteAfterTouchEvent(int c);
static bool IsProgramEvent(int c);
static bool IsChannelAftertouchEvent(int c);
static bool IsPitchbendEvent(int c);
static bool IsStatusByte(int c);
};
using MidiChannelEventPtr = std::shared_ptr<MidiChannelEvent>;

View file

@ -1,6 +1,37 @@
#include "MidiEvent.h" #include "MidiEvent.h"
MidiEvent::MidiEvent() MidiEvent::MidiEvent()
: mTimeDelta(0)
{ {
} }
void MidiEvent::SetTimeDelta(int delta)
{
mTimeDelta = delta;
}
std::shared_ptr<MidiEvent> MidiEvent::Create()
{
return std::make_shared<MidiEvent>();
}
bool MidiEvent::IsMetaEvent(char c)
{
return (c & META_EVENT) == META_EVENT;
}
bool MidiEvent::IsSysExEvent(char c)
{
return IsNormalSysExEvent(c) || IsDividedSysExEvent(c);
}
bool MidiEvent::IsNormalSysExEvent(char c)
{
return (c & SYSEX_EVENT) == SYSEX_EVENT;
}
bool MidiEvent::IsDividedSysExEvent(char c)
{
return (c & DIVIDED_SYSEX_EVENT) == DIVIDED_SYSEX_EVENT;
}

View file

@ -1,17 +1,26 @@
#pragma once #pragma once
#include <memory>
class MidiEvent class MidiEvent
{ {
public:
int mTimeDelta = 0;
MidiEvent();
static bool IsMetaEvent(char c)
{
return (c & META_EVENT) == META_EVENT;
}
public:
static const int META_EVENT = 0xFF; // 1111 1111 static const int META_EVENT = 0xFF; // 1111 1111
static const int SYSEX_EVENT = 0xF0;
static const int DIVIDED_SYSEX_EVENT = 0xF7;
int mTimeDelta;
public:
MidiEvent();
virtual ~MidiEvent() = default;
static std::shared_ptr<MidiEvent> Create();
void SetTimeDelta(int delta);
static bool IsMetaEvent(char c);
static bool IsSysExEvent(char c);
static bool IsNormalSysExEvent(char c);
static bool IsDividedSysExEvent(char c);
}; };
using MidiEventPtr = std::shared_ptr<MidiEvent>;

View file

@ -1,85 +1,57 @@
#include "MidiReader.h" #include "MidiReader.h"
#include "MidiDocument.h"
#include "ByteUtils.h"
#include "MidiTrack.h"
#include "BinaryFile.h"
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
#include <cstring> #include <cstring>
#include <bitset> #include <bitset>
#include "MidiDocument.h"
#include "ByteUtils.h"
#include "MidiTrack.h"
MidiReader::MidiReader() MidiReader::MidiReader()
:mDocument(),
mTrackByteCount(0),
mLastChannelEventType(MidiChannelEvent::Type::NONE)
{ {
} }
bool GetBytes(std::ifstream& file, char* buffer, unsigned number)
{
char c;
for(unsigned idx=0; idx<number; idx++)
{
if(file.get(c))
{
buffer[idx] = c;
}
else
{
return false;
}
}
return true;
}
bool GetWord(std::ifstream& file, char* buffer)
{
return GetBytes(file, buffer, 2);
}
bool GetDWord(std::ifstream& file, char* buffer)
{
return GetBytes(file, buffer, 4);
}
bool MidiReader::ProcessHeader(std::ifstream& file) bool MidiReader::ProcessHeader(std::ifstream& file)
{ {
char c; if(!BinaryFile::CheckNextDWord(file, HeaderLabel))
unsigned bufferSize = ByteUtils::BYTES_PER_DWORD;
char buffer[bufferSize];
if(!GetDWord(file, buffer))
{ {
return false; return false;
} }
if(!ByteUtils::CompareDWords(buffer, HeaderLabel)) int length = 0;
if(!BinaryFile::GetNextDWord(file, length))
{ {
return false; return false;
} }
if(!GetDWord(file, buffer)) if(!BinaryFile::GetNextWord(file, mDocument.mFormatType))
{ {
return false; return false;
} }
int length = ByteUtils::ToDWord(buffer); if(!BinaryFile::GetNextWord(file, mDocument.mExpectedTracks))
if(!GetWord(file, buffer))
{ {
return false; return false;
} }
mDocument.mFormatType = ByteUtils::ToWord(buffer);
if(!GetWord(file, buffer)) ProcessTimeDivision(file);
{ return true;
return false;
} }
mDocument.mExpectedTracks = ByteUtils::ToWord(buffer);
if(!GetWord(file, buffer)) bool MidiReader::ProcessTimeDivision(std::ifstream& file)
{ {
return false;
}
int time_division; int time_division;
std::memcpy(&time_division, buffer, sizeof(int)); if(!BinaryFile::GetNextWord(file, time_division, false))
{
return false;
}
const int TOP_7_BITS = 0x7F00; // 0111 1111 - 0000 0000 const int TOP_7_BITS = 0x7F00; // 0111 1111 - 0000 0000
mDocument.mUseFps = ByteUtils::GetWordFirstBit(time_division); mDocument.mUseFps = ByteUtils::GetWordFirstBit(time_division);
@ -92,16 +64,103 @@ int MidiReader::ProcessTimeDelta(std::ifstream& file)
{ {
char c; char c;
file.get(c); file.get(c);
bool needs_next = c & ByteUtils::BYTE_FIRST_BIT;
int time_offset = 0;
if(!needs_next)
{
time_offset = int(c);
mTrackByteCount ++; mTrackByteCount ++;
if(unsigned(c >> 7) == 0)
{
int delta = int(c);
std::cout << "Time delta final: " << delta << "|" << std::bitset<16>(c)<< std::endl;
return delta;
} }
std::cout << "Next " << needs_next <<std::endl;
std::cout << "Offset " << time_offset <<std::endl; int working_c = c;
return time_offset; int final_c = 0;
unsigned count = 0;
std::cout << "Working " << std::bitset<8>(working_c) << std::endl;
while(unsigned(working_c >> 7) != 0)
{
char corrected = (working_c &= ~(1UL << 7));
final_c <<= 7;
final_c |= (corrected << 7*count);
char file_c;
file.get(file_c);
mTrackByteCount ++;
working_c = int(file_c);
std::cout << "Working " << std::bitset<8>(working_c) << std::endl;
count ++;
}
std::cout << "Time delta start: " << std::bitset<16>(final_c) << std::endl;
final_c <<= 7;
std::cout << "Time delta pre: " << std::bitset<16>(final_c) << std::endl;
final_c |= (working_c << 7*(count-1));
int delta = int(final_c);
std::cout << "Time delta final: " << delta << "|" << std::bitset<16>(final_c)<< std::endl;
return delta;
}
bool MidiReader::ProcessTrackNameMetaEvent(std::ifstream& file, MetaMidiEvent& event)
{
event.SetIsTrackName();
int length = 0;
BinaryFile::GetNextByteAsInt(file, length);
mTrackByteCount ++;
std::string name;
BinaryFile::GetNextString(file, name, length);
mTrackByteCount += length;
std::cout << "Track name: " << name << "|" << length <<std::endl;
event.SetLabel(name);
return true;
}
bool MidiReader::ProcessSetTempoMetaEvent(std::ifstream& file, MetaMidiEvent& event)
{
event.SetIsSetTempo();
int length = 0;
BinaryFile::GetNextByteAsInt(file, length);
mTrackByteCount ++;
char buffer[length];
BinaryFile::GetNextNBytes(file, buffer, length);
mTrackByteCount += length;
int tempo = ByteUtils::ToInt(buffer, length);
const int MICROSECONDS_PER_MINUTE = 60000000;
std::cout << "Got tempo "<< tempo << "|" << MICROSECONDS_PER_MINUTE/tempo<< std::endl;
event.SetValue(tempo);
return true;
}
bool MidiReader::ProcessTimeSignatureMetaEvent(std::ifstream& file, MetaMidiEvent& event)
{
event.SetIsTimeSignature();
int length = 0;
BinaryFile::GetNextByteAsInt(file, length);
mTrackByteCount ++;
int numer = 0;
BinaryFile::GetNextByteAsInt(file, numer);
mTrackByteCount ++;
int denom = 0;
BinaryFile::GetNextByteAsInt(file, denom);
mTrackByteCount ++;
int metro = 0;
BinaryFile::GetNextByteAsInt(file, metro);
mTrackByteCount ++;
int f32s = 0;
BinaryFile::GetNextByteAsInt(file, f32s);
mTrackByteCount ++;
std::cout << "Time sig " << length << "|" << numer << "|" << denom << "|" << metro << "|" << f32s << std::endl;
return true;
} }
bool MidiReader::ProcessMetaEvent(std::ifstream& file, MetaMidiEvent& event) bool MidiReader::ProcessMetaEvent(std::ifstream& file, MetaMidiEvent& event)
@ -111,21 +170,15 @@ bool MidiReader::ProcessMetaEvent(std::ifstream& file, MetaMidiEvent& event)
mTrackByteCount ++; mTrackByteCount ++;
if(MetaMidiEvent::IsTrackName(c)) if(MetaMidiEvent::IsTrackName(c))
{ {
event.mType = MetaMidiEvent::Type::TRACK_NAME; ProcessTrackNameMetaEvent(file, event);
file.get(c);
mTrackByteCount ++;
int length = int(c);
std::string name;
std::cout << "Track name: " << length <<std::endl;
for(unsigned idx=0; idx<length; idx++)
{
file.get(c);
mTrackByteCount ++;
name += c;
} }
std::cout << name << std::endl; else if(MetaMidiEvent::IsSetTempo(c))
event.mLabel = "Track name"; {
ProcessSetTempoMetaEvent(file, event);
}
else if(MetaMidiEvent::IsTimeSignature(c))
{
ProcessTimeSignatureMetaEvent(file, event);
} }
else else
{ {
@ -135,59 +188,160 @@ bool MidiReader::ProcessMetaEvent(std::ifstream& file, MetaMidiEvent& event)
return true; return true;
} }
bool MidiReader::ProcessEvent(std::ifstream& file) bool MidiReader::ProcessMidiEventData(std::ifstream& file, MidiChannelEvent& event, char c)
{
int value0 = int(c);
int value1 = 0;
BinaryFile::GetNextByteAsInt(file, value1);
mTrackByteCount ++;
event.SetValues(value0, value1);
std::cout << "sdata: " << value0 << "|" << value1 << "|" << std::endl;
return true;
}
bool MidiReader::ProcessMidiEventData(std::ifstream& file, MidiChannelEvent& event)
{
int value0 = 0;
BinaryFile::GetNextByteAsInt(file, value0);
mTrackByteCount ++;
int value1 = 0;
BinaryFile::GetNextByteAsInt(file, value1);
mTrackByteCount ++;
event.SetValues(value0, value1);
std::cout << "data: " << value0 << "|" << value1 << "|" << std::endl;
return true;
}
bool MidiReader::ProcessMidiChannelEvent(std::ifstream& file, char firstByte, MidiChannelEvent& event)
{
int first_four_bits = 0xF0;
int second_four_bits = 0xF;
int event_type = (firstByte & first_four_bits) >> 4;
int midi_channel = (firstByte & second_four_bits) >> 4;
std::cout << "Channel: " << midi_channel << std::endl;
if(MidiChannelEvent::IsStatusByte(event_type))
{
if(MidiChannelEvent::IsControllerEvent(event_type))
{
event.SetType(MidiChannelEvent::Type::CONTROLLER);
mLastChannelEventType = MidiChannelEvent::Type::CONTROLLER;
std::cout << "Controller Event"<< std::endl;
ProcessMidiEventData(file, event);
}
else if(MidiChannelEvent::IsProgramEvent(event_type))
{
event.SetType(MidiChannelEvent::Type::PROGRAM);
mLastChannelEventType = MidiChannelEvent::Type::PROGRAM;
std::cout << "Program Event"<< std::endl;
int value0 = 0;
BinaryFile::GetNextByteAsInt(file, value0);
mTrackByteCount ++;
std::cout << "value " << value0 << std::endl;
}
else if(MidiChannelEvent::IsNoteOnEvent(event_type))
{
event.SetType(MidiChannelEvent::Type::NOTE_ON);
mLastChannelEventType = MidiChannelEvent::Type::NOTE_ON;
std::cout << "Note on Event"<< std::endl;
ProcessMidiEventData(file, event);
}
else if(MidiChannelEvent::IsNoteOffEvent(event_type))
{
event.SetType(MidiChannelEvent::Type::NOTE_OFF);
mLastChannelEventType = MidiChannelEvent::Type::NOTE_OFF;
std::cout << "Note off Event"<< std::endl;
ProcessMidiEventData(file, event);
}
else
{
std::cout << "Unknown status event: " << std::bitset<8>(firstByte) << "|" << event_type <<std::endl;
}
}
else
{
if(mLastChannelEventType == MidiChannelEvent::Type::CONTROLLER)
{
std::cout << "Controller running event: " <<std::endl;
ProcessMidiEventData(file, event, firstByte);
}
else if(mLastChannelEventType == MidiChannelEvent::Type::NOTE_ON)
{
std::cout << "Note on running event: " <<std::endl;
ProcessMidiEventData(file, event, firstByte);
}
else if(mLastChannelEventType == MidiChannelEvent::Type::NOTE_OFF)
{
std::cout << "Note off running event: " <<std::endl;
ProcessMidiEventData(file, event, firstByte);
}
else
{
std::cout << "Unknown running event: " <<std::endl;
}
}
return true;
}
bool MidiReader::ProcessEvent(std::ifstream& file, MidiTrack& track)
{ {
char c; char c;
int timeDelta = ProcessTimeDelta(file); int timeDelta = ProcessTimeDelta(file);
file.get(c); file.get(c);
std::cout << std::bitset<8>(c) << std::endl;
mTrackByteCount ++; mTrackByteCount ++;
if(MidiEvent::IsMetaEvent(c)) if(MidiEvent::IsMetaEvent(c))
{ {
MetaMidiEvent event; MetaMidiEvent event;
event.mTimeDelta = timeDelta; event.SetTimeDelta(timeDelta);
std::cout << "Meta event " <<std::endl; std::cout << "Meta event " <<std::endl;
ProcessMetaEvent(file, event); ProcessMetaEvent(file, event);
track.AddEvent(event);
}
else if(MidiEvent::IsSysExEvent(c))
{
std::cout << "Sysex event" << std::endl;
} }
else else
{ { // Midi event
int first_byte = 0xF0; MidiChannelEvent event;
int event_type = (c & first_byte) >> 4; event.SetTimeDelta(timeDelta);
std::cout << "Next " << std::bitset<8>(c) << "|" << event_type <<std::endl; std::cout << "Midi event" << std::endl;
std::cout << event_type << std::endl; ProcessMidiChannelEvent(file, c, event);
} }
return true; return true;
} }
bool MidiReader::ProcessTrackChunk(std::ifstream& file) bool MidiReader::ProcessTrackChunk(std::ifstream& file, bool debug)
{ {
char c; if(!BinaryFile::CheckNextDWord(file, TrackChunkLabel))
unsigned bufferSize = ByteUtils::BYTES_PER_DWORD;
char buffer[bufferSize];
if(!GetDWord(file, buffer))
{ {
return false; return false;
} }
if(!ByteUtils::CompareDWords(buffer, TrackChunkLabel)) int chunkSize = 0;
if(!BinaryFile::GetNextDWord(file, chunkSize))
{ {
return false; return false;
} }
if(!GetDWord(file, buffer))
{
return false;
}
int chunkSize = ByteUtils::ToDWord(buffer);
std::cout << "Chunk size: "<< chunkSize << std::endl; std::cout << "Chunk size: "<< chunkSize << std::endl;
mTrackByteCount = 0; mTrackByteCount = 0;
MidiTrack track; MidiTrack track;
ProcessEvent(file); unsigned iter_count = 0;
while(mTrackByteCount < chunkSize)
{
std::cout << "-------------" << std::endl;
ProcessEvent(file, track);
std::cout << "Track byte count: "<< mTrackByteCount << std::endl; std::cout << "Track byte count: "<< mTrackByteCount << std::endl;
if(debug && iter_count == 25)
ProcessEvent(file); {
return true;
}
iter_count ++;
}
mDocument.mTracks.push_back(track); mDocument.mTracks.push_back(track);
return true; return true;
@ -199,12 +353,26 @@ void MidiReader::Read(const std::string& path)
if(!ProcessHeader(file)) if(!ProcessHeader(file))
{ {
std::cout << "Problem processing header" << std::endl; std::cout << "Problem processing header" << std::endl;
return;
} }
int trackCount = 0;
if(!ProcessTrackChunk(file)) if(!ProcessTrackChunk(file))
{ {
std::cout << "Problem processing track chunk" << std::endl; std::cout << "Problem processing track chunk" << std::endl;
return;
} }
trackCount ++;
std::cout << "****************************************" << std::endl;
std::cout << "Track 2" << std::endl;
if(!ProcessTrackChunk(file, true))
{
std::cout << "Problem processing track chunk" << std::endl;
return;
}
trackCount ++;
file.close(); file.close();

View file

@ -2,6 +2,7 @@
#include "MidiDocument.h" #include "MidiDocument.h"
#include "MetaMidiEvent.h" #include "MetaMidiEvent.h"
#include "MidiChannelEvent.h"
#include <string> #include <string>
class MidiReader class MidiReader
@ -10,6 +11,7 @@ class MidiReader
static constexpr const char HeaderLabel[] = "MThd"; static constexpr const char HeaderLabel[] = "MThd";
MidiDocument mDocument; MidiDocument mDocument;
unsigned mTrackByteCount; unsigned mTrackByteCount;
MidiChannelEvent::Type mLastChannelEventType;
public: public:
@ -21,11 +23,21 @@ private:
bool ProcessHeader(std::ifstream& file); bool ProcessHeader(std::ifstream& file);
bool ProcessTrackChunk(std::ifstream& file); bool ProcessTimeDivision(std::ifstream& file);
bool ProcessEvent(std::ifstream& file); bool ProcessTrackChunk(std::ifstream& file, bool debug=false);
bool ProcessEvent(std::ifstream& file, MidiTrack& track);
bool ProcessMidiEventData(std::ifstream& file, MidiChannelEvent& event, char c);
bool ProcessMidiEventData(std::ifstream& file, MidiChannelEvent& event);
bool ProcessMidiChannelEvent(std::ifstream& file, char firstByte, MidiChannelEvent& event);
bool ProcessMetaEvent(std::ifstream& file, MetaMidiEvent& event); bool ProcessMetaEvent(std::ifstream& file, MetaMidiEvent& event);
int ProcessTimeDelta(std::ifstream& file); int ProcessTimeDelta(std::ifstream& file);
bool ProcessTrackNameMetaEvent(std::ifstream& file, MetaMidiEvent& event);
bool ProcessSetTempoMetaEvent(std::ifstream& file, MetaMidiEvent& event);
bool ProcessTimeSignatureMetaEvent(std::ifstream& file, MetaMidiEvent& event);
}; };

View file

@ -3,6 +3,7 @@ list(APPEND core_LIB_INCLUDES
Color.cpp Color.cpp
CommandLineArgs.cpp CommandLineArgs.cpp
loggers/FileLogger.cpp loggers/FileLogger.cpp
file_utilities/BinaryFile.cpp
StringUtils.cpp StringUtils.cpp
http/HttpResponse.cpp) http/HttpResponse.cpp)

View file

@ -0,0 +1,88 @@
#include "BinaryFile.h"
#include "ByteUtils.h"
bool BinaryFile::GetNextByteAsInt(std::ifstream& file, int& target)
{
char c;
file.get(c);
target = int(c);
return true;
}
bool BinaryFile::GetNextNBytes(std::ifstream& file, char* buffer, unsigned number)
{
char c;
for(unsigned idx=0; idx<number; idx++)
{
if(file.get(c))
{
buffer[idx] = c;
}
else
{
return false;
}
}
return true;
}
bool BinaryFile::GetNextWord(std::ifstream& file, char* buffer)
{
return GetNextNBytes(file, buffer, ByteUtils::BYTES_PER_WORD);
}
bool BinaryFile::GetNextDWord(std::ifstream& file, char* buffer)
{
return GetNextNBytes(file, buffer, ByteUtils::BYTES_PER_DWORD);
}
bool BinaryFile::GetNextWord(std::ifstream& file, int& target, bool reverse)
{
char buffer[ByteUtils::BYTES_PER_WORD];
if(!BinaryFile::GetNextWord(file, buffer))
{
return false;
}
target = ByteUtils::ToWord(buffer, reverse);
return true;
}
bool BinaryFile::GetNextDWord(std::ifstream& file, int& target)
{
char buffer[ByteUtils::BYTES_PER_DWORD];
if(!BinaryFile::GetNextDWord(file, buffer))
{
return false;
}
target = ByteUtils::ToDWord(buffer);
return true;
}
bool BinaryFile::CheckNextDWord(std::ifstream& file, const char* target)
{
char buffer[ByteUtils::BYTES_PER_DWORD];
if(!BinaryFile::GetNextDWord(file, buffer))
{
return false;
}
if(!ByteUtils::CompareDWords(buffer, target))
{
return false;
}
return true;
}
bool BinaryFile::GetNextString(std::ifstream& file, std::string& target, unsigned numBytes)
{
char c;
for(unsigned idx=0; idx<numBytes; idx++)
{
if(!file.get(c))
{
return false;
}
target += c;
}
return true;
}

View file

@ -0,0 +1,25 @@
#pragma once
#include <fstream>
#include <string>
class BinaryFile
{
public:
static bool GetNextByteAsInt(std::ifstream& file, int& target);
static bool GetNextNBytes(std::ifstream& file, char* buffer, unsigned numBytes);
static bool GetNextWord(std::ifstream& file, char* buffer);
static bool GetNextDWord(std::ifstream& file, char* buffer);
static bool GetNextWord(std::ifstream& file, int& target, bool reverse = true);
static bool GetNextDWord(std::ifstream& file, int& target);
static bool CheckNextDWord(std::ifstream& file, const char* target);
static bool GetNextString(std::ifstream& file, std::string& target, unsigned numBytes);
};