Skip to content

Commit

Permalink
Added support for .mid files in songs folder.
Browse files Browse the repository at this point in the history
  • Loading branch information
KevAquila committed Nov 5, 2024
1 parent b9167cf commit b9ab710
Show file tree
Hide file tree
Showing 19 changed files with 11,290 additions and 31 deletions.
14 changes: 14 additions & 0 deletions Guitar Player/Guitar Player.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -135,11 +135,25 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="Midifile\Binasc.cpp" />
<ClCompile Include="Midifile\MidiEvent.cpp" />
<ClCompile Include="Midifile\MidiEventList.cpp" />
<ClCompile Include="Midifile\MidiFile.cpp" />
<ClCompile Include="Midifile\MidiMessage.cpp" />
<ClCompile Include="Midifile\Options.cpp" />
<ClCompile Include="MidiProcessing.cpp" />
<ClCompile Include="Source.cpp" />
<ClCompile Include="WindowsUtility.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="InputBlocker.h" />
<ClInclude Include="Midifile\Binasc.h" />
<ClInclude Include="Midifile\MidiEvent.h" />
<ClInclude Include="Midifile\MidiEventList.h" />
<ClInclude Include="Midifile\MidiFile.h" />
<ClInclude Include="Midifile\MidiMessage.h" />
<ClInclude Include="Midifile\Options.h" />
<ClInclude Include="MidiProcessing.h" />
<ClInclude Include="PlayerFunctionality.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="VersionNum.h" />
Expand Down
48 changes: 48 additions & 0 deletions Guitar Player/Guitar Player.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
<Filter Include="Header Files\Midifile">
<UniqueIdentifier>{19b42c73-e11c-4ee2-91aa-e619142630f6}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\Midifile">
<UniqueIdentifier>{3ab8f3c8-c8c2-4bcd-9a19-f4268a52cdb2}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Source.cpp">
Expand All @@ -21,6 +27,27 @@
<ClCompile Include="WindowsUtility.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Midifile\MidiEvent.cpp">
<Filter>Source Files\Midifile</Filter>
</ClCompile>
<ClCompile Include="Midifile\MidiEventList.cpp">
<Filter>Source Files\Midifile</Filter>
</ClCompile>
<ClCompile Include="Midifile\MidiFile.cpp">
<Filter>Source Files\Midifile</Filter>
</ClCompile>
<ClCompile Include="Midifile\MidiMessage.cpp">
<Filter>Source Files\Midifile</Filter>
</ClCompile>
<ClCompile Include="Midifile\Options.cpp">
<Filter>Source Files\Midifile</Filter>
</ClCompile>
<ClCompile Include="Midifile\Binasc.cpp">
<Filter>Source Files\Midifile</Filter>
</ClCompile>
<ClCompile Include="MidiProcessing.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="PlayerFunctionality.h">
Expand All @@ -38,6 +65,27 @@
<ClInclude Include="InputBlocker.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Midifile\MidiEventList.h">
<Filter>Header Files\Midifile</Filter>
</ClInclude>
<ClInclude Include="Midifile\MidiFile.h">
<Filter>Header Files\Midifile</Filter>
</ClInclude>
<ClInclude Include="Midifile\MidiMessage.h">
<Filter>Header Files\Midifile</Filter>
</ClInclude>
<ClInclude Include="Midifile\Options.h">
<Filter>Header Files\Midifile</Filter>
</ClInclude>
<ClInclude Include="Midifile\Binasc.h">
<Filter>Header Files\Midifile</Filter>
</ClInclude>
<ClInclude Include="Midifile\MidiEvent.h">
<Filter>Header Files\Midifile</Filter>
</ClInclude>
<ClInclude Include="MidiProcessing.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
Expand Down
104 changes: 104 additions & 0 deletions Guitar Player/MidiProcessing.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
#include "MidiProcessing.h"

