diff --git a/examples/ggwave-gui/main.cpp b/examples/ggwave-gui/main.cpp index e9176ce..2df3cf4 100644 --- a/examples/ggwave-gui/main.cpp +++ b/examples/ggwave-gui/main.cpp @@ -96,7 +96,8 @@ int main(int argc, char** argv) { bool received; std::time_t timestamp; std::string data; - std::string protocol; + int protocolId; + float volume; }; struct State { @@ -137,7 +138,12 @@ int main(int argc, char** argv) { } if (inputCurrent.update) { - ggWave->init(inputCurrent.message.data.size(), inputCurrent.message.data.data(), ggWave->getTxProtocols()[2], 50); + ggWave->init( + inputCurrent.message.data.size(), + inputCurrent.message.data.data(), + ggWave->getTxProtocols()[inputCurrent.message.protocolId], + 100*inputCurrent.message.volume); + inputCurrent.update = false; } @@ -146,7 +152,13 @@ int main(int argc, char** argv) { lastRxDataLength = ggWave->takeRxData(lastRxData); if (lastRxDataLength > 0) { buffer.stateCore.update = true; - buffer.stateCore.message = { true, std::time(nullptr), std::string((char *) lastRxData.data(), lastRxDataLength), "" }; + buffer.stateCore.message = { + true, + std::time(nullptr), + std::string((char *) lastRxData.data(), lastRxDataLength), + ggWave->getRxProtocolId(), + 0, + }; } { @@ -176,6 +188,20 @@ int main(int argc, char** argv) { } } + enum class WindowId { + Settings, + Messages, + Commands, + }; + + struct Settings { + int protocolId = 1; + float volume = 0.25f; + }; + + static WindowId windowId = WindowId::Messages; + static Settings settings; + static char inputBuf[256]; static bool doInputFocus = false; @@ -222,106 +248,162 @@ int main(int argc, char** argv) { ImGui::InvisibleButton("StatusBar", { ImGui::GetContentRegionAvailWidth(), statusBarHeight }); if (ImGui::Button(ICON_FA_COGS, { menuButtonHeight, menuButtonHeight } )) { + windowId = WindowId::Settings; } ImGui::SameLine(); if (ImGui::Button(ICON_FA_COMMENT_ALT " Messages", { 0.5f*ImGui::GetContentRegionAvailWidth(), menuButtonHeight })) { + windowId = WindowId::Messages; } ImGui::SameLine(); if (ImGui::Button(ICON_FA_LIST_UL " Commands", { 1.0f*ImGui::GetContentRegionAvailWidth(), menuButtonHeight })) { + windowId = WindowId::Commands; } - const float messagesInputHeight = ImGui::GetTextLineHeightWithSpacing(); - const float messagesHistoryHeigthMax = ImGui::GetContentRegionAvail().y - messagesInputHeight - 2.0f*style.ItemSpacing.x; - float messagesHistoryHeigth = messagesHistoryHeigthMax; + if (windowId == WindowId::Settings) { + ImGui::BeginChild("Settings:main", ImGui::GetContentRegionAvail(), true); + ImGui::Text("Waver v0.1"); + ImGui::Separator(); - // no automatic screen resize support for iOS + ImGui::Text("%s", ""); + ImGui::Text("Sample rate (capture): %g, %d B/sample", ggWave->getSampleRateIn(), ggWave->getSampleSizeBytesIn()); + ImGui::Text("Sample rate (playback): %g, %d B/sample", ggWave->getSampleRateOut(), ggWave->getSampleSizeBytesOut()); + + static float kLabelWidth = 100.0f; + + // volume + ImGui::Text("%s", ""); + { + auto posSave = ImGui::GetCursorScreenPos(); + ImGui::Text("Volume: "); + ImGui::SetCursorScreenPos({ posSave.x + kLabelWidth, posSave.y }); + } + ImGui::SliderFloat("##volume", &settings.volume, 0.0f, 1.0f); + + // protocol + ImGui::Text("%s", ""); + { + auto posSave = ImGui::GetCursorScreenPos(); + ImGui::Text("Tx Protocol: "); + ImGui::SetCursorScreenPos({ posSave.x + kLabelWidth, posSave.y }); + } + ImGui::SameLine(); + if (ImGui::BeginCombo("##protocol", ggWave->getTxProtocols()[settings.protocolId].name)) { + for (int i = 0; i < (int) ggWave->getTxProtocols().size(); ++i) { + const bool isSelected = (settings.protocolId == i); + if (ImGui::Selectable(ggWave->getTxProtocols()[i].name, isSelected)) { + settings.protocolId = i; + } + + if (isSelected) { + ImGui::SetItemDefaultFocus(); + } + } + ImGui::EndCombo(); + } + + ImGui::EndChild(); + } + + if (windowId == WindowId::Messages) { + const float messagesInputHeight = ImGui::GetTextLineHeightWithSpacing(); + const float messagesHistoryHeigthMax = ImGui::GetContentRegionAvail().y - messagesInputHeight - 2.0f*style.ItemSpacing.x; + float messagesHistoryHeigth = messagesHistoryHeigthMax; + + // no automatic screen resize support for iOS #ifdef IOS - if (displaySize.x < displaySize.y) { - if (isTextInput) { - messagesHistoryHeigth -= 0.5f*messagesHistoryHeigthMax*std::min(tShowKeyboard, ImGui::GetTime() - tStartInput) / tShowKeyboard; + if (displaySize.x < displaySize.y) { + if (isTextInput) { + messagesHistoryHeigth -= 0.5f*messagesHistoryHeigthMax*std::min(tShowKeyboard, ImGui::GetTime() - tStartInput) / tShowKeyboard; + } else { + messagesHistoryHeigth -= 0.5f*messagesHistoryHeigthMax - 0.5f*messagesHistoryHeigthMax*std::min(tShowKeyboard, ImGui::GetTime() - tEndInput) / tShowKeyboard; + } } else { - messagesHistoryHeigth -= 0.5f*messagesHistoryHeigthMax - 0.5f*messagesHistoryHeigthMax*std::min(tShowKeyboard, ImGui::GetTime() - tEndInput) / tShowKeyboard; + if (isTextInput) { + messagesHistoryHeigth -= 0.5f*displaySize.y*std::min(tShowKeyboard, ImGui::GetTime() - tStartInput) / tShowKeyboard; + } else { + messagesHistoryHeigth -= 0.5f*displaySize.y - 0.5f*displaySize.y*std::min(tShowKeyboard, ImGui::GetTime() - tEndInput) / tShowKeyboard; + } } - } else { - if (isTextInput) { - messagesHistoryHeigth -= 0.5f*displaySize.y*std::min(tShowKeyboard, ImGui::GetTime() - tStartInput) / tShowKeyboard; - } else { - messagesHistoryHeigth -= 0.5f*displaySize.y - 0.5f*displaySize.y*std::min(tShowKeyboard, ImGui::GetTime() - tEndInput) / tShowKeyboard; - } - } #endif - ImGui::BeginChild("Messages:history", { ImGui::GetContentRegionAvailWidth(), messagesHistoryHeigth }, true); + ImGui::BeginChild("Messages:history", { ImGui::GetContentRegionAvailWidth(), messagesHistoryHeigth }, true); - for (int i = 0; i < (int) messageHistory.size(); ++i) { - ImGui::PushID(i); - const auto & message = messageHistory[i]; - if (message.received) { - ImGui::TextColored({ 0.0f, 1.0f, 0.0f, 1.0f }, "[%s] Recv:", ::toTimeString(message.timestamp)); - ImGui::SameLine(); - if (ImGui::SmallButton("Resend")) { - buffer.inputUI.update = true; - buffer.inputUI.message = { false, std::time(nullptr), message.data, "" }; + for (int i = 0; i < (int) messageHistory.size(); ++i) { + ImGui::PushID(i); + const auto & message = messageHistory[i]; + if (message.received) { + ImGui::TextColored({ 0.0f, 1.0f, 0.0f, 1.0f }, "[%s] Recv (%s):", ::toTimeString(message.timestamp), ggWave->getTxProtocols()[message.protocolId].name); + ImGui::SameLine(); + if (ImGui::SmallButton("Resend")) { + buffer.inputUI.update = true; + buffer.inputUI.message = { false, std::time(nullptr), message.data, message.protocolId, settings.volume }; - messageHistory.push_back(buffer.inputUI.message); + messageHistory.push_back(buffer.inputUI.message); + } + ImGui::Text("%s", message.data.c_str()); + } else { + ImGui::TextColored({ 1.0f, 1.0f, 0.0f, 1.0f }, "[%s] Sent (%s):", ::toTimeString(message.timestamp), ggWave->getTxProtocols()[message.protocolId].name); + ImGui::SameLine(); + if (ImGui::SmallButton("Resend")) { + buffer.inputUI.update = true; + buffer.inputUI.message = { false, std::time(nullptr), message.data, message.protocolId, settings.volume }; + + messageHistory.push_back(buffer.inputUI.message); + } + ImGui::Text("%s", message.data.c_str()); } - ImGui::Text("%s", message.data.c_str()); - } else { - ImGui::TextColored({ 1.0f, 1.0f, 0.0f, 1.0f }, "[%s] Sent:", ::toTimeString(message.timestamp)); - ImGui::SameLine(); - if (ImGui::SmallButton("Resend")) { - buffer.inputUI.update = true; - buffer.inputUI.message = { false, std::time(nullptr), message.data, "" }; - - messageHistory.push_back(buffer.inputUI.message); - } - ImGui::Text("%s", message.data.c_str()); + ImGui::Text("%s", ""); + ImGui::PopID(); + } + + if (scrollMessagesToBottom) { + ImGui::SetScrollHereY(); + scrollMessagesToBottom = false; + } + + ImVec2 mouse_delta = ImGui::GetIO().MouseDelta; + ScrollWhenDraggingOnVoid(ImVec2(0.0f, -mouse_delta.y), ImGuiMouseButton_Left); + ImGui::EndChild(); + + if (doInputFocus) { + ImGui::SetKeyboardFocusHere(); + doInputFocus = false; + } + ImGui::PushItemWidth(ImGui::GetContentRegionAvailWidth() - ImGui::CalcTextSize(sendButtonText).x - 2*style.ItemSpacing.x); + ImGui::InputText("##Messages:Input", inputBuf, 256, ImGuiInputTextFlags_EnterReturnsTrue); + ImGui::PopItemWidth(); + if (ImGui::IsItemActive() && isTextInput == false) { + SDL_StartTextInput(); + isTextInput = true; + tStartInput = ImGui::GetTime(); + } + bool requestStopTextInput = false; + if (ImGui::IsItemDeactivated()) { + requestStopTextInput = true; + } + ImGui::SameLine(); + if (ImGui::Button(sendButtonText) && inputBuf[0] != 0) { + buffer.inputUI.update = true; + buffer.inputUI.message = { false, std::time(nullptr), std::string(inputBuf), settings.protocolId, settings.volume }; + + messageHistory.push_back(buffer.inputUI.message); + + inputBuf[0] = 0; + doInputFocus = true; + } + if (!ImGui::IsItemHovered() && requestStopTextInput) { + SDL_StopTextInput(); + isTextInput = false; + tEndInput = ImGui::GetTime(); } - ImGui::Text("%s", ""); - ImGui::PopID(); } - if (scrollMessagesToBottom) { - ImGui::SetScrollHereY(); - scrollMessagesToBottom = false; - } - - ImVec2 mouse_delta = ImGui::GetIO().MouseDelta; - ScrollWhenDraggingOnVoid(ImVec2(0.0f, -mouse_delta.y), ImGuiMouseButton_Left); - ImGui::EndChild(); - - if (doInputFocus) { - ImGui::SetKeyboardFocusHere(); - doInputFocus = false; - } - ImGui::PushItemWidth(ImGui::GetContentRegionAvailWidth() - ImGui::CalcTextSize(sendButtonText).x - 2*style.ItemSpacing.x); - ImGui::InputText("##Messages:Input", inputBuf, 256, ImGuiInputTextFlags_EnterReturnsTrue); - ImGui::PopItemWidth(); - if (ImGui::IsItemActive() && isTextInput == false) { - SDL_StartTextInput(); - isTextInput = true; - tStartInput = ImGui::GetTime(); - } - bool requestStopTextInput = false; - if (ImGui::IsItemDeactivated()) { - requestStopTextInput = true; - } - ImGui::SameLine(); - if (ImGui::Button(sendButtonText) && inputBuf[0] != 0) { - buffer.inputUI.update = true; - buffer.inputUI.message = { false, std::time(nullptr), std::string(inputBuf), "" }; - - messageHistory.push_back(buffer.inputUI.message); - - inputBuf[0] = 0; - doInputFocus = true; - } - if (!ImGui::IsItemHovered() && requestStopTextInput) { - SDL_StopTextInput(); - isTextInput = false; - tEndInput = ImGui::GetTime(); + if (windowId == WindowId::Commands) { + ImGui::BeginChild("Commands:main", ImGui::GetContentRegionAvail(), true); + ImGui::Text("Todo"); + ImGui::EndChild(); } ImGui::End(); diff --git a/include/ggwave/ggwave.h b/include/ggwave/ggwave.h index 3f5282e..c781b55 100644 --- a/include/ggwave/ggwave.h +++ b/include/ggwave/ggwave.h @@ -72,12 +72,14 @@ public: const int & getSampleSizeBytesOut() const { return m_sampleSizeBytesOut; } const float & getSampleRateIn() const { return m_sampleRateIn; } + const float & getSampleRateOut() const { return m_sampleRateOut; } const TxProtocol & getDefultTxProtocol() const { return kTxProtocols[1]; } const TxProtocols & getTxProtocols() const { return kTxProtocols; } const TxRxData & getRxData() const { return m_rxData; } const TxProtocol & getRxProtocol() const { return m_rxProtocol; } + const int & getRxProtocolId() const { return m_rxProtocolId; } int takeRxData(TxRxData & dst); private: @@ -128,6 +130,7 @@ private: int m_lastRxDataLength; TxRxData m_rxData; TxProtocol m_rxProtocol; + int m_rxProtocolId; int m_historyId = 0; AmplitudeData m_sampleAmplitudeAverage; diff --git a/src/ggwave.cpp b/src/ggwave.cpp index 5aa8d6d..dd7a7f8 100644 --- a/src/ggwave.cpp +++ b/src/ggwave.cpp @@ -427,7 +427,9 @@ void GGWave::receive(const CBDequeueAudio & CBDequeueAudio) { std::unique_ptr rsData; bool isValid = false; - for (const auto & rxProtocol : kTxProtocols) { + for (int rxProtocolId = 0; rxProtocolId < (int) kTxProtocols.size(); ++rxProtocolId) { + const auto & rxProtocol = kTxProtocols[rxProtocolId]; + // skip Rx protocol if start frequency is different from detected one if (rxProtocol.freqStart != m_markerFreqStart) { continue; @@ -517,6 +519,7 @@ void GGWave::receive(const CBDequeueAudio & CBDequeueAudio) { m_hasNewRxData = true; m_lastRxDataLength = decodedLength; m_rxProtocol = rxProtocol; + m_rxProtocolId = rxProtocolId; } } }