modulemanager.cpp 10.2 KB
Newer Older
Leander Schulten's avatar
Leander Schulten committed
1
2
3
#include "modulemanager.h"
#include <QLibrary>
#include "module.h"
Leander Schulten's avatar
Leander Schulten committed
4
#include <QDebug>
5
#include "settings.h"
Leander Schulten's avatar
Leander Schulten committed
6
7
#include <QJsonObject>
#include <QJsonArray>
8
#include "audio/audiocapturemanager.h"
Leander Schulten's avatar
Leander Schulten committed
9
10
11

namespace Modules {

Leander Schulten's avatar
Leander Schulten committed
12
13
14
namespace detail {

    PropertyInformation::PropertyInformation(const QJsonObject &o):name(o["name"].toString("no name")),
15
16
        description(o["description"].toString()),type(static_cast<Type>(o["type"].toInt())),max(o["maxValue"].toInt()),
        min(o["minValue"].toInt()),defaultValue(o["defaultValue"].toInt()){
Leander Schulten's avatar
Leander Schulten committed
17
18
19
20
21
22
23

    }

    void PropertyInformation::writeJsonObject(QJsonObject &o)const{
            o["type"] = type;
            o["name"] = name;
            o["description"] = description;
24
25
26
            o["minValue"] = min;
            o["maxValue"] = max;
            o["defaultValue"] = defaultValue;
Leander Schulten's avatar
Leander Schulten committed
27
28
29
30
31
32
    }

}

Module::Module(const QJsonObject &o):name(o["name"].toString("no name")),
    description(o["description"].toString()),code(o["code"].toString()),
33
34
    inputType(static_cast<ValueType>(o["inputType"].toInt())),
    outputType(static_cast<ValueType>(o["outputType"].toInt())),
Leander Schulten's avatar
Leander Schulten committed
35
36
37
38
39
40
41
42
43
44
45
46
    type(static_cast<Type>(o["type"].toInt())){
    QJsonArray a = o["properties"].toArray();
    for(const auto i : a){
        QJsonObject ob = i.toObject();
        properties.push_back(new detail::PropertyInformation(ob));
    }
}

void Module::writeJsonObject(QJsonObject &o)const{
    o["name"] = name;
    o["description"] = description;
    o["code"] = code;
47
48
    o["inputType"] = inputType;
    o["outputType"] = outputType;
Leander Schulten's avatar
Leander Schulten committed
49
50
51
52
53
54
55
56
57
58
    o["type"] = type;
    QJsonArray a;
    for(const auto & p : properties){
        QJsonObject prop;
        p->writeJsonObject(prop);
        a.append(prop);
    }
    o["properties"] = a;
}

Leander Schulten's avatar
Leander Schulten committed
59
60
61
62
63
64
typedef  bool (*Have_Func)(MODUL_TYPE t);


typedef unsigned int (*GetNumberOfProgramms)();
typedef std::string (*GetNameOfProgramm)(unsigned int index);
typedef std::string (*GetDescriptionOfProgramm)(unsigned int index);
Leander Schulten's avatar
Leander Schulten committed
65
typedef Modules::Program* (*CreateProgramm)(unsigned int index);
Leander Schulten's avatar
Leander Schulten committed
66
67
68