// Function to calculate the optimal shift for notes
int calculateOptimalShift(const std::vector<uint8_t>& notes) {
ShiftParameters parameters;
int bestShift = 0;
double bestScore = -std::numeric_limits<double>::max();

for (int shift = -127; shift <= 127; shift++) {
int playableNotes = 0;
for (uint8_t note : notes) {
if (note + shift >= 40 && note + shift <= 79) {
playableNotes++;
}
}

// Calculate normalized score
double normalizedPlayableScore = static_cast<double>(playableNotes) / notes.size();
double score = normalizedPlayableScore * parameters.playableNoteWeight;

// Apply bonuses for preferred shifts
if (shift == 0) {
score += parameters.noShiftBonus;
}
else if (shift % 12 == 0) {
score += parameters.octaveShiftBonus;
}

// Penalize larger shifts
score -= std::abs(shift) * parameters.maxShiftPenalty / 127.0;

if (score > bestScore || (score == bestScore && std::abs(shift) < std::abs(bestShift))) {
bestScore = score;
bestShift = shift;
}
}

return bestShift;
}

std::string convertMidiToText(const std::filesystem::path& midiFilePath) {
smf::MidiFile midifile;
if (!midifile.read(midiFilePath.string())) {
throw std::runtime_error("Error reading MIDI file: " + midiFilePath.string());
}

midifile.doTimeAnalysis();
midifile.linkNotePairs();

std::vector<SoundEvent> song;
std::vector<uint8_t> allNotes;

// Process MIDI events
for (int track = 0; track < midifile.getTrackCount(); track++) {
for (int event = 0; event < midifile[track].size(); event++) {
if (midifile[track][event].isNoteOn()) {
int timestamp = static_cast<int>(midifile[track][event].seconds * 1000);
uint8_t noteNumber = midifile[track][event][1];

if (!song.empty() && timestamp <= song.back().timestamp + 30) {
song.back().notes.push_back(noteNumber);
}
else {
song.emplace_back(timestamp, noteNumber);
}
allNotes.push_back(noteNumber);
}
}
}

if (song.empty()) {
throw std::runtime_error("No notes found in MIDI file: " + midiFilePath.string());
}

// Calculate optimal shift
int optimalShift = calculateOptimalShift(allNotes);

// Build the output string
std::stringstream output;
int offsetNotes = song[0].timestamp;

for (const auto& event : song) {
std::vector<int> shiftedNotes;
for (uint8_t note : event.notes) {
int shiftedNote = note + optimalShift;
if (shiftedNote >= 40 && shiftedNote <= 79) {
shiftedNotes.push_back(shiftedNote);
}
}

if (!shiftedNotes.empty()) {
// Sort notes in ascending order
std::sort(shiftedNotes.begin(), shiftedNotes.end());

output << (event.timestamp - offsetNotes);
for (int note : shiftedNotes) {
output << " " << note;
}
output << "\n";
}
}

return output.str();
}
34 changes: 34 additions & 0 deletions Guitar Player/MidiProcessing.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#pragma once

#include <iostream>
#include <vector>
#include <string>
#include <filesystem>
#include <sstream>
#include <algorithm>
#include <cmath>
#include "Midifile/MidiFile.h"


struct SoundEvent {
int timestamp;
std::vector<uint8_t> notes;

SoundEvent(int time, uint8_t note) : timestamp(time) {
notes.push_back(note);
}

SoundEvent(int time, const std::vector<uint8_t>& tempNotes)
: timestamp(time), notes(tempNotes) {
}
};

struct ShiftParameters {
double noShiftBonus = 0.11;
double octaveShiftBonus = 0.15;
double maxShiftPenalty = 0.3;
double playableNoteWeight = 2.2;
};

int calculateOptimalShift(const std::vector<uint8_t>& notes);
std::string convertMidiToText(const std::filesystem::path& midiFilePath);
Loading

0 comments on commit b9ab710

Please sign in to comment.