root/trunk/src/core/src/basics/song.cpp @ 2261

Revision 2261, 39.5 KB (checked in by jeremyz, 23 months ago)

start cleaning Pattern class

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 "hydrogen/version.h"
24
25#include <cassert>
26
27#include <hydrogen/basics/adsr.h>
28#include <hydrogen/LocalFileMng.h>
29#include <hydrogen/Preferences.h>
30
31#include <hydrogen/fx/Effects.h>
32#include <hydrogen/globals.h>
33#include <hydrogen/basics/song.h>
34#include <hydrogen/basics/sample.h>
35#include <hydrogen/basics/instrument.h>
36#include <hydrogen/basics/instrument_list.h>
37#include <hydrogen/basics/instrument_layer.h>
38#include <hydrogen/basics/pattern.h>
39#include <hydrogen/basics/pattern_list.h>
40#include <hydrogen/basics/note.h>
41#include <hydrogen/helpers/filesystem.h>
42#include <hydrogen/hydrogen.h>
43
44#include <QDomDocument>
45
46namespace
47{
48
49void addEdges( std::set<H2Core::Pattern*> &patternSet )
50{
51    std::set<H2Core::Pattern*> curPatternSet = patternSet;
52
53    for ( std::set<H2Core::Pattern*>::const_iterator setIter = curPatternSet.begin(); setIter != curPatternSet.end(); ++setIter ) {
54        for ( std::set<H2Core::Pattern*>::const_iterator innerSetIter = ( *setIter )->virtual_pattern_set.begin(); innerSetIter != ( *setIter )->virtual_pattern_set.end(); ++innerSetIter ) {
55            patternSet.insert( *innerSetIter );
56        }//for
57    }//for
58
59    if ( patternSet.size() != curPatternSet.size() ) {
60        addEdges( patternSet );
61    }//if
62}//addEdges
63
64void computeVirtualPatternTransitiveClosure( H2Core::PatternList* pPatternList )
65{
66    //std::map<Pattern*, SimplePatternNode*> patternNodeGraph;
67
68    int listsize = pPatternList->size();
69    for ( unsigned int index = 0; index < listsize; ++index ) {
70        H2Core::Pattern* curPattern = pPatternList->get( index );
71        //SimplePatternNode *newNode = new SimplePatternNode();
72        //newNode->curPattern = curPattern;
73        //newNode->colour = 0;
74        //newNode->edges = curPattern->virtual_pattern_set;
75
76        curPattern->virtual_pattern_transitive_closure_set = curPattern->virtual_pattern_set;
77
78        addEdges( curPattern->virtual_pattern_transitive_closure_set );
79
80        //patternNodeGraph[curPattern] = newNode;
81    }//for
82}//computeVirtualPatternTransitiveClosure
83
84}//anonymous namespace
85namespace H2Core
86{
87
88const char* Song::__class_name = "Song";
89
90Song::Song( const QString& name, const QString& author, float bpm, float volume )
91    : Object( __class_name )
92    , __is_muted( false )
93    , __resolution( 48 )
94    , __bpm( bpm )
95    , __is_modified( false )
96    , __name( name )
97    , __author( author )
98    , __volume( volume )
99    , __metronome_volume( 0.5 )
100    , __pattern_list( NULL )
101    , __pattern_group_sequence( NULL )
102    , __instrument_list( NULL )
103    , __filename( "" )
104    , __is_loop_enabled( false )
105    , __humanize_time_value( 0.0 )
106    , __humanize_velocity_value( 0.0 )
107    , __swing_factor( 0.0 )
108    , __song_mode( PATTERN_MODE )
109{
110    INFOLOG( QString( "INIT '%1'" ).arg( __name ) );
111
112    //m_bDelayFXEnabled = false;
113    //m_fDelayFXWetLevel = 0.8;
114    //m_fDelayFXFeedback = 0.5;
115    //m_nDelayFXTime = MAX_NOTES / 8;
116}
117
118
119
120Song::~Song()
121{
122    // delete all patterns
123    delete __pattern_list;
124
125    if ( __pattern_group_sequence ) {
126        for ( unsigned i = 0; i < __pattern_group_sequence->size(); ++i ) {
127            PatternList* pPatternList = ( *__pattern_group_sequence )[i];
128            pPatternList->clear();      // pulisco tutto, i pattern non vanno distrutti qua
129            delete pPatternList;
130        }
131        delete __pattern_group_sequence;
132    }
133
134    delete __instrument_list;
135
136    INFOLOG( QString( "DESTROY '%1'" ).arg( __name ) );
137}
138
139void Song::purge_instrument( Instrument* I )
140{
141    for ( int nPattern = 0; nPattern < ( int )__pattern_list->size(); ++nPattern ) {
142        __pattern_list->get( nPattern )->purge_instrument( I );
143    }
144}
145
146
147///Load a song from file
148Song* Song::load( const QString& filename )
149{
150    Song* song = NULL;
151
152    SongReader reader;
153    song = reader.readSong( filename );
154
155    return song;
156}
157
158
159
160/// Save a song to file
161bool Song::save( const QString& filename )
162{
163    SongWriter writer;
164    int err;
165    err = writer.writeSong( this, filename );
166
167    if( err ) {
168        return false;
169    }
170    return QFile::exists( filename );
171}
172
173
174/// Create default song
175Song* Song::get_default_song()
176{
177
178    Song* song = new Song( "empty", "hydrogen", 120, 0.5 );
179
180    song->set_metronome_volume( 0.5 );
181    song->set_notes( "..." );
182    song->set_license( "" );
183    song->set_loop_enabled( false );
184    song->set_mode( Song::PATTERN_MODE );
185    song->set_humanize_time_value( 0.0 );
186    song->set_humanize_velocity_value( 0.0 );
187    song->set_swing_factor( 0.0 );
188
189    InstrumentList* pList = new InstrumentList();
190    Instrument* pNewInstr = new Instrument( EMPTY_INSTR_ID, "New instrument" );
191    pList->add( pNewInstr );
192    song->set_instrument_list( pList );
193
194#ifdef H2CORE_HAVE_JACK
195    Hydrogen::get_instance()->renameJackPorts();
196#endif
197
198    PatternList* patternList = new PatternList();
199    Pattern* emptyPattern = new Pattern();
200    emptyPattern->set_name( QString( "Pattern 1" ) );
201    emptyPattern->set_category( QString( "not_categorized" ) );
202    patternList->add( emptyPattern );
203    song->set_pattern_list( patternList );
204    std::vector<PatternList*>* pPatternGroupVector = new std::vector<PatternList*>;
205    PatternList* patternSequence = new PatternList();
206    patternSequence->add( emptyPattern );
207    pPatternGroupVector->push_back( patternSequence );
208    song->set_pattern_group_vector( pPatternGroupVector );
209    song->__is_modified = false;
210    song->set_filename( "empty_song" );
211
212    return song;
213
214}
215
216/// Return an empty song
217Song* Song::get_empty_song()
218{
219
220    Song* song = Song::load( Filesystem::empty_song() );
221
222    /* if file DefaultSong.h2song not accessible
223     * create a simple default song.
224     */
225    if( !song ) {
226        song = Song::get_default_song();
227    }
228
229    return song;
230}
231
232
233
234void Song::set_swing_factor( float factor )
235{
236    if ( factor < 0.0 ) {
237        factor = 0.0;
238    } else if ( factor > 1.0 ) {
239        factor = 1.0;
240    }
241
242    __swing_factor = factor;
243}
244
245
246void Song::readTempPatternList( QString filename )
247{
248    Hydrogen* engine = Hydrogen::get_instance();
249
250    //AudioEngine::get_instance()->lock( RIGHT_HERE );
251
252    Song* song = engine->getSong();
253
254    if ( QFile( filename ).exists() == false ) {
255        ERRORLOG( "tep file " + filename + " not found." );
256        return;
257    }
258
259    QDomDocument doc = LocalFileMng::openXmlDocument( filename );
260    QDomNodeList nodeList = doc.elementsByTagName( "tempPatternList" );
261
262
263    if( nodeList.isEmpty() ) {
264        ERRORLOG( "Error reading tmp file" );
265        return;
266    }
267
268    QDomNode songNode = nodeList.at( 0 );
269
270
271
272    // Virtual Patterns
273    QDomNode  virtualPatternListNode = songNode.firstChildElement( "virtualPatternList" );
274    QDomNode virtualPatternNode = virtualPatternListNode.firstChildElement( "pattern" );
275    if ( !virtualPatternNode.isNull() ) {
276
277        while (  ! virtualPatternNode.isNull()  ) {
278            QString sName = "";
279            sName = LocalFileMng::readXmlString( virtualPatternNode, "name", sName );
280
281            Pattern* curPattern = NULL;
282            unsigned nPatterns = song->get_pattern_list()->size();
283            for ( unsigned i = 0; i < nPatterns; i++ ) {
284                Pattern* pat = song->get_pattern_list()->get( i );
285
286                if ( pat->get_name() == sName ) {
287                    curPattern = pat;
288                    break;
289                }//if
290            }//for
291
292            if ( curPattern != NULL ) {
293                QDomNode  virtualNode = virtualPatternNode.firstChildElement( "virtual" );
294                while (  !virtualNode.isNull()  ) {
295                    QString virtName = virtualNode.firstChild().nodeValue();
296
297                    Pattern* virtPattern = NULL;
298                    for ( unsigned i = 0; i < nPatterns; i++ ) {
299                        Pattern* pat = song->get_pattern_list()->get( i );
300
301                        if ( pat->get_name() == virtName ) {
302                            virtPattern = pat;
303                            break;
304                        }//if
305                    }//for
306
307                    if ( virtPattern != NULL ) {
308                        curPattern->virtual_pattern_set.insert( virtPattern );
309                    } else {
310                        ERRORLOG( "Song had invalid virtual pattern list data (virtual)" );
311                    }//if
312                    virtualNode = ( QDomNode ) virtualNode.nextSiblingElement( "virtual" );
313                }//while
314            } else {
315                ERRORLOG( "Song had invalid virtual pattern list data (name)" );
316            }//if
317            virtualPatternNode = ( QDomNode ) virtualPatternNode.nextSiblingElement( "pattern" );
318        }//while
319    }//if
320
321    computeVirtualPatternTransitiveClosure( song->get_pattern_list() );
322
323    // Pattern sequence
324    QDomNode patternSequenceNode = songNode.firstChildElement( "patternSequence" );
325
326    std::vector<PatternList*> *pPatternGroupVector = song->get_pattern_group_vector();
327    pPatternGroupVector->clear();
328
329    PatternList* patternSequence;
330    QDomNode groupNode = patternSequenceNode.firstChildElement( "group" );
331    while (  !groupNode.isNull()  ) {
332        patternSequence = new PatternList();
333        QDomNode patternId = groupNode.firstChildElement( "patternID" );
334        while (  !patternId.isNull()  ) {
335            QString patId = patternId.firstChild().nodeValue();
336
337            Pattern* pat = NULL;
338            for ( unsigned i = 0; i < song->get_pattern_list()->size(); i++ ) {
339                Pattern* tmp = song->get_pattern_list()->get( i );
340                if ( tmp ) {
341                    if ( tmp->get_name() == patId ) {
342                        pat = tmp;
343                        break;
344                    }
345                }
346            }
347            if ( pat == NULL ) {
348                WARNINGLOG( "patternid not found in patternSequence" );
349                patternId = ( QDomNode ) patternId.nextSiblingElement( "patternID" );
350                continue;
351            }
352            patternSequence->add( pat );
353            patternId = ( QDomNode ) patternId.nextSiblingElement( "patternID" );
354        }
355        pPatternGroupVector->push_back( patternSequence );
356
357        groupNode = groupNode.nextSiblingElement( "group" );
358    }
359
360    song->set_pattern_group_vector( pPatternGroupVector );
361
362}
363
364//::::::::::::::::::::
365
366
367
368
369
370
371
372//-----------------------------------------------------------------------------
373//      Implementation of SongReader class
374//-----------------------------------------------------------------------------
375
376const char* SongReader::__class_name = "SongReader";
377
378SongReader::SongReader()
379    : Object( __class_name )
380{
381//      infoLog("init");
382}
383
384
385
386SongReader::~SongReader()
387{
388//      infoLog("destroy");
389}
390
391
392
393///
394/// Reads a song.
395/// return NULL = error reading song file.
396///
397Song* SongReader::readSong( const QString& filename )
398{
399    INFOLOG( filename );
400    Song* song = NULL;
401
402    if ( QFile( filename ).exists() == false ) {
403        ERRORLOG( "Song file " + filename + " not found." );
404        return NULL;
405    }
406
407    QDomDocument doc = LocalFileMng::openXmlDocument( filename );
408    QDomNodeList nodeList = doc.elementsByTagName( "song" );
409
410
411    if( nodeList.isEmpty() ) {
412        ERRORLOG( "Error reading song: song node not found" );
413        return NULL;
414    }
415
416    QDomNode songNode = nodeList.at( 0 );
417
418    m_sSongVersion = LocalFileMng::readXmlString( songNode , "version", "Unknown version" );
419
420
421    if ( m_sSongVersion != QString( get_version().c_str() ) ) {
422        WARNINGLOG( "Trying to load a song created with a different version of hydrogen." );
423        WARNINGLOG( "Song [" + filename + "] saved with version " + m_sSongVersion );
424    }
425
426
427
428
429    float fBpm = LocalFileMng::readXmlFloat( songNode, "bpm", 120 );
430    Hydrogen::get_instance()->setNewBpmJTM( fBpm );
431    float fVolume = LocalFileMng::readXmlFloat( songNode, "volume", 0.5 );
432    float fMetronomeVolume = LocalFileMng::readXmlFloat( songNode, "metronomeVolume", 0.5 );
433    QString sName( LocalFileMng::readXmlString( songNode, "name", "Untitled Song" ) );
434    QString sAuthor( LocalFileMng::readXmlString( songNode, "author", "Unknown Author" ) );
435    QString sNotes( LocalFileMng::readXmlString( songNode, "notes", "..." ) );
436    QString sLicense( LocalFileMng::readXmlString( songNode, "license", "Unknown license" ) );
437    bool bLoopEnabled = LocalFileMng::readXmlBool( songNode, "loopEnabled", false );
438
439    Song::SongMode nMode = Song::PATTERN_MODE;  // Mode (song/pattern)
440    QString sMode = LocalFileMng::readXmlString( songNode, "mode", "pattern" );
441    if ( sMode == "song" ) {
442        nMode = Song::SONG_MODE;
443    }
444
445    float fHumanizeTimeValue = LocalFileMng::readXmlFloat( songNode, "humanize_time", 0.0 );
446    float fHumanizeVelocityValue = LocalFileMng::readXmlFloat( songNode, "humanize_velocity", 0.0 );
447    float fSwingFactor = LocalFileMng::readXmlFloat( songNode, "swing_factor", 0.0 );
448
449    song = new Song( sName, sAuthor, fBpm, fVolume );
450    song->set_metronome_volume( fMetronomeVolume );
451    song->set_notes( sNotes );
452    song->set_license( sLicense );
453    song->set_loop_enabled( bLoopEnabled );
454    song->set_mode( nMode );
455    song->set_humanize_time_value( fHumanizeTimeValue );
456    song->set_humanize_velocity_value( fHumanizeVelocityValue );
457    song->set_swing_factor( fSwingFactor );
458
459
460
461    /*
462    song->m_bDelayFXEnabled = LocalFileMng::readXmlBool( songNode, "delayFXEnabled", false, false );
463    song->m_fDelayFXWetLevel = LocalFileMng::readXmlFloat( songNode, "delayFXWetLevel", 1.0, false, false );
464    song->m_fDelayFXFeedback= LocalFileMng::readXmlFloat( songNode, "delayFXFeedback", 0.4, false, false );
465    song->m_nDelayFXTime = LocalFileMng::readXmlInt( songNode, "delayFXTime", MAX_NOTES / 4, false, false );
466    */
467
468
469    //  Instrument List
470
471    LocalFileMng localFileMng;
472    InstrumentList* instrumentList = new InstrumentList();
473
474    QDomNode instrumentListNode = songNode.firstChildElement( "instrumentList" );
475    if ( ( ! instrumentListNode.isNull()  ) ) {
476        // INSTRUMENT NODE
477        int instrumentList_count = 0;
478        QDomNode instrumentNode;
479        instrumentNode = instrumentListNode.firstChildElement( "instrument" );
480        while ( ! instrumentNode.isNull()  ) {
481            instrumentList_count++;
482
483            int id = LocalFileMng::readXmlInt( instrumentNode, "id", -1 );                      // instrument id
484            QString sDrumkit = LocalFileMng::readXmlString( instrumentNode, "drumkit", "" );    // drumkit
485            Hydrogen::get_instance()->setCurrentDrumkitname( sDrumkit );
486            QString sName = LocalFileMng::readXmlString( instrumentNode, "name", "" );          // name
487            float fVolume = LocalFileMng::readXmlFloat( instrumentNode, "volume", 1.0 );        // volume
488            bool bIsMuted = LocalFileMng::readXmlBool( instrumentNode, "isMuted", false );      // is muted
489            float fPan_L = LocalFileMng::readXmlFloat( instrumentNode, "pan_L", 0.5 );  // pan L
490            float fPan_R = LocalFileMng::readXmlFloat( instrumentNode, "pan_R", 0.5 );  // pan R
491            float fFX1Level = LocalFileMng::readXmlFloat( instrumentNode, "FX1Level", 0.0 );    // FX level
492            float fFX2Level = LocalFileMng::readXmlFloat( instrumentNode, "FX2Level", 0.0 );    // FX level
493            float fFX3Level = LocalFileMng::readXmlFloat( instrumentNode, "FX3Level", 0.0 );    // FX level
494            float fFX4Level = LocalFileMng::readXmlFloat( instrumentNode, "FX4Level", 0.0 );    // FX level
495            float fGain = LocalFileMng::readXmlFloat( instrumentNode, "gain", 1.0, false, false );      // instrument gain
496
497            int fAttack = LocalFileMng::readXmlInt( instrumentNode, "Attack", 0, false, false );                // Attack
498            int fDecay = LocalFileMng::readXmlInt( instrumentNode, "Decay", 0, false, false );          // Decay
499            float fSustain = LocalFileMng::readXmlFloat( instrumentNode, "Sustain", 1.0, false, false );        // Sustain
500            int fRelease = LocalFileMng::readXmlInt( instrumentNode, "Release", 1000, false, false );   // Release
501
502            float fRandomPitchFactor = LocalFileMng::readXmlFloat( instrumentNode, "randomPitchFactor", 0.0f, false, false );
503
504            bool bFilterActive = LocalFileMng::readXmlBool( instrumentNode, "filterActive", false );
505            float fFilterCutoff = LocalFileMng::readXmlFloat( instrumentNode, "filterCutoff", 1.0f, false );
506            float fFilterResonance = LocalFileMng::readXmlFloat( instrumentNode, "filterResonance", 0.0f, false );
507            QString sMuteGroup = LocalFileMng::readXmlString( instrumentNode, "muteGroup", "-1", false );
508            QString sMidiOutChannel = LocalFileMng::readXmlString( instrumentNode, "midiOutChannel", "-1", false, false );
509            QString sMidiOutNote = LocalFileMng::readXmlString( instrumentNode, "midiOutNote", "60", false, false );
510            int nMuteGroup = sMuteGroup.toInt();
511            bool isStopNote = LocalFileMng::readXmlBool( instrumentNode, "isStopNote", false );
512            int nMidiOutChannel = sMidiOutChannel.toInt();
513            int nMidiOutNote = sMidiOutNote.toInt();
514
515            if ( id==-1 ) {
516                ERRORLOG( "Empty ID for instrument '" + sName + "'. skipping." );
517                instrumentNode = ( QDomNode ) instrumentNode.nextSiblingElement( "instrument" );
518                continue;
519            }
520
521
522            // create a new instrument
523            Instrument* pInstrument = new Instrument( id, sName, new ADSR( fAttack, fDecay, fSustain, fRelease ) );
524            pInstrument->set_volume( fVolume );
525            pInstrument->set_muted( bIsMuted );
526            pInstrument->set_pan_l( fPan_L );
527            pInstrument->set_pan_r( fPan_R );
528            //pInstrument->set_drumkit_name( sDrumkit );
529            pInstrument->set_fx_level( fFX1Level, 0 );
530            pInstrument->set_fx_level( fFX2Level, 1 );
531            pInstrument->set_fx_level( fFX3Level, 2 );
532            pInstrument->set_fx_level( fFX4Level, 3 );
533            pInstrument->set_random_pitch_factor( fRandomPitchFactor );
534            pInstrument->set_filter_active( bFilterActive );
535            pInstrument->set_filter_cutoff( fFilterCutoff );
536            pInstrument->set_filter_resonance( fFilterResonance );
537            pInstrument->set_gain( fGain );
538            pInstrument->set_mute_group( nMuteGroup );
539            pInstrument->set_stop_notes( isStopNote );
540            pInstrument->set_midi_out_channel( nMidiOutChannel );
541            pInstrument->set_midi_out_note( nMidiOutNote );
542
543            QString drumkitPath;
544            if ( ( !sDrumkit.isEmpty() ) && ( sDrumkit != "-" ) ) {
545                drumkitPath = Filesystem::drumkit_path_search( sDrumkit );
546            }
547
548
549            QDomNode filenameNode = instrumentNode.firstChildElement( "filename" );
550
551
552            // back compatibility code ( song version <= 0.9.0 )
553            if ( ! filenameNode.isNull() ) {
554                WARNINGLOG( "Using back compatibility code. filename node found" );
555                QString sFilename = LocalFileMng::readXmlString( instrumentNode, "filename", "" );
556
557                if ( !QFile( sFilename ).exists() && !drumkitPath.isEmpty() ) {
558                    sFilename = drumkitPath + "/" + sFilename;
559                }
560                Sample* pSample = Sample::load( sFilename );
561                if ( pSample == NULL ) {
562                    // nel passaggio tra 0.8.2 e 0.9.0 il drumkit di default e' cambiato.
563                    // Se fallisce provo a caricare il corrispettivo file in formato flac
564//                                      warningLog( "[readSong] Error loading sample: " + sFilename + " not found. Trying to load a flac..." );
565                    sFilename = sFilename.left( sFilename.length() - 4 );
566                    sFilename += ".flac";
567                    pSample = Sample::load( sFilename );
568                }
569                if ( pSample == NULL ) {
570                    ERRORLOG( "Error loading sample: " + sFilename + " not found" );
571                    pInstrument->set_muted( true );
572                }
573                InstrumentLayer* pLayer = new InstrumentLayer( pSample );
574                pInstrument->set_layer( pLayer, 0 );
575            }
576            //~ back compatibility code
577            else {
578                unsigned nLayer = 0;
579                QDomNode layerNode = instrumentNode.firstChildElement( "layer" );
580                while (  ! layerNode.isNull()  ) {
581                    if ( nLayer >= MAX_LAYERS ) {
582                        ERRORLOG( "nLayer > MAX_LAYERS" );
583                        continue;
584                    }
585                    //bool sIsModified = false;
586                    QString sFilename = LocalFileMng::readXmlString( layerNode, "filename", "" );
587                    bool sIsModified = LocalFileMng::readXmlBool( layerNode, "ismodified", false );
588                    Sample::Loops lo;
589                    lo.mode = Sample::parse_loop_mode( LocalFileMng::readXmlString( layerNode, "smode", "forward" ) );
590                    lo.start_frame = LocalFileMng::readXmlInt( layerNode, "startframe", 0 );
591                    lo.loop_frame = LocalFileMng::readXmlInt( layerNode, "loopframe", 0 );
592                    lo.count = LocalFileMng::readXmlInt( layerNode, "loops", 0 );
593                    lo.end_frame = LocalFileMng::readXmlInt( layerNode, "endframe", 0 );
594                    Sample::Rubberband ro;
595                    ro.use = LocalFileMng::readXmlInt( layerNode, "userubber", 0, false );
596                    ro.divider = LocalFileMng::readXmlFloat( layerNode, "rubberdivider", 0.0 );
597                    ro.c_settings = LocalFileMng::readXmlInt( layerNode, "rubberCsettings", 1 );
598                    ro.pitch = LocalFileMng::readXmlFloat( layerNode, "rubberPitch", 0.0 );
599
600                    float fMin = LocalFileMng::readXmlFloat( layerNode, "min", 0.0 );
601                    float fMax = LocalFileMng::readXmlFloat( layerNode, "max", 1.0 );
602                    float fGain = LocalFileMng::readXmlFloat( layerNode, "gain", 1.0 );
603                    float fPitch = LocalFileMng::readXmlFloat( layerNode, "pitch", 0.0, false, false );
604
605                    if ( !QFile( sFilename ).exists() && !drumkitPath.isEmpty() ) {
606                        sFilename = drumkitPath + "/" + sFilename;
607                    }
608
609                    QString program = Preferences::get_instance()->m_rubberBandCLIexecutable;
610                    //test the path. if test fails, disable rubberband
611                    if ( QFile( program ).exists() == false ) {
612                        ro.use = false;
613                    }
614
615                    Sample* pSample = NULL;
616                    if ( !sIsModified ) {
617                        pSample = Sample::load( sFilename );
618                    } else {
619                        Sample::EnvelopePoint pt;
620
621                        Sample::VelocityEnvelope velocity;
622                        QDomNode volumeNode = layerNode.firstChildElement( "volume" );
623                        while (  ! volumeNode.isNull()  ) {
624                            pt.frame = LocalFileMng::readXmlInt( volumeNode, "volume-position", 0 );
625                            pt.value = LocalFileMng::readXmlInt( volumeNode, "volume-value", 0 );
626                            velocity.push_back( pt );
627                            volumeNode = volumeNode.nextSiblingElement( "volume" );
628                            //ERRORLOG( QString("volume-posi %1").arg(LocalFileMng::readXmlInt( volumeNode, "volume-position", 0)) );
629                        }
630
631                        Sample::VelocityEnvelope pan;
632                        QDomNode  panNode = layerNode.firstChildElement( "pan" );
633                        while (  ! panNode.isNull()  ) {
634                            pt.frame = LocalFileMng::readXmlInt( panNode, "pan-position", 0 );
635                            pt.value = LocalFileMng::readXmlInt( panNode, "pan-value", 0 );
636                            pan.push_back( pt );
637                            panNode = panNode.nextSiblingElement( "pan" );
638                        }
639
640                        pSample = Sample::load( sFilename, lo, ro, velocity, pan );
641                    }
642                    if ( pSample == NULL ) {
643                        ERRORLOG( "Error loading sample: " + sFilename + " not found" );
644                        pInstrument->set_muted( true );
645                    }
646                    InstrumentLayer* pLayer = new InstrumentLayer( pSample );
647                    pLayer->set_start_velocity( fMin );
648                    pLayer->set_end_velocity( fMax );
649                    pLayer->set_gain( fGain );
650                    pLayer->set_pitch( fPitch );
651                    pInstrument->set_layer( pLayer, nLayer );
652                    nLayer++;
653
654                    layerNode = ( QDomNode ) layerNode.nextSiblingElement( "layer" );
655                }
656            }
657
658            instrumentList->add( pInstrument );
659            instrumentNode = ( QDomNode ) instrumentNode.nextSiblingElement( "instrument" );
660        }
661        if ( instrumentList_count == 0 ) {
662            WARNINGLOG( "0 instruments?" );
663        }
664
665        song->set_instrument_list( instrumentList );
666    } else {
667        ERRORLOG( "Error reading song: instrumentList node not found" );
668        delete song;
669        return NULL;
670    }
671
672
673
674    // Pattern list
675    QDomNode patterns = songNode.firstChildElement( "patternList" );
676
677    PatternList* patternList = new PatternList();
678    int pattern_count = 0;
679
680    QDomNode patternNode =  patterns.firstChildElement( "pattern" );
681    while (  !patternNode.isNull()  ) {
682        pattern_count++;
683        Pattern* pat = getPattern( patternNode, instrumentList );
684        if ( pat ) {
685            patternList->add( pat );
686        } else {
687            ERRORLOG( "Error loading pattern" );
688            delete patternList;
689            delete song;
690            return NULL;
691        }
692        patternNode = ( QDomNode ) patternNode.nextSiblingElement( "pattern" );
693    }
694    if ( pattern_count == 0 ) {
695        WARNINGLOG( "0 patterns?" );
696    }
697    song->set_pattern_list( patternList );
698
699    // Virtual Patterns
700    QDomNode  virtualPatternListNode = songNode.firstChildElement( "virtualPatternList" );
701    QDomNode virtualPatternNode = virtualPatternListNode.firstChildElement( "pattern" );
702    if ( !virtualPatternNode.isNull() ) {
703
704        while (  ! virtualPatternNode.isNull()  ) {
705            QString sName = "";
706            sName = LocalFileMng::readXmlString( virtualPatternNode, "name", sName );
707
708            Pattern* curPattern = NULL;
709            unsigned nPatterns = patternList->size();
710            for ( unsigned i = 0; i < nPatterns; i++ ) {
711                Pattern* pat = patternList->get( i );
712
713                if ( pat->get_name() == sName ) {
714                    curPattern = pat;
715                    break;
716                }//if
717            }//for
718
719            if ( curPattern != NULL ) {
720                QDomNode  virtualNode = virtualPatternNode.firstChildElement( "virtual" );
721                while (  !virtualNode.isNull()  ) {
722                    QString virtName = virtualNode.firstChild().nodeValue();
723
724                    Pattern* virtPattern = NULL;
725                    for ( unsigned i = 0; i < nPatterns; i++ ) {
726                        Pattern* pat = patternList->get( i );
727
728                        if ( pat->get_name() == virtName ) {
729                            virtPattern = pat;
730                            break;
731                        }//if
732                    }//for
733
734                    if ( virtPattern != NULL ) {
735                        curPattern->virtual_pattern_set.insert( virtPattern );
736                    } else {
737                        ERRORLOG( "Song had invalid virtual pattern list data (virtual)" );
738                    }//if
739                    virtualNode = ( QDomNode ) virtualNode.nextSiblingElement( "virtual" );
740                }//while
741            } else {
742                ERRORLOG( "Song had invalid virtual pattern list data (name)" );
743            }//if
744            virtualPatternNode = ( QDomNode ) virtualPatternNode.nextSiblingElement( "pattern" );
745        }//while
746    }//if
747
748    computeVirtualPatternTransitiveClosure( patternList );
749
750    // Pattern sequence
751    QDomNode patternSequenceNode = songNode.firstChildElement( "patternSequence" );
752
753    std::vector<PatternList*>* pPatternGroupVector = new std::vector<PatternList*>;
754
755    // back-compatibility code..
756    QDomNode pPatternIDNode = patternSequenceNode.firstChildElement( "patternID" );
757    while ( ! pPatternIDNode.isNull()  ) {
758        WARNINGLOG( "Using old patternSequence code for back compatibility" );
759        PatternList* patternSequence = new PatternList();
760        QString patId = pPatternIDNode.firstChildElement().text();
761        ERRORLOG( patId );
762
763        Pattern* pat = NULL;
764        for ( unsigned i = 0; i < patternList->size(); i++ ) {
765            Pattern* tmp = patternList->get( i );
766            if ( tmp ) {
767                if ( tmp->get_name() == patId ) {
768                    pat = tmp;
769                    break;
770                }
771            }
772        }
773        if ( pat == NULL ) {
774            WARNINGLOG( "patternid not found in patternSequence" );
775            pPatternIDNode = ( QDomNode ) pPatternIDNode.nextSiblingElement( "patternID" );
776            continue;
777        }
778        patternSequence->add( pat );
779
780        pPatternGroupVector->push_back( patternSequence );
781
782        pPatternIDNode = ( QDomNode ) pPatternIDNode.nextSiblingElement( "patternID" );
783    }
784
785    QDomNode groupNode = patternSequenceNode.firstChildElement( "group" );
786    while (  !groupNode.isNull()  ) {
787        PatternList* patternSequence = new PatternList();
788        QDomNode patternId = groupNode.firstChildElement( "patternID" );
789        while (  !patternId.isNull()  ) {
790            QString patId = patternId.firstChild().nodeValue();
791
792            Pattern* pat = NULL;
793            for ( unsigned i = 0; i < patternList->size(); i++ ) {
794                Pattern* tmp = patternList->get( i );
795                if ( tmp ) {
796                    if ( tmp->get_name() == patId ) {
797                        pat = tmp;
798                        break;
799                    }
800                }
801            }
802            if ( pat == NULL ) {
803                WARNINGLOG( "patternid not found in patternSequence" );
804                patternId = ( QDomNode ) patternId.nextSiblingElement( "patternID" );
805                continue;
806            }
807            patternSequence->add( pat );
808            patternId = ( QDomNode ) patternId.nextSiblingElement( "patternID" );
809        }
810        pPatternGroupVector->push_back( patternSequence );
811
812        groupNode = groupNode.nextSiblingElement( "group" );
813    }
814
815    song->set_pattern_group_vector( pPatternGroupVector );
816
817#ifdef H2CORE_HAVE_LADSPA
818    // reset FX
819    for ( int fx = 0; fx < MAX_FX; ++fx ) {
820        //LadspaFX* pFX = Effects::get_instance()->getLadspaFX( fx );
821        //delete pFX;
822        Effects::get_instance()->setLadspaFX( NULL, fx );
823    }
824#endif
825
826    // LADSPA FX
827    QDomNode ladspaNode = songNode.firstChildElement( "ladspa" );
828    if ( !ladspaNode.isNull() ) {
829        int nFX = 0;
830        QDomNode fxNode = ladspaNode.firstChildElement( "fx" );
831        while (  !fxNode.isNull()  ) {
832            QString sName = LocalFileMng::readXmlString( fxNode, "name", "" );
833            QString sFilename = LocalFileMng::readXmlString( fxNode, "filename", "" );
834            bool bEnabled = LocalFileMng::readXmlBool( fxNode, "enabled", false );
835            float fVolume = LocalFileMng::readXmlFloat( fxNode, "volume", 1.0 );
836
837            if ( sName != "no plugin" ) {
838                // FIXME: il caricamento va fatto fare all'engine, solo lui sa il samplerate esatto
839#ifdef H2CORE_HAVE_LADSPA
840                LadspaFX* pFX = LadspaFX::load( sFilename, sName, 44100 );
841                Effects::get_instance()->setLadspaFX( pFX, nFX );
842                if ( pFX ) {
843                    pFX->setEnabled( bEnabled );
844                    pFX->setVolume( fVolume );
845                    QDomNode inputControlNode = fxNode.firstChildElement( "inputControlPort" );
846                    while ( !inputControlNode.isNull() ) {
847                        QString sName = LocalFileMng::readXmlString( inputControlNode, "name", "" );
848                        float fValue = LocalFileMng::readXmlFloat( inputControlNode, "value", 0.0 );
849
850                        for ( unsigned nPort = 0; nPort < pFX->inputControlPorts.size(); nPort++ ) {
851                            LadspaControlPort* port = pFX->inputControlPorts[ nPort ];
852                            if ( QString( port->sName ) == sName ) {
853                                port->fControlValue = fValue;
854                            }
855                        }
856                        inputControlNode = ( QDomNode ) inputControlNode.nextSiblingElement( "inputControlPort" );
857                    }
858
859                    /*
860                    TiXmlNode* outputControlNode;
861                    for ( outputControlNode = fxNode->FirstChild( "outputControlPort" ); outputControlNode; outputControlNode = outputControlNode->NextSibling( "outputControlPort" ) ) {
862                    }*/
863                }
864#endif
865            }
866            nFX++;
867            fxNode = ( QDomNode ) fxNode.nextSiblingElement( "fx" );
868        }
869    } else {
870        WARNINGLOG( "ladspa node not found" );
871    }
872
873
874    Hydrogen::get_instance()->m_timelinevector.clear();
875    Hydrogen::HTimelineVector tlvector;
876    QDomNode bpmTimeLine = songNode.firstChildElement( "BPMTimeLine" );
877    if ( !bpmTimeLine.isNull() ) {
878        QDomNode newBPMNode = bpmTimeLine.firstChildElement( "newBPM" );
879        while( !newBPMNode.isNull() ) {
880            tlvector.m_htimelinebeat = LocalFileMng::readXmlInt( newBPMNode, "BAR", 0 );
881            tlvector.m_htimelinebpm = LocalFileMng::readXmlFloat( newBPMNode, "BPM", 120.0 );
882            Hydrogen::get_instance()->m_timelinevector.push_back( tlvector );
883            Hydrogen::get_instance()->sortTimelineVector();
884            newBPMNode = newBPMNode.nextSiblingElement( "newBPM" );
885        }
886    } else {
887        WARNINGLOG( "bpmTimeLine node not found" );
888    }
889
890
891    Hydrogen::get_instance()->m_timelinetagvector.clear();
892    Hydrogen::HTimelineTagVector tltagvector;
893    QDomNode timeLineTag = songNode.firstChildElement( "timeLineTag" );
894    if ( !timeLineTag.isNull() ) {
895        QDomNode newTAGNode = timeLineTag.firstChildElement( "newTAG" );
896        while( !newTAGNode.isNull() ) {
897            tltagvector.m_htimelinetagbeat = LocalFileMng::readXmlInt( newTAGNode, "BAR", 0 );
898            tltagvector.m_htimelinetag = LocalFileMng::readXmlString( newTAGNode, "TAG", "" );
899            Hydrogen::get_instance()->m_timelinetagvector.push_back( tltagvector );
900            Hydrogen::get_instance()->sortTimelineTagVector();
901            newTAGNode = newTAGNode.nextSiblingElement( "newTAG" );
902        }
903    } else {
904        WARNINGLOG( "TagTimeLine node not found" );
905    }
906
907
908    song->__is_modified = false;
909    song->set_filename( filename );
910
911
912    return song;
913
914}
915
916
917
918Pattern* SongReader::getPattern( QDomNode pattern, InstrumentList* instrList )
919{
920    Pattern* pPattern = NULL;
921
922    QString sName;      // name
923    sName = LocalFileMng::readXmlString( pattern, "name", sName );
924
925    QString sCategory = ""; // category
926    sCategory = LocalFileMng::readXmlString( pattern, "category", sCategory ,false ,false );
927    int nSize = -1;
928    nSize = LocalFileMng::readXmlInt( pattern, "size", nSize, false, false );
929
930    pPattern = new Pattern( sName, sCategory, nSize );
931
932
933
934    QDomNode pNoteListNode = pattern.firstChildElement( "noteList" );
935    if ( ! pNoteListNode.isNull() ) {
936        // new code :)
937        QDomNode noteNode = pNoteListNode.firstChildElement( "note" );
938        while ( ! noteNode.isNull()  ) {
939
940            Note* pNote = NULL;
941
942            unsigned nPosition = LocalFileMng::readXmlInt( noteNode, "position", 0 );
943            float fLeadLag = LocalFileMng::readXmlFloat( noteNode, "leadlag", 0.0 , false , false );
944            float fVelocity = LocalFileMng::readXmlFloat( noteNode, "velocity", 0.8f );
945            float fPan_L = LocalFileMng::readXmlFloat( noteNode, "pan_L", 0.5 );
946            float fPan_R = LocalFileMng::readXmlFloat( noteNode, "pan_R", 0.5 );
947            int nLength = LocalFileMng::readXmlInt( noteNode, "length", -1, true );
948            float nPitch = LocalFileMng::readXmlFloat( noteNode, "pitch", 0.0, false, false );
949            QString sKey = LocalFileMng::readXmlString( noteNode, "key", "C0", false, false );
950            QString nNoteOff = LocalFileMng::readXmlString( noteNode, "note_off", "false", false, false );
951
952            int instrId = LocalFileMng::readXmlInt( noteNode, "instrument", -1 );
953
954            Instrument* instrRef = NULL;
955            // search instrument by ref
956            instrRef = instrList->find( instrId );
957            if ( !instrRef ) {
958                ERRORLOG( QString( "Instrument with ID: '%1' not found. Note skipped." ).arg( instrId ) );
959                noteNode = ( QDomNode ) noteNode.nextSiblingElement( "note" );
960                continue;
961            }
962            //assert( instrRef );
963            bool noteoff = false;
964            if ( nNoteOff == "true" )
965                noteoff = true;
966
967            pNote = new Note( instrRef, nPosition, fVelocity, fPan_L, fPan_R, nLength, nPitch );
968            pNote->set_key_octave( sKey );
969            pNote->set_lead_lag( fLeadLag );
970            pNote->set_note_off( noteoff );
971            pPattern->note_map.insert( std::make_pair( pNote->get_position(), pNote ) );
972
973            noteNode = ( QDomNode ) noteNode.nextSiblingElement( "note" );
974        }
975    } else {
976        // Back compatibility code. Version < 0.9.4
977        QDomNode sequenceListNode = pattern.firstChildElement( "sequenceList" );
978
979        int sequence_count = 0;
980        QDomNode sequenceNode = sequenceListNode.firstChildElement( "sequence" );
981        while ( ! sequenceNode.isNull()  ) {
982            sequence_count++;
983
984            QDomNode noteListNode = sequenceNode.firstChildElement( "noteList" );
985            QDomNode noteNode = noteListNode.firstChildElement( "note" );
986            while (  !noteNode.isNull() ) {
987
988                Note* pNote = NULL;
989
990                unsigned nPosition = LocalFileMng::readXmlInt( noteNode, "position", 0 );
991                float fLeadLag = LocalFileMng::readXmlFloat( noteNode, "leadlag", 0.0 , false , false );
992                float fVelocity = LocalFileMng::readXmlFloat( noteNode, "velocity", 0.8f );
993                float fPan_L = LocalFileMng::readXmlFloat( noteNode, "pan_L", 0.5 );
994                float fPan_R = LocalFileMng::readXmlFloat( noteNode, "pan_R", 0.5 );
995                int nLength = LocalFileMng::readXmlInt( noteNode, "length", -1, true );
996                float nPitch = LocalFileMng::readXmlFloat( noteNode, "pitch", 0.0, false, false );
997
998                QString instrId = LocalFileMng::readXmlString( noteNode, "instrument", "" );
999
1000                Instrument* instrRef = instrList->find( instrId );
1001                assert( instrRef );
1002
1003                pNote = new Note( instrRef, nPosition, fVelocity, fPan_L, fPan_R, nLength, nPitch );
1004                pNote->set_lead_lag( fLeadLag );
1005
1006                //infoLog( "new note!! pos: " + toString( pNote->m_nPosition ) + "\t instr: " + instrId );
1007                pPattern->note_map.insert( std::make_pair( pNote->get_position(), pNote ) );
1008
1009                noteNode = ( QDomNode ) noteNode.nextSiblingElement( "note" );
1010
1011
1012            }
1013            sequenceNode = ( QDomNode ) sequenceNode.nextSiblingElement( "sequence" );
1014        }
1015    }
1016
1017    return pPattern;
1018}
1019
1020};
1021
1022
1023
1024
Note: See TracBrowser for help on using the browser.