    ModuleManager::ModuleManager()
    {
69
70
71
72
73
74
75
76
        fftOutputView = Audio::AudioCaptureManager::get().getFFTOutput();
        QObject::connect(&Audio::AudioCaptureManager::get(),&Audio::AudioCaptureManager::capturingStatusChanged,[this](){
            for(const auto & info : loadedLibraryMap){
                if(info.second.supportAudioFunc){
                    info.second.supportAudioFunc(Audio::AudioCaptureManager::get().isCapturing());
                }
            }
        });
Leander Schulten's avatar
Leander Schulten committed
77
78
    }

Leander Schulten's avatar
Leander Schulten committed
79
80
81
82
83
84
85
86
    void ModuleManager::loadModules(const QJsonObject & o){
        QJsonArray a = o["modules"].toArray();
        for(const auto _o : a){
            QJsonObject ob = _o.toObject();
            modules.push_back(new Module(ob));
        }
    }

87
88
89
    bool ModuleManager::unloadLibrary(QString filePath){
        for(auto e = loadedLibraryMap.begin();e!=loadedLibraryMap.end();++e){
            qDebug()<<e->first;
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
            qDebug()<<filePath+"____";
            // add "____" to avoid subname conflicts. eg we unload print ans e have name print_super
            if(e->first.startsWith(filePath+"____",Qt::CaseInsensitive)){
                for(auto it = filter.cbegin();it != filter.cend();){
                    if(it->libraryIdentifier == e->second.libraryIdentifier){
                        it = filter.erase(it);
                    }else{
                        ++it;
                    }
                }
                for(auto it = programms.cbegin();it != programms.cend();){
                    if(it->libraryIdentifier == e->second.libraryIdentifier){
                        it = programms.erase(it);
                    }else{
                        ++it;
                    }
                }
                for(auto it = consumer.cbegin();it != consumer.cend();){
                    if(it->libraryIdentifier == e->second.libraryIdentifier){
                        it = consumer.erase(it);
                    }else{
                        ++it;
                    }
                }
                QLibrary lib(e->first);
115
116
117
118
119
120
121
122
123
                bool suc = lib.unload();
                if(suc){
                   loadedLibraryMap.erase(e);
                   QFile f(filePath);
                   if(!f.remove()){
                       return f.rename(f.fileName()+".old");
                   }
                   return true;
                }
124
                suc = QFile::rename(e->first,e->first+ ".old");
125
126
127
128
129
130
131
132
133
                if(suc){
                    loadedLibraryMap.erase(e);
                }
                return suc;
            }
        }
        return true;
    }

Leander Schulten's avatar
Leander Schulten committed
134
135
136
137
138
139
140
141
142
143
    void ModuleManager::writeJsonObject(QJsonObject &o){
        QJsonArray a ;
        for(const auto &m : modules){
            QJsonObject ob;
            m->writeJsonObject(ob);
            a.append(ob);
        }
        o["modules"] = a;
    }

144
145
146
147
148
149
150
151
152
    QString ModuleManager::getFreeAbsoluteFilePathForModule(const QString & name)const{
#ifdef Q_OS_WIN
#define SHARED_LIB_FILE_SUFFIX ".dll"
#else
#define SHARED_LIB_FILE_SUFFIX ".so"
#endif
        for(int counter = 0; ;++counter){
            auto fileName = name + "____" + QString::number(counter)+ SHARED_LIB_FILE_SUFFIX;
            if(!QFileInfo::exists(fileName)&&!QFileInfo::exists(fileName+".old")){
153
154
155
156
                if(!QFile::rename(name,fileName)){
                    auto msg = ("Renaming from " + name + " to " + fileName + " does not work").toLatin1();
                    qCritical(msg.data());
                }
157
158
159
160
161
                return fileName;
            }
        }
    }

162
    void ModuleManager::loadModule(QString name, bool replaceNewInPBs){
163
164
165
166

        if(!QLibrary::isLibrary(name))
            return;

Leander Schulten's avatar
Leander Schulten committed
167
        qDebug()<<"load lib  : " << name;
Leander Schulten's avatar
Leander Schulten committed
168
169
170
        QLibrary lib(name);
        if(lib.load()){
            Have_Func f = reinterpret_cast<Have_Func>(lib.resolve("have"));
Leander Schulten's avatar
Leander Schulten committed
171
172
            if(!f){
                qDebug()<<"have funktion is missing";
Leander Schulten's avatar
Leander Schulten committed
173
                return;
Leander Schulten's avatar
Leander Schulten committed
174
            }
Leander Schulten's avatar
Leander Schulten committed
175
            if(f(MODUL_TYPE::Program)){
176
177
178
179
180
181
182
183
184
                loadType(lib,programms,"Program",lastLibraryIdentifier,[&](const auto p){
                    if(replaceNewInPBs){
                        for(const auto & pb : ProgramBlockManager::model){
                            for(const auto & v : pb->getUsedProgramsByName(p->name())){
                                pb->replaceProgram(v,std::shared_ptr<Program>(p->create()));
                            }
                        }
                    }
                });
Leander Schulten's avatar
Leander Schulten committed
185
            }if(f(MODUL_TYPE::LoopProgram)){
186
187
188
189
190
191
192
193
194
                loadType(lib,programms,"LoopProgram",lastLibraryIdentifier,[&](const auto p){
                    if(replaceNewInPBs){
                        for(const auto & pb : ProgramBlockManager::model){
                            for(const auto & v : pb->getUsedProgramsByName(p->name())){
                                pb->replaceProgram(v,std::shared_ptr<Program>(p->create()));
                            }
                        }
                    }
                });
Leander Schulten's avatar
Leander Schulten committed
195
            }if(f(MODUL_TYPE::Filter)){
196
197
198
199
200
201
202
203
204
                loadType(lib,filter,"Filter",lastLibraryIdentifier,[&](const auto p){
                    if(replaceNewInPBs){
                        for(const auto & pb : ProgramBlockManager::model){
                            for(const auto & v : pb->getUsedFiltersByName(p->name())){
                                pb->replaceFilter(v,std::shared_ptr<Filter>(p->create()));
                            }
                        }
                    }
                });
Leander Schulten's avatar
Leander Schulten committed
205
            }if(f(MODUL_TYPE::Consumer)){
Leander Schulten's avatar
Leander Schulten committed
206
                qDebug()<< "Loading Consumer";
207
208
209
210
211
212
213
214
215
                loadType(lib,consumer,"Consumer",lastLibraryIdentifier,[&](const auto p){
                    if(replaceNewInPBs){
                        for(const auto & pb : ProgramBlockManager::model){
                            for(const auto & v : pb->getUsedConsumersByName(p->name())){
                                pb->replaceConsumer(v,std::shared_ptr<Consumer>(p->create()));
                            }
                        }
                    }
                });
Leander Schulten's avatar
Leander Schulten committed
216
            }
217
218
219
220
221
222
223
            SupportAudioFunc supportAudioFunc = nullptr;
            if(f(MODUL_TYPE::Audio)){
                //qDebug()<< "Loading Audio";
                supportAudioFunc = loadAudio(lib,&fftOutputView);
            }
            lastLibraryIdentifier++;
            loadedLibraryMap.emplace_back(lib.fileName(),LibInfo{lastLibraryIdentifier,supportAudioFunc});
224
            qDebug() << lib.errorString();
Leander Schulten's avatar
Leander Schulten committed
225
        }else{
226
            qDebug()<<"Cant load lib :" << name<< " because : " << lib.errorString() ;
Leander Schulten's avatar
Leander Schulten committed
227
228
229
230
        }
    }

