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

Revision 284, 38.7 KB (checked in by smoors, 5 years ago)

removed experimental LIB_ID from patterns

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