root/branches/jackMidi/libs/hydrogen/src/local_file_mgr.cpp @ 534

Revision 534, 42.4 KB (checked in by gabriel, 5 years ago)

Merge rev 428:439 from trunk

Conflicts:

libs/hydrogen/src/hydrogen.cpp

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