root/trunk/libs/hydrogen/src/local_file_mgr.cpp @ 334

Revision 334, 38.9 KB (checked in by jakoblund, 5 years ago)

Fix error messages in 'local file manager'

Line 
1/*
2 * Hydrogen
3 * Copyright(c) 2002-2008 by Alex >Comix< Cominu [comix@users.sourceforge.net]
4 *
5 * http://www.hydrogen-music.org
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY, without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20 *
21 */
22
23#include "config.h"
24#include "version.h"
25
26
27#include <hydrogen/adsr.h>
28#include <hydrogen/data_path.h>
29#include <hydrogen/hydrogen.h>
30#include <hydrogen/h2_exception.h>
31#include <hydrogen/instrument.h>
32#include <hydrogen/LocalFileMng.h>
33#include <hydrogen/note.h>
34#include <hydrogen/Pattern.h>
35#include <hydrogen/Preferences.h>
36#include <hydrogen/Song.h>
37#include <hydrogen/SoundLibrary.h>
38#include <hydrogen/sample.h>
39#include <hydrogen/fx/Effects.h>
40
41
42#include <cstdlib>
43#include <cassert>
44#include <sys/stat.h>
45
46#include <QDir>
47#include <QApplication>
48
49#include "xml/tinyxml.h"
50
51
52
53namespace H2Core
54{
55
56LocalFileMng::LocalFileMng()
57                : Object( "LocalFileMng" )
58{
59//      infoLog("INIT");
60}
61
62
63
64LocalFileMng::~LocalFileMng()
65{
66//      infoLog("DESTROY");
67}
68
69
70QString LocalFileMng::getDrumkitNameForPattern( const QString& patternDir )
71{
72        QString patternInfoFile = patternDir;
73
74        TiXmlDocument doc( patternInfoFile.toAscii() );
75        doc.LoadFile();
76
77        TiXmlNode* rootNode;    // root element
78        if ( !( rootNode = doc.FirstChild( "drumkit_pattern" ) ) ) {
79                ERRORLOG( "Error reading Pattern: Pattern_drumkit_infonode not found " + patternDir); return NULL;
80        }
81
82
83        QString sDrumkitName( LocalFileMng::readXmlString( rootNode,"pattern_for_drumkit", "" ) );
84        return sDrumkitName;
85       
86}
87
88
89Pattern* LocalFileMng::loadPattern( const QString& directory )
90{
91
92        InstrumentList* instrList = Hydrogen::get_instance()->getSong()->get_instrument_list();
93        Pattern *pPattern = NULL;
94        QString patternInfoFile = directory;
95
96        QFile check( patternInfoFile );
97        if (check.exists() == false) {
98                ERRORLOG( QString("Load Pattern: Data file %1 not found." ).arg( patternInfoFile ) );
99                return NULL;
100        }
101
102
103        TiXmlDocument doc( patternInfoFile.toAscii() );
104        doc.LoadFile();
105
106        // root element
107        TiXmlNode* rootNode;    // root element
108        if ( !( rootNode = doc.FirstChild( "drumkit_pattern" ) ) ) {
109                ERRORLOG( "Error reading Pattern: Pattern_drumkit_infonode not found" ); return NULL;
110        }
111
112        TiXmlNode* patternNode = rootNode->FirstChild( "pattern" );
113
114        QString sName( LocalFileMng::readXmlString( patternNode,"pattern_name", "" ) );
115        QString sCategory( LocalFileMng::readXmlString( patternNode,"category", "" ) );
116
117        int nSize = -1;
118        nSize = LocalFileMng::readXmlInt( patternNode, "size",nSize ,false,false );
119        pPattern = new Pattern( sName, sCategory, nSize );
120
121
122
123        TiXmlNode* pNoteListNode = patternNode->FirstChild( "noteList" );
124        if ( pNoteListNode )
125        {
126                // new code  :)
127                for ( TiXmlNode* noteNode = pNoteListNode->FirstChild( "note" ); noteNode; noteNode = noteNode->NextSibling( "note" ) )
128                {
129                        Note* pNote = NULL;
130                        unsigned nPosition = LocalFileMng::readXmlInt( noteNode, "position", 0 );
131                        float fLeadLag = LocalFileMng::readXmlFloat( noteNode, "leadlag", 0.0 );
132                        float fVelocity = LocalFileMng::readXmlFloat( noteNode, "velocity", 0.8f );
133                        float fPan_L = LocalFileMng::readXmlFloat( noteNode, "pan_L", 0.5 );
134                        float fPan_R = LocalFileMng::readXmlFloat( noteNode, "pan_R", 0.5 );
135                        int nLength = LocalFileMng::readXmlInt( noteNode, "length", -1, true );
136                        float nPitch = LocalFileMng::readXmlFloat( noteNode, "pitch", 0.0, false, false );
137                        QString sKey = LocalFileMng::readXmlString( noteNode, "key", "C0", false, false );
138
139                        QString instrId = LocalFileMng::readXmlString( noteNode, "instrument", "" );
140
141                        Instrument *instrRef = NULL;
142                        // search instrument by ref
143                        for ( unsigned i = 0; i < instrList->get_size(); i++ ) { Instrument *instr = instrList->get( i );
144                                if ( instrId == instr->get_id() ) {
145                                        instrRef = instr;
146                                        break;
147                                }
148                        }
149                        if ( !instrRef ) {
150                                ERRORLOG( QString( "Instrument with ID: '%1' not found. Note skipped." ).arg( instrId ) );
151                                continue;
152                        }
153                        //assert( instrRef );
154
155                        pNote = new Note( instrRef, nPosition, fVelocity, fPan_L, fPan_R, nLength, nPitch, Note::stringToKey( sKey ) );
156                        pNote->set_leadlag(fLeadLag);
157                        pPattern->note_map.insert( std::make_pair( pNote->get_position(),pNote ) );
158                }
159        }
160
161        return pPattern;
162
163}
164
165
166int LocalFileMng::savePattern( Song *song , int selectedpattern , const QString& patternname, const QString& realpatternname, int mode)
167{
168        //int mode = 1 save, int mode = 2 save as
169        // INSTRUMENT NODE
170
171        Instrument *instr = song->get_instrument_list()->get( 0 );
172        assert( instr );
173
174        Pattern *pat = song->get_pattern_list()->get( selectedpattern );
175
176        QString sPatternDir = Preferences::getInstance()->getDataDirectory() + "patterns/" +  instr->get_drumkit_name();
177
178        INFOLOG( "[savePattern]" + sPatternDir );
179
180        // check if the directory exists
181        QDir dir( sPatternDir );
182        QDir dirPattern( sPatternDir );
183        if ( !dir.exists() ) {
184                dir.mkdir( sPatternDir );// create the drumkit directory
185        }
186
187        QString sPatternXmlFilename = "";
188        // create the drumkit.xml file
189        switch ( mode ){
190                case 1: //save
191                        sPatternXmlFilename = sPatternDir + "/" + QString( patternname + QString( ".h2pattern" ));
192                        WARNINGLOG( "Patternfile" + sPatternXmlFilename );
193                        //TiXmlDocument doc( sPatternXmlFilename.c_str() );
194                        break;
195                case 2: //save as
196                        sPatternXmlFilename = patternname;
197                        WARNINGLOG( "Patternfile" + sPatternXmlFilename );
198                        //TiXmlDocument doc( sPatternXmlFilename.c_str() );
199                        break;
200                default:
201                        WARNINGLOG( "Pattern Save unknown status");
202                        break;
203
204        }
205        TiXmlDocument doc( sPatternXmlFilename.toAscii() );
206
207        TiXmlElement rootNode( "drumkit_pattern" );
208        //LIB_ID just in work to get better usability
209        //writeXmlString( &rootNode, "LIB_ID", "in_work" );
210        writeXmlString( &rootNode, "pattern_for_drumkit", instr->get_drumkit_name() );
211
212
213        // pattern
214        TiXmlElement patternNode( "pattern" );
215        LocalFileMng::writeXmlString( &patternNode, "pattern_name", realpatternname );
216        LocalFileMng::writeXmlString( &patternNode, "category", pat->get_category() );
217        writeXmlString( &patternNode, "size", to_string( pat->get_lenght() ) );
218
219                TiXmlElement noteListNode( "noteList" );
220                std::multimap <int, Note*>::iterator pos;
221                for ( pos = pat->note_map.begin(); pos != pat->note_map.end(); ++pos ) {
222                        Note *pNote = pos->second;
223                        assert( pNote );
224
225                        TiXmlElement noteNode( "note" );
226                        writeXmlString( &noteNode, "position", to_string( pNote->get_position() ) );
227                        writeXmlString( &noteNode, "leadlag", to_string( pNote->get_leadlag() ) );
228                        writeXmlString( &noteNode, "velocity", to_string( pNote->get_velocity() ) );
229                        writeXmlString( &noteNode, "pan_L", to_string( pNote->get_pan_l() ) );
230                        writeXmlString( &noteNode, "pan_R", to_string( pNote->get_pan_r() ) );
231                        writeXmlString( &noteNode, "pitch", to_string( pNote->get_pitch() ) );
232
233                        writeXmlString( &noteNode, "key", Note::keyToString( pNote->m_noteKey ) );
234
235                        writeXmlString( &noteNode, "length", to_string( pNote->get_lenght() ) );
236                        writeXmlString( &noteNode, "instrument", pNote->get_instrument()->get_id() );
237                        noteListNode.InsertEndChild( noteNode );
238                }
239                patternNode.InsertEndChild( noteListNode );
240
241        rootNode.InsertEndChild( patternNode );
242
243        doc.InsertEndChild( rootNode );
244        doc.SaveFile();
245
246
247
248        return 0; // ok
249}
250
251
252
253
254void LocalFileMng::fileCopy( const QString& sOrigFilename, const QString& sDestFilename )
255{
256        // TODO: use QT copy functions
257
258        INFOLOG( sOrigFilename + " --> " + sDestFilename );
259
260        if ( sOrigFilename == sDestFilename ) {
261                return;
262        }
263
264        FILE *inputFile = fopen( sOrigFilename.toAscii(), "rb" );
265        if ( inputFile == NULL ) {
266                ERRORLOG( "Error opening " + sOrigFilename );
267                return;
268        }
269
270        FILE *outputFile = fopen( sDestFilename.toAscii(), "wb" );
271        if ( outputFile == NULL ) {
272                ERRORLOG( "Error opening " + sDestFilename );
273                return;
274        }
275
276        const int bufferSize = 512;
277        char buffer[ bufferSize ];
278        while ( feof( inputFile ) == 0 ) {
279                size_t read = fread( buffer, sizeof( char ), bufferSize, inputFile );
280                fwrite( buffer, sizeof( char ), read, outputFile );
281        }
282
283        fclose( inputFile );
284        fclose( outputFile );
285}
286
287
288
289std::vector<QString> LocalFileMng::getSongList()
290{
291        std::vector<QString> list;
292        QString sDirectory = Preferences::getInstance()->getDataDirectory()  + "/songs/";
293
294        QDir dir( sDirectory );
295
296        if ( !dir.exists() ) {
297                ERRORLOG( QString( "[getSongList] Directory %1 not found" ).arg( sDirectory ) );
298        } else {
299                QFileInfoList fileList = dir.entryInfoList();
300                dir.setFilter( QDir::Dirs );
301                for ( int i = 0; i < fileList.size(); ++i ) {
302                        QString sFile = fileList.at( i ).fileName();
303
304                        if ( ( sFile == "." ) || ( sFile == ".." ) || ( sFile == "CVS" )  || ( sFile == ".svn" ) ) {
305                                continue;
306                        }
307
308                        list.push_back( sFile.left( sFile.indexOf( "." ) ) );
309                }
310        }
311
312        return list;
313}
314
315std::vector<QString> LocalFileMng::getPatternList()
316{
317        std::vector<QString> list;
318        QString sDirectory = Preferences::getInstance()->getDataDirectory()  + "/patterns/";
319
320        QDir dir( sDirectory );
321
322        if ( !dir.exists() ) {
323                ERRORLOG( QString( "[getPatternList] Directory %1patterns not found" ).arg( sDirectory ) );
324        } else {
325                dir.setFilter( QDir::Files );
326                QFileInfoList fileList = dir.entryInfoList();
327               
328                for ( int i = 0; i < fileList.size(); ++i ) {
329                        QString sFile = fileList.at( i ).fileName();
330                       
331                        if( sFile.endsWith(".h2pattern") ){
332                                list.push_back( sFile.left( sFile.indexOf( "." ) ) );
333                        }
334                }
335        }
336
337        return list;
338}
339
340// only to know what is better
341std::vector<QString> LocalFileMng::getPatternsForDrumkit( const QString& sDrumkit )
342{
343        std::vector<QString> list;
344
345        QDir dir( Preferences::getInstance()->getDataDirectory() + "/patterns/" + sDrumkit );
346
347        if ( !dir.exists() ) {
348                WARNINGLOG( QString( "No patterns for drumkit '%1'." ).arg( sDrumkit ) );
349        } else {
350                QFileInfoList fileList = dir.entryInfoList();
351                dir.setFilter( QDir::Dirs );
352                for ( int i = 0; i < fileList.size(); ++i ) {
353                        QString sFile = fileList.at( i ).fileName();
354
355                        if ( ( sFile == "." ) || ( sFile == ".." ) || ( sFile == "CVS" )  || ( sFile == ".svn" ) ) {
356                                continue;
357                        }
358
359                        list.push_back( sFile.left( sFile.indexOf( "." ) ) );
360                }
361        }
362
363        return list;
364}
365
366
367
368std::vector<QString> LocalFileMng::getDrumkitsFromDirectory( QString sDirectory )
369{
370        /*
371                returns a list of all drumkits in the given directory
372        */
373
374        std::vector<QString> list;
375
376        QDir dir( sDirectory );
377        if ( !dir.exists() ) {
378                ERRORLOG( QString( "[getDrumkitList] Directory %1 not found" ).arg( sDirectory ) );
379        } else {
380                QFileInfoList fileList = dir.entryInfoList();
381                dir.setFilter( QDir::Dirs );
382                for ( int i = 0; i < fileList.size(); ++i ) {
383                        QString sFile = fileList.at( i ).fileName();
384                        if ( ( sFile == "." ) || ( sFile == ".." ) || ( sFile == "CVS" )  || ( sFile == ".svn" ) ||
385                        (sFile =="songs" ) || ( sFile == "patterns" )  || (sFile == "drumkits" || sFile == "playlists" ) || (sFile == "scripts" )) {
386                                continue;
387                        }
388                        if(! sDirectory.endsWith("/")) sDirectory = sDirectory + "/";
389                        list.push_back( sDirectory + sFile );
390                }
391        }
392
393        return list;
394}
395
396std::vector<QString> mergeQStringVectors( std::vector<QString> firstVector , std::vector<QString> secondVector )
397{
398        /*
399                 merges two vectors ( containing drumkits). Elements of the first vector have priority
400        */
401
402        if( firstVector.size() == 0 ) return secondVector;
403        if( secondVector.size() == 0 ) return firstVector;
404       
405        std::vector<QString> newVector;
406
407        newVector = firstVector;
408        newVector.resize(firstVector.size()+ secondVector.size());
409
410
411        for ( int i = 0; i < (int)secondVector.size(); ++i )
412        {
413                QString toFind = secondVector[i];
414               
415                for ( int ii = 0; ii < (int)firstVector.size(); ++ii )
416                {
417                        if( toFind == firstVector[ii])
418                        {
419                                //the String already exists in firstVector, don't copy it to the resulting vector
420                                break;
421                        }
422                }
423                newVector[firstVector.size() + i] = toFind;
424        }
425
426        return newVector;
427}
428
429
430std::vector<QString> LocalFileMng::getUserDrumkitList()
431{
432        std::vector<QString> oldLocation = getDrumkitsFromDirectory( Preferences::getInstance()->getDataDirectory() );
433        std::vector<QString> newLocation = getDrumkitsFromDirectory( Preferences::getInstance()->getDataDirectory() + "drumkits" );
434        return mergeQStringVectors( newLocation ,  oldLocation );
435}
436
437std::vector<QString> LocalFileMng::getSystemDrumkitList()
438{
439        return getDrumkitsFromDirectory( DataPath::get_data_path() + "/drumkits" );
440}
441
442
443QString LocalFileMng::getDrumkitDirectory( const QString& drumkitName )
444{
445        // search in system drumkit
446        std::vector<QString> systemDrumkits = Drumkit::getSystemDrumkitList();
447        for ( unsigned i = 0; i < systemDrumkits.size(); i++ ) {
448                if ( systemDrumkits[ i ].endsWith(drumkitName) ) {
449                        QString path = QString( DataPath::get_data_path() ) + "/drumkits/";
450                        return path;
451                }
452        }
453
454        // search in user drumkit
455        std::vector<QString> userDrumkits = Drumkit::getUserDrumkitList();
456        for ( unsigned i = 0; i < userDrumkits.size(); i++ ) {
457                if ( userDrumkits[ i ].endsWith(drumkitName) ) {
458                        QString path = Preferences::getInstance()->getDataDirectory();
459                        return userDrumkits[ i ].remove(userDrumkits[ i ].length() - drumkitName.length(),drumkitName.length());
460                }
461        }
462
463        ERRORLOG( "drumkit \"" + drumkitName + "\" not found" );
464        return "";      // FIXME
465}
466
467
468
469/// Restituisce un oggetto DrumkitInfo.
470/// Gli strumenti non hanno dei veri propri sample,
471/// viene utilizzato solo il campo filename.
472Drumkit* LocalFileMng::loadDrumkit( const QString& directory )
473{
474        //INFOLOG( directory );
475
476        // che if the drumkit.xml file exists
477        QString drumkitInfoFile = directory + "/drumkit.xml";
478
479        if ( QFile( drumkitInfoFile ).exists() == false ) {
480                ERRORLOG( "Load Instrument: Data file " + drumkitInfoFile + " not found." );
481                return NULL;
482        }
483
484        TiXmlDocument doc( drumkitInfoFile.toAscii() );
485        doc.LoadFile();
486
487        // root element
488        TiXmlNode* drumkitNode; // root element
489        if ( !( drumkitNode = doc.FirstChild( "drumkit_info" ) ) ) {
490                ERRORLOG( "Error reading drumkit: drumkit_info node not found" );
491                return NULL;
492        }
493
494        // Name
495        QString sDrumkitName = readXmlString( drumkitNode, "name", "" );
496        if ( sDrumkitName == "" ) {
497                ERRORLOG( "Error reading drumkit: name node not found" );
498                return NULL;
499        }
500
501        QString author = readXmlString( drumkitNode, "author", "undefined author", true );
502        QString info = readXmlString( drumkitNode, "info", "defaultInfo", true );
503        QString license = readXmlString( drumkitNode, "license", "undefined license", true );
504
505        Drumkit *drumkitInfo = new Drumkit();
506        drumkitInfo->setName( sDrumkitName );
507        drumkitInfo->setAuthor( author );
508        drumkitInfo->setInfo( info );
509        drumkitInfo->setLicense( license );
510
511        InstrumentList *instrumentList = new InstrumentList();
512
513        TiXmlNode* instrumentListNode;
514        if ( ( instrumentListNode = drumkitNode->FirstChild( "instrumentList" ) ) ) {
515                // INSTRUMENT NODE
516                int instrumentList_count = 0;
517                TiXmlNode* instrumentNode = 0;
518                for ( instrumentNode = instrumentListNode->FirstChild( "instrument" ); instrumentNode; instrumentNode = instrumentNode->NextSibling( "instrument" ) ) {
519                        instrumentList_count++;
520                        if ( instrumentList_count > MAX_INSTRUMENTS ) {
521                                ERRORLOG( "Instrument count >= MAX_INSTRUMENTS. Drumkit: " + drumkitInfo->getName() );
522                                break;
523                        }
524
525                        QString id = readXmlString( instrumentNode, "id", "" );
526                        QString name = readXmlString( instrumentNode, "name", "" );
527                        float volume = readXmlFloat( instrumentNode, "volume", 1.0f );
528                        bool isMuted = readXmlBool( instrumentNode, "isMuted", false );
529                        float pan_L = readXmlFloat( instrumentNode, "pan_L", 1.0f );
530                        float pan_R = readXmlFloat( instrumentNode, "pan_R", 1.0f );
531                        bool bFilterActive = readXmlBool( instrumentNode, "filterActive", false, false );
532                        float fFilterCutoff = readXmlFloat( instrumentNode, "filterCutoff", 1.0f, false, false );
533                        float fFilterResonance = readXmlFloat( instrumentNode, "filterResonance", 0.0f, false, false );
534                        float fRandomPitchFactor = readXmlFloat( instrumentNode, "randomPitchFactor", 0.0f, false, false );
535                        float fAttack = LocalFileMng::readXmlFloat( instrumentNode, "Attack", 0, false, false );                // Attack
536                        float fDecay = LocalFileMng::readXmlFloat( instrumentNode, "Decay", 0, false, false  );         // Decay
537                        float fSustain = LocalFileMng::readXmlFloat( instrumentNode, "Sustain", 1.0, false, false );    // Sustain
538                        float fRelease = LocalFileMng::readXmlFloat( instrumentNode, "Release", 1000, false, false );   // Release
539                        float fGain = readXmlFloat( instrumentNode, "gain", 1.0f, false, false );
540                        QString sMuteGroup = readXmlString( instrumentNode, "muteGroup", "-1", false, false );
541                        int nMuteGroup = sMuteGroup.toInt();
542
543                        // some sanity checks
544                        if ( id == "" ) {
545                                ERRORLOG( "Empty ID for instrument. The drumkit '" + sDrumkitName + "' is corrupted. Skipping instrument '" + name + "'" );
546                                continue;
547                        }
548
549                        Instrument *pInstrument = new Instrument( id, name, new ADSR() );
550                        pInstrument->set_volume( volume );
551
552
553                        // back compatibility code
554                        TiXmlNode* filenameNode = instrumentNode->FirstChild( "filename" );
555                        if ( filenameNode ) {
556                                //warningLog( "Using back compatibility code. filename node found" );
557                                QString sFilename = LocalFileMng::readXmlString( instrumentNode, "filename", "" );
558                                Sample *pSample = new Sample( 0, sFilename );
559                                InstrumentLayer *pLayer = new InstrumentLayer( pSample );
560                                pInstrument->set_layer( pLayer, 0 );
561                        }
562                        //~ back compatibility code
563                        else {
564                                unsigned nLayer = 0;
565                                for ( TiXmlNode* layerNode = instrumentNode->FirstChild( "layer" ); layerNode; layerNode = layerNode->NextSibling( "layer" ) ) {
566                                        if ( nLayer >= MAX_LAYERS ) {
567                                                ERRORLOG( "nLayer > MAX_LAYERS" );
568                                                continue;
569                                        }
570                                        QString sFilename = LocalFileMng::readXmlString( layerNode, "filename", "" );
571                                        float fMin = LocalFileMng::readXmlFloat( layerNode, "min", 0.0 );
572                                        float fMax = LocalFileMng::readXmlFloat( layerNode, "max", 1.0 );
573                                        float fGain = LocalFileMng::readXmlFloat( layerNode, "gain", 1.0, false, false );
574                                        float fPitch = LocalFileMng::readXmlFloat( layerNode, "pitch", 0.0, false, false );
575
576                                        Sample *pSample = new Sample( 0, sFilename );
577                                        InstrumentLayer *pLayer = new InstrumentLayer( pSample );
578                                        pLayer->set_start_velocity( fMin );
579                                        pLayer->set_end_velocity( fMax );
580                                        pLayer->set_gain( fGain );
581                                        pLayer->set_pitch( fPitch );
582                                        pInstrument->set_layer( pLayer, nLayer );
583
584                                        nLayer++;
585                                }
586                        }
587
588                        pInstrument->set_filter_active( bFilterActive );
589                        pInstrument->set_filter_cutoff( fFilterCutoff );
590                        pInstrument->set_filter_resonance( fFilterResonance );
591                        pInstrument->set_muted( isMuted );
592                        pInstrument->set_pan_l( pan_L );
593                        pInstrument->set_pan_r( pan_R );
594                        pInstrument->set_random_pitch_factor( fRandomPitchFactor );
595                        pInstrument->set_drumkit_name( drumkitInfo->getName() );
596                        pInstrument->set_gain( fGain );
597                        pInstrument->set_mute_group( nMuteGroup );
598
599                        pInstrument->set_adsr( new ADSR( fAttack, fDecay, fSustain, fRelease ) );
600                        instrumentList->add( pInstrument );
601                }
602        } else {
603                WARNINGLOG( "Error reading drumkit: instrumentList node not found" );
604        }
605        drumkitInfo->setInstrumentList( instrumentList );
606
607        return drumkitInfo;
608}
609
610
611
612int LocalFileMng::saveDrumkit( Drumkit *info )
613{
614        INFOLOG( "[saveDrumkit]" );
615        info->dump();   // debug
616
617        QString sDrumkitDir = Preferences::getInstance()->getDataDirectory() + "drumkits/" + info->getName();
618
619        // check if the directory exists
620        QDir dir( sDrumkitDir );
621        if ( !dir.exists() ) {
622                dir.mkdir( sDrumkitDir );// create the drumkit directory
623                //mkdir( sDrumkitDir.c_str(), S_IRWXU );
624        } else {
625               
626                //warningLog( "[saveDrumkit] Cleaning directory " + sDrumkitDir );
627                // clear all the old files in the directory
628                //string clearCmd = "rm -f " + sDrumkitDir + "/*";
629                //system( clearCmd.c_str() );
630        }
631
632
633        // create the drumkit.xml file
634        QString sDrumkitXmlFilename = sDrumkitDir + QString( "/drumkit.xml" );
635
636        TiXmlDocument doc( sDrumkitXmlFilename.toAscii() );
637
638        TiXmlElement rootNode( "drumkit_info" );
639
640        writeXmlString( &rootNode, "name", info->getName() );   // name
641        writeXmlString( &rootNode, "author", info->getAuthor() );       // author
642        writeXmlString( &rootNode, "info", info->getInfo() );   // info
643        writeXmlString( &rootNode, "license", info->getLicense() );     // license
644
645        TiXmlElement instrumentListNode( "instrumentList" );            // instrument list
646        unsigned nInstrument = info->getInstrumentList()->get_size();
647        // INSTRUMENT NODE
648        for ( unsigned i = 0; i < nInstrument; i++ ) {
649                Instrument *instr = info->getInstrumentList()->get( i );
650
651                for ( unsigned nLayer = 0; nLayer < MAX_LAYERS; nLayer++ ) {
652                        InstrumentLayer *pLayer = instr->get_layer( nLayer );
653                        if ( pLayer ) {
654                                Sample *pSample = pLayer->get_sample();
655                                QString sOrigFilename = pSample->get_filename();
656
657                                QString sDestFilename = sOrigFilename;
658
659                                int nPos = sDestFilename.lastIndexOf( '/' );
660                                sDestFilename = sDestFilename.mid( nPos + 1, sDestFilename.size() - nPos - 1 );
661                                sDestFilename = sDrumkitDir + "/" + sDestFilename;
662
663                                fileCopy( sOrigFilename, sDestFilename );
664                        }
665                }
666
667                TiXmlElement instrumentNode( "instrument" );
668
669                LocalFileMng::writeXmlString( &instrumentNode, "id", instr->get_id() );
670                LocalFileMng::writeXmlString( &instrumentNode, "name", instr->get_name() );
671                LocalFileMng::writeXmlString( &instrumentNode, "volume", to_string( instr->get_volume() ) );
672                LocalFileMng::writeXmlBool( &instrumentNode, "isMuted", instr->is_muted() );
673                LocalFileMng::writeXmlString( &instrumentNode, "pan_L", to_string( instr->get_pan_l() ) );
674                LocalFileMng::writeXmlString( &instrumentNode, "pan_R", to_string( instr->get_pan_r() ) );
675                LocalFileMng::writeXmlString( &instrumentNode, "randomPitchFactor", to_string( instr->get_random_pitch_factor() ) );
676                LocalFileMng::writeXmlString( &instrumentNode, "gain", to_string( instr->get_gain() ) );
677
678                LocalFileMng::writeXmlBool( &instrumentNode, "filterActive", instr->is_filter_active() );
679                LocalFileMng::writeXmlString( &instrumentNode, "filterCutoff", to_string( instr->get_filter_cutoff() ) );
680                LocalFileMng::writeXmlString( &instrumentNode, "filterResonance", to_string( instr->get_filter_resonance() ) );
681
682                LocalFileMng::writeXmlString( &instrumentNode, "Attack", to_string( instr->get_adsr()->__attack ) );
683                LocalFileMng::writeXmlString( &instrumentNode, "Decay", to_string( instr->get_adsr()->__decay ) );
684                LocalFileMng::writeXmlString( &instrumentNode, "Sustain", to_string( instr->get_adsr()->__sustain ) );
685                LocalFileMng::writeXmlString( &instrumentNode, "Release", to_string( instr->get_adsr()->__release ) );
686
687                LocalFileMng::writeXmlString( &instrumentNode, "muteGroup", to_string( instr->get_mute_group() ) );
688
689                for ( unsigned nLayer = 0; nLayer < MAX_LAYERS; nLayer++ ) {
690                        InstrumentLayer *pLayer = instr->get_layer( nLayer );
691                        if ( pLayer == NULL ) continue;
692                        Sample *pSample = pLayer->get_sample();
693
694                        QString sFilename = pSample->get_filename();
695
696                        //if (instr->getDrumkitName() != "") {
697                        // se e' specificato un drumkit, considero solo il nome del file senza il path
698                        int nPos = sFilename.lastIndexOf( "/" );
699                        sFilename = sFilename.mid( nPos + 1, sFilename.length() );
700                        //}
701
702                        TiXmlElement layerNode( "layer" );
703                        LocalFileMng::writeXmlString( &layerNode, "filename", sFilename );
704                        LocalFileMng::writeXmlString( &layerNode, "min", to_string( pLayer->get_start_velocity() ) );
705                        LocalFileMng::writeXmlString( &layerNode, "max", to_string( pLayer->get_end_velocity() ) );
706                        LocalFileMng::writeXmlString( &layerNode, "gain", to_string( pLayer->get_gain() ) );
707                        LocalFileMng::writeXmlString( &layerNode, "pitch", to_string( pLayer->get_pitch() ) );
708
709                        instrumentNode.InsertEndChild( layerNode );
710                }
711
712                instrumentListNode.InsertEndChild( instrumentNode );
713        }
714
715        rootNode.InsertEndChild( instrumentListNode );
716
717        doc.InsertEndChild( rootNode );
718        doc.SaveFile();
719
720        return 0; // ok
721}
722
723int LocalFileMng::savePlayList( const std::string& patternname)
724{
725        TiXmlDocument doc = patternname.c_str();
726        std::string name = patternname.c_str();
727
728        std::string realname = name.substr(name.rfind("/")+1);
729
730       
731        TiXmlElement rootNode( "playlist" );
732        //LIB_ID just in work to get better usability
733        writeXmlString( &rootNode, "Name", QString (realname.c_str()) );
734        writeXmlString( &rootNode, "LIB_ID", "in_work" );
735               
736        TiXmlElement playlistNode( "Songs" );
737                        for ( uint i = 0; i < Hydrogen::get_instance()->m_PlayList.size(); ++i ){
738                        TiXmlElement nextNode( "next" );
739                        LocalFileMng::writeXmlString ( &nextNode, "song", Hydrogen::get_instance()->m_PlayList[i].m_hFile );
740                        LocalFileMng::writeXmlString ( &nextNode, "script", Hydrogen::get_instance()->m_PlayList[i].m_hScript );
741                        LocalFileMng::writeXmlString ( &nextNode, "enabled", Hydrogen::get_instance()->m_PlayList[i].m_hScriptEnabled );
742                        playlistNode.InsertEndChild( nextNode );
743        }
744
745        rootNode.InsertEndChild( playlistNode );
746        doc.InsertEndChild( rootNode );
747        doc.SaveFile();
748        return 0; // ok
749
750}
751
752int LocalFileMng::loadPlayList( const std::string& patternname)
753{
754
755       
756        std::string playlistInfoFile = patternname;
757        std::ifstream verify( playlistInfoFile.c_str() , std::ios::in | std::ios::binary );
758        if ( verify == NULL ) {
759                //ERRORLOG( "Load Playlist: Data file " + playlistInfoFile + " not found." );
760                return NULL;
761        }
762
763        TiXmlDocument doc( playlistInfoFile.c_str() );
764        doc.LoadFile();
765
766        Hydrogen::get_instance()->m_PlayList.clear();
767
768        TiXmlNode* rootNode;    // root element
769                if ( !( rootNode = doc.FirstChild( "playlist" ) ) ) {
770                ERRORLOG( "Error reading playlist: playlist node not found" );
771                return NULL;
772        }
773       
774        TiXmlNode* playlistNode = rootNode->FirstChild( "Songs" );
775
776        if ( playlistNode ) {
777                // new code :)
778                Hydrogen::get_instance()->m_PlayList.clear();
779                for ( TiXmlNode* nextNode = playlistNode->FirstChild( "next" ); nextNode; nextNode = nextNode->NextSibling( "next" ) ) {
780                        std::string song =  LocalFileMng::readXmlString( nextNode, "song", "" ).toStdString();
781                        std::string script = LocalFileMng::readXmlString( nextNode, "script", "" ).toStdString();
782                        std::string ScriptEnabled = LocalFileMng::readXmlString( nextNode, "enabled", "" ).toStdString();
783
784                        Hydrogen::HPlayListNode playListItem;
785                        playListItem.m_hFile = song.c_str();
786                        playListItem.m_hScript = script.c_str();
787                        playListItem.m_hScriptEnabled = ScriptEnabled.c_str();
788                        Hydrogen::get_instance()->m_PlayList.push_back( playListItem );
789                }
790        }
791        return 0; // ok
792}
793
794
795
796QString LocalFileMng::readXmlString( TiXmlNode* parent, const QString& nodeName, const QString& defaultValue, bool bCanBeEmpty, bool bShouldExists )
797{
798        TiXmlNode* node;
799        if ( parent && ( node = parent->FirstChild( nodeName.toAscii() ) ) ) {
800                if ( node->FirstChild() ) {
801                        return node->FirstChild()->Value();
802                } else {
803                        if ( !bCanBeEmpty ) {
804                                _WARNINGLOG( "Using default value in " + nodeName );
805                        }
806                        return defaultValue;
807                }
808        } else {
809                if ( bShouldExists ) {
810                        _WARNINGLOG( "'" + nodeName + "' node not found" );
811                }
812                return defaultValue;
813        }
814}
815
816
817
818float LocalFileMng::readXmlFloat( TiXmlNode* parent, const QString& nodeName, float defaultValue, bool bCanBeEmpty, bool bShouldExists )
819{
820        TiXmlNode* node;
821        if ( parent && ( node = parent->FirstChild( nodeName.toAscii() ) ) ) {
822                if ( node->FirstChild() ) {
823                        float res = string_to_float( node->FirstChild()->Value() );
824                        return res;
825                } else {
826                        if ( !bCanBeEmpty ) {
827                                _WARNINGLOG( "Using default value in " + nodeName );
828                        }
829                        return defaultValue;
830                }
831        } else {
832                if ( bShouldExists ) {
833                        _WARNINGLOG( "'" + nodeName + "' node not found" );
834                }
835                return defaultValue;
836        }
837}
838
839
840
841int LocalFileMng::readXmlInt( TiXmlNode* parent, const QString& nodeName, int defaultValue, bool bCanBeEmpty, bool bShouldExists )
842{
843        TiXmlNode* node;
844        if ( parent && ( node = parent->FirstChild( nodeName.toAscii() ) ) ) {
845                if ( node->FirstChild() ) {
846                        return atoi( node->FirstChild()->Value() );
847                } else {
848                        if ( !bCanBeEmpty ) {
849                                _WARNINGLOG( "Using default value in " + nodeName );
850                        }
851                        return defaultValue;
852                }
853        } else {
854                if ( bShouldExists )  {
855                        _WARNINGLOG( "'" + nodeName + "' node not found" );
856                }
857                return defaultValue;
858        }
859}
860
861
862
863bool LocalFileMng::readXmlBool( TiXmlNode* parent, const QString& nodeName, bool defaultValue, bool bShouldExists )
864{
865        TiXmlNode* node;
866        if ( parent && ( node = parent->FirstChild( nodeName.toAscii() ) ) ) {
867                if ( node->FirstChild() ) {
868                        if ( QString( node->FirstChild()->Value() ) == "true" ) {
869                                return true;
870                        } else {
871                                return false;
872                        }
873                } else {
874                        _WARNINGLOG( "Using default value in " + nodeName );
875                        return defaultValue;
876                }
877        } else {
878                if ( bShouldExists ) {
879                        _WARNINGLOG( "'" + nodeName + "' node not found" );
880                }
881                return defaultValue;
882        }
883}
884
885
886
887void LocalFileMng::writeXmlString( TiXmlNode *parent, const QString& name, const QString& text )
888{
889        TiXmlElement versionNode( name.toAscii() );
890        TiXmlText versionText( text.toAscii() );
891        versionNode.InsertEndChild( versionText );
892        parent->InsertEndChild( versionNode );
893}
894
895
896
897void LocalFileMng::writeXmlBool( TiXmlNode *parent, const QString& name, bool value )
898{
899        if ( value ) {
900                writeXmlString( parent, name, QString( "true" ) );
901        } else {
902                writeXmlString( parent, name, QString( "false" ) );
903        }
904}
905
906
907
908
909
910
911
912
913
914
915
916
917//-----------------------------------------------------------------------------
918//      Implementation of SongWriter class
919//-----------------------------------------------------------------------------
920
921
922SongWriter::SongWriter()
923                : Object( "SongWriter" )
924{
925//      infoLog("init");
926}
927
928
929
930SongWriter::~SongWriter()
931{
932//      infoLog("destroy");
933}
934
935
936
937void SongWriter::writeSong( Song *song, const QString& filename )
938{
939        INFOLOG( "Saving song " + filename );
940
941        // FIXME: verificare se e' possibile scrivere il file
942        // FIXME: verificare che il file non sia gia' esistente
943        // FIXME: effettuare copia di backup per il file gia' esistente
944
945        TiXmlDocument doc( filename.toAscii() );
946
947        TiXmlElement songNode( "song" );
948
949        LocalFileMng::writeXmlString( &songNode, "version", QString( VERSION.c_str() ) );
950        LocalFileMng::writeXmlString( &songNode, "bpm", to_string( song->__bpm ) );
951        LocalFileMng::writeXmlString( &songNode, "volume", to_string( song->get_volume() ) );
952        LocalFileMng::writeXmlString( &songNode, "metronomeVolume", to_string( song->get_metronome_volume() ) );
953        LocalFileMng::writeXmlString( &songNode, "name", song->__name );
954        LocalFileMng::writeXmlString( &songNode, "author", song->__author );
955        LocalFileMng::writeXmlString( &songNode, "notes", song->get_notes() );
956        LocalFileMng::writeXmlString( &songNode, "license", song->get_license() );
957        LocalFileMng::writeXmlBool( &songNode, "loopEnabled", song->is_loop_enabled() );
958
959        if ( song->get_mode() == Song::SONG_MODE ) {
960                LocalFileMng::writeXmlString( &songNode, "mode", QString( "song" ) );
961        } else {
962                LocalFileMng::writeXmlString( &songNode, "mode", QString( "pattern" ) );
963        }
964
965        LocalFileMng::writeXmlString( &songNode, "humanize_time", to_string( song->get_humanize_time_value() ) );
966        LocalFileMng::writeXmlString( &songNode, "humanize_velocity", to_string( song->get_humanize_velocity_value() ) );
967        LocalFileMng::writeXmlString( &songNode, "swing_factor", to_string( song->get_swing_factor() ) );
968
969        /*      LocalFileMng::writeXmlBool( &songNode, "delayFXEnabled", song->m_bDelayFXEnabled );
970                LocalFileMng::writeXmlString( &songNode, "delayFXWetLevel", to_string( song->m_fDelayFXWetLevel ) );
971                LocalFileMng::writeXmlString( &songNode, "delayFXFeedback", to_string( song->m_fDelayFXFeedback ) );
972                LocalFileMng::writeXmlString( &songNode, "delayFXTime", to_string( song->m_nDelayFXTime ) );
973        */
974
975        // instrument list
976        TiXmlElement instrumentListNode( "instrumentList" );
977        unsigned nInstrument = song->get_instrument_list()->get_size();
978
979        // INSTRUMENT NODE
980        for ( unsigned i = 0; i < nInstrument; i++ ) {
981                Instrument *instr = song->get_instrument_list()->get( i );
982                assert( instr );
983
984                TiXmlElement instrumentNode( "instrument" );
985
986                LocalFileMng::writeXmlString( &instrumentNode, "id", instr->get_id() );
987                LocalFileMng::writeXmlString( &instrumentNode, "drumkit", instr->get_drumkit_name() );
988                LocalFileMng::writeXmlString( &instrumentNode, "name", instr->get_name() );
989                LocalFileMng::writeXmlString( &instrumentNode, "volume", to_string( instr->get_volume() ) );
990                LocalFileMng::writeXmlBool( &instrumentNode, "isMuted", instr->is_muted() );
991                LocalFileMng::writeXmlString( &instrumentNode, "pan_L", to_string( instr->get_pan_l() ) );
992                LocalFileMng::writeXmlString( &instrumentNode, "pan_R", to_string( instr->get_pan_r() ) );
993                LocalFileMng::writeXmlString( &instrumentNode, "gain", to_string( instr->get_gain() ) );
994
995                LocalFileMng::writeXmlBool( &instrumentNode, "filterActive", instr->is_filter_active() );
996                LocalFileMng::writeXmlString( &instrumentNode, "filterCutoff", to_string( instr->get_filter_cutoff() ) );
997                LocalFileMng::writeXmlString( &instrumentNode, "filterResonance", to_string( instr->get_filter_resonance() ) );
998
999                LocalFileMng::writeXmlString( &instrumentNode, "FX1Level", to_string( instr->get_fx_level( 0 ) ) );
1000                LocalFileMng::writeXmlString( &instrumentNode, "FX2Level", to_string( instr->get_fx_level( 1 ) ) );
1001                LocalFileMng::writeXmlString( &instrumentNode, "FX3Level", to_string( instr->get_fx_level( 2 ) ) );
1002                LocalFileMng::writeXmlString( &instrumentNode, "FX4Level", to_string( instr->get_fx_level( 3 ) ) );
1003
1004                assert( instr->get_adsr() );
1005                LocalFileMng::writeXmlString( &instrumentNode, "Attack", to_string( instr->get_adsr()->__attack ) );
1006                LocalFileMng::writeXmlString( &instrumentNode, "Decay", to_string( instr->get_adsr()->__decay ) );
1007                LocalFileMng::writeXmlString( &instrumentNode, "Sustain", to_string( instr->get_adsr()->__sustain ) );
1008                LocalFileMng::writeXmlString( &instrumentNode, "Release", to_string( instr->get_adsr()->__release ) );
1009
1010                LocalFileMng::writeXmlString( &instrumentNode, "randomPitchFactor", to_string( instr->get_random_pitch_factor() ) );
1011
1012                LocalFileMng::writeXmlString( &instrumentNode, "muteGroup", to_string( instr->get_mute_group() ) );
1013
1014                for ( unsigned nLayer = 0; nLayer < MAX_LAYERS; nLayer++ ) {
1015                        InstrumentLayer *pLayer = instr->get_layer( nLayer );
1016                        if ( pLayer == NULL ) continue;
1017                        Sample *pSample = pLayer->get_sample();
1018                        if ( pSample == NULL ) continue;
1019
1020                        QString sFilename = pSample->get_filename();
1021
1022                        if ( instr->get_drumkit_name() != "" ) {
1023                                // se e' specificato un drumkit, considero solo il nome del file senza il path
1024                                int nPos = sFilename.lastIndexOf( "/" );
1025                                sFilename = sFilename.mid( nPos + 1, sFilename.length() );
1026                        }
1027
1028                        TiXmlElement layerNode( "layer" );
1029                        LocalFileMng::writeXmlString( &layerNode, "filename", sFilename );
1030                        LocalFileMng::writeXmlString( &layerNode, "min", to_string( pLayer->get_start_velocity() ) );
1031                        LocalFileMng::writeXmlString( &layerNode, "max", to_string( pLayer->get_end_velocity() ) );
1032                        LocalFileMng::writeXmlString( &layerNode, "gain", to_string( pLayer->get_gain() ) );
1033                        LocalFileMng::writeXmlString( &layerNode, "pitch", to_string( pLayer->get_pitch() ) );
1034
1035                        instrumentNode.InsertEndChild( layerNode );
1036                }
1037
1038                instrumentListNode.InsertEndChild( instrumentNode );
1039        }
1040        songNode.InsertEndChild( instrumentListNode );
1041
1042
1043        // pattern list
1044        TiXmlElement patternListNode( "patternList" );
1045
1046        unsigned nPatterns = song->get_pattern_list()->get_size();
1047        for ( unsigned i = 0; i < nPatterns; i++ ) {
1048                Pattern *pat = song->get_pattern_list()->get( i );
1049
1050                // pattern
1051                TiXmlElement patternNode( "pattern" );
1052                LocalFileMng::writeXmlString( &patternNode, "name", pat->get_name() );
1053                LocalFileMng::writeXmlString( &patternNode, "category", pat->get_category() );
1054                LocalFileMng::writeXmlString( &patternNode, "size", to_string( pat->get_lenght() ) );
1055
1056                TiXmlElement noteListNode( "noteList" );
1057                std::multimap <int, Note*>::iterator pos;
1058                for ( pos = pat->note_map.begin(); pos != pat->note_map.end(); ++pos ) {
1059                        Note *pNote = pos->second;
1060                        assert( pNote );
1061
1062                        TiXmlElement noteNode( "note" );
1063                        LocalFileMng::writeXmlString( &noteNode, "position", to_string( pNote->get_position() ) );
1064                        LocalFileMng::writeXmlString( &noteNode, "leadlag", to_string( pNote->get_leadlag() ) );
1065                        LocalFileMng::writeXmlString( &noteNode, "velocity", to_string( pNote->get_velocity() ) );
1066                        LocalFileMng::writeXmlString( &noteNode, "pan_L", to_string( pNote->get_pan_l() ) );
1067                        LocalFileMng::writeXmlString( &noteNode, "pan_R", to_string( pNote->get_pan_r() ) );
1068                        LocalFileMng::writeXmlString( &noteNode, "pitch", to_string( pNote->get_pitch() ) );
1069
1070                        LocalFileMng::writeXmlString( &noteNode, "key", Note::keyToString( pNote->m_noteKey ) );
1071
1072                        LocalFileMng::writeXmlString( &noteNode, "length", to_string( pNote->get_lenght() ) );
1073                        LocalFileMng::writeXmlString( &noteNode, "instrument", pNote->get_instrument()->get_id() );
1074                        noteListNode.InsertEndChild( noteNode );
1075                }
1076                patternNode.InsertEndChild( noteListNode );
1077
1078                patternListNode.InsertEndChild( patternNode );
1079        }
1080        songNode.InsertEndChild( patternListNode );
1081
1082
1083        // pattern sequence
1084        TiXmlElement patternSequenceNode( "patternSequence" );
1085
1086        unsigned nPatternGroups = song->get_pattern_group_vector()->size();
1087        for ( unsigned i = 0; i < nPatternGroups; i++ ) {
1088                TiXmlElement groupNode( "group" );
1089
1090                PatternList *pList = ( *song->get_pattern_group_vector() )[i];
1091                for ( unsigned j = 0; j < pList->get_size(); j++ ) {
1092                        Pattern *pPattern = pList->get( j );
1093                        LocalFileMng::writeXmlString( &groupNode, "patternID", pPattern->get_name() );
1094                }
1095                patternSequenceNode.InsertEndChild( groupNode );
1096        }
1097
1098        songNode.InsertEndChild( patternSequenceNode );
1099
1100
1101        // LADSPA FX
1102        TiXmlElement ladspaFxNode( "ladspa" );
1103
1104        for ( unsigned nFX = 0; nFX < MAX_FX; nFX++ ) {
1105                TiXmlElement fxNode( "fx" );
1106
1107#ifdef LADSPA_SUPPORT
1108                LadspaFX *pFX = Effects::getInstance()->getLadspaFX( nFX );
1109                if ( pFX ) {
1110                        LocalFileMng::writeXmlString( &fxNode, "name", pFX->getPluginLabel() );
1111                        LocalFileMng::writeXmlString( &fxNode, "filename", pFX->getLibraryPath() );
1112                        LocalFileMng::writeXmlBool( &fxNode, "enabled", pFX->isEnabled() );
1113                        LocalFileMng::writeXmlString( &fxNode, "volume", to_string( pFX->getVolume() ) );
1114                        for ( unsigned nControl = 0; nControl < pFX->inputControlPorts.size(); nControl++ ) {
1115                                LadspaControlPort *pControlPort = pFX->inputControlPorts[ nControl ];
1116                                TiXmlElement controlPortNode( "inputControlPort" );
1117                                LocalFileMng::writeXmlString( &controlPortNode, "name", pControlPort->sName );
1118                                LocalFileMng::writeXmlString( &controlPortNode, "value", to_string( pControlPort->fControlValue ) );
1119                                fxNode.InsertEndChild( controlPortNode );
1120                        }
1121                        for ( unsigned nControl = 0; nControl < pFX->outputControlPorts.size(); nControl++ ) {
1122                                LadspaControlPort *pControlPort = pFX->inputControlPorts[ nControl ];
1123                                TiXmlElement controlPortNode( "outputControlPort" );
1124                                LocalFileMng::writeXmlString( &controlPortNode, "name", pControlPort->sName );
1125                                LocalFileMng::writeXmlString( &controlPortNode, "value", to_string( pControlPort->fControlValue ) );
1126                                fxNode.InsertEndChild( controlPortNode );
1127                        }
1128                }
1129#else
1130                if ( false ) {
1131                }
1132#endif
1133                else {
1134                        LocalFileMng::writeXmlString( &fxNode, "name", QString( "no plugin" ) );
1135                        LocalFileMng::writeXmlString( &fxNode, "filename", QString( "-" ) );
1136                        LocalFileMng::writeXmlBool( &fxNode, "enabled", false );
1137                        LocalFileMng::writeXmlString( &fxNode, "volume", to_string( 0.0 ) );
1138                }
1139                ladspaFxNode.InsertEndChild( fxNode );
1140        }
1141
1142        songNode.InsertEndChild( ladspaFxNode );
1143
1144
1145
1146
1147        doc.InsertEndChild( songNode );
1148        doc.SaveFile();
1149
1150        song->__is_modified = false;
1151        song->set_filename( filename );
1152}
1153
1154
1155};
1156
Note: See TracBrowser for help on using the browser.