Skip to content

Commit

Permalink
Merge pull request #19 from aaronfisher-code/main
Browse files Browse the repository at this point in the history
Update string/fret selection and added refresh button
  • Loading branch information
KevAquila authored Nov 3, 2024
2 parents e6ae61d + f0b5bd6 commit bf48c39
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 40 deletions.
103 changes: 66 additions & 37 deletions Guitar Player/PlayerFunctionality.h
Original file line number Diff line number Diff line change
Expand Up @@ -167,58 +167,87 @@ void playNotes(const std::vector<float>& notes) {

auto currentTime = std::chrono::steady_clock::now();

// Helper function to find the best string to use
auto findBestString = [&](const std::array<int, 16>& stringNotes, int stringIndex, char key, int intNote) -> bool {
auto it = std::find(stringNotes.begin(), stringNotes.end(), intNote);
if (it != stringNotes.end() && !stringUsed[stringIndex]) {
int index = static_cast<int>(std::distance(stringNotes.begin(), it));
if (lastClickedPositions[stringIndex] != index) {
auto [clickX, clickY] = getClickPosition(windowWidth, windowHeight, stringIndex, index);
clicksToSend.push_back({ clickX, clickY, true });
lastClickedPositions[stringIndex] = index;
// Helper struct to store possible positions for a note
struct StringPosition {
int stringIndex;
int fretPosition;
bool requiresPositionChange;
};

// Helper function to find all possible positions for a note
auto findAllPositions = [&](int intNote) -> std::vector<StringPosition> {
std::vector<StringPosition> positions;

// Array of string data for iteration
const std::array<std::pair<const std::array<int, 16>*, int>, 6> strings = {
std::make_pair(&high_e, 5),
std::make_pair(&b, 4),
std::make_pair(&g, 3),
std::make_pair(&d, 2),
std::make_pair(&a, 1),
std::make_pair(&low_e, 0)
};

for (const auto& [stringNotes, stringIndex] : strings) {
if (stringUsed[stringIndex]) continue;

auto it = std::find(stringNotes->begin(), stringNotes->end(), intNote);
if (it != stringNotes->end()) {
int fretPos = static_cast<int>(std::distance(stringNotes->begin(), it));
bool requiresChange = (lastClickedPositions[stringIndex] != fretPos);

positions.push_back({
stringIndex,
fretPos,
requiresChange
});
}
keysToPress.push_back(key);
stringUsed[stringIndex] = true;
lastStringUsageTime[stringIndex] = currentTime;
return true;
}
return false;
};
return positions;
};

// Process each note
for (float note : sortedNotes) {
int intNote = static_cast<int>(std::round(note));
auto positions = findAllPositions(intNote);

// Create a vector of pairs: (string index, time since last use)
std::vector<std::pair<int, std::chrono::duration<double>>> stringCandidates;
for (int i = 0; i < 6; ++i) {
if (!stringUsed[i]) {
auto timeSinceLastUse = std::chrono::duration_cast<std::chrono::duration<double>>(currentTime - lastStringUsageTime[i]);
stringCandidates.emplace_back(i, timeSinceLastUse);
}
}
if (!positions.empty()) {
// First, try to find a position that doesn't require a change
auto noChangeIt = std::find_if(positions.begin(), positions.end(),
[](const StringPosition& pos) { return !pos.requiresPositionChange; });

// Sort candidates by time since last use (descending order)
std::sort(stringCandidates.begin(), stringCandidates.end(),
[](const auto& a, const auto& b) { return a.second > b.second; });
// If no position without change is found, use the first available position
const auto& bestPos = (noChangeIt != positions.end()) ? *noChangeIt : positions[0];
int stringIndex = bestPos.stringIndex;

bool noteMatched = false;
for (const auto& [stringIndex, _] : stringCandidates) {
// Update tracking variables
if (bestPos.requiresPositionChange) {
auto [clickX, clickY] = getClickPosition(windowWidth, windowHeight, stringIndex, bestPos.fretPosition);
clicksToSend.push_back({ clickX, clickY, true });
lastClickedPositions[stringIndex] = bestPos.fretPosition;
}

// Add appropriate key press
char key;
switch (stringIndex) {
case 5: noteMatched = findBestString(high_e, 5, 'y', intNote); break;
case 4: noteMatched = findBestString(b, 4, 't', intNote); break;
case 3: noteMatched = findBestString(g, 3, 'r', intNote); break;
case 2: noteMatched = findBestString(d, 2, 'e', intNote); break;
case 1: noteMatched = findBestString(a, 1, 'w', intNote); break;
case 0: noteMatched = findBestString(low_e, 0, 'q', intNote); break;
case 0: key = 'q'; break;
case 1: key = 'w'; break;
case 2: key = 'e'; break;
case 3: key = 'r'; break;
case 4: key = 't'; break;
case 5: key = 'y'; break;
default: continue;
}
if (noteMatched) break;
keysToPress.push_back(key);
stringUsed[stringIndex] = true;
lastStringUsageTime[stringIndex] = currentTime;
}

if (!noteMatched) {
else {
std::cout << " No match found for note " << note << " (int: " << intNote << ")" << std::endl;
}
}

// Send all accumulated clicks and key presses
if (!clicksToSend.empty()) {
sendMultipleClicks(clicksToSend, 1, true);
}
Expand Down
23 changes: 20 additions & 3 deletions Guitar Player/Source.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -398,17 +398,22 @@ class MainFrame : public wxFrame {
// Create main sizer
wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);



DarkPanel* groupPanelSongs = new DarkPanel(this);
wxBoxSizer* groupSizerSongs = new wxBoxSizer(wxVERTICAL);
wxBoxSizer* searchSizer = new wxBoxSizer(wxHORIZONTAL);

searchBox = new DarkSearchBox(groupPanelSongs, wxID_ANY);
refreshButton = new DarkButton(groupPanelSongs, wxID_ANY, "Refresh");

// Add search box and refresh button to the horizontal sizer
searchSizer->Add(searchBox, 1, wxEXPAND | wxRIGHT, 5);
searchSizer->Add(refreshButton, 0, wxEXPAND);

listBox = new DarkListBox(groupPanelSongs, wxID_ANY);

LoadSongs("songs");

groupSizerSongs->Add(searchBox, 0, wxEXPAND | wxALL, 10);
groupSizerSongs->Add(searchSizer, 0, wxEXPAND | wxALL, 10);
groupSizerSongs->Add(listBox, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 10);
groupPanelSongs->SetSizer(groupSizerSongs);
mainSizer->Add(groupPanelSongs, 1, wxEXPAND | wxALL, 10);
Expand Down Expand Up @@ -462,6 +467,7 @@ class MainFrame : public wxFrame {
stopButton->Bind(wxEVT_BUTTON, &MainFrame::OnStop, this);
listBox->Bind(wxEVT_LISTBOX, &MainFrame::OnSongSelect, this);
progressBar->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &MainFrame::OnSeek, this);
refreshButton->Bind(wxEVT_BUTTON, &MainFrame::OnRefresh, this);

// Create timer for progress updates
progressTimer = new wxTimer(this);
Expand All @@ -476,6 +482,7 @@ class MainFrame : public wxFrame {
stopButton->SetFont(customFont);
timeLabel->SetFont(customFont);
currentSongLabel->SetFont(customFont);
refreshButton->SetFont(customFont);

// Bind the close event
Bind(wxEVT_CLOSE_WINDOW, &MainFrame::OnClose, this);
Expand All @@ -494,6 +501,15 @@ class MainFrame : public wxFrame {
RefreshButtonsInWindow(this);
}

void OnRefresh(wxCommandEvent& event) {
wxString currentSearch = searchBox->GetValue();
LoadSongs("songs");
if (!currentSearch.IsEmpty()) {
FilterSongs(currentSearch);
}
RefreshAllButtons();
}

private:
void RefreshButtonsInWindow(wxWindow* window) {
// Refresh buttons in the current window
Expand Down Expand Up @@ -752,6 +768,7 @@ class MainFrame : public wxFrame {
DarkButton* playButton;
DarkButton* pauseButton;
DarkButton* stopButton;
DarkButton* refreshButton;
CustomProgressBar* progressBar;
wxStaticText* timeLabel;
wxTimer* progressTimer;
Expand Down

0 comments on commit bf48c39

Please sign in to comment.