drumstick 2.10.0
C++ MIDI libraries using Qt objects, idioms, and style.
backendmanager.cpp
Go to the documentation of this file.
1/*
2 Drumstick RT (realtime MIDI In/Out)
3 Copyright (C) 2009-2024 Pedro Lopez-Cabanillas <plcl@users.sf.net>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19#include <QCoreApplication>
20#include <QDir>
21#include <QLibraryInfo>
22#include <QPluginLoader>
23#include <QtGlobal>
25
31namespace drumstick { namespace rt {
32
50 class BackendManager::BackendManagerPrivate {
51 public:
52 QList<QPluginLoader *> m_loaders;
53 QList<MIDIInput *> m_inputsList;
54 QList<MIDIOutput *> m_outputsList;
55
56 QString m_inputBackend{QLatin1String("Network")};
57#if defined(Q_OS_LINUX)
58 QStringList m_outputBackends{QLatin1String("SonivoxEAS"),QLatin1String("FluidSynth"),QLatin1String("ALSA")};
59#elif defined(Q_OS_DARWIN)
60 QStringList m_outputBackends{QLatin1String("DLS Synth"),QLatin1String("FluidSynth"),QLatin1String("CoreMIDI")};
61#elif defined(Q_OS_WINDOWS)
62 QStringList m_outputBackends{QLatin1String("Windows MM"),QLatin1String("FluidSynth")};
63#elif defined(Q_OS_UNIX)
64 QStringList m_outputBackends{QLatin1String("FluidSynth"),QLatin1String("OSS")};
65#else
66 QStringList m_outputBackends{m_inputBackend};
67#endif
68
69 ~BackendManagerPrivate()
70 {
71 clearLists();
72 }
73
74 void clearLists()
75 {
76 // qDebug() << Q_FUNC_INFO << "loaders:" << m_loaders.count()
77 // << "inputs:" << m_inputsList.count() << "outputs:" << m_outputsList.count();
78 while (!m_loaders.empty()) {
79 QPluginLoader* pluginLoader = m_loaders.takeFirst();
80 //qDebug() << "unloading:" << pluginLoader->fileName();
81 pluginLoader->unload();
82 delete pluginLoader;
83 }
84 m_inputsList.clear();
85 m_outputsList.clear();
86 m_loaders.clear();
87 }
88
89 void appendDir(const QString &candidate, QStringList &result)
90 {
91 QDir checked(candidate.trimmed());
92 //qDebug() << Q_FUNC_INFO << candidate << "exists:" << checked.exists();
93 if (checked.exists() && !result.contains(checked.absolutePath())) {
94 result << checked.absolutePath();
95 }
96 }
97
98 bool isLoaderNeeded(const QString &fileName)
99 {
100 auto it = std::find_if(m_loaders.constBegin(),
101 m_loaders.constEnd(),
102 [=](QPluginLoader *loader) {
103 return loader->fileName() == fileName;
104 });
105 return it == m_loaders.constEnd();
106 }
107 };
108
113 : d{new BackendManagerPrivate}
114 {
115 //qDebug() << Q_FUNC_INFO;
116 QVariantMap defaultSettings {
117 { QSTR_DRUMSTICKRT_PUBLICNAMEIN, QStringLiteral("MIDI In")},
118 { QSTR_DRUMSTICKRT_PUBLICNAMEOUT, QStringLiteral("MIDI Out")}
119 };
120 refresh(defaultSettings);
121 }
122
127 {
128 //qDebug() << Q_FUNC_INFO;
129 }
130
136 {
137 QStringList result;
138 QString appPath = QCoreApplication::applicationDirPath() + QDir::separator();
139 #if defined(Q_OS_WIN)
140 d->appendDir( appPath + QSTR_DRUMSTICK, result );
141 d->appendDir( appPath + "../lib/" + QSTR_DRUMSTICK, result );
142 #else
143 #if defined(Q_OS_MAC)
144 d->appendDir( appPath + QStringLiteral("../PlugIns/") + QSTR_DRUMSTICK, result );
145 #endif // Linux, Unix...
146 QStringList libs;
147 libs << "../lib/";
148 #if defined(LIBSUFFIX)
149 QString libextra(QT_STRINGIFY(LIBSUFFIX));
150 if (QDir::isAbsolutePath(libextra)) {
151 d->appendDir( libextra + QDir::separator() + QSTR_DRUMSTICK, result );
152 } else {
153 libs << QString("../%1/").arg(libextra);
154 }
155 #endif
156 foreach(const QString& lib, libs) {
157 d->appendDir( appPath + lib + QSTR_DRUMSTICK, result );
158 }
159 #endif
160 d->appendDir( appPath + ".." + QDir::separator() + QSTR_DRUMSTICK, result );
161 QByteArray envdir = qgetenv(QSTR_DRUMSTICKRT.toLatin1());
162 //qDebug() << Q_FUNC_INFO << "envdir:" << envdir;
163 if(!envdir.isEmpty()) {
164 d->appendDir(QString(envdir), result );
165 }
166 d->appendDir( QDir::homePath() + QDir::separator() + QSTR_DRUMSTICK, result );
167#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
168 d->appendDir( QLibraryInfo::location(QLibraryInfo::PluginsPath) + QDir::separator() + QSTR_DRUMSTICK, result );
169#else
170 d->appendDir( QLibraryInfo::path(QLibraryInfo::PluginsPath) + QDir::separator() + QSTR_DRUMSTICK, result );
171#endif
172 foreach(const QString& path, QCoreApplication::libraryPaths()) {
173 d->appendDir( path + QDir::separator() + QSTR_DRUMSTICK, result );
174 }
175 return result;
176 }
177
183 {
184 //qDebug() << Q_FUNC_INFO;
185 QVariantMap tmpMap;
186 settings->beginGroup(QSTR_DRUMSTICKRT_GROUP);
187 const QStringList allKeys = settings->allKeys();
188 //qDebug() << Q_FUNC_INFO << allKeys;
189 for(const auto &k : allKeys) {
190 tmpMap.insert(k, settings->value(k));
191 }
192 settings->endGroup();
193 refresh(tmpMap);
194 }
195
201 void BackendManager::refresh(const QVariantMap &map)
202 {
203 QString name_in;
204 QString name_out;
205 QStringList names;
206 QStringList paths;
207
208 d->appendDir(map.value(QSTR_DRUMSTICKRT_PATH).toString(), paths);
209 name_in = map.value(QSTR_DRUMSTICKRT_PUBLICNAMEIN).toString();
210 name_out = map.value(QSTR_DRUMSTICKRT_PUBLICNAMEOUT).toString();
211 names << map.value(QSTR_DRUMSTICKRT_EXCLUDED).toStringList();
212 names << (name_in.isEmpty() ? QStringLiteral("MIDI In") : name_in);
213 names << (name_out.isEmpty() ? QStringLiteral("MIDI Out") : name_out);
214 paths << defaultPaths();
215
216 //qDebug() << Q_FUNC_INFO << "names:" << names << "paths:" << paths;
217
218 // Dynamic backends
219 foreach(const QString& dir, paths) {
220 QDir pluginsDir(dir);
221 foreach (QString fileName, pluginsDir.entryList(QDir::Files)) {
222 auto absolutePath = pluginsDir.absoluteFilePath(fileName);
223 if (QLibrary::isLibrary(absolutePath) && d->isLoaderNeeded(absolutePath)) {
224 QPluginLoader *loader = new QPluginLoader(absolutePath);
225 //qDebug() << "plugin loader created:" << loader->fileName();
226 d->m_loaders << loader;
227 QObject *obj = loader->instance();
228 if (obj != nullptr) {
229 MIDIInput *input = qobject_cast<MIDIInput *>(obj);
230 if (input != nullptr && !d->m_inputsList.contains(input)) {
231 //qDebug() << "input plugin instantiated:" << name_in;
232 if (!name_in.isEmpty()) {
233 input->setPublicName(name_in);
234 }
235 input->setExcludedConnections(names);
236 d->m_inputsList << input;
237 } else {
238 MIDIOutput *output = qobject_cast<MIDIOutput *>(obj);
239 if (output != nullptr && !d->m_outputsList.contains(output)) {
240 //qDebug() << "output plugin instantiated:" << name_out;
241 if (!name_out.isEmpty()) {
242 output->setPublicName(name_out);
243 }
244 output->setExcludedConnections(names);
245 d->m_outputsList << output;
246 }
247 }
248 }
249 }
250 }
251 }
252
253 // Static backends
254 foreach(QObject* obj, QPluginLoader::staticInstances()) {
255 if (obj != nullptr) {
256 MIDIInput *input = qobject_cast<MIDIInput*>(obj);
257 if (input != nullptr && !d->m_inputsList.contains(input)) {
258 if (!name_in.isEmpty()) {
259 input->setPublicName(name_in);
260 }
261 input->setExcludedConnections(names);
262 d->m_inputsList << input;
263 } else {
264 MIDIOutput *output = qobject_cast<MIDIOutput*>(obj);
265 if (output != nullptr && !d->m_outputsList.contains(output)) {
266 if (!name_out.isEmpty()) {
267 output->setPublicName(name_out);
268 }
269 output->setExcludedConnections(names);
270 d->m_outputsList << output;
271 }
272 }
273 }
274 }
275 }
276
278 {
279 return d->m_inputsList;
280 }
281
283 {
284 return d->m_outputsList;
285 }
286
288 {
289 foreach (MIDIInput* i, d->m_inputsList) {
290 if (i->backendName() == name) {
291 return i;
292 }
293 }
294 return nullptr;
295 }
296
298 {
299 foreach (MIDIOutput* i, d->m_outputsList) {
300 if (i->backendName() == name) {
301 return i;
302 }
303 }
304 return nullptr;
305 }
306
308 {
309 QStringList names{name};
310 names << d->m_inputBackend;
311 names.removeDuplicates();
312 if (!names.isEmpty()) {
313 foreach(const QString& n, names) {
314 foreach(MIDIInput* input, d->m_inputsList) {
315 if (input->backendName() == n) {
316 return input;
317 }
318 }
319 }
320 }
321 return nullptr;
322 }
323
325 {
326 QStringList names{name};
327 names << d->m_outputBackends;
328 names.removeDuplicates();
329 if (!names.isEmpty()) {
330 foreach(const QString& n, names) {
331 foreach(MIDIOutput* output, d->m_outputsList) {
332 if (output->backendName() == n) {
333 return output;
334 }
335 }
336 }
337 }
338 return nullptr;
339 }
340
341 const QString BackendManager::QSTR_DRUMSTICK = QStringLiteral("drumstick2");
342 const QString BackendManager::QSTR_DRUMSTICK_VERSION = QStringLiteral(QT_STRINGIFY(VERSION));
343 const QString BackendManager::QSTR_DRUMSTICKRT = QStringLiteral("DRUMSTICKRT");
344 const QString BackendManager::QSTR_DRUMSTICKRT_GROUP = QStringLiteral("DrumstickRT");
345 const QString BackendManager::QSTR_DRUMSTICKRT_PUBLICNAMEIN = QStringLiteral("PublicNameIN");
346 const QString BackendManager::QSTR_DRUMSTICKRT_PUBLICNAMEOUT = QStringLiteral("PublicNameOUT");
347 const QString BackendManager::QSTR_DRUMSTICKRT_EXCLUDED = QStringLiteral("ExcludedNames");
348 const QString BackendManager::QSTR_DRUMSTICKRT_PATH = QStringLiteral("BackendsPath");
349
355 {
356 return BackendManager::QSTR_DRUMSTICK_VERSION;
357 }
358
359} // namespace rt
360} // namespace drumstick
BackendManager class declaration.
The QObject class is the base class of all Qt objects.
The QSettings class provides persistent platform-independent application settings.
QList< MIDIInput * > availableInputs()
availableInputs
virtual ~BackendManager()
~BackendManager destructor
BackendManager()
BackendManager constructor.
MIDIOutput * outputBackendByName(const QString name)
outputBackendByName
void refresh(QSettings *settings=nullptr)
refresh the list of backends
QList< MIDIOutput * > availableOutputs()
availableOutputs
MIDIOutput * findOutput(QString name)
findOutput returns the backend corresponding to the provided name, or a suitable output instead.
MIDIInput * findInput(QString name)
findInput returns the backend corresponding to the provided name, or a suitable input instead.
QStringList defaultPaths()
defaultPaths
MIDIInput * inputBackendByName(const QString name)
inputBackendByName
MIDI IN interface.
Definition: rtmidiinput.h:56
virtual void setExcludedConnections(QStringList conns)=0
setExcludedConnections
virtual QString backendName()=0
backendName
virtual void setPublicName(QString name)=0
setPublicName
MIDI OUT interface.
Definition: rtmidioutput.h:122
virtual void setExcludedConnections(QStringList conns)=0
setExcludedConnections
virtual QString backendName()=0
backendName
virtual void setPublicName(QString name)=0
setPublicName
QString DRUMSTICK_RT_EXPORT drumstickLibraryVersion()
drumstickLibraryVersion provides the Drumstick version as an edited QString
Drumstick common.
Definition: alsaclient.cpp:71