root/branches/transport_redesign_2/libs/hydrogen/src/song.cpp @ 1074

Revision 1074, 22.7 KB (checked in by gabriel@…, 4 years ago)

Remove position info from H2Core::Note

Note that ADSR and the Filter parameters don't really belong in Note,
but they are being used by the sampler to keep track of where it is
in playing the sample. This information should be tracked by the
instrument, and not inside something called "Note."

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#include <cassert>
27
28#include "xml/tinyxml.h"
29
30#include <hydrogen/adsr.h>
31#include <hydrogen/data_path.h>
32#include <hydrogen/LocalFileMng.h>
33
34#include <hydrogen/fx/Effects.h>
35#include <hydrogen/globals.h>
36#include <hydrogen/Song.h>
37#include <hydrogen/sample.h>
38#include <hydrogen/instrument.h>
39#include <hydrogen/Pattern.h>
40#include <hydrogen/note.h>
41#include <hydrogen/hydrogen.h>
42
43namespace H2Core
44{
45
46Song::Song( const QString& name, const QString& author, float bpm, float volume )
47                : Object( "Song" )
48                , __is_muted( false )
49                , __resolution( 48 )
50                , __bpm( bpm )
51                , __is_modified( false )
52                , __name( name )
53                , __author( author )
54                , __volume( volume )
55                , __metronome_volume( 0.5 )
56                , __pattern_list( NULL )
57                , __pattern_group_sequence( NULL )
58                , __instrument_list( NULL )
59                , __filename( "" )
60                , __is_loop_enabled( false )
61                , __humanize_time_value( 0.0 )
62                , __humanize_velocity_value( 0.0 )
63                , __swing_factor( 0.0 )
64                , __song_mode( PATTERN_MODE )
65{
66        INFOLOG( QString( "INIT '%1'" ).arg( __name ) );
67
68        //m_bDelayFXEnabled = false;
69        //m_fDelayFXWetLevel = 0.8;
70        //m_fDelayFXFeedback = 0.5;
71        //m_nDelayFXTime = MAX_NOTES / 8;
72}
73
74
75
76Song::~Song()
77{
78        // delete all patterns
79        delete __pattern_list;
80
81        if ( __pattern_group_sequence ) {
82                for ( unsigned i = 0; i < __pattern_group_sequence->size(); ++i ) {
83                        PatternList *pPatternList = ( *__pattern_group_sequence )[i];
84                        pPatternList->clear();  // pulisco tutto, i pattern non vanno distrutti qua
85                        delete pPatternList;
86                }
87                delete __pattern_group_sequence;
88        }
89
90        delete __instrument_list;
91
92        INFOLOG( QString( "DESTROY '%1'" ).arg( __name ) );
93}
94
95void Song::purge_instrument( Instrument * I )
96{
97        for ( int nPattern = 0; nPattern < (int)__pattern_list->get_size(); ++nPattern ) {
98                __pattern_list->get( nPattern )->purge_instrument( I );
99        }
100}
101
102
103///Load a song from file
104Song* Song::load( const QString& filename )
105{
106        Song *song = NULL;
107
108        SongReader reader;
109        song = reader.readSong( filename );
110
111        return song;
112}
113
114
115
116/// Save a song to file
117bool Song::save( const QString& filename )
118{
119        SongWriter writer;
120        int err;
121        err = writer.writeSong( this, filename );
122
123        if( err ) {
124                return false;
125        }
126        return QFile::exists( filename );
127}
128
129
130/// Create default song
131Song* Song::get_default_song(){
132                Song *song = new Song( "empty", "hydrogen", 120, 0.5 );
133
134                song->set_metronome_volume( 0.5 );
135                song->set_notes( "..." );
136                song->set_license( "" );
137                song->set_loop_enabled( false );
138                song->set_mode( Song::PATTERN_MODE );
139                song->set_humanize_time_value( 0.0 );
140                song->set_humanize_velocity_value( 0.0 );
141                song->set_swing_factor( 0.0 );
142
143                InstrumentList* pList = new InstrumentList();
144                Instrument *pNewInstr = new Instrument(to_string( 0 ), "New instrument", new ADSR());
145                pList->add( pNewInstr );
146                song->set_instrument_list( pList );
147               
148                #ifdef JACK_SUPPORT
149                Hydrogen::get_instance()->renameJackPorts();
150                #endif
151
152                PatternList *patternList = new PatternList();
153                Pattern *emptyPattern = Pattern::get_empty_pattern();
154                emptyPattern->set_name( QString("Pattern 1") );
155                emptyPattern->set_category( QString("not_categorized") );
156                patternList->add( emptyPattern );
157                song->set_pattern_list( patternList );
158                std::vector<PatternList*>* pPatternGroupVector = new std::vector<PatternList*>;
159                PatternList *patternSequence = new PatternList();
160                patternSequence->add( emptyPattern );
161                pPatternGroupVector->push_back( patternSequence );
162                song->set_pattern_group_vector( pPatternGroupVector );
163                song->__is_modified = false;
164                song->set_filename( "empty_song" );
165               
166                return song;
167}
168
169/// Return an empty song
170Song* Song::get_empty_song()
171{
172        QString dataDir = DataPath::get_data_path();   
173        QString filename = dataDir + "/DefaultSong.h2song";
174
175        if( ! QFile::exists( filename ) ){
176                _ERRORLOG("File " + filename + " exists not. Failed to load default song.");
177                filename = dataDir + "/DefaultSong.h2song";
178        }
179       
180        Song *song = Song::load( filename );
181       
182        /* if file DefaultSong.h2song not accessible
183         * create a simple default song.
184         */
185        if(!song){
186                song = Song::get_default_song();
187        }
188
189        return song;
190}
191
192
193
194void Song::set_swing_factor( float factor )
195{
196        if ( factor < 0.0 ) {
197                factor = 0.0;
198        } else if ( factor > 1.0 ) {
199                factor = 1.0;
200        }
201
202        __swing_factor = factor;
203}
204
205
206
207//::::::::::::::::::::
208
209
210
211
212
213
214
215//-----------------------------------------------------------------------------
216//      Implementation of SongReader class
217//-----------------------------------------------------------------------------
218
219
220SongReader::SongReader()
221                : Object( "SongReader" )
222{
223//      infoLog("init");
224}
225
226
227
228SongReader::~SongReader()
229{
230//      infoLog("destroy");
231}
232
233
234
235///
236/// Reads a song.
237/// return NULL = error reading song file.
238///
239Song* SongReader::readSong( const QString& filename )
240{
241        INFOLOG( filename );
242        Song* song = NULL;
243
244        if (QFile( filename ).exists() == false ) {
245                ERRORLOG( "Song file " + filename + " not found." );
246                return NULL;
247        }
248
249
250        #ifdef WIN32
251                TiXmlDocument doc( filename.toAscii().constData() );
252        #else
253                TiXmlDocument doc( filename.toUtf8().constData() );
254        #endif
255
256
257        doc.LoadFile();
258
259        TiXmlNode* songNode;    // root element
260        if ( !( songNode = doc.FirstChild( "song" ) ) ) {
261                ERRORLOG( "Error reading song: song node not found" );
262                return NULL;
263        }
264
265
266        m_sSongVersion = LocalFileMng::readXmlString( songNode, "version", "Unknown version" );
267        if ( m_sSongVersion != QString( get_version().c_str() ) ) {
268                WARNINGLOG( "Trying to load a song created with a different version of hydrogen." );
269                WARNINGLOG( "Song [" + filename + "] saved with version " + m_sSongVersion );
270        }
271
272        float fBpm = LocalFileMng::readXmlFloat( songNode, "bpm", 120 );
273        Hydrogen::get_instance()->setNewBpmJTM( fBpm );
274        float fVolume = LocalFileMng::readXmlFloat( songNode, "volume", 0.5 );
275        float fMetronomeVolume = LocalFileMng::readXmlFloat( songNode, "metronomeVolume", 0.5 );
276        QString sName( LocalFileMng::readXmlString( songNode, "name", "Untitled Song" ) );
277        QString sAuthor( LocalFileMng::readXmlString( songNode, "author", "Unknown Author" ) );
278        QString sNotes( LocalFileMng::readXmlString( songNode, "notes", "..." ) );
279        QString sLicense( LocalFileMng::readXmlString( songNode, "license", "Unknown license" ) );
280        bool bLoopEnabled = LocalFileMng::readXmlBool( songNode, "loopEnabled", false );
281
282        Song::SongMode nMode = Song::PATTERN_MODE;      // Mode (song/pattern)
283        QString sMode = LocalFileMng::readXmlString( songNode, "mode", "pattern" );
284        if ( sMode == "song" ) {
285                nMode = Song::SONG_MODE;
286        }
287
288        float fHumanizeTimeValue = LocalFileMng::readXmlFloat( songNode, "humanize_time", 0.0 );
289        float fHumanizeVelocityValue = LocalFileMng::readXmlFloat( songNode, "humanize_velocity", 0.0 );
290        float fSwingFactor = LocalFileMng::readXmlFloat( songNode, "swing_factor", 0.0 );
291
292        song = new Song( sName, sAuthor, fBpm, fVolume );
293        song->set_metronome_volume( fMetronomeVolume );
294        song->set_notes( sNotes );
295        song->set_license( sLicense );
296        song->set_loop_enabled( bLoopEnabled );
297        song->set_mode( nMode );
298        song->set_humanize_time_value( fHumanizeTimeValue );
299        song->set_humanize_velocity_value( fHumanizeVelocityValue );
300        song->set_swing_factor( fSwingFactor );
301
302        /*
303        song->m_bDelayFXEnabled = LocalFileMng::readXmlBool( songNode, "delayFXEnabled", false, false );
304        song->m_fDelayFXWetLevel = LocalFileMng::readXmlFloat( songNode, "delayFXWetLevel", 1.0, false, false );
305        song->m_fDelayFXFeedback= LocalFileMng::readXmlFloat( songNode, "delayFXFeedback", 0.4, false, false );
306        song->m_nDelayFXTime = LocalFileMng::readXmlInt( songNode, "delayFXTime", MAX_NOTES / 4, false, false );
307        */
308
309
310        //  Instrument List
311        LocalFileMng localFileMng;
312        InstrumentList *instrumentList = new InstrumentList();
313
314        TiXmlNode* instrumentListNode;
315        if ( ( instrumentListNode = songNode->FirstChild( "instrumentList" ) ) ) {
316                // INSTRUMENT NODE
317                int instrumentList_count = 0;
318                TiXmlNode* instrumentNode = 0;
319                for ( instrumentNode = instrumentListNode->FirstChild( "instrument" ); instrumentNode; instrumentNode = instrumentNode->NextSibling( "instrument" ) ) {
320                        instrumentList_count++;
321
322                        QString sId = LocalFileMng::readXmlString( instrumentNode, "id", "" );                  // instrument id
323                        QString sDrumkit = LocalFileMng::readXmlString( instrumentNode, "drumkit", "" );        // drumkit
324                        Hydrogen::get_instance()->setCurrentDrumkitname( sDrumkit );
325                        QString sName = LocalFileMng::readXmlString( instrumentNode, "name", "" );              // name
326                        float fVolume = LocalFileMng::readXmlFloat( instrumentNode, "volume", 1.0 );    // volume
327                        bool bIsMuted = LocalFileMng::readXmlBool( instrumentNode, "isMuted", false );  // is muted
328                        float fPan_L = LocalFileMng::readXmlFloat( instrumentNode, "pan_L", 0.5 );      // pan L
329                        float fPan_R = LocalFileMng::readXmlFloat( instrumentNode, "pan_R", 0.5 );      // pan R
330                        float fFX1Level = LocalFileMng::readXmlFloat( instrumentNode, "FX1Level", 0.0 );        // FX level
331                        float fFX2Level = LocalFileMng::readXmlFloat( instrumentNode, "FX2Level", 0.0 );        // FX level
332                        float fFX3Level = LocalFileMng::readXmlFloat( instrumentNode, "FX3Level", 0.0 );        // FX level
333                        float fFX4Level = LocalFileMng::readXmlFloat( instrumentNode, "FX4Level", 0.0 );        // FX level
334                        float fGain = LocalFileMng::readXmlFloat( instrumentNode, "gain", 1.0, false, false );  // instrument gain
335
336                        int fAttack = LocalFileMng::readXmlInt( instrumentNode, "Attack", 0, false, false );            // Attack
337                        int fDecay = LocalFileMng::readXmlInt( instrumentNode, "Decay", 0, false, false );              // Decay
338                        float fSustain = LocalFileMng::readXmlFloat( instrumentNode, "Sustain", 1.0, false, false );    // Sustain
339                        int fRelease = LocalFileMng::readXmlInt( instrumentNode, "Release", 1000, false, false );       // Release
340
341                        float fRandomPitchFactor = LocalFileMng::readXmlFloat( instrumentNode, "randomPitchFactor", 0.0f, false, false );
342
343                        bool bFilterActive = LocalFileMng::readXmlBool( instrumentNode, "filterActive", false );
344                        float fFilterCutoff = LocalFileMng::readXmlFloat( instrumentNode, "filterCutoff", 1.0f, false );
345                        float fFilterResonance = LocalFileMng::readXmlFloat( instrumentNode, "filterResonance", 0.0f, false );
346                        QString sMuteGroup = LocalFileMng::readXmlString( instrumentNode, "muteGroup", "-1", false );
347                        int nMuteGroup = sMuteGroup.toInt();
348
349
350                        if ( sId == "" ) {
351                                ERRORLOG( "Empty ID for instrument '" + sName + "'. skipping." );
352                                continue;
353                        }
354
355
356                        // create a new instrument
357                        Instrument *pInstrument = new Instrument( sId, sName, new ADSR( fAttack, fDecay, fSustain, fRelease ) );
358                        pInstrument->set_volume( fVolume );
359                        pInstrument->set_muted( bIsMuted );
360                        pInstrument->set_pan_l( fPan_L );
361                        pInstrument->set_pan_r( fPan_R );
362                        pInstrument->set_drumkit_name( sDrumkit );
363                        pInstrument->set_fx_level( fFX1Level, 0 );
364                        pInstrument->set_fx_level( fFX2Level, 1 );
365                        pInstrument->set_fx_level( fFX3Level, 2 );
366                        pInstrument->set_fx_level( fFX4Level, 3 );
367                        pInstrument->set_random_pitch_factor( fRandomPitchFactor );
368                        pInstrument->set_filter_active( bFilterActive );
369                        pInstrument->set_filter_cutoff( fFilterCutoff );
370                        pInstrument->set_filter_resonance( fFilterResonance );
371                        pInstrument->set_gain( fGain );
372                        pInstrument->set_mute_group( nMuteGroup );
373
374                        QString drumkitPath = "";
375                        if ( ( sDrumkit != "" ) && ( sDrumkit != "-" ) ) {
376//                              drumkitPath = localFileMng.getDrumkitDirectory( sDrumkit ) + sDrumkit + "/";
377                                drumkitPath = localFileMng.getDrumkitDirectory( sDrumkit ) + sDrumkit;
378                        }
379
380                        // back compatibility code ( song version <= 0.9.0 )
381                        TiXmlNode* filenameNode = instrumentNode->FirstChild( "filename" );
382                        if ( filenameNode ) {
383                                WARNINGLOG( "Using back compatibility code. filename node found" );
384                                QString sFilename = LocalFileMng::readXmlString( instrumentNode, "filename", "" );
385
386                                if ( drumkitPath != "" ) {
387                                        sFilename = drumkitPath + "/" + sFilename;
388                                }
389                                Sample *pSample = Sample::load( sFilename );
390                                if ( pSample == NULL ) {
391                                        // nel passaggio tra 0.8.2 e 0.9.0 il drumkit di default e' cambiato.
392                                        // Se fallisce provo a caricare il corrispettivo file in formato flac
393//                                      warningLog( "[readSong] Error loading sample: " + sFilename + " not found. Trying to load a flac..." );
394                                        sFilename = sFilename.left( sFilename.length() - 4 );
395                                        sFilename += ".flac";
396                                        pSample = Sample::load( sFilename );
397                                }
398                                if ( pSample == NULL ) {
399                                        ERRORLOG( "Error loading sample: " + sFilename + " not found" );
400                                        pInstrument->set_muted( true );
401                                }
402                                InstrumentLayer *pLayer = new InstrumentLayer( pSample );
403                                pInstrument->set_layer( pLayer, 0 );
404                        }
405                        //~ back compatibility code
406                        else {
407                                unsigned nLayer = 0;
408                                for ( TiXmlNode* layerNode = instrumentNode->FirstChild( "layer" ); layerNode; layerNode = layerNode->NextSibling( "layer" ) ) {
409                                        if ( nLayer >= MAX_LAYERS ) {
410                                                ERRORLOG( "nLayer > MAX_LAYERS" );
411                                                continue;
412                                        }
413                                        QString sFilename = LocalFileMng::readXmlString( layerNode, "filename", "" );
414                                        float fMin = LocalFileMng::readXmlFloat( layerNode, "min", 0.0 );
415                                        float fMax = LocalFileMng::readXmlFloat( layerNode, "max", 1.0 );
416                                        float fGain = LocalFileMng::readXmlFloat( layerNode, "gain", 1.0 );
417                                        float fPitch = LocalFileMng::readXmlFloat( layerNode, "pitch", 0.0, false, false );
418
419                                        if ( drumkitPath != "" ) {
420                                                sFilename = drumkitPath + "/" + sFilename;
421                                        }
422                                        Sample *pSample = Sample::load( sFilename );
423                                        if ( pSample == NULL ) {
424                                                ERRORLOG( "Error loading sample: " + sFilename + " not found" );
425                                                pInstrument->set_muted( true );
426                                        }
427                                        InstrumentLayer *pLayer = new InstrumentLayer( pSample );
428                                        pLayer->set_start_velocity( fMin );
429                                        pLayer->set_end_velocity( fMax );
430                                        pLayer->set_gain( fGain );
431                                        pLayer->set_pitch( fPitch );
432                                        pInstrument->set_layer( pLayer, nLayer );
433                                        nLayer++;
434                                }
435                        }
436
437                        instrumentList->add( pInstrument );
438                }
439                if ( instrumentList_count == 0 ) {
440                        WARNINGLOG( "0 instruments?" );
441                }
442
443                song->set_instrument_list( instrumentList );
444        } else {
445                ERRORLOG( "Error reading song: instrumentList node not found" );
446                delete song;
447                return NULL;
448        }
449
450
451
452
453
454        // Pattern list
455        TiXmlNode* patterns = songNode->FirstChild( "patternList" );
456
457        PatternList *patternList = new PatternList();
458        int pattern_count = 0;
459        TiXmlNode* patternNode = 0;
460        for ( patternNode = patterns->FirstChild( "pattern" ); patternNode; patternNode = patternNode->NextSibling( "pattern" ) ) {
461                pattern_count++;
462                Pattern *pat = getPattern( patternNode, instrumentList );
463                if ( pat ) {
464                        patternList->add( pat );
465                } else {
466                        ERRORLOG( "Error loading pattern" );
467                        delete patternList;
468                        delete song;
469                        return NULL;
470                }
471        }
472        if ( pattern_count == 0 ) {
473                WARNINGLOG( "0 patterns?" );
474        }
475        song->set_pattern_list( patternList );
476
477
478        // Pattern sequence
479        TiXmlNode* patternSequenceNode = songNode->FirstChild( "patternSequence" );
480
481        std::vector<PatternList*>* pPatternGroupVector = new std::vector<PatternList*>;
482
483        // back-compatibility code..
484        for ( TiXmlNode* pPatternIDNode = patternSequenceNode->FirstChild( "patternID" ); pPatternIDNode; pPatternIDNode = pPatternIDNode->NextSibling( "patternID" ) ) {
485                WARNINGLOG( "Using old patternSequence code for back compatibility" );
486                PatternList *patternSequence = new PatternList();
487                QString patId = pPatternIDNode->FirstChild()->Value();
488
489                Pattern *pat = NULL;
490                for ( unsigned i = 0; i < patternList->get_size(); i++ ) {
491                        Pattern *tmp = patternList->get( i );
492                        if ( tmp ) {
493                                if ( tmp->get_name() == patId ) {
494                                        pat = tmp;
495                                        break;
496                                }
497                        }
498                }
499                if ( pat == NULL ) {
500                        WARNINGLOG( "patternid not found in patternSequence" );
501                        continue;
502                }
503                patternSequence->add( pat );
504
505                pPatternGroupVector->push_back( patternSequence );
506        }
507
508        for ( TiXmlNode* groupNode = patternSequenceNode->FirstChild( "group" ); groupNode; groupNode = groupNode->NextSibling( "group" ) ) {
509                PatternList *patternSequence = new PatternList();
510                for ( TiXmlNode* patternId = groupNode->FirstChild( "patternID" ); patternId; patternId = patternId->NextSibling( "patternID" ) ) {
511                        QString patId = patternId->FirstChild()->Value();
512
513                        Pattern *pat = NULL;
514                        for ( unsigned i = 0; i < patternList->get_size(); i++ ) {
515                                Pattern *tmp = patternList->get( i );
516                                if ( tmp ) {
517                                        if ( tmp->get_name() == patId ) {
518                                                pat = tmp;
519                                                break;
520                                        }
521                                }
522                        }
523                        if ( pat == NULL ) {
524                                WARNINGLOG( "patternid not found in patternSequence" );
525                                continue;
526                        }
527                        patternSequence->add( pat );
528                }
529                pPatternGroupVector->push_back( patternSequence );
530        }
531
532        song->set_pattern_group_vector( pPatternGroupVector );
533
534#ifdef LADSPA_SUPPORT
535        // reset FX
536        for ( int fx = 0; fx < MAX_FX; ++fx ) {
537                //LadspaFX* pFX = Effects::getInstance()->getLadspaFX( fx );
538                //delete pFX;
539                Effects::getInstance()->setLadspaFX( NULL, fx );
540        }
541#endif
542
543        // LADSPA FX
544        TiXmlNode* ladspaNode = songNode->FirstChild( "ladspa" );
545        if ( ladspaNode ) {
546                int nFX = 0;
547                TiXmlNode* fxNode;
548                for ( fxNode = ladspaNode->FirstChild( "fx" ); fxNode; fxNode = fxNode->NextSibling( "fx" ) ) {
549                        QString sName = LocalFileMng::readXmlString( fxNode, "name", "" );
550                        QString sFilename = LocalFileMng::readXmlString( fxNode, "filename", "" );
551                        bool bEnabled = LocalFileMng::readXmlBool( fxNode, "enabled", false );
552                        float fVolume = LocalFileMng::readXmlFloat( fxNode, "volume", 1.0 );
553
554                        if ( sName != "no plugin" ) {
555                                // FIXME: il caricamento va fatto fare all'engine, solo lui sa il samplerate esatto
556#ifdef LADSPA_SUPPORT
557                                LadspaFX* pFX = LadspaFX::load( sFilename, sName, 44100 );
558                                Effects::getInstance()->setLadspaFX( pFX, nFX );
559                                if ( pFX ) {
560                                        pFX->setEnabled( bEnabled );
561                                        pFX->setVolume( fVolume );
562                                        TiXmlNode* inputControlNode;
563                                        for ( inputControlNode = fxNode->FirstChild( "inputControlPort" ); inputControlNode; inputControlNode = inputControlNode->NextSibling( "inputControlPort" ) ) {
564                                                QString sName = LocalFileMng::readXmlString( inputControlNode, "name", "" );
565                                                float fValue = LocalFileMng::readXmlFloat( inputControlNode, "value", 0.0 );
566
567                                                for ( unsigned nPort = 0; nPort < pFX->inputControlPorts.size(); nPort++ ) {
568                                                        LadspaControlPort *port = pFX->inputControlPorts[ nPort ];
569                                                        if ( QString( port->sName ) == sName ) {
570                                                                port->fControlValue = fValue;
571                                                        }
572                                                }
573                                        }
574
575                                        TiXmlNode* outputControlNode;
576                                        for ( outputControlNode = fxNode->FirstChild( "outputControlPort" ); outputControlNode; outputControlNode = outputControlNode->NextSibling( "outputControlPort" ) ) {
577                                        }
578                                }
579#endif
580                        }
581                        nFX++;
582                }
583        } else {
584                WARNINGLOG( "ladspa node not found" );
585        }
586
587
588        song->__is_modified = false;
589        song->set_filename( filename );
590
591        return song;
592}
593
594
595
596Pattern* SongReader::getPattern( TiXmlNode* pattern, InstrumentList* instrList )
597{
598        Pattern *pPattern = NULL;
599
600        QString sName = "";     // name
601        sName = LocalFileMng::readXmlString( pattern, "name", sName );
602
603        QString sCategory = ""; // category
604        sCategory = LocalFileMng::readXmlString( pattern, "category", sCategory );
605        int nSize = -1;
606        nSize = LocalFileMng::readXmlInt( pattern, "size", nSize, false, false );
607
608        pPattern = new Pattern( sName, sCategory, nSize );
609
610
611
612        TiXmlNode* pNoteListNode = pattern->FirstChild( "noteList" );
613        if ( pNoteListNode ) {
614                // new code :)
615                for ( TiXmlNode* noteNode = pNoteListNode->FirstChild( "note" ); noteNode; noteNode = noteNode->NextSibling( "note" ) ) {
616
617                        Note* pNote = NULL;
618
619                        unsigned nPosition = LocalFileMng::readXmlInt( noteNode, "position", 0 );
620                        float fLeadLag = LocalFileMng::readXmlFloat( noteNode, "leadlag", 0.0 );
621                        float fVelocity = LocalFileMng::readXmlFloat( noteNode, "velocity", 0.8f );
622                        float fPan_L = LocalFileMng::readXmlFloat( noteNode, "pan_L", 0.5 );
623                        float fPan_R = LocalFileMng::readXmlFloat( noteNode, "pan_R", 0.5 );
624                        int nLength = LocalFileMng::readXmlInt( noteNode, "length", -1, true );
625                        float nPitch = LocalFileMng::readXmlFloat( noteNode, "pitch", 0.0, false, false );
626                        QString sKey = LocalFileMng::readXmlString( noteNode, "key", "C0", false, false );
627
628                        QString instrId = LocalFileMng::readXmlString( noteNode, "instrument", "" );
629
630                        Instrument *instrRef = NULL;
631                        // search instrument by ref
632                        for ( unsigned i = 0; i < instrList->get_size(); i++ ) {
633                                Instrument *instr = instrList->get( i );
634                                if ( instrId == instr->get_id() ) {
635                                        instrRef = instr;
636                                        break;
637                                }
638                        }
639                        if ( !instrRef ) {
640                                ERRORLOG( "Instrument with ID: '" + instrId + "' not found. Note skipped." );
641                                continue;
642                        }
643                        //assert( instrRef );
644
645                        pNote = new Note( instrRef, fVelocity, fPan_L, fPan_R, nLength, nPitch, Note::stringToKey( sKey ) );
646                        pNote->set_leadlag(fLeadLag);
647                        pPattern->note_map.insert( std::make_pair( nPosition, pNote ) );
648                }
649        } else {
650                // Back compatibility code. Version < 0.9.4
651                TiXmlNode* sequenceListNode = pattern->FirstChild( "sequenceList" );
652
653                int sequence_count = 0;
654                TiXmlNode* sequenceNode = 0;
655                for ( sequenceNode = sequenceListNode->FirstChild( "sequence" ); sequenceNode; sequenceNode = sequenceNode->NextSibling( "sequence" ) ) {
656                        sequence_count++;
657
658                        TiXmlNode* noteListNode = sequenceNode->FirstChild( "noteList" );
659                        for ( TiXmlNode* noteNode = noteListNode->FirstChild( "note" ); noteNode; noteNode = noteNode->NextSibling( "note" ) ) {
660
661                                Note* pNote = NULL;
662
663                                unsigned nPosition = LocalFileMng::readXmlInt( noteNode, "position", 0 );
664                                float fLeadLag = LocalFileMng::readXmlFloat( noteNode, "leadlag", 0.0 );
665                                float fVelocity = LocalFileMng::readXmlFloat( noteNode, "velocity", 0.8f );
666                                float fPan_L = LocalFileMng::readXmlFloat( noteNode, "pan_L", 0.5 );
667                                float fPan_R = LocalFileMng::readXmlFloat( noteNode, "pan_R", 0.5 );
668                                int nLength = LocalFileMng::readXmlInt( noteNode, "length", -1, true );
669                                float nPitch = LocalFileMng::readXmlFloat( noteNode, "pitch", 0.0, false, false );
670
671                                QString instrId = LocalFileMng::readXmlString( noteNode, "instrument", "" );
672
673                                Instrument *instrRef = NULL;
674                                // search instrument by ref
675                                for ( unsigned i = 0; i < instrList->get_size(); i++ ) {
676                                        Instrument *instr = instrList->get( i );
677                                        if ( instrId == instr->get_id() ) {
678                                                instrRef = instr;
679                                                break;
680                                        }
681                                }
682                                assert( instrRef );
683
684                                pNote = new Note( instrRef, fVelocity, fPan_L, fPan_R, nLength, nPitch );
685                                pNote->set_leadlag(fLeadLag);
686
687                                //infoLog( "new note!! pos: " + toString( pNote->m_nPosition ) + "\t instr: " + instrId );
688                                pPattern->note_map.insert( std::make_pair( nPosition, pNote ) );
689                        }
690                }
691        }
692
693        return pPattern;
694}
695
696};
697
698
699
700
Note: See TracBrowser for help on using the browser.