# HG changeset patch # User František Kučera # Date 1609763888 -3600 # Node ID 5b351628a37767e22605f62e454fffcb78d5b3dc # Parent 4d95b089457d1cf415a754f3da31ffd9ec3ab2d5 Find card by a name pattern (regular expression) instead using hardcoded name. By default, we look for card with name matching the "Pioneer DJ.*" pattern and we expect exactly one card to be found. Custom pattern can be provided as a command-line argument. Whole name would look something like this: "Pioneer DJ Corporation DJM-250MK2 at usb-0000:01:00.0-10.1, high speed". diff -r 4d95b089457d -r 5b351628a377 AlsaBridge.cpp --- a/AlsaBridge.cpp Mon Jan 04 00:15:56 2021 +0100 +++ b/AlsaBridge.cpp Mon Jan 04 13:38:08 2021 +0100 @@ -19,6 +19,7 @@ #include #include #include +#include #include @@ -36,6 +37,34 @@ std::recursive_mutex midiMutex; std::atomic stopped{false}; + std::string findDeviceName(std::regex cardNamePattern) { + + std::vector cardNumbers; + + std::cerr << "Looking for available cards:" << std::endl; // TODO: do not mess STDIO + + for (int card = -1; snd_card_next(&card) == 0 && card >= 0;) { + char* longName = nullptr; + snd_card_get_longname(card, &longName); + std::cerr << "card: #" << card << ": '" << longName << "'"; // TODO: do not mess STDIO + if (std::regex_match(longName, cardNamePattern)) { + cardNumbers.push_back(card); + std::cerr << " [matches]"; // TODO: do not mess STDIO + } + std::cerr << std::endl; + free(longName); + } + + if (cardNumbers.size() == 1) { + std::cerr << "Going to fix card #" << cardNumbers[0] << std::endl; // TODO: do not mess STDIO + return "hw:" + std::to_string(cardNumbers[0]); + } else if (cardNumbers.empty()) { + throw std::invalid_argument("No card with matching name found. Is the card connected? Maybe try to provide different name pattern."); + } else { + throw std::invalid_argument("Multiple cards with matching name found. Please provide a name pattern that matches only one card"); + } + } + void run() { while (!stopped) { { @@ -53,9 +82,11 @@ } public: - AlsaBridgeImpl(djmfix::DJMFix* djmFix, const std::string& deviceName) : djmFix(djmFix) { + AlsaBridgeImpl(djmfix::DJMFix* djmFix, const std::string& cardNamePattern) : djmFix(djmFix) { if (djmFix == nullptr) throw std::invalid_argument("need a djmFix for AlsaBridge"); + std::string deviceName = findDeviceName(std::regex(cardNamePattern)); + int error = snd_rawmidi_open(&input, &output, deviceName.c_str(), SND_RAWMIDI_NONBLOCK); if (error) throw std::invalid_argument("unable to open ALSA device"); diff -r 4d95b089457d -r 5b351628a377 AlsaBridge.h --- a/AlsaBridge.h Mon Jan 04 00:15:56 2021 +0100 +++ b/AlsaBridge.h Mon Jan 04 13:38:08 2021 +0100 @@ -31,7 +31,7 @@ }; -AlsaBridge* create(djmfix::DJMFix* djmFix, const std::string& deviceName); +AlsaBridge* create(djmfix::DJMFix* djmFix, const std::string& cardNamePattern); } } diff -r 4d95b089457d -r 5b351628a377 djm-fix.cpp --- a/djm-fix.cpp Mon Jan 04 00:15:56 2021 +0100 +++ b/djm-fix.cpp Mon Jan 04 13:38:08 2021 +0100 @@ -70,22 +70,29 @@ * make # we can skip this step, it will be compiled on the first run * * Run: - * make run + * make run # in most cases + * build/djm-fix 'Pioneer DJ.*' # or provide custom name pattern (regular expression) to select the proper card * * Stop: * press Ctrl+C + * + * Look for updates in the Mercurial repositories and at . */ int main(int argc, char**argv) { - std::string deviceName = argc == 2 ? argv[1] : "hw:1"; // FIXME: parse CLI options + automatic device search + try { + std::string cardNamePattern = argc == 2 ? argv[1] : "Pioneer DJ.*"; - signal(SIGINT, interrupt); - std::unique_ptr djmFix(djmfix::create()); - std::unique_ptr alsaBridge(djmfix::alsa::create(djmFix.get(), deviceName)); + signal(SIGINT, interrupt); + std::unique_ptr djmFix(djmfix::create()); + std::unique_ptr alsaBridge(djmfix::alsa::create(djmFix.get(), cardNamePattern)); - alsaBridge->start(); - while (run) std::this_thread::sleep_for(std::chrono::milliseconds(100)); - alsaBridge->stop(); + alsaBridge->start(); + while (run) std::this_thread::sleep_for(std::chrono::milliseconds(100)); + alsaBridge->stop(); - return 0; + return 0; + } catch (const std::exception& e) { + std::cerr << "ERROR: " << e.what() << std::endl; // TODO: do not mess STDIO + } }