    void ModuleManager::loadAllModulesInDir(QDir dir){
Leander Schulten's avatar
Leander Schulten committed
231
232
         qDebug() << dir;
        for(auto s : dir.entryInfoList(QDir::Files)){
233
234
235
            if(s.suffix() == "old"){
                QFile::remove(s.filePath());
            }
236
237
238
            if(QLibrary::isLibrary(s.fileName())){
                loadModule(s.absoluteFilePath());
            }
239
            //qDebug()<<"found : " << s;
Leander Schulten's avatar
Leander Schulten committed
240
        }
241
        for(auto s : dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)){
242
243
            loadAllModulesInDir(s);
        }
Leander Schulten's avatar
Leander Schulten committed
244
        for(const auto & m : getProgrammModules())
245
            qDebug() << m.name().c_str();
Leander Schulten's avatar
Leander Schulten committed
246
        for(const auto & m : getFilterModules())
247
            qDebug() << m.name().c_str();
Leander Schulten's avatar
Leander Schulten committed
248
        for(const auto & m : getConsumerModules())
249
250
            qDebug() << m.name().c_str();

Leander Schulten's avatar
Leander Schulten committed
251
252
    }

253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270


    ModuleManager::SupportAudioFunc ModuleManager::loadAudio(QLibrary & lib, Modules::FFTOutputView<float> * fftOutputView){
        //typedef void (*SupportAudioFunc )(bool);
        typedef void (*SetFFTOutputViewFunc )(Modules::FFTOutputView<float>*);
        //using SupportAudioFunc = unsigned int (bool);
        //using SetFFTOutputViewFunc = char const * (Modules::FFTOutputView<float>*);
        auto supportAudioFunc = reinterpret_cast<SupportAudioFunc>(lib.resolve("_supportAudio"));
        auto setFFTOutputViewFunc = reinterpret_cast<SetFFTOutputViewFunc>(lib.resolve("_setFFTOutputView"));
        if (!supportAudioFunc || !setFFTOutputViewFunc) {
            qDebug() << "Error loading audio functions : "<< supportAudioFunc << setFFTOutputViewFunc;
            return nullptr;
        }
        setFFTOutputViewFunc(fftOutputView);
        supportAudioFunc(Audio::AudioCaptureManager::get().isCapturing());
        return  supportAudioFunc;
    }

Leander Schulten's avatar
Leander Schulten committed
271
}
272