Start midi file processing.
This commit is contained in:
parent
59c6161fdb
commit
36826fa1d4
22 changed files with 528 additions and 44 deletions
10
README.md
Normal file
10
README.md
Normal file
|
@ -0,0 +1,10 @@
|
|||
# MediaTool
|
||||
Hobby project - the idea is to build a set of multimedia tools 'from scratch' in C++ for fun/practice.
|
||||
|
||||
```bash
|
||||
mkdir build
|
||||
cd build
|
||||
cmake $PATH_TO_SOURCE
|
||||
make
|
||||
apps/$NAME_OF_APP
|
||||
```
|
|
@ -19,9 +19,9 @@ target_link_libraries(sample_console PUBLIC console core network
|
|||
add_executable(xml_practice xml-practice.cpp)
|
||||
target_include_directories(xml_practice PUBLIC
|
||||
"${PROJECT_SOURCE_DIR}/src/core"
|
||||
"${PROJECT_SOURCE_DIR}/src/core/xml"
|
||||
"${PROJECT_SOURCE_DIR}/src/web/xml"
|
||||
)
|
||||
target_link_libraries(xml_practice PUBLIC core)
|
||||
target_link_libraries(xml_practice PUBLIC core web)
|
||||
|
||||
# Markdown practice
|
||||
add_executable(markdown_practice markdown-practice.cpp)
|
||||
|
|
|
@ -1,16 +1,37 @@
|
|||
#include <filesystem>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <iostream>
|
||||
#include "CommandLineArgs.h"
|
||||
#include "MainApplication.h"
|
||||
|
||||
int main()
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
CommandLineArgs command_line_args;
|
||||
command_line_args.Process(argc, argv);
|
||||
|
||||
std::string program_type;
|
||||
if(command_line_args.GetNumberOfArgs() > 1)
|
||||
{
|
||||
program_type = command_line_args.GetArg(1);
|
||||
}
|
||||
|
||||
// Start the main app
|
||||
auto main_app = MainApplication::Create();
|
||||
main_app->Initialize(std::filesystem::current_path());
|
||||
|
||||
//main_app->RunServer();
|
||||
if(program_type == "server")
|
||||
{
|
||||
main_app->RunServer();
|
||||
}
|
||||
else if(program_type == "audio")
|
||||
{
|
||||
main_app->PlayAudio();
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Unknown program type" << std::endl;
|
||||
}
|
||||
|
||||
main_app->ShutDown();
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,13 +1,20 @@
|
|||
list(APPEND audio_LIB_INCLUDES
|
||||
AudioDevice.cpp
|
||||
AudioManager.cpp
|
||||
audio_interfaces/AlsaInterface.cpp)
|
||||
audio_interfaces/AlsaInterface.cpp
|
||||
midi/MidiReader.cpp
|
||||
midi/MidiTrack.cpp
|
||||
midi/MidiDocument.cpp
|
||||
midi/MidiEvent.cpp
|
||||
midi/MetaMidiEvent.cpp)
|
||||
|
||||
|
||||
add_library(audio SHARED ${audio_LIB_INCLUDES})
|
||||
target_include_directories(audio PUBLIC
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
"${PROJECT_SOURCE_DIR}/src/core/loggers"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/audio_interfaces"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/midi"
|
||||
)
|
||||
|
||||
target_link_libraries(audio PUBLIC asound)
|
||||
target_link_libraries(audio PUBLIC core asound)
|
|
@ -1,6 +1,5 @@
|
|||
#include "AlsaInterface.h"
|
||||
|
||||
#include <iostream>
|
||||
#include "FileLogger.h"
|
||||
|
||||
AlsaInterface::AlsaInterface()
|
||||
:mHandle(),
|
||||
|
@ -22,17 +21,18 @@ std::shared_ptr<AlsaInterface> AlsaInterface::Create()
|
|||
|
||||
void AlsaInterface::OpenDevice(AudioDevicePtr device)
|
||||
{
|
||||
MLOG_INFO("Opening Device");
|
||||
snd_pcm_stream_t stream = SND_PCM_STREAM_PLAYBACK;
|
||||
if (snd_pcm_open(&mHandle, device->GetName().c_str(), stream, 0) < 0)
|
||||
{
|
||||
std::cerr << "Error opening PCM device: " << device->GetName() << std::endl;
|
||||
MLOG_ERROR("Error opening PCM device: " + device->GetName());
|
||||
return;
|
||||
}
|
||||
|
||||
snd_pcm_hw_params_alloca(&mHardwareParams);
|
||||
if (snd_pcm_hw_params_any(mHandle, mHardwareParams) < 0)
|
||||
{
|
||||
std::cerr << "Can not configure this PCM device.\n" << std::endl;
|
||||
MLOG_ERROR("Can not configure this PCM device.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -46,7 +46,7 @@ void AlsaInterface::OpenDevice(AudioDevicePtr device)
|
|||
/* Apply HW parameter settings to */
|
||||
/* PCM device and prepare device */
|
||||
if (snd_pcm_hw_params(mHandle, mHardwareParams) < 0) {
|
||||
std::cerr << "Error setting HW params." << std::endl;
|
||||
MLOG_ERROR("Error setting HW params.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ void AlsaInterface::OpenDevice(AudioDevicePtr device)
|
|||
void AlsaInterface::SetAccessType(AudioDevicePtr device)
|
||||
{
|
||||
if (snd_pcm_hw_params_set_access(mHandle, mHardwareParams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
|
||||
std::cerr << "Error setting device access." << std::endl;
|
||||
MLOG_ERROR("Error setting device access.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ void AlsaInterface::SetSampleFormat(AudioDevicePtr device)
|
|||
{
|
||||
/* Set sample format */
|
||||
if (snd_pcm_hw_params_set_format(mHandle, mHardwareParams, SND_PCM_FORMAT_S16_LE) < 0) {
|
||||
std::cerr << "Error setting format. " << std::endl;
|
||||
MLOG_ERROR("Error setting format. ");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -74,11 +74,11 @@ void AlsaInterface::SetSampleRate(AudioDevicePtr device)
|
|||
unsigned exact_rate = rate;
|
||||
if (snd_pcm_hw_params_set_rate_near(mHandle, mHardwareParams, &exact_rate, 0) < 0)
|
||||
{
|
||||
std::cerr << "Error setting rate. " << std::endl;
|
||||
MLOG_ERROR("Error setting rate. ");
|
||||
return;
|
||||
}
|
||||
if (rate != exact_rate) {
|
||||
std::cerr << "The rate is not supported by your hardware." << std::endl;
|
||||
MLOG_ERROR("The rate is not supported by your hardware.");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -87,7 +87,7 @@ void AlsaInterface::SetPeriod(AudioDevicePtr device)
|
|||
/* Set number of periods. Periods used to be called fragments. */
|
||||
if (snd_pcm_hw_params_set_periods(mHandle, mHardwareParams, device->GetPeriod(), 0) < 0)
|
||||
{
|
||||
std::cerr << "Error setting periods. " << std::endl;
|
||||
MLOG_ERROR("Error setting periods. ");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -101,7 +101,7 @@ void AlsaInterface::SetBufferSize(AudioDevicePtr device)
|
|||
/* latency = periodsize * periods / (rate * bytes_per_frame) */
|
||||
if (snd_pcm_hw_params_set_buffer_size(mHandle, mHardwareParams, (mPeriodSize * periods)>>2) < 0)
|
||||
{
|
||||
std::cerr << "Error setting buffersize. " << std::endl;
|
||||
MLOG_ERROR("Error setting buffersize. ");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -111,13 +111,14 @@ void AlsaInterface::SetChannelNumber(AudioDevicePtr device)
|
|||
/* Set number of channels */
|
||||
if (snd_pcm_hw_params_set_channels(mHandle, mHardwareParams, device->GetNumChannels()) < 0)
|
||||
{
|
||||
std::cout << "Error setting channels" << std::endl;
|
||||
MLOG_ERROR("Error setting channels");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void AlsaInterface::Play(AudioDevicePtr device)
|
||||
{
|
||||
MLOG_INFO("Playing audio");
|
||||
int num_frames = 10;
|
||||
unsigned char *data = (unsigned char *)malloc(mPeriodSize);
|
||||
int frames = mPeriodSize >> 2;
|
||||
|
@ -135,7 +136,7 @@ void AlsaInterface::Play(AudioDevicePtr device)
|
|||
while ((snd_pcm_writei(mHandle, data, frames)) < 0)
|
||||
{
|
||||
snd_pcm_prepare(mHandle);
|
||||
fprintf(stderr, "<<<<<<<<<<<<<<< Buffer Underrun >>>>>>>>>>>>>>>\n");
|
||||
MLOG_ERROR("<<<<<<<<<<<<<<< Buffer Underrun >>>>>>>>>>>>>>>");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
7
src/audio/midi/MetaMidiEvent.cpp
Normal file
7
src/audio/midi/MetaMidiEvent.cpp
Normal file
|
@ -0,0 +1,7 @@
|
|||
#include "MetaMidiEvent.h"
|
||||
|
||||
MetaMidiEvent::MetaMidiEvent()
|
||||
: MidiEvent()
|
||||
{
|
||||
|
||||
}
|
26
src/audio/midi/MetaMidiEvent.h
Normal file
26
src/audio/midi/MetaMidiEvent.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "MidiEvent.h"
|
||||
|
||||
class MetaMidiEvent : public MidiEvent
|
||||
{
|
||||
public:
|
||||
enum class Type
|
||||
{
|
||||
UNSET,
|
||||
TRACK_NAME
|
||||
};
|
||||
|
||||
Type mType = Type::UNSET;
|
||||
std::string mLabel;
|
||||
MetaMidiEvent();
|
||||
|
||||
static bool IsTrackName(char c)
|
||||
{
|
||||
return (c & META_TRACK_NAME) == META_TRACK_NAME;
|
||||
}
|
||||
|
||||
static const int META_TRACK_NAME = 0x3; // 0000 0011
|
||||
};
|
6
src/audio/midi/MidiDocument.cpp
Normal file
6
src/audio/midi/MidiDocument.cpp
Normal file
|
@ -0,0 +1,6 @@
|
|||
#include "MidiDocument.h"
|
||||
|
||||
MidiDocument::MidiDocument()
|
||||
{
|
||||
|
||||
}
|
16
src/audio/midi/MidiDocument.h
Normal file
16
src/audio/midi/MidiDocument.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "MidiTrack.h"
|
||||
|
||||
class MidiDocument
|
||||
{
|
||||
public:
|
||||
int mFormatType = 0;
|
||||
int mExpectedTracks = 0;
|
||||
bool mUseFps = true;
|
||||
int mFps = 0;
|
||||
int ticksPerFrame = 0;
|
||||
std::vector<MidiTrack> mTracks;
|
||||
MidiDocument();
|
||||
};
|
6
src/audio/midi/MidiEvent.cpp
Normal file
6
src/audio/midi/MidiEvent.cpp
Normal file
|
@ -0,0 +1,6 @@
|
|||
#include "MidiEvent.h"
|
||||
|
||||
MidiEvent::MidiEvent()
|
||||
{
|
||||
|
||||
}
|
17
src/audio/midi/MidiEvent.h
Normal file
17
src/audio/midi/MidiEvent.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
#pragma once
|
||||
|
||||
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
|
||||
};
|
211
src/audio/midi/MidiReader.cpp
Normal file
211
src/audio/midi/MidiReader.cpp
Normal file
|
@ -0,0 +1,211 @@
|
|||
#include "MidiReader.h"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
#include <bitset>
|
||||
#include "MidiDocument.h"
|
||||
#include "ByteUtils.h"
|
||||
#include "MidiTrack.h"
|
||||
|
||||
MidiReader::MidiReader()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
char c;
|
||||
unsigned bufferSize = ByteUtils::BYTES_PER_DWORD;
|
||||
char buffer[bufferSize];
|
||||
|
||||
if(!GetDWord(file, buffer))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!ByteUtils::CompareDWords(buffer, HeaderLabel))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!GetDWord(file, buffer))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int length = ByteUtils::ToDWord(buffer);
|
||||
|
||||
if(!GetWord(file, buffer))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
mDocument.mFormatType = ByteUtils::ToWord(buffer);
|
||||
|
||||
if(!GetWord(file, buffer))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
mDocument.mExpectedTracks = ByteUtils::ToWord(buffer);
|
||||
|
||||
if(!GetWord(file, buffer))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
int time_division;
|
||||
std::memcpy(&time_division, buffer, sizeof(int));
|
||||
|
||||
const int TOP_7_BITS = 0x7F00; // 0111 1111 - 0000 0000
|
||||
mDocument.mUseFps = ByteUtils::GetWordFirstBit(time_division);
|
||||
mDocument.mFps = ((~time_division & TOP_7_BITS) >> 8) - 1; // Reverse 2complement of next 7 bits
|
||||
mDocument.ticksPerFrame = ByteUtils::GetWordLastByte(time_division);
|
||||
return true;
|
||||
}
|
||||
|
||||
int MidiReader::ProcessTimeDelta(std::ifstream& file)
|
||||
{
|
||||
char c;
|
||||
file.get(c);
|
||||
bool needs_next = c & ByteUtils::BYTE_FIRST_BIT;
|
||||
int time_offset = 0;
|
||||
if(!needs_next)
|
||||
{
|
||||
time_offset = int(c);
|
||||
mTrackByteCount ++;
|
||||
}
|
||||
std::cout << "Next " << needs_next <<std::endl;
|
||||
std::cout << "Offset " << time_offset <<std::endl;
|
||||
return time_offset;
|
||||
}
|
||||
|
||||
bool MidiReader::ProcessMetaEvent(std::ifstream& file, MetaMidiEvent& event)
|
||||
{
|
||||
char c;
|
||||
file.get(c);
|
||||
mTrackByteCount ++;
|
||||
if(MetaMidiEvent::IsTrackName(c))
|
||||
{
|
||||
event.mType = MetaMidiEvent::Type::TRACK_NAME;
|
||||
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;
|
||||
event.mLabel = "Track name";
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "something else" << std::endl;
|
||||
std::cout << "Next " << std::bitset<8>(c) << "|" <<std::endl;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MidiReader::ProcessEvent(std::ifstream& file)
|
||||
{
|
||||
char c;
|
||||
int timeDelta = ProcessTimeDelta(file);
|
||||
|
||||
file.get(c);
|
||||
mTrackByteCount ++;
|
||||
if(MidiEvent::IsMetaEvent(c))
|
||||
{
|
||||
MetaMidiEvent event;
|
||||
event.mTimeDelta = timeDelta;
|
||||
std::cout << "Meta event " <<std::endl;
|
||||
ProcessMetaEvent(file, event);
|
||||
}
|
||||
else
|
||||
{
|
||||
int first_byte = 0xF0;
|
||||
int event_type = (c & first_byte) >> 4;
|
||||
std::cout << "Next " << std::bitset<8>(c) << "|" << event_type <<std::endl;
|
||||
std::cout << event_type << std::endl;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MidiReader::ProcessTrackChunk(std::ifstream& file)
|
||||
{
|
||||
char c;
|
||||
unsigned bufferSize = ByteUtils::BYTES_PER_DWORD;
|
||||
char buffer[bufferSize];
|
||||
|
||||
if(!GetDWord(file, buffer))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!ByteUtils::CompareDWords(buffer, TrackChunkLabel))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!GetDWord(file, buffer))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
int chunkSize = ByteUtils::ToDWord(buffer);
|
||||
std::cout << "Chunk size: "<< chunkSize << std::endl;
|
||||
|
||||
mTrackByteCount = 0;
|
||||
MidiTrack track;
|
||||
ProcessEvent(file);
|
||||
std::cout << "Track byte count: "<< mTrackByteCount << std::endl;
|
||||
|
||||
ProcessEvent(file);
|
||||
|
||||
mDocument.mTracks.push_back(track);
|
||||
return true;
|
||||
}
|
||||
|
||||
void MidiReader::Read(const std::string& path)
|
||||
{
|
||||
std::ifstream file(path);
|
||||
if(!ProcessHeader(file))
|
||||
{
|
||||
std::cout << "Problem processing header" << std::endl;
|
||||
}
|
||||
|
||||
if(!ProcessTrackChunk(file))
|
||||
{
|
||||
std::cout << "Problem processing track chunk" << std::endl;
|
||||
}
|
||||
|
||||
|
||||
file.close();
|
||||
}
|
31
src/audio/midi/MidiReader.h
Normal file
31
src/audio/midi/MidiReader.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
#pragma once
|
||||
|
||||
#include "MidiDocument.h"
|
||||
#include "MetaMidiEvent.h"
|
||||
#include <string>
|
||||
|
||||
class MidiReader
|
||||
{
|
||||
static constexpr const char TrackChunkLabel[] = "MTrk";
|
||||
static constexpr const char HeaderLabel[] = "MThd";
|
||||
MidiDocument mDocument;
|
||||
unsigned mTrackByteCount;
|
||||
|
||||
public:
|
||||
|
||||
MidiReader();
|
||||
|
||||
void Read(const std::string& path);
|
||||
|
||||
private:
|
||||
|
||||
bool ProcessHeader(std::ifstream& file);
|
||||
|
||||
bool ProcessTrackChunk(std::ifstream& file);
|
||||
|
||||
bool ProcessEvent(std::ifstream& file);
|
||||
|
||||
bool ProcessMetaEvent(std::ifstream& file, MetaMidiEvent& event);
|
||||
|
||||
int ProcessTimeDelta(std::ifstream& file);
|
||||
};
|
11
src/audio/midi/MidiTrack.cpp
Normal file
11
src/audio/midi/MidiTrack.cpp
Normal file
|
@ -0,0 +1,11 @@
|
|||
#include "MidiTrack.h"
|
||||
|
||||
MidiTrack::MidiTrack()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void MidiTrack::AddEvent(const MidiEvent& event)
|
||||
{
|
||||
mEvents.push_back(event);
|
||||
}
|
15
src/audio/midi/MidiTrack.h
Normal file
15
src/audio/midi/MidiTrack.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "MidiEvent.h"
|
||||
|
||||
class MidiTrack
|
||||
{
|
||||
std::vector<MidiEvent> mEvents;
|
||||
|
||||
public:
|
||||
|
||||
MidiTrack();
|
||||
|
||||
void AddEvent(const MidiEvent& event);
|
||||
};
|
|
@ -9,5 +9,6 @@ target_include_directories(console PUBLIC
|
|||
"${PROJECT_SOURCE_DIR}/src/network"
|
||||
"${PROJECT_SOURCE_DIR}/src/network/sockets"
|
||||
"${PROJECT_SOURCE_DIR}/src/audio"
|
||||
"${PROJECT_SOURCE_DIR}/src/audio/midi"
|
||||
"${PROJECT_SOURCE_DIR}/src/audio/audio_interfaces"
|
||||
)
|
|
@ -1,8 +1,9 @@
|
|||
#include "MainApplication.h"
|
||||
#include "FileLogger.h"
|
||||
#include "MidiReader.h"
|
||||
|
||||
MainApplication::MainApplication()
|
||||
:mLogger(),
|
||||
mDatabaseManager()
|
||||
: mDatabaseManager()
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -14,10 +15,9 @@ MainApplication::~MainApplication()
|
|||
|
||||
void MainApplication::Initialize(const std::filesystem::path& workDir)
|
||||
{
|
||||
mLogger = FileLogger::Create();
|
||||
mLogger->SetWorkDirectory(workDir.string());
|
||||
mLogger->Open();
|
||||
mLogger->LogLine("Launched");
|
||||
FileLogger::GetInstance().SetWorkDirectory(workDir.string());
|
||||
FileLogger::GetInstance().Open();
|
||||
MLOG_INFO("Launched");
|
||||
|
||||
mDatabaseManager = DatabaseManager::Create();
|
||||
mDatabaseManager->CreateDatabase(workDir.string() + "/database.db");
|
||||
|
@ -34,16 +34,19 @@ void MainApplication::RunServer()
|
|||
|
||||
void MainApplication::PlayAudio()
|
||||
{
|
||||
auto device = AudioDevice::Create();
|
||||
mAudioManager->GetAudioInterface()->OpenDevice(device);
|
||||
mAudioManager->GetAudioInterface()->Play(device);
|
||||
MidiReader reader;
|
||||
reader.Read("/home/james/sample.mid");
|
||||
// auto device = AudioDevice::Create();
|
||||
// mAudioManager->GetAudioInterface()->OpenDevice(device);
|
||||
// mAudioManager->GetAudioInterface()->Play(device);
|
||||
}
|
||||
|
||||
void MainApplication::ShutDown()
|
||||
{
|
||||
mLogger->Close();
|
||||
mDatabaseManager->OnShutDown();
|
||||
mNetworkManager->ShutDown();
|
||||
MLOG_INFO("Shut down");
|
||||
FileLogger::GetInstance().Close();
|
||||
}
|
||||
|
||||
std::shared_ptr<MainApplication> MainApplication::Create()
|
||||
|
|
|
@ -12,7 +12,6 @@ class MainApplication
|
|||
{
|
||||
private:
|
||||
|
||||
FileLoggerPtr mLogger;
|
||||
DatabaseManagerPtr mDatabaseManager;
|
||||
NetworkManagerPtr mNetworkManager;
|
||||
AudioManagerPtr mAudioManager;
|
||||
|
|
81
src/core/ByteUtils.h
Normal file
81
src/core/ByteUtils.h
Normal file
|
@ -0,0 +1,81 @@
|
|||
#pragma once
|
||||
#include <cstring>
|
||||
|
||||
class ByteUtils
|
||||
{
|
||||
public:
|
||||
using Word = int;
|
||||
using DWord = int;
|
||||
|
||||
static int GetWordFirstBit(const Word word)
|
||||
{
|
||||
return word & ByteUtils::WORD_FIRST_BIT;
|
||||
};
|
||||
|
||||
static int GetWordLastByte(const Word word)
|
||||
{
|
||||
return word & ByteUtils::WORD_LAST_BYTE;
|
||||
}
|
||||
|
||||
static void ReverseBuffer(char* buffer, char* reverse, unsigned size)
|
||||
{
|
||||
for(unsigned idx=0; idx<size; idx++)
|
||||
{
|
||||
reverse[idx] = buffer[size - 1 -idx];
|
||||
}
|
||||
}
|
||||
|
||||
static int ToInt(char* buffer, unsigned size, bool reverse = true)
|
||||
{
|
||||
int result;
|
||||
if(reverse)
|
||||
{
|
||||
char reversed[size];
|
||||
ReverseBuffer(buffer, reversed, size);
|
||||
std::memcpy(&result, reversed, sizeof(int));
|
||||
}
|
||||
else
|
||||
{
|
||||
std::memcpy(&result, buffer, sizeof(int));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static Word ToWord(char* buffer, bool reverse = true)
|
||||
{
|
||||
return ToInt(buffer, BYTES_PER_WORD, reverse);
|
||||
}
|
||||
|
||||
static DWord ToDWord(char* buffer, bool reverse = true)
|
||||
{
|
||||
return ToInt(buffer, BYTES_PER_DWORD, reverse);
|
||||
}
|
||||
|
||||
static bool Compare(char* buffer, const char* tag, unsigned size)
|
||||
{
|
||||
for(unsigned idx=0; idx<size; idx++)
|
||||
{
|
||||
if(tag[idx] != buffer[idx])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool CompareDWords(char* buffer, const char* tag)
|
||||
{
|
||||
return Compare(buffer, tag, BYTES_PER_DWORD);
|
||||
}
|
||||
|
||||
static bool CompareWords(char* buffer, const char* tag)
|
||||
{
|
||||
return Compare(buffer, tag, BYTES_PER_WORD);
|
||||
}
|
||||
|
||||
static const int BYTES_PER_WORD = 2;
|
||||
static const int BYTES_PER_DWORD = 4;
|
||||
static const int BYTE_FIRST_BIT = 0x40; // 1000 0000
|
||||
static const int WORD_FIRST_BIT = 0x8000; // 1000 0000 - 0000 0000
|
||||
static const int WORD_LAST_BYTE = 0x00FF; // 0000 0000 - 1111 1111
|
||||
};
|
|
@ -3,7 +3,8 @@ list(APPEND core_LIB_INCLUDES
|
|||
Color.cpp
|
||||
CommandLineArgs.cpp
|
||||
loggers/FileLogger.cpp
|
||||
StringUtils.cpp)
|
||||
StringUtils.cpp
|
||||
http/HttpResponse.cpp)
|
||||
|
||||
# add the executable
|
||||
add_library(core SHARED ${core_LIB_INCLUDES})
|
||||
|
|
|
@ -1,12 +1,7 @@
|
|||
#include "FileLogger.h"
|
||||
#include <ctime>
|
||||
#include <iomanip>
|
||||
|
||||
FileLogger::FileLogger()
|
||||
:mWorkDirectory(),
|
||||
mFileName("MT_Log.txt"),
|
||||
mFileStream()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
FileLogger::~FileLogger()
|
||||
{
|
||||
|
@ -38,7 +33,9 @@ void FileLogger::LogLine(const std::string& line)
|
|||
mFileStream << line << std::endl;
|
||||
}
|
||||
|
||||
std::shared_ptr<FileLogger> FileLogger::Create()
|
||||
void FileLogger::LogLine(const std::string& logType, const std::string& line, const std::string& fileName, const std::string& functionName, int lineNumber)
|
||||
{
|
||||
return std::make_shared<FileLogger>();
|
||||
std::time_t t = std::time(nullptr);
|
||||
const std::string cleanedFileName = fileName.substr(fileName.find_last_of("/\\") + 1);
|
||||
mFileStream << logType << "|" << std::put_time(std::gmtime(&t), "%T") << "|" << cleanedFileName << "::" << functionName << "::" << lineNumber << "|" << line << std::endl;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
#pragma once
|
||||
#define MLOG_INFO(msg) FileLogger::GetInstance().LogLine("Info", msg, __FILE__, __FUNCTION__, __LINE__);
|
||||
#define MLOG_ERROR(msg) FileLogger::GetInstance().LogLine("Error", msg, __FILE__, __FUNCTION__, __LINE__);
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
@ -12,9 +14,24 @@ class FileLogger
|
|||
|
||||
std::ofstream mFileStream;
|
||||
|
||||
FileLogger()
|
||||
:mWorkDirectory(),
|
||||
mFileName("MT_Log.txt"),
|
||||
mFileStream()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
FileLogger();
|
||||
static FileLogger& GetInstance()
|
||||
{
|
||||
static FileLogger instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
FileLogger(FileLogger const&) = delete;
|
||||
void operator=(FileLogger const&) = delete;
|
||||
|
||||
~FileLogger();
|
||||
|
||||
|
@ -28,7 +45,7 @@ public:
|
|||
|
||||
void LogLine(const std::string& line);
|
||||
|
||||
static std::shared_ptr<FileLogger> Create();
|
||||
void LogLine(const std::string& logType, const std::string& line, const std::string& fileName = "", const std::string& functionName = "", int lineNumber=-1);
|
||||
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue