root/branches/jackMidi/libs/hydrogen/src/song.cpp @ 820

Revision 820, 21.1 KB (checked in by gabriel@…, 4 years ago)

Merge rev 544:555 from trunk

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