diff --git a/Benchmark/Benchmark.cpp b/Benchmark/Benchmark.cpp index 660b059..78e094e 100644 --- a/Benchmark/Benchmark.cpp +++ b/Benchmark/Benchmark.cpp @@ -87,6 +87,7 @@ int main(int argc, char** argv) printf("Processing %d frames from %d channel(s)\n", frameCount, channelCount); ParametricEQ peq; + peq.setDeviceInfo(L"Benchmark", L"File output", L""); peq.initialize((float)sampleRate, channelCount); PrecisionTimer timer; diff --git a/Benchmark/Benchmark.vcxproj b/Benchmark/Benchmark.vcxproj index e1fcba8..7deb58f 100644 --- a/Benchmark/Benchmark.vcxproj +++ b/Benchmark/Benchmark.vcxproj @@ -152,12 +152,14 @@ + + diff --git a/Configurator/Configurator.cpp b/Configurator/Configurator.cpp index 7cf55c6..7beffc7 100644 --- a/Configurator/Configurator.cpp +++ b/Configurator/Configurator.cpp @@ -20,6 +20,7 @@ #define WIN32_LEAN_AND_MEAN #include #include +#include "../StringHelper.h" #include "../RegistryHelper.h" #include "Configurator.h" @@ -41,11 +42,15 @@ void Configurator::onInitDialog(HWND hDlg) okButton = GetDlgItem(hDlg, IDOK); cancelButton = GetDlgItem(hDlg, IDCANCEL); requestLabel = GetDlgItem(hDlg, IDC_REQUEST); + copyDeviceCommandButton = GetDlgItem(hDlg, IDC_COPY_DEVICE_COMMAND); wchar_t stringBuf[255]; LoadStringW(hInstance, IDS_REQUEST, stringBuf, sizeof(stringBuf)/sizeof(wchar_t)); SetWindowTextW(requestLabel, stringBuf); + LoadStringW(hInstance, IDS_COPY_DEVICE_COMMAND, stringBuf, sizeof(stringBuf)/sizeof(wchar_t)); + SetWindowTextW(copyDeviceCommandButton, stringBuf); + ListView_SetExtendedListViewStyle(deviceList, ListView_GetExtendedListViewStyle(deviceList) | LVS_EX_CHECKBOXES); LVCOLUMN column; column.pszText = stringBuf; @@ -139,6 +144,8 @@ void Configurator::onLvnItemChanged(unsigned sourceId, LPNMLISTVIEW info) } EnableWindow(okButton, changed); + + EnableWindow(copyDeviceCommandButton, ListView_GetSelectedCount(deviceList) > 0); } } @@ -168,8 +175,45 @@ void Configurator::onButtonClicked(unsigned sourceId) MessageBoxW(hDlg, e.getMessage().c_str(), L"Error while accessing the registry", MB_ICONERROR | MB_OK); } } + else if(sourceId = IDC_COPY_DEVICE_COMMAND) + { + wstring command = L"Device: "; - if(cmdLine == L"/i") + bool first = true; + for(int i = 0; i < ListView_GetItemCount(deviceList); i++) + { + LVITEM item; + item.iItem = i; + item.iSubItem = 0; + item.mask = LVIF_PARAM | LVIF_STATE; + item.stateMask = LVIS_SELECTED; + ListView_GetItem(deviceList, &item); + + if(item.state & LVIS_SELECTED) + { + if(first) + first = false; + else + command += L"; "; + + DeviceAPOInfo info = apoInfos[item.lParam]; + command += StringHelper::replaceCharacters(info.deviceName + L" " + info.connectionName + L" " + info.deviceGuid, L";", L' '); + } + } + + OpenClipboard(hDlg); + + HGLOBAL hData = GlobalAlloc(GMEM_MOVEABLE, (command.length() + 1) * sizeof(wchar_t)); + wchar_t* data = (wchar_t*)GlobalLock(hData); + memcpy(data, command.c_str(), (command.length() + 1) * sizeof(wchar_t)); + GlobalUnlock(data); + + SetClipboardData(CF_UNICODETEXT, hData); + + CloseClipboard(); + } + + if((sourceId == IDOK || sourceId == IDCANCEL) && cmdLine == L"/i") { wchar_t stringBuf[255]; LoadStringW(hInstance, IDS_AFTERINSTALL, stringBuf, sizeof(stringBuf)/sizeof(wchar_t)); @@ -229,10 +273,10 @@ INT_PTR CALLBACK dlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) return (INT_PTR)TRUE; case WM_COMMAND: + configurator->onButtonClicked(LOWORD(wParam)); + if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) { - configurator->onButtonClicked(LOWORD(wParam)); - EndDialog(hDlg, LOWORD(wParam)); return (INT_PTR)TRUE; } diff --git a/Configurator/Configurator.h b/Configurator/Configurator.h index 5726ab6..5a6c5f0 100644 --- a/Configurator/Configurator.h +++ b/Configurator/Configurator.h @@ -22,7 +22,7 @@ #include "resource.h" #include #include -#include "DeviceAPOInfo.h" +#include "../DeviceAPOInfo.h" class Configurator { @@ -38,6 +38,7 @@ private: HWND deviceList; HWND okButton; HWND cancelButton; + HWND copyDeviceCommandButton; HWND requestLabel; std::wstring cmdLine; diff --git a/Configurator/Configurator.rc b/Configurator/Configurator.rc index b848a81..70a8074 100644 Binary files a/Configurator/Configurator.rc and b/Configurator/Configurator.rc differ diff --git a/Configurator/Configurator.vcxproj b/Configurator/Configurator.vcxproj index 2752ad5..13f57a0 100644 --- a/Configurator/Configurator.vcxproj +++ b/Configurator/Configurator.vcxproj @@ -19,15 +19,17 @@ + + - + + - diff --git a/Configurator/resource.h b/Configurator/resource.h index 187970e..0a5b33c 100644 Binary files a/Configurator/resource.h and b/Configurator/resource.h differ diff --git a/Configurator/DeviceAPOInfo.cpp b/DeviceAPOInfo.cpp similarity index 67% rename from Configurator/DeviceAPOInfo.cpp rename to DeviceAPOInfo.cpp index 97588a8..8e7543c 100644 --- a/Configurator/DeviceAPOInfo.cpp +++ b/DeviceAPOInfo.cpp @@ -19,9 +19,10 @@ #include "DeviceAPOInfo.h" -#include "../EqualizerAPO.h" -#include "../ParametricEQ.h" -#include "../RegistryHelper.h" +#include "EqualizerAPO.h" +#include "ParametricEQ.h" +#include "StringHelper.h" +#include "RegistryHelper.h" using namespace std; @@ -38,30 +39,35 @@ vector DeviceAPOInfo::loadAllInfos() { wstring deviceGuidString = *it; - if(!RegistryHelper::keyExists(renderKeyPath L"\\" + deviceGuidString + L"\\FxProperties")) - continue; - - wstring connectionName = RegistryHelper::readValue(renderKeyPath L"\\" + deviceGuidString + L"\\Properties", connectionValueName); - wstring deviceName = RegistryHelper::readValue(renderKeyPath L"\\" + deviceGuidString + L"\\Properties", deviceValueName); - wstring apoGuidString = RegistryHelper::readValue(renderKeyPath L"\\" + deviceGuidString + L"\\FxProperties", apoGuidValueName); - - GUID apoGuid; - if(!SUCCEEDED(CLSIDFromString(apoGuidString.c_str(), &apoGuid))) - continue; - - bool installed = false; - if(apoGuid == __uuidof(EqualizerAPO)) - { - installed = true; - } - - DeviceAPOInfo info = {deviceName, connectionName, deviceGuidString, apoGuidString, installed}; - result.push_back(info); + DeviceAPOInfo info; + if(info.load(deviceGuidString)) + result.push_back(info); } return result; } +bool DeviceAPOInfo::load(const wstring& deviceGuid) +{ + if(!RegistryHelper::keyExists(renderKeyPath L"\\" + deviceGuid + L"\\FxProperties")) + return false; + + this->deviceGuid = deviceGuid; + connectionName = RegistryHelper::readValue(renderKeyPath L"\\" + deviceGuid + L"\\Properties", connectionValueName); + deviceName = RegistryHelper::readValue(renderKeyPath L"\\" + deviceGuid + L"\\Properties", deviceValueName); + originalApoGuid = RegistryHelper::readValue(renderKeyPath L"\\" + deviceGuid + L"\\FxProperties", apoGuidValueName); + + GUID apoGuid; + if(!SUCCEEDED(CLSIDFromString(originalApoGuid.c_str(), &apoGuid))) + return false; + + isInstalled = false; + if(apoGuid == __uuidof(EqualizerAPO)) + isInstalled = true; + + return true; +} + void DeviceAPOInfo::install() { RegistryHelper::createKey(APP_REGPATH L"\\Child APOs"); @@ -69,7 +75,7 @@ void DeviceAPOInfo::install() RegistryHelper::writeValue(APP_REGPATH L"\\Child APOs", deviceGuid, originalApoGuid); RegistryHelper::saveToFile(renderKeyPath L"\\" + deviceGuid + L"\\FxProperties", apoGuidValueName, - L"backup_" + RegistryHelper::replaceIllegalCharacters(deviceName) + L"_" + RegistryHelper::replaceIllegalCharacters(connectionName) + L".reg"); + L"backup_" + StringHelper::replaceIllegalCharacters(deviceName) + L"_" + StringHelper::replaceIllegalCharacters(connectionName) + L".reg"); RegistryHelper::writeValue(renderKeyPath L"\\" + deviceGuid + L"\\FxProperties", apoGuidValueName, RegistryHelper::getGuidString(__uuidof(EqualizerAPO))); } diff --git a/Configurator/DeviceAPOInfo.h b/DeviceAPOInfo.h similarity index 93% rename from Configurator/DeviceAPOInfo.h rename to DeviceAPOInfo.h index aaf61bc..837748a 100644 --- a/Configurator/DeviceAPOInfo.h +++ b/DeviceAPOInfo.h @@ -26,6 +26,7 @@ class DeviceAPOInfo { public: static std::vector loadAllInfos(); + bool load(const std::wstring& deviceGuid); void install(); void uninstall(); diff --git a/EqualizerAPO.cpp b/EqualizerAPO.cpp index a48b751..f6d6f02 100644 --- a/EqualizerAPO.cpp +++ b/EqualizerAPO.cpp @@ -24,6 +24,7 @@ #include "LogHelper.h" #include "RegistryHelper.h" +#include "DeviceAPOInfo.h" #include "EqualizerAPO.h" using namespace std; @@ -109,7 +110,12 @@ HRESULT EqualizerAPO::Initialize(UINT32 cbDataSize, BYTE* pbyData) LogF(L"Can't read endpoint guid"); return hr; } - TraceF(L"Endpoint GUID: %s", var.pwszVal); + wstring deviceGuid = var.pwszVal; + TraceF(L"Endpoint GUID: %s", deviceGuid.c_str()); + + DeviceAPOInfo apoInfo; + if(apoInfo.load(deviceGuid)) + peq.setDeviceInfo(apoInfo.deviceName, apoInfo.connectionName, apoInfo.deviceGuid); wstring apoGuid; try diff --git a/EqualizerAPO.vcxproj b/EqualizerAPO.vcxproj index e45cff2..e2b898a 100644 --- a/EqualizerAPO.vcxproj +++ b/EqualizerAPO.vcxproj @@ -158,20 +158,24 @@ + + + + diff --git a/ParametricEQ.cpp b/ParametricEQ.cpp index 242ecf7..33098a6 100644 --- a/ParametricEQ.cpp +++ b/ParametricEQ.cpp @@ -22,10 +22,12 @@ #include #include #include +#include #define WIN32_LEAN_AND_MEAN #include #include +#include "StringHelper.h" #include "RegistryHelper.h" #include "LogHelper.h" #include "ParametricEQ.h" @@ -77,6 +79,13 @@ ParametricEQ::~ParametricEQ() } } +void ParametricEQ::setDeviceInfo(const wstring& deviceName, const wstring& connectionName, const wstring& deviceGuid) +{ + this->deviceName = deviceName; + this->connectionName = connectionName; + this->deviceGuid = deviceGuid; +} + void ParametricEQ::initialize(float sampleRate, unsigned channelCount) { this->sampleRate = sampleRate; @@ -135,32 +144,95 @@ void ParametricEQ::loadConfig(wstring path, unsigned& loadFilterCount, float& lo return; } + boolean deviceMatches = true; + wstring deviceString = StringHelper::toLowerCase(deviceName + L" " + connectionName + L" " + deviceGuid); + while(!inputStream.eof()) { - string line; - getline(inputStream, line); + string encodedLine; + getline(inputStream, encodedLine); - size_t pos = line.find(':'); + wstring line = StringHelper::toWString(encodedLine, CP_UTF8); + if(line.find(L'\uFFFD') != -1) + line = StringHelper::toWString(encodedLine, CP_ACP); + + size_t pos = line.find(L':'); if(pos != -1) { - string key = line.substr(0, pos); - string value = line.substr(pos + 1); + wstring key = line.substr(0, pos); + wstring value = line.substr(pos + 1); - //Conversion to period as decimal mark, if needed - for(unsigned i=0;i> fullList; + vector currentList; + wstring currentWord; + + for(unsigned i=0; i 0) + { + currentList.push_back(currentWord); + currentWord.clear(); + } + if(c == L';' && currentList.size() > 0) + { + fullList.push_back(currentList); + currentList.clear(); + } + } + else + { + currentWord += value[i]; + } + } + + boolean matches = false; + + for(unsigned i=0; i 0 && iswspace(value[0])) value = value.substr(1); - int length = MultiByteToWideChar(CP_UTF8, 0, value.c_str(), -1, NULL, 0); - wchar_t* charBuf = new wchar_t[length]; - MultiByteToWideChar(CP_UTF8, 0, value.c_str(), -1, charBuf, length); - wstring includePath; - if(PathIsRelativeA(value.c_str())) + if(PathIsRelativeW(value.c_str())) { wchar_t filePath[MAX_PATH]; path._Copy_s(filePath, sizeof(filePath), MAX_PATH); if(path.size() < MAX_PATH) - filePath[path.size()]=L'\0'; + filePath[path.size()] = L'\0'; else - filePath[MAX_PATH - 1]=L'\0'; + filePath[MAX_PATH - 1] = L'\0'; PathRemoveFileSpecW(filePath); - PathAppendW(filePath, charBuf); + PathAppendW(filePath, value.c_str()); includePath = filePath; } else - includePath = charBuf; - - delete charBuf; + includePath = value; loadConfig(includePath, loadFilterCount, loadPreamp); } @@ -282,16 +351,15 @@ void ParametricEQ::process(float *output, float *input, unsigned frameCount) } } -float ParametricEQ::getFreq(char* freqString) +float ParametricEQ::getFreq(const wstring& freqString) { - size_t len = strlen(freqString); float result; - int matched = sscanf_s(freqString, "%f", &result); + int matched = swscanf_s(freqString.c_str(), L"%f", &result); if(matched == 1) { - if(len >= 5) + if(freqString.length() >= 5) { - if(freqString[len - 4] == '.') + if(freqString[freqString.length() - 4] == L'.') { //Interpret as thousands separator because of Room EQ Wizard result *= 1000.0f; diff --git a/ParametricEQ.h b/ParametricEQ.h index 800b4c5..dd34bd6 100644 --- a/ParametricEQ.h +++ b/ParametricEQ.h @@ -36,15 +36,19 @@ public: ParametricEQ(); ~ParametricEQ(); + void setDeviceInfo(const std::wstring& deviceName, const std::wstring& connectionName, const std::wstring& deviceGuid); void initialize(float sampleRate, unsigned channelCount); void loadConfig(); void process(float *output, float *input, unsigned frameCount); private: void loadConfig(std::wstring path, unsigned& loadFilterCount, float& loadPreamp); - float getFreq(char* freqString); + float getFreq(const std::wstring& freqString); static unsigned long __stdcall notificationThread(void* parameter); + std::wstring deviceName; + std::wstring connectionName; + std::wstring deviceGuid; std::wstring configPath; float sampleRate; unsigned channelCount; diff --git a/RegistryHelper.cpp b/RegistryHelper.cpp index eebe9cf..4f0593b 100644 --- a/RegistryHelper.cpp +++ b/RegistryHelper.cpp @@ -212,34 +212,6 @@ wstring RegistryHelper::getGuidString(GUID guid) return result; } -wstring RegistryHelper::replaceIllegalCharacters(wstring filename) -{ - wstringstream stream; - - for(unsigned i=0; i': - case L':': - case L'"': - case L'/': - case L'\\': - case L'|': - case L'?': - case L'*': - stream.put(L'_'); - break; - default: - stream.put(c); - } - } - - return stream.str(); -} - wstring RegistryHelper::getSystemErrorString(long status) { wchar_t* buf; diff --git a/RegistryHelper.h b/RegistryHelper.h index ca7ae57..64f2094 100644 --- a/RegistryHelper.h +++ b/RegistryHelper.h @@ -38,7 +38,6 @@ public: static unsigned long valueCount(std::wstring key); static void saveToFile(std::wstring key, std::wstring valuename, std::wstring filepath); static std::wstring getGuidString(GUID guid); - static std::wstring replaceIllegalCharacters(std::wstring filename); private: static std::wstring getSystemErrorString(long status); diff --git a/StringHelper.cpp b/StringHelper.cpp new file mode 100644 index 0000000..b0d9ade --- /dev/null +++ b/StringHelper.cpp @@ -0,0 +1,56 @@ + +#include +#include +#define WIN32_LEAN_AND_MEAN +#include +#include "StringHelper.h" + +using namespace std; + +wstring StringHelper::replaceCharacters(std::wstring s, std::wstring chars, wchar_t replacement) +{ + wstring result; + result.reserve(s.length()); + + for(unsigned i=0; i:\"/\\|?*", '_'); +} + +wstring StringHelper::toWString(string s, unsigned codepage) +{ + int length = MultiByteToWideChar(codepage, 0, s.c_str(), -1, NULL, 0); + wchar_t* charBuf = new wchar_t[length]; + MultiByteToWideChar(codepage, 0, s.c_str(), -1, charBuf, length); + wstring result = charBuf; + delete charBuf; + + return result; +} + +wstring StringHelper::toLowerCase(wstring s) +{ + wchar_t* charBuf = new wchar_t[s.length() + 1]; + memcpy(charBuf, s.c_str(), (s.length() + 1) * sizeof(wchar_t)); + errno_t err = _wcslwr_s(charBuf, s.length() + 1); + + wstring result = charBuf; + delete charBuf; + + if(err == 0) + return result; + else + return s; +} diff --git a/StringHelper.h b/StringHelper.h new file mode 100644 index 0000000..f7ecc0f --- /dev/null +++ b/StringHelper.h @@ -0,0 +1,32 @@ +/* + This file is part of EqualizerAPO, a system-wide equalizer. + Copyright (C) 2013 Jonas Thedering + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#pragma once + +#include +#include + +class StringHelper +{ +public: + static std::wstring replaceCharacters(std::wstring s, std::wstring chars, wchar_t replacement); + static std::wstring replaceIllegalCharacters(std::wstring filename); + static std::wstring toWString(std::string s, unsigned codepage); + static std::wstring toLowerCase(std::wstring s); +};