hydrogen 1.2.6
Effects.cpp
Go to the documentation of this file.
1/*
2 * Hydrogen
3 * Copyright(c) 2002-2008 by Alex >Comix< Cominu [comix@users.sourceforge.net]
4 * Copyright(c) 2008-2025 The hydrogen development team [hydrogen-devel@lists.sourceforge.net]
5 *
6 * http://www.hydrogen-music.org
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY, without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see https://www.gnu.org/licenses
20 *
21 */
22#include <core/FX/Effects.h>
24
25#if defined(H2CORE_HAVE_LADSPA) || _DOXYGEN_
26
28#include <core/FX/LadspaFX.h>
29#include <core/Hydrogen.h>
30#include <core/Basics/Song.h>
32
33#include <algorithm>
34#include <QDir>
35#include <QLibrary>
36#include <cassert>
37
38#ifdef H2CORE_HAVE_LRDF
39#include <lrdf.h>
40#endif
41
42namespace H2Core
43{
44
45// static data
47
49 : m_pRootGroup( nullptr )
50 , m_pRecentGroup( nullptr )
51{
52 __instance = this;
53
54 for ( int nFX = 0; nFX < MAX_FX; ++nFX ) {
55 m_FXList[ nFX ] = nullptr;
56 }
57
59}
60
61
62
64{
65 if ( __instance == nullptr ) {
66 __instance = new Effects;
67 }
68}
69
70
71
72
74{
75 //INFOLOG( "DESTROY" );
76 if ( m_pRootGroup != nullptr ) delete m_pRootGroup;
77
78 //INFOLOG( "destroying " + to_string( m_pluginList.size() ) + " LADSPA plugins" );
79 for ( unsigned i = 0; i < m_pluginList.size(); i++ ) {
80 delete m_pluginList[i];
81 }
82 m_pluginList.clear();
83
84 for ( int nFX = 0; nFX < MAX_FX; ++nFX ) {
85 delete m_FXList[ nFX ];
86 }
87}
88
89
90
92{
93 assert( nFX < MAX_FX );
94 return m_FXList[ nFX ];
95}
96
97
98
99void Effects::setLadspaFX( LadspaFX* pFX, int nFX )
100{
101 assert( nFX < MAX_FX );
102 //INFOLOG( "[setLadspaFX] FX: " + pFX->getPluginLabel() + ", " + to_string( nFX ) );
103
105
106
107 if ( m_FXList[ nFX ] ) {
108 ( m_FXList[ nFX ] )->deactivate();
109 delete m_FXList[ nFX ];
110 }
111
112 m_FXList[ nFX ] = pFX;
113
114 if ( pFX != nullptr ) {
117 }
118
119
121 if ( Hydrogen::get_instance()->getSong() != nullptr ) {
123 }
124}
125
126
127
131std::vector<LadspaFXInfo*> Effects::getPluginList()
132{
133 if ( m_pluginList.size() != 0 ) {
134 return m_pluginList;
135 }
136
137 foreach ( const QString& sPluginDir, Filesystem::ladspa_paths() ) {
138 INFOLOG( "*** [getPluginList] reading directory: " + sPluginDir );
139
140 QDir dir( sPluginDir );
141 if ( !dir.exists() ) {
142 INFOLOG( "Directory " + sPluginDir + " not found" );
143 continue;
144 }
145
146 QFileInfoList list = dir.entryInfoList();
147 for ( int i = 0; i < list.size(); ++i ) {
148 QString sPluginName = list.at( i ).fileName();
149
150 if ( ( sPluginName == "." ) || ( sPluginName == ".." ) ) {
151 continue;
152 }
153
154 // if the file ends with .so or .dll is a plugin, else...
155#ifdef WIN32
156 int pos = sPluginName.indexOf( ".dll" );
157#else
158#ifdef Q_OS_MACX
159 int pos = sPluginName.indexOf( ".dylib" );
160#else
161 int pos = sPluginName.indexOf( ".so" );
162#endif
163#endif
164 if ( pos == -1 ) {
165 continue;
166 }
167 //warningLog( "[getPluginList] Loading: " + sPluginName );
168
169 QString sAbsPath = QString( "%1/%2" ).arg( sPluginDir ).arg( sPluginName );
170
171 QLibrary lib( sAbsPath );
172 LADSPA_Descriptor_Function desc_func = ( LADSPA_Descriptor_Function )lib.resolve( "ladspa_descriptor" );
173 if ( desc_func == nullptr ) {
174 ERRORLOG( "Error loading the library. (" + sAbsPath + ")" );
175 continue;
176 }
177 const LADSPA_Descriptor * d;
178 if ( desc_func ) {
179 for ( unsigned i = 0; ( d = desc_func ( i ) ) != nullptr; i++ ) {
180 LadspaFXInfo* pFX = new LadspaFXInfo( QString::fromLocal8Bit(d->Name) );
181 pFX->m_sFilename = sAbsPath;
182 pFX->m_sLabel = QString::fromLocal8Bit(d->Label);
183 pFX->m_sID = QString::number(d->UniqueID);
184 pFX->m_sMaker = QString::fromLocal8Bit(d->Maker);
185 pFX->m_sCopyright = QString::fromLocal8Bit(d->Copyright);
186
187 //INFOLOG( "Loading: " + pFX->m_sLabel );
188
189 for ( unsigned j = 0; j < d->PortCount; j++ ) {
190 LADSPA_PortDescriptor pd = d->PortDescriptors[j];
191 if ( LADSPA_IS_PORT_INPUT( pd ) && LADSPA_IS_PORT_CONTROL( pd ) ) {
192 pFX->m_nICPorts++;
193 } else if ( LADSPA_IS_PORT_INPUT( pd ) && LADSPA_IS_PORT_AUDIO( pd ) ) {
194 pFX->m_nIAPorts++;
195 } else if ( LADSPA_IS_PORT_OUTPUT( pd ) && LADSPA_IS_PORT_CONTROL( pd ) ) {
196 pFX->m_nOCPorts++;
197 } else if ( LADSPA_IS_PORT_OUTPUT( pd ) && LADSPA_IS_PORT_AUDIO( pd ) ) {
198 pFX->m_nOAPorts++;
199 } else {
200// string sPortName = d->PortNames[ j ];
201 QString sPortName;
202 ERRORLOG( QString( "%1::%2 unknown port type" ).arg( pFX->m_sLabel ).arg( sPortName ) );
203 }
204 }
205 if ( ( pFX->m_nIAPorts == 2 ) && ( pFX->m_nOAPorts == 2 ) ) { // Stereo plugin
206 m_pluginList.push_back( pFX );
207 } else if ( ( pFX->m_nIAPorts == 1 ) && ( pFX->m_nOAPorts == 1 ) ) { // Mono plugin
208 m_pluginList.push_back( pFX );
209 } else { // not supported plugin
210 //WARNINGLOG( "Plugin not supported: " + sPluginName );
211 delete pFX;
212 }
213 }
214 } else {
215 ERRORLOG( "Error loading: " + sPluginName );
216 }
217 }
218 }
219
220 INFOLOG( QString( "Loaded %1 LADSPA plugins" ).arg( m_pluginList.size() ) );
221 std::sort( m_pluginList.begin(), m_pluginList.end(), LadspaFXInfo::alphabeticOrder );
222 return m_pluginList;
223}
224
225
226
228{
229 INFOLOG( "[getLadspaFXGroup]" );
230
231// LadspaFX::getPluginList(); // load the list
232
233 if ( m_pRootGroup ) {
234 return m_pRootGroup;
235 }
236
237 m_pRootGroup = new LadspaFXGroup( "Root" );
238
239 // Adding recent FX.
240 m_pRecentGroup = new LadspaFXGroup( "Recently Used" );
241 m_pRootGroup->addChild( m_pRecentGroup );
243
244 LadspaFXGroup *pUncategorizedGroup = new LadspaFXGroup( "Uncategorized" );
245 m_pRootGroup->addChild( pUncategorizedGroup );
246
247 char C = 0;
248 LadspaFXGroup* pGroup = nullptr;
249 for ( std::vector<LadspaFXInfo*>::iterator i = m_pluginList.begin(); i < m_pluginList.end(); i++ ) {
250 char ch = (*i)->m_sName.toLocal8Bit().at(0);
251 if ( ch != C ) {
252 C = ch;
253 pGroup = new LadspaFXGroup( QString( C ) );
254 pUncategorizedGroup->addChild( pGroup );
255 }
256
257 if(pGroup){
258 pGroup->addLadspaInfo( *i );
259 }
260 }
261
262
263#ifdef H2CORE_HAVE_LRDF
264 LadspaFXGroup *pLRDFGroup = new LadspaFXGroup( "Categorized(LRDF)" );
265 m_pRootGroup->addChild( pLRDFGroup );
266 getRDF( pLRDFGroup, m_pluginList );
267#endif
268
269 return m_pRootGroup;
270}
271
273{
274 if ( m_pRecentGroup == nullptr ) {
275 return; // Too early :s
276 }
277
278 m_pRecentGroup->clear();
279
280
281 QString sRecent; // The recent fx names sit in the preferences object
282 foreach ( sRecent, Preferences::get_instance()->getRecentFX() ) {
283 for ( std::vector<LadspaFXInfo*>::iterator i = m_pluginList.begin(); i < m_pluginList.end(); i++ ) {
284 if ( sRecent == (*i)->m_sName ) {
285 m_pRecentGroup->addLadspaInfo( *i );
286 break;
287 }
288 }
289 }
291}
292
293#ifdef H2CORE_HAVE_LRDF
294
295
296void Effects::getRDF( LadspaFXGroup *pGroup, std::vector<LadspaFXInfo*> pluginList )
297{
298 lrdf_init();
299
300 QString sDir = "/usr/share/ladspa/rdf";
301
302 QDir dir( sDir );
303 if ( !dir.exists() ) {
304 WARNINGLOG( QString( "Directory %1 not found" ).arg( sDir ) );
305 return;
306 }
307
308 QFileInfoList list = dir.entryInfoList();
309 for ( int i = 0; i < list.size(); ++i ) {
310 QString sFilename = list.at( i ).fileName();
311 int pos = sFilename.indexOf( ".rdf" );
312 if ( pos == -1 ) {
313 continue;
314 }
315
316 QString sRDFFile = QString( "file://%1/%2" ).arg( sDir ).arg( sFilename );
317
318 int err = lrdf_read_file( sRDFFile.toLocal8Bit() );
319 if ( err ) {
320 ERRORLOG( "Error parsing rdf file " + sFilename );
321 }
322
323 QString sBase = "http://ladspa.org/ontology#Plugin";
324 RDFDescend( sBase, pGroup, pluginList );
325 }
326}
327
328
329
330// funzione ricorsiva
331void Effects::RDFDescend( const QString& sBase, LadspaFXGroup *pGroup, std::vector<LadspaFXInfo*> pluginList )
332{
333 //cout << "LadspaFX::RDFDescend " << sBase.toLocal8Bit().constData() << endl;
334
335 lrdf_uris* uris = lrdf_get_subclasses( sBase.toLocal8Bit() );
336 if ( uris ) {
337 for ( int i = 0; i < ( int )uris->count; i++ ) {
338 QString sGroup = QString::fromLocal8Bit(lrdf_get_label( uris->items[ i ] ));
339
340 LadspaFXGroup *pNewGroup = nullptr;
341 // verifico se esiste gia una categoria con lo stesso nome
342 std::vector<LadspaFXGroup*> childGroups = pGroup-> getChildList();
343 for ( unsigned nGroup = 0; nGroup < childGroups.size(); nGroup++ ) {
344 LadspaFXGroup *pOldGroup = childGroups[nGroup];
345 if ( pOldGroup->getName() == sGroup ) {
346 pNewGroup = pOldGroup;
347 break;
348 }
349 }
350 if ( pNewGroup == nullptr ) { // il gruppo non esiste, lo creo
351 pNewGroup = new LadspaFXGroup( sGroup );
352 pGroup->addChild( pNewGroup );
353 }
354 RDFDescend( QString::fromLocal8Bit(uris->items[i]), pNewGroup, pluginList );
355 }
356 lrdf_free_uris ( uris );
357 }
358
359 uris = lrdf_get_instances( sBase.toLocal8Bit() );
360 if ( uris ) {
361 for ( int i = 0; i < ( int )uris->count; i++ ) {
362 int uid = lrdf_get_uid ( uris->items[i] );
363
364 // verifico che il plugin non sia gia nella lista
365 bool bExists = false;
366 std::vector<LadspaFXInfo*> fxVect = pGroup->getLadspaInfo();
367 for ( unsigned nFX = 0; nFX < fxVect.size(); nFX++ ) {
368 LadspaFXInfo *pFX = fxVect[nFX];
369 if ( pFX->m_sID.toInt() == uid ) {
370 bExists = true;
371 continue;
372 }
373 }
374
375 if ( bExists == false ) {
376 // find the ladspaFXInfo
377 for ( unsigned i = 0; i < pluginList.size(); i++ ) {
378 LadspaFXInfo *pInfo = pluginList[i];
379
380 if ( pInfo->m_sID.toInt() == uid ) {
381 pGroup->addLadspaInfo( pInfo ); // copy the LadspaFXInfo
382 }
383 }
384 }
385 }
386 lrdf_free_uris ( uris );
387 }
388 pGroup->sort();
389}
390
391
392#endif // H2CORE_HAVE_LRDF
393
394};
395
396#endif // H2CORE_HAVE_LADSPA
#define RIGHT_HERE
Macro intended to be used for the logging of the locking of the H2Core::AudioEngine.
Definition AudioEngine.h:61
#define INFOLOG(x)
Definition Object.h:240
#define WARNINGLOG(x)
Definition Object.h:241
#define ERRORLOG(x)
Definition Object.h:242
void unlock()
Mutex unlocking of the AudioEngine.
void lock(const char *file, unsigned int line, const char *function)
Mutex locking of the AudioEngine.
std::vector< LadspaFXInfo * > m_pluginList
Definition Effects.h:71
LadspaFXGroup * m_pRecentGroup
Definition Effects.h:73
LadspaFXGroup * getLadspaFXGroup()
Definition Effects.cpp:227
std::vector< LadspaFXInfo * > getPluginList()
Loads only usable plugins.
Definition Effects.cpp:131
LadspaFXGroup * m_pRootGroup
Definition Effects.h:72
void updateRecentGroup()
Definition Effects.cpp:272
static void create_instance()
If __instance equals 0, a new Effects singleton will be created and stored in it.
Definition Effects.cpp:63
void setLadspaFX(LadspaFX *pFX, int nFX)
Definition Effects.cpp:99
LadspaFX * getLadspaFX(int nFX) const
Definition Effects.cpp:91
void RDFDescend(const QString &sBase, LadspaFXGroup *pGroup, std::vector< LadspaFXInfo * > pluginList)
static Effects * __instance
Object holding the current Effects singleton.
Definition Effects.h:70
void getRDF(LadspaFXGroup *pGroup, std::vector< LadspaFXInfo * > pluginList)
LadspaFX * m_FXList[MAX_FX]
Definition Effects.h:77
static QStringList ladspa_paths()
returns user ladspa paths
static Hydrogen * get_instance()
Returns the current Hydrogen instance __instance.
Definition Hydrogen.h:84
AudioEngine * getAudioEngine() const
Definition Hydrogen.h:663
void setIsModified(bool bIsModified)
Wrapper around Song::setIsModified() that checks whether a song is set.
void addChild(LadspaFXGroup *pChild)
Definition LadspaFx.cpp:71
void addLadspaInfo(LadspaFXInfo *pInfo)
Definition LadspaFx.cpp:64
QString m_sFilename
plugin filename
Definition LadspaFX.h:46
unsigned m_nIAPorts
input audio port
Definition LadspaFX.h:54
unsigned m_nOAPorts
output audio port
Definition LadspaFX.h:55
static bool alphabeticOrder(LadspaFXInfo *a, LadspaFXInfo *b)
Definition LadspaFx.cpp:112
unsigned m_nICPorts
input control port
Definition LadspaFX.h:52
unsigned m_nOCPorts
output control port
Definition LadspaFX.h:53
const QString & getPluginName() const
Definition LadspaFX.h:146
static Preferences * get_instance()
Returns a pointer to the current Preferences singleton stored in __instance.
void setMostRecentFX(QString)
#define MAX_FX
Maximum number of effects.
Definition config.dox:83