root/branches/new_fx_rack_and_sample_fun/libs/hydrogen/src/local_file_mgr.cpp @ 625

Revision 625, 43.0 KB (checked in by wolke, 5 years ago)

samples play reverse and pingpong

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