Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update string/fret selection and added refresh button #19

Merged
merged 4 commits into from
Nov 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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