SF.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *                                                                         *
00003  *   libsf2 - C++ cross-platform SF2 format file access library            *
00004  *                                                                         *
00005  *   Copyright (C) 2009-2010 Grigor Iliev  <grigor@grigoriliev.com>,       *
00006  *    Christian Schoenebeck and Andreas Persson                            *
00007  *                                                                         *
00008  *   This library is free software; you can redistribute it and/or modify  *
00009  *   it under the terms of the GNU General Public License as published by  *
00010  *   the Free Software Foundation; either version 2 of the License, or     *
00011  *   (at your option) any later version.                                   *
00012  *                                                                         *
00013  *   This library is distributed in the hope that it will be useful,       *
00014  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00015  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00016  *   GNU General Public License for more details.                          *
00017  *                                                                         *
00018  *   You should have received a copy of the GNU General Public License     *
00019  *   along with this library; if not, write to the Free Software           *
00020  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston,                 *
00021  *   MA  02111-1307  USA                                                   *
00022  ***************************************************************************/
00023 
00024 #include "RIFF.h"
00025 
00026 #include "SF.h"
00027 
00028 #include "helper.h"
00029 #include <math.h>
00030 
00031 #define _1200TH_ROOT_OF_2 1.000577789506555
00032 #define _200TH_ROOT_OF_10 1.011579454259899
00033 
00034 namespace sf2 {
00035     double ToSeconds(int Timecents) {
00036         if (Timecents == NONE) return NONE;
00037         if (Timecents == 0) return 1.0;
00038         if (Timecents == -32768) return 0.0;
00039         return pow(_1200TH_ROOT_OF_2, Timecents);
00040     }
00041 
00042     double ToPermilles(int Centibels) {
00043         if (Centibels == NONE) return NONE;
00044         if (Centibels == 0) return 1000.0;
00045         if (Centibels < 0) return 0.0;
00046         return pow(_200TH_ROOT_OF_10, Centibels);
00047     }
00048 
00049     double ToHz(int cents) {
00050         if (cents == NONE) return NONE;
00051         if (cents == 0) return 8.176;
00052         return pow(_1200TH_ROOT_OF_2, cents) * 8.176;
00053     }
00054 
00055     RIFF::Chunk* GetMandatoryChunk(RIFF::List* list, uint32_t chunkId) {
00056         RIFF::Chunk* ck = list->GetSubChunk(chunkId);
00057         if(ck == NULL) throw Exception("Mandatory chunk in RIFF list chunk not found: " + ToString(chunkId));
00058         return ck;
00059     }
00060 
00061     void LoadString(RIFF::Chunk* ck, std::string& s, int strLength) {
00062         if(ck == NULL) return;
00063         char* buf = new char[strLength];
00064         int len = 0;
00065         for(int i = 0; i < strLength; i++) {
00066             buf[i] = ck->ReadInt8();
00067             if(buf[i] == 0 && !len) len = i;
00068         }
00069         if(!len) len = strLength;
00070         s.assign(buf, len);
00071         delete [] buf;
00072     }
00073 
00078     void VerifySize(RIFF::Chunk* ck, int size) {
00079         if (ck == NULL) throw Exception("NULL chunk");
00080         if (ck->GetSize() < size) {
00081             throw Exception("Invalid chunk size. Chunk ID: " + ToString(ck->GetChunkID()));
00082         }
00083     }
00084 
00085     Modulator::Modulator(SFModulator mod) {
00086         Type = mod >> 10; // The last 6 bits
00087         Polarity = mod & (1 << 9);
00088         Direction = mod & (1 << 8);
00089         MidiPalete = mod & (1 << 7); // two paletes - general or MIDI
00090         Index = mod & 0x7f; /* index field */;
00091 
00092     }
00093 
00094     ModulatorItem::ModulatorItem(ModList& mod) :
00095         ModSrcOper(Modulator(mod.ModSrcOper)),
00096         ModAmtSrcOper(Modulator(mod.ModAmtSrcOper))
00097     {
00098 
00099     }
00100 
00101     Version::Version(RIFF::Chunk* ck) {
00102         if(ck != NULL) VerifySize(ck, 4);
00103         Major = ck ? ck->ReadUint16() : 0;
00104         Minor = ck ? ck->ReadUint16() : 0;
00105     }
00106 
00107     // *************** Info  ***************
00108     // *
00109 
00116     Info::Info(RIFF::List* list) {
00117         if (list) {
00118             RIFF::List* lstINFO = list->GetSubList(LIST_TYPE_INFO);
00119             if (lstINFO) {
00120                 pVer = new Version(GetMandatoryChunk(lstINFO, CHUNK_ID_IFIL));
00121                 LoadString(CHUNK_ID_ISNG, lstINFO, SoundEngine);
00122                 LoadString(CHUNK_ID_INAM, lstINFO, BankName);
00123                 LoadString(CHUNK_ID_IROM, lstINFO, RomName);
00124                 pRomVer = new Version(lstINFO->GetSubChunk(CHUNK_ID_IVER));
00125                 LoadString(CHUNK_ID_ICRD, lstINFO, CreationDate);
00126                 LoadString(CHUNK_ID_IENG, lstINFO, Engineers);
00127                 LoadString(CHUNK_ID_IPRD, lstINFO, Product);
00128                 LoadString(CHUNK_ID_ICOP, lstINFO, Copyright);
00129                 LoadString(CHUNK_ID_ICMT, lstINFO, Comments);
00130                 LoadString(CHUNK_ID_ISFT, lstINFO, Software);
00131 
00132             }
00133         }
00134     }
00135 
00136     Info::~Info() {
00137         delete pVer;
00138         delete pRomVer;
00139     }
00140 
00146     void Info::LoadString(uint32_t ChunkID, RIFF::List* lstINFO, String& s) {
00147         RIFF::Chunk* ck = lstINFO->GetSubChunk(ChunkID);
00148         ::LoadString(ck, s); // function from helper.h
00149     }
00150 
00151     Sample::Sample(RIFF::Chunk* ck, RIFF::Chunk* pCkSmpl, RIFF::Chunk* pCkSm24) {
00152         this->pCkSmpl = pCkSmpl;
00153         this->pCkSm24 = pCkSm24;
00154 
00155         LoadString(ck, Name, 20);
00156         Start = ck->ReadInt32();
00157         End = ck->ReadInt32();
00158         StartLoop = ck->ReadInt32();
00159         EndLoop = ck->ReadInt32();
00160         SampleRate = ck->ReadInt32();
00161         OriginalPitch = ck->ReadInt8();
00162         PitchCorrection = ck->ReadInt8();
00163         SampleLink = ck->ReadInt16();
00164         SampleType = ck->ReadInt16();
00165 
00166         if (Start > End || !pCkSmpl || pCkSmpl->GetSize() <= End) {
00167             throw Exception("Broken SF2 file (invalid sample info)");
00168         }
00169 
00170         ChannelCount = 1;
00171         switch(SampleType) {
00172             case 0                              : // terminal sample
00173             case sf2::Sample::MONO_SAMPLE       :
00174             case sf2::Sample::ROM_MONO_SAMPLE   : break;
00175             case sf2::Sample::RIGHT_SAMPLE      :
00176             case sf2::Sample::LEFT_SAMPLE       :
00177             case sf2::Sample::ROM_RIGHT_SAMPLE  :
00178             case sf2::Sample::ROM_LEFT_SAMPLE   : ChannelCount = 2; break;
00179             case sf2::Sample::LINKED_SAMPLE     :
00180             case sf2::Sample::ROM_LINKED_SAMPLE : std::cerr << "Linked samples not implemented yet"; break;
00181             default: throw Exception("Broken SF2 file (invalid sample type)");
00182         }
00183 
00184         RAMCache.Size              = 0;
00185         RAMCache.pStart            = NULL;
00186         RAMCache.NullExtensionSize = 0;
00187     }
00188 
00189     int Sample::GetChannelCount() {
00190         return ChannelCount;
00191     }
00192 
00193     long Sample::GetTotalFrameCount() {
00194         return (End - Start);
00195     }
00196 
00200     int Sample::GetFrameSize() {
00201         return ChannelCount * ((pCkSm24 != NULL) ? 3 : 2);
00202     }
00203 
00204     bool Sample::HasLoops() {
00205         return StartLoop != 0 && EndLoop != 0;
00206     }
00207 
00234     unsigned long Sample::ReadAndLoop (
00235         void*           pBuffer,
00236         unsigned long   FrameCount,
00237         PlaybackState*  pPlaybackState,
00238         Region*         pRegion
00239     ) {
00240         // TODO: startAddrsCoarseOffset, endAddrsCoarseOffset
00241         unsigned long samplestoread = FrameCount, totalreadsamples = 0, readsamples, samplestoloopend;
00242         uint8_t* pDst = (uint8_t*) pBuffer;
00243         SetPos(pPlaybackState->position);
00244         if (pRegion->HasLoop) {
00245             do {
00246                 samplestoloopend  = pRegion->LoopEnd - GetPos();
00247                 readsamples       = Read(&pDst[totalreadsamples * GetFrameSize()], Min(samplestoread, samplestoloopend));
00248                 samplestoread    -= readsamples;
00249                 totalreadsamples += readsamples;
00250                 if (readsamples == samplestoloopend) {
00251                     SetPos(pRegion->LoopStart);
00252                 }
00253             } while (samplestoread && readsamples);
00254         } else {
00255             totalreadsamples = Read(pBuffer, FrameCount);
00256         }
00257 
00258         pPlaybackState->position = GetPos();
00259 
00260         return totalreadsamples;
00261     }
00262 
00263     Region::Region() {
00264         pSample = NULL;
00265         pInstrument = NULL;
00266         pParentInstrument = NULL;
00267         loKey = hiKey = NONE;
00268         minVel = maxVel = NONE;
00269         startAddrsOffset = startAddrsCoarseOffset = endAddrsOffset = endAddrsCoarseOffset = 0;
00270         startloopAddrsOffset = startloopAddrsCoarseOffset = endloopAddrsOffset = endloopAddrsCoarseOffset = 0;
00271         pan = fineTune = coarseTune = 0;
00272         overridingRootKey = -1; // -1 means not used
00273 
00274         HasLoop = false;
00275         LoopStart = LoopEnd = 0;
00276 
00277         EG1PreAttackDelay = EG1Attack = EG1Hold = EG1Decay = EG1Release = -12000;
00278         EG1Sustain = 0;
00279         EG2PreAttackDelay = EG2Attack = EG2Hold = EG2Decay = EG2Release = -12000;
00280         EG2Sustain = 0;
00281 
00282         modEnvToPitch = modLfoToPitch = modEnvToFilterFc = modLfoToFilterFc = modLfoToVolume = 0;
00283         freqModLfo = 0;
00284         delayModLfo = -12000;
00285         vibLfoToPitch = 0;
00286         freqVibLfo = 0;
00287         delayVibLfo = -12000;
00288 
00289         exclusiveClass = 0;
00290     }
00291 
00292     int Region::GetUnityNote() {
00293         return overridingRootKey != -1 ? overridingRootKey : pSample->OriginalPitch;
00294     }
00295 
00296     void Region::SetGenerator(sf2::File* pFile, GenList& Gen) {
00297         switch(Gen.GenOper) {
00298             case START_ADDRS_OFFSET:
00299                 startAddrsOffset = Gen.GenAmount.wAmount;
00300                 break;
00301             case END_ADDRS_OFFSET:
00302                 if (Gen.GenAmount.shAmount <= 0) {
00303                     endAddrsOffset = Gen.GenAmount.shAmount;
00304                 } else {
00305                     std::cerr << "Ignoring invalid endAddrsOffset" << std::endl;
00306                 }
00307                 break;
00308             case STARTLOOP_ADDRS_OFFSET:
00309                 startloopAddrsOffset = Gen.GenAmount.shAmount;
00310                 LoopStart += startloopAddrsOffset;
00311                 break;
00312             case ENDLOOP_ADDRS_OFFSET:
00313                 endloopAddrsOffset = Gen.GenAmount.shAmount;
00314                 LoopEnd += endloopAddrsOffset;
00315                 break;
00316             case START_ADDRS_COARSE_OFFSET:
00317                 startAddrsCoarseOffset = Gen.GenAmount.wAmount;
00318                 break;
00319             case MOD_LFO_TO_PITCH:
00320                 modLfoToPitch = Gen.GenAmount.shAmount;
00321                 break;
00322             case VIB_LFO_TO_PITCH:
00323                 vibLfoToPitch = Gen.GenAmount.shAmount;
00324                 break;
00325             case MOD_ENV_TO_PITCH:
00326                 modEnvToPitch = Gen.GenAmount.shAmount;
00327                 break;
00328             case INITIAL_FILTER_FC:
00329                 break;
00330             case INITIAL_FILTER_Q:
00331                 break;
00332             case MOD_LFO_TO_FILTER_FC:
00333                 modLfoToFilterFc = Gen.GenAmount.shAmount;
00334                 break;
00335             case MOD_ENV_TO_FILTER_FC:
00336                 modEnvToFilterFc = Gen.GenAmount.shAmount;
00337                 break;
00338             case END_ADDRS_COARSE_OFFSET:
00339                 endAddrsCoarseOffset = Gen.GenAmount.wAmount;
00340                 break;
00341             case MOD_LFO_TO_VOLUME:
00342                 modLfoToVolume = Gen.GenAmount.shAmount;
00343                 break;
00344             case CHORUS_EFFECTS_SEND:
00345                 break;
00346             case REVERB_EFFECTS_SEND:
00347                 break;
00348             case PAN:
00349                 pan = Gen.GenAmount.shAmount;
00350                 pan * 64; pan /= 500;
00351                 if (pan < -64) pan = -64;
00352                 if (pan >  63) pan =  63;
00353                 break;
00354             case DELAY_MOD_LFO:
00355                 delayModLfo = Gen.GenAmount.shAmount;
00356                 break;
00357             case FREQ_MOD_LFO:
00358                 freqModLfo = Gen.GenAmount.shAmount;
00359                 break;
00360             case DELAY_VIB_LFO:
00361                 delayVibLfo = Gen.GenAmount.shAmount;
00362                 break;
00363             case FREQ_VIB_LFO:
00364                 freqVibLfo = Gen.GenAmount.shAmount;
00365                 break;
00366             case DELAY_MOD_ENV:
00367                 EG2PreAttackDelay = Gen.GenAmount.shAmount;
00368                 break;
00369             case ATTACK_MOD_ENV:
00370                 EG2Attack = Gen.GenAmount.shAmount;
00371                 break;
00372             case HOLD_MOD_ENV:
00373                 EG2Hold = Gen.GenAmount.shAmount;
00374                 break;
00375             case DECAY_MOD_ENV:
00376                 EG2Decay = Gen.GenAmount.shAmount;
00377                 break;
00378             case SUSTAIN_MOD_ENV:
00379                 EG2Sustain = Gen.GenAmount.shAmount;
00380                 break;
00381             case RELEASEMODENV:
00382                 EG2Release = Gen.GenAmount.shAmount;
00383                 break;
00384             case KEYNUM_TO_MOD_ENV_HOLD:
00385                 break;
00386             case KEYNUM_TO_MOD_ENV_DECAY:
00387                 break;
00388             case DELAY_VOL_ENV:
00389                 EG1PreAttackDelay = Gen.GenAmount.shAmount;
00390                 break;
00391             case ATTACK_VOL_ENV:
00392                 EG1Attack = Gen.GenAmount.shAmount;
00393                 break;
00394             case HOLD_VOL_ENV:
00395                 EG1Hold = Gen.GenAmount.shAmount;
00396                 break;
00397             case DECAY_VOL_ENV:
00398                 EG1Decay = Gen.GenAmount.shAmount;
00399                 break;
00400             case SUSTAIN_VOL_ENV:
00401                 EG1Sustain = Gen.GenAmount.shAmount;
00402                 break;
00403             case RELEASE_VOL_ENV:
00404                 EG1Release = Gen.GenAmount.shAmount;
00405                 break;
00406             case KEYNUM_TO_VOL_ENV_HOLD:
00407                 break;
00408             case KEYNUM_TO_VOL_ENV_DECAY:
00409                 break;
00410             case INSTRUMENT: {
00411                 uint16_t id = Gen.GenAmount.wAmount;
00412                 if (id >= pFile->Instruments.size()) {
00413                     throw Exception("Broken SF2 file (missing instruments)");
00414                 }
00415                 pInstrument = pFile->Instruments[id];
00416                 break;
00417             }
00418             case KEY_RANGE:
00419                 loKey = Gen.GenAmount.ranges.byLo;
00420                 hiKey = Gen.GenAmount.ranges.byHi;
00421                 break;
00422             case VEL_RANGE:
00423                 minVel = Gen.GenAmount.ranges.byLo;
00424                 maxVel = Gen.GenAmount.ranges.byHi;
00425                 break;
00426             case STARTLOOP_ADDRS_COARSE_OFFSET:
00427                 startloopAddrsCoarseOffset = Gen.GenAmount.wAmount;
00428                 LoopStart += startloopAddrsCoarseOffset * 32768;
00429                 break;
00430             case KEYNUM:
00431                 break;
00432             case VELOCITY:
00433                 break;
00434             case INITIAL_ATTENUATION:
00435                 break;
00436             case ENDLOOP_ADDRS_COARSE_OFFSET:
00437                 endloopAddrsCoarseOffset = Gen.GenAmount.wAmount;
00438                 LoopEnd += endloopAddrsCoarseOffset * 32768;
00439                 break;
00440             case COARSE_TUNE:
00441                 coarseTune = Gen.GenAmount.shAmount;
00442                 if (coarseTune < -120) coarseTune = -120;
00443                 if (coarseTune >  120) coarseTune =  120;
00444                 break;
00445             case FINE_TUNE:
00446                 fineTune = Gen.GenAmount.shAmount;
00447                 break;
00448             case SAMPLE_ID: {
00449                 uint16_t sid = Gen.GenAmount.wAmount;
00450                 if (sid >= pFile->Samples.size()) {
00451                     throw Exception("Broken SF2 file (missing samples)");
00452                 }
00453                 pSample = pFile->Samples[sid];
00454 
00455                 if (HasLoop) {
00456                     LoopStart += pSample->StartLoop;
00457                     LoopEnd   += pSample->EndLoop;
00458                     if ( LoopStart < pSample->Start || LoopStart > pSample->End ||
00459                          LoopStart > LoopEnd        || LoopEnd   > pSample->End    ) {
00460                         throw Exception("Broken SF2 file (invalid loops)");
00461                     }
00462                     LoopStart -= pSample->Start; // Relative to the sample start
00463                     LoopEnd   -= pSample->Start; // Relative to the sample start
00464                 }
00465                 break;
00466             }
00467             case SAMPLE_MODES:
00468                 HasLoop = Gen.GenAmount.wAmount & 1;
00469                 // TODO: 3 indicates a sound which loops for the duration of key depression
00470                 //       then proceeds to play the remainder of the sample.
00471                 break;
00472             case SCALE_TUNING:
00473                 break;
00474             case EXCLUSIVE_CLASS:
00475                 exclusiveClass = Gen.GenAmount.wAmount;
00476                 break;
00477             case OVERRIDING_ROOT_KEY:
00478                 overridingRootKey = Gen.GenAmount.shAmount;
00479                 break;
00480         }
00481     }
00482 
00483     void Region::SetModulator(sf2::File* pFile, ModList& Mod) {
00484         modulators.push_back(ModulatorItem(Mod));
00485         /*switch(srcType) {
00486             case NO_CONTROLLER:
00487                 break;
00488             case NOTE_ON_VELOCITY:
00489                 break;
00490             case NOTE_ON_KEY_NUMBER:
00491                 break;
00492             case POLY_PRESSURE:
00493                 break;
00494             case CHANNEL_PRESSURE:
00495                 break;
00496             case PITCH_WHEEL:
00497                 break;
00498             case PITCH_WHEEL_SENSITIVITY:
00499                 break;
00500             case LINK:
00501                 break;
00502             default: std::cout << "Unknown controller source: " << srcType << std::endl;
00503         }*/
00504     }
00505 
00506     int Region::GetPan(Region* pPresetRegion) {
00507         if (pPresetRegion == NULL) return pan;
00508         int p = pPresetRegion->pan + pan;
00509         if (p < -64) p = -64;
00510         if (p >  63) p =  63;
00511         return p;
00512     }
00513 
00514     int Region::GetFineTune(Region* pPresetRegion) {
00515         if (pPresetRegion == NULL) return fineTune;
00516         int t = pPresetRegion->fineTune + fineTune;
00517         if (t < -99) t = -99;
00518         if (t >  99) t =  99;
00519         return t;
00520     }
00521 
00522     int Region::GetCoarseTune(Region* pPresetRegion) {
00523          if (pPresetRegion == NULL) return coarseTune;
00524         int t = pPresetRegion->coarseTune + coarseTune;
00525         if (t < -120) t = -120;
00526         if (t >  120) t =  120;
00527         return t;
00528     }
00529 
00530     double Region::GetEG1PreAttackDelay(Region* pPresetRegion) {
00531         if (pPresetRegion == NULL || pPresetRegion->EG1PreAttackDelay == NONE) return ToSeconds(EG1PreAttackDelay);
00532         return ToSeconds(pPresetRegion->EG1PreAttackDelay + EG1PreAttackDelay);
00533     }
00534 
00535     double Region::GetEG1Attack(Region* pPresetRegion) {
00536         if (pPresetRegion == NULL || pPresetRegion->EG1Attack == NONE) return ToSeconds(EG1Attack);
00537         return ToSeconds(pPresetRegion->EG1Attack + EG1Attack);
00538     }
00539 
00540     double Region::GetEG1Hold(Region* pPresetRegion) {
00541         if (pPresetRegion == NULL || pPresetRegion->EG1Hold == NONE) return ToSeconds(EG1Hold);
00542         return ToSeconds(pPresetRegion->EG1Hold + EG1Hold);
00543     }
00544 
00545     double Region::GetEG1Decay(Region* pPresetRegion) {
00546         if (pPresetRegion == NULL || pPresetRegion->EG1Decay == NONE) return ToSeconds(EG1Decay);
00547         return ToSeconds(pPresetRegion->EG1Decay + EG1Decay);
00548     }
00549 
00550     double Region::GetEG1Sustain(Region* pPresetRegion) {
00551         if (pPresetRegion == NULL || pPresetRegion->EG1Sustain == NONE) return ToPermilles(EG1Sustain);
00552         return ToPermilles(pPresetRegion->EG1Sustain + EG1Sustain);
00553     }
00554 
00555     double Region::GetEG1Release(Region* pPresetRegion) {
00556         if (pPresetRegion == NULL || pPresetRegion->EG1Release == NONE) return ToSeconds(EG1Release);
00557         return ToSeconds(pPresetRegion->EG1Release + EG1Release);
00558     }
00559 
00560     double Region::GetEG2PreAttackDelay(Region* pPresetRegion) {
00561         if (pPresetRegion == NULL || pPresetRegion->EG2PreAttackDelay == NONE) return ToSeconds(EG2PreAttackDelay);
00562         return ToSeconds(pPresetRegion->EG2PreAttackDelay + EG2PreAttackDelay);
00563     }
00564 
00565     double Region::GetEG2Attack(Region* pPresetRegion) {
00566         if (pPresetRegion == NULL || pPresetRegion->EG2Attack == NONE) return ToSeconds(EG2Attack);
00567         return ToSeconds(pPresetRegion->EG2Attack + EG2Attack);
00568     }
00569 
00570     double Region::GetEG2Hold(Region* pPresetRegion) {
00571         if (pPresetRegion == NULL || pPresetRegion->EG2Hold == NONE) return ToSeconds(EG2Hold);
00572         return ToSeconds(pPresetRegion->EG2Hold + EG2Hold);
00573     }
00574 
00575     double Region::GetEG2Decay(Region* pPresetRegion) {
00576         if (pPresetRegion == NULL || pPresetRegion->EG2Decay == NONE) return ToSeconds(EG2Decay);
00577         return ToSeconds(pPresetRegion->EG2Decay + EG2Decay);
00578     }
00579 
00580     double Region::GetEG2Sustain(Region* pPresetRegion) {
00581         if (pPresetRegion == NULL || pPresetRegion->EG2Sustain == NONE) {
00582             return EG2Sustain == NONE ? NONE : 1000 - EG2Sustain;
00583         }
00584         return 1000 - (pPresetRegion->EG2Sustain + EG2Sustain);
00585     }
00586 
00587     double Region::GetEG2Release(Region* pPresetRegion) {
00588         if (pPresetRegion == NULL || pPresetRegion->EG2Release == NONE) return ToSeconds(EG2Release);
00589         return ToSeconds(pPresetRegion->EG2Release + EG2Release);
00590     }
00591 
00592     int Region::GetModEnvToPitch(Region* pPresetRegion) {
00593         return modEnvToPitch + (pPresetRegion ? pPresetRegion->modEnvToPitch : 0);
00594     }
00595 
00596     int Region::GetModLfoToPitch(Region* pPresetRegion) {
00597         return modLfoToPitch + (pPresetRegion ? pPresetRegion->modLfoToPitch : 0);
00598     }
00599 
00600     int Region::GetModEnvToFilterFc(Region* pPresetRegion) {
00601         return modEnvToFilterFc + (pPresetRegion ? pPresetRegion->modEnvToFilterFc : 0);
00602     }
00603 
00604     int Region::GetModLfoToFilterFc(Region* pPresetRegion) {
00605         return modLfoToFilterFc + (pPresetRegion ? pPresetRegion->modLfoToFilterFc : 0);
00606     }
00607 
00608     double Region::GetModLfoToVolume(Region* pPresetRegion) {
00609         return ToPermilles(modLfoToVolume + (pPresetRegion ? pPresetRegion->modLfoToVolume : 0));
00610     }
00611 
00612     double Region::GetFreqModLfo(Region* pPresetRegion) {
00613         if (pPresetRegion == NULL || pPresetRegion->freqModLfo == NONE) return ToHz(freqModLfo);
00614         return ToHz(pPresetRegion->freqModLfo + freqModLfo);
00615     }
00616 
00617     double Region::GetDelayModLfo(Region* pPresetRegion) {
00618         if (pPresetRegion == NULL || pPresetRegion->delayModLfo == NONE) return ToSeconds(delayModLfo);
00619         return ToSeconds(pPresetRegion->delayModLfo + delayModLfo);
00620     }
00621 
00622     int Region::GetVibLfoToPitch(Region* pPresetRegion) {
00623         return vibLfoToPitch + (pPresetRegion ? pPresetRegion->vibLfoToPitch : 0);
00624     }
00625 
00626     double Region::GetFreqVibLfo(Region* pPresetRegion) {
00627         if (pPresetRegion == NULL || pPresetRegion->freqVibLfo == NONE) return ToHz(freqVibLfo);
00628         return ToHz(pPresetRegion->freqVibLfo + freqVibLfo);
00629     }
00630 
00631     double Region::GetDelayVibLfo(Region* pPresetRegion) {
00632         if (pPresetRegion == NULL || pPresetRegion->delayVibLfo == NONE) return ToSeconds(delayVibLfo);
00633         return ToSeconds(pPresetRegion->delayVibLfo + delayVibLfo);
00634     }
00635 
00636     InstrumentBase::InstrumentBase(sf2::File* pFile) {
00637         this->pFile = pFile;
00638         pGlobalRegion = NULL;
00639     }
00640 
00641     InstrumentBase::~InstrumentBase() {
00642         if (pGlobalRegion) delete pGlobalRegion;
00643         for (int i = regions.size() - 1; i >= 0; i--) {
00644             if (regions[i]) delete (regions[i]);
00645         }
00646     }
00647 
00648     int InstrumentBase::GetRegionCount() {
00649         return regions.size();
00650     }
00651 
00652     Region* InstrumentBase::GetRegion(int idx) {
00653          if (idx < 0 || idx >= GetRegionCount()) {
00654             throw Exception("Region index out of bounds");
00655         }
00656 
00657         return regions[idx];
00658     }
00659 
00660     Query::Query(InstrumentBase& instrument) : instrument(instrument) {
00661         i = 0;
00662     }
00663 
00664     Region* Query::next() {
00665         while (i < instrument.GetRegionCount()) {
00666             Region* r = instrument.GetRegion(i++);
00667             if (((r->loKey  == NONE && r->hiKey  == NONE) || (key >= r->loKey && key <= r->hiKey)) &&
00668                 ((r->minVel == NONE && r->maxVel == NONE) || (vel >= r->minVel && vel <= r->maxVel))) {
00669                 return r;
00670             }
00671         }
00672         return 0;
00673     }
00674 
00675     Instrument::Instrument(sf2::File* pFile, RIFF::Chunk* ck) : InstrumentBase(pFile) {
00676         this->pFile = pFile;
00677         LoadString(ck, Name, 20);
00678         InstBagNdx = ck->ReadInt16();
00679     }
00680 
00681     Instrument::~Instrument() {
00682     }
00683 
00684     Region* Instrument::CreateRegion() {
00685         Region* r = new Region;
00686         r->pParentInstrument = this;
00687 
00688         if (pGlobalRegion != NULL) {
00689             r->loKey       = pGlobalRegion->loKey;
00690             r->hiKey       = pGlobalRegion->hiKey;
00691             r->minVel      = pGlobalRegion->minVel;
00692             r->maxVel      = pGlobalRegion->maxVel;
00693             r->pan         = pGlobalRegion->pan;
00694             r->fineTune    = pGlobalRegion->fineTune;
00695             r->coarseTune  = pGlobalRegion->coarseTune;
00696             r->overridingRootKey = pGlobalRegion->overridingRootKey;
00697             r->startAddrsOffset            = pGlobalRegion->startAddrsOffset;
00698             r->startAddrsCoarseOffset      = pGlobalRegion->startAddrsCoarseOffset;
00699             r->endAddrsOffset              = pGlobalRegion->endAddrsOffset;
00700             r->endAddrsCoarseOffset        = pGlobalRegion->endAddrsCoarseOffset;
00701             r->startloopAddrsOffset        = pGlobalRegion->startloopAddrsOffset;
00702             r->startloopAddrsCoarseOffset  = pGlobalRegion->startloopAddrsCoarseOffset;
00703             r->endloopAddrsOffset          = pGlobalRegion->endloopAddrsOffset;
00704             r->endloopAddrsCoarseOffset    = pGlobalRegion->endloopAddrsCoarseOffset;
00705 
00706             r->EG1PreAttackDelay  = pGlobalRegion->EG1PreAttackDelay;
00707             r->EG1Attack          = pGlobalRegion->EG1Attack;
00708             r->EG1Hold            = pGlobalRegion->EG1Hold;
00709             r->EG1Decay           = pGlobalRegion->EG1Decay;
00710             r->EG1Sustain         = pGlobalRegion->EG1Sustain;
00711             r->EG1Release         = pGlobalRegion->EG1Release;
00712 
00713             r->EG2PreAttackDelay  = pGlobalRegion->EG2PreAttackDelay;
00714             r->EG2Attack          = pGlobalRegion->EG2Attack;
00715             r->EG2Hold            = pGlobalRegion->EG2Hold;
00716             r->EG2Decay           = pGlobalRegion->EG2Decay;
00717             r->EG2Sustain         = pGlobalRegion->EG2Sustain;
00718             r->EG2Release         = pGlobalRegion->EG2Release;
00719 
00720             r->modEnvToPitch     = pGlobalRegion->modEnvToPitch;
00721             r->modLfoToPitch     = pGlobalRegion->modLfoToPitch;
00722             r->modEnvToFilterFc  = pGlobalRegion->modEnvToFilterFc;
00723             r->modLfoToFilterFc  = pGlobalRegion->modLfoToFilterFc;
00724             r->modLfoToVolume    = pGlobalRegion->modLfoToVolume;
00725             r->freqModLfo        = pGlobalRegion->freqModLfo;
00726             r->delayModLfo       = pGlobalRegion->delayModLfo;
00727             r->vibLfoToPitch     = pGlobalRegion->vibLfoToPitch;
00728             r->freqVibLfo        = pGlobalRegion->freqVibLfo;
00729             r->delayVibLfo       = pGlobalRegion->delayVibLfo;
00730 
00731             r->HasLoop    = pGlobalRegion->HasLoop;
00732             r->LoopStart  = pGlobalRegion->LoopStart;
00733             r->LoopEnd    = pGlobalRegion->LoopEnd;
00734 
00735             r->exclusiveClass = pGlobalRegion->exclusiveClass;
00736         }
00737 
00738         return r;
00739     }
00740 
00741     void Instrument::DeleteRegion(Region* pRegion) {
00742         for (int i = 0; i < regions.size(); i++) {
00743             if (regions[i] == pRegion) {
00744                 delete pRegion;
00745                 regions[i] = NULL;
00746                 return;
00747             }
00748         }
00749 
00750         std::cerr << "Can't remove unknown Region" << std::endl;
00751     }
00752 
00753     void Instrument::LoadRegions(int idx1, int idx2) {
00754         for (int i = idx1; i < idx2; i++) {
00755             int gIdx1 = pFile->InstBags[i].InstGenNdx;
00756             int gIdx2 = pFile->InstBags[i + 1].InstGenNdx;
00757 
00758             if (gIdx1 < 0 || gIdx2 < 0 || gIdx1 > gIdx2 || gIdx2 >= pFile->InstGenLists.size()) {
00759                 throw Exception("Broken SF2 file (invalid InstGenNdx)");
00760             }
00761 
00762             int mIdx1 = pFile->InstBags[i].InstModNdx;
00763             int mIdx2 = pFile->InstBags[i + 1].InstModNdx;
00764 
00765             if (mIdx1 < 0 || mIdx2 < 0 || mIdx1 > mIdx2 || mIdx2 >= pFile->InstModLists.size()) {
00766                 throw Exception("Broken SF2 file (invalid InstModNdx)");
00767             }
00768 
00769             Region* reg = CreateRegion();
00770 
00771             for (int j = gIdx1; j < gIdx2; j++) {
00772                 reg->SetGenerator(pFile, pFile->InstGenLists[j]);
00773                 // TODO: ignore generators following a sampleID generator
00774             }
00775 
00776             for (int j = mIdx1; j < mIdx2; j++) {
00777                 reg->SetModulator(pFile, pFile->InstModLists[j]);
00778             }
00779 
00780             if (reg->pSample == NULL) {
00781                 if (i == idx1 && idx2 - idx1 > 1) {
00782                     pGlobalRegion = reg;  // global zone
00783                 } else {
00784                     std::cerr << "Ignoring instrument's region without sample" << std::endl;
00785                     delete reg;
00786                 }
00787             } else {
00788                 regions.push_back(reg);
00789             }
00790         }
00791     }
00792 
00793     Preset::Preset(sf2::File* pFile, RIFF::Chunk* ck): InstrumentBase(pFile) {
00794         this->pFile = pFile;
00795         LoadString(ck, Name, 20);
00796         PresetNum = ck->ReadInt16();
00797         Bank = ck->ReadInt16();
00798         PresetBagNdx = ck->ReadInt16();
00799         Library = ck->ReadInt32();
00800         Genre = ck->ReadInt32();
00801         Morphology = ck->ReadInt32();
00802     }
00803 
00804     Preset::~Preset() {
00805     }
00806 
00807     Region* Preset::CreateRegion() {
00808         Region* r = new Region;
00809 
00810         r->EG1PreAttackDelay = r->EG1Attack = r->EG1Hold = r->EG1Decay = r->EG1Sustain = r->EG1Release = NONE;
00811         r->EG2PreAttackDelay = r->EG2Attack = r->EG2Hold = r->EG2Decay = r->EG2Sustain = r->EG2Release = NONE;
00812         r->freqModLfo = r->delayModLfo = r->freqVibLfo = r->delayVibLfo = NONE;
00813 
00814         if (pGlobalRegion != NULL) {
00815             r->pan         = pGlobalRegion->pan;
00816             r->fineTune    = pGlobalRegion->fineTune;
00817             r->coarseTune  = pGlobalRegion->coarseTune;
00818 
00819             r->EG1PreAttackDelay  = pGlobalRegion->EG1PreAttackDelay;
00820             r->EG1Attack          = pGlobalRegion->EG1Attack;
00821             r->EG1Hold            = pGlobalRegion->EG1Hold;
00822             r->EG1Decay           = pGlobalRegion->EG1Decay;
00823             r->EG1Sustain         = pGlobalRegion->EG1Sustain;
00824             r->EG1Release         = pGlobalRegion->EG1Release;
00825 
00826             r->EG2PreAttackDelay  = pGlobalRegion->EG2PreAttackDelay;
00827             r->EG2Attack          = pGlobalRegion->EG2Attack;
00828             r->EG2Hold            = pGlobalRegion->EG2Hold;
00829             r->EG2Decay           = pGlobalRegion->EG2Decay;
00830             r->EG2Sustain         = pGlobalRegion->EG2Sustain;
00831             r->EG2Release         = pGlobalRegion->EG2Release;
00832 
00833             r->modEnvToPitch     = pGlobalRegion->modEnvToPitch;
00834             r->modLfoToPitch     = pGlobalRegion->modLfoToPitch;
00835             r->modEnvToFilterFc  = pGlobalRegion->modEnvToFilterFc;
00836             r->modLfoToFilterFc  = pGlobalRegion->modLfoToFilterFc;
00837             r->modLfoToVolume    = pGlobalRegion->modLfoToVolume;
00838             r->freqModLfo        = pGlobalRegion->freqModLfo;
00839             r->delayModLfo       = pGlobalRegion->delayModLfo;
00840             r->vibLfoToPitch     = pGlobalRegion->vibLfoToPitch;
00841             r->freqVibLfo        = pGlobalRegion->freqVibLfo;
00842             r->delayVibLfo       = pGlobalRegion->delayVibLfo;
00843         }
00844 
00845         return r;
00846     }
00847 
00848     void Preset::LoadRegions(int idx1, int idx2) {
00849         for (int i = idx1; i < idx2; i++) {
00850             int gIdx1 = pFile->PresetBags[i].GenNdx;
00851             int gIdx2 = pFile->PresetBags[i + 1].GenNdx;
00852 
00853             if (gIdx1 < 0 || gIdx2 < 0 || gIdx1 > gIdx2 || gIdx2 >= pFile->PresetGenLists.size()) {
00854                 throw Exception("Broken SF2 file (invalid PresetGenNdx)");
00855             }
00856 
00857             Region* reg = CreateRegion();
00858 
00859             for (int j = gIdx1; j < gIdx2; j++) {
00860                 reg->SetGenerator(pFile, pFile->PresetGenLists[j]);
00861             }
00862             if (reg->pInstrument == NULL) {
00863                 if (i == idx1 && idx2 - idx1 > 1) {
00864                     pGlobalRegion = reg;  // global zone
00865                 } else {
00866                     std::cerr << "Ignoring preset's region without instrument" << std::endl;
00867                     delete reg;
00868                 }
00869             } else {
00870                 regions.push_back(reg);
00871             }
00872         }
00873     }
00874 
00884     File::File(RIFF::File* pRIFF) {
00885         if (!pRIFF) throw Exception("NULL pointer reference to RIFF::File object.");
00886         this->pRIFF = pRIFF;
00887 
00888         if (pRIFF->GetListType() != RIFF_TYPE_SF2) {
00889             throw Exception("Not a SF2 file");
00890         }
00891 
00892         pInfo = new Info(pRIFF);
00893         if (pInfo->pVer->Major != 2) {
00894             throw Exception("Unsupported version: " + ToString(pInfo->pVer->Major));
00895         }
00896 
00897         RIFF::List* lstSDTA = pRIFF->GetSubList(LIST_TYPE_SDTA);
00898         if (lstSDTA == NULL) {
00899             throw Exception("Broken SF2 file (missing sdta)");
00900         }
00901 
00902         RIFF::Chunk* pCkSmpl = lstSDTA->GetSubChunk(CHUNK_ID_SMPL);
00903         RIFF::Chunk* pCkSm24 = lstSDTA->GetSubChunk(CHUNK_ID_SM24);
00904         if (pCkSmpl != NULL && pCkSm24 != NULL) {
00905             long l = pCkSmpl->GetSize() / 2;
00906             if (l%2) l++;
00907             if (pCkSm24->GetSize() != l) {
00908                 pCkSm24 = NULL; // ignoring sm24 due to invalid size
00909             }
00910         }
00911 
00912         RIFF::List* lstPDTA = pRIFF->GetSubList(LIST_TYPE_PDTA);
00913         if (lstPDTA == NULL) {
00914             throw Exception("Broken SF2 file (missing pdta)");
00915         }
00916 
00917         RIFF::Chunk* ck = lstPDTA->GetSubChunk(CHUNK_ID_PHDR);
00918         if (ck->GetSize() < 38) {
00919             throw Exception("Broken SF2 file (broken phdr)");
00920         }
00921 
00922         int count = ck->GetSize() / 38;
00923         for (int i = 0; i < count; i++) {
00924             Presets.push_back(new Preset(this, ck));
00925         }
00926 
00927         ck = GetMandatoryChunk(lstPDTA, CHUNK_ID_PBAG);
00928         if (ck->GetSize() < 4 || (ck->GetSize() % 4)) {
00929             throw Exception("Broken SF2 file (broken pbag)");
00930         }
00931 
00932         count = ck->GetSize() / 4;
00933         for (int i = 0; i < count; i++) {
00934             PresetBag pb;
00935             pb.GenNdx = ck->ReadInt16();
00936             pb.ModNdx = ck->ReadInt16();
00937             PresetBags.push_back(pb);
00938         }
00939         //std::cout << "Preset bags: " << PresetBags.size() << std::endl;
00940 
00941         ck = GetMandatoryChunk(lstPDTA, CHUNK_ID_PMOD);
00942         if (ck->GetSize() % 10) {
00943             throw Exception("Broken SF2 file (broken pmod)");
00944         }
00945 
00946         count = ck->GetSize() / 10;
00947         for (int i = 0; i < count; i++) {
00948             ModList ml;
00949             ml.ModSrcOper = ck->ReadInt16();
00950             ml.ModDestOper = ck->ReadInt16();
00951             ml.ModAmount = ck->ReadInt16();
00952             ml.ModAmtSrcOper = ck->ReadInt16();
00953             ml.ModTransOper = ck->ReadInt16();
00954             PresetModLists.push_back(ml);
00955         }
00956         //std::cout << "Preset mod lists: " << PresetModLists.size() << std::endl;
00957 
00958         ck = GetMandatoryChunk(lstPDTA, CHUNK_ID_PGEN);
00959         if (ck->GetSize() < 4 || (ck->GetSize() % 4)) {
00960             throw Exception("Broken SF2 file (broken pgen)");
00961         }
00962 
00963         count = ck->GetSize() / 4;
00964         for (int i = 0; i < count; i++) {
00965             GenList gl;
00966             gl.GenOper = ck->ReadInt16();
00967             gl.GenAmount.wAmount = ck->ReadInt16();
00968             PresetGenLists.push_back(gl);
00969         }
00970         //std::cout << "Preset gen lists: " << PresetGenLists.size() << std::endl;
00971 
00972         ck = GetMandatoryChunk(lstPDTA, CHUNK_ID_INST);
00973         if (ck->GetSize() < (22 * 2) || (ck->GetSize() % 22)) {
00974             throw Exception("Broken SF2 file (broken inst)");
00975         }
00976         count = ck->GetSize() / 22;
00977         for (int i = 0; i < count; i++) {
00978             Instruments.push_back(new Instrument(this, ck));
00979         }
00980 
00981         ck = GetMandatoryChunk(lstPDTA, CHUNK_ID_IBAG);
00982         if (ck->GetSize() < 4 || (ck->GetSize() % 4)) {
00983             throw Exception("Broken SF2 file (broken ibag)");
00984         }
00985 
00986         count = ck->GetSize() / 4;
00987         for (int i = 0; i < count; i++) {
00988             InstBag ib;
00989             ib.InstGenNdx = ck->ReadInt16();
00990             ib.InstModNdx = ck->ReadInt16();
00991             InstBags.push_back(ib);
00992         }
00993         //std::cout << "Instrument bags: " << InstBags.size() << std::endl;
00994 
00995         ck = GetMandatoryChunk(lstPDTA, CHUNK_ID_IMOD);
00996         if (ck->GetSize() % 10) {
00997             throw Exception("Broken SF2 file (broken imod)");
00998         }
00999 
01000         count = ck->GetSize() / 10;
01001         for (int i = 0; i < count; i++) {
01002             ModList ml;
01003             ml.ModSrcOper = ck->ReadInt16();
01004             ml.ModDestOper = ck->ReadInt16();
01005             ml.ModAmount = ck->ReadInt16();
01006             ml.ModAmtSrcOper = ck->ReadInt16();
01007             ml.ModTransOper = ck->ReadInt16();
01008             InstModLists.push_back(ml);
01009         }
01010         //std::cout << "Instrument mod lists: " << InstModLists.size() << std::endl;
01011 
01012         ck = GetMandatoryChunk(lstPDTA, CHUNK_ID_IGEN);
01013         if (ck->GetSize() < 4 || (ck->GetSize() % 4)) {
01014             throw Exception("Broken SF2 file (broken igen)");
01015         }
01016 
01017         count = ck->GetSize() / 4;
01018         for (int i = 0; i < count; i++) {
01019             GenList gl;
01020             gl.GenOper = ck->ReadInt16();
01021             gl.GenAmount.wAmount = ck->ReadInt16();
01022             InstGenLists.push_back(gl);
01023         }
01024         //std::cout << "Instrument gen lists: " << InstGenLists.size() << std::endl;
01025 
01026         ck = GetMandatoryChunk(lstPDTA, CHUNK_ID_SHDR);
01027         if ((ck->GetSize() % 46)) {
01028             throw Exception("Broken SF2 file (broken shdr)");
01029         }
01030         count = ck->GetSize() / 46;
01031         for (int i = 0; i < count; i++) {
01032             Samples.push_back(new Sample(ck, pCkSmpl, pCkSm24));
01033         }
01034 
01035         // Loading instrument regions
01036         for (int i = 0; i < Instruments.size() - 1; i++) {
01037             Instrument* instr = Instruments[i];
01038             int x1 = instr->InstBagNdx;
01039             int x2 = Instruments[i + 1]->InstBagNdx;
01040             if (x1 < 0 || x2 < 0 || x1 > x2 || x2 >= InstBags.size()) {
01041                 throw Exception("Broken SF2 file (invalid InstBagNdx)");
01042             }
01043 
01044             instr->LoadRegions(x1, x2);
01045         }
01046 
01047         // Loading preset regions
01048         for (int i = 0; i < Presets.size() - 1; i++) {
01049             Preset* preset = Presets[i];
01050             int x1 = preset->PresetBagNdx;
01051             int x2 = Presets[i + 1]->PresetBagNdx;
01052             if (x1 < 0 || x2 < 0 || x1 > x2 || x2 >= PresetBags.size()) {
01053                 throw Exception("Broken SF2 file (invalid PresetBagNdx)");
01054             }
01055 
01056             preset->LoadRegions(x1, x2);
01057         }
01058     }
01059 
01060     File::~File() {
01061         delete pInfo;
01062         for (int i = Presets.size() - 1; i >= 0; i--) {
01063             if (Presets[i]) delete (Presets[i]);
01064         }
01065         for (int i = Instruments.size() - 1; i >= 0; i--) {
01066             if (Instruments[i]) delete (Instruments[i]);
01067         }
01068         for (int i = Samples.size() - 1; i >= 0; i--) {
01069             if (Samples[i]) delete (Samples[i]);
01070         }
01071     }
01072 
01073     int File::GetPresetCount() {
01074         return Presets.size() - 1; // exclude terminal preset (EOP)
01075     }
01076 
01077     Preset* File::GetPreset(int idx) {
01078         if (idx < 0 || idx >= GetPresetCount()) {
01079             throw Exception("Preset index out of bounds");
01080         }
01081 
01082         return Presets[idx];
01083     }
01084 
01085     int File::GetInstrumentCount() {
01086         return Instruments.size() - 1; // exclude terminal instrument (EOI)
01087     }
01088 
01089     Instrument* File::GetInstrument(int idx) {
01090         if (idx < 0 || idx >= GetInstrumentCount()) {
01091             throw Exception("Instrument index out of bounds");
01092         }
01093 
01094         return Instruments[idx];
01095     }
01096 
01097     void File::DeleteInstrument(Instrument* pInstrument) {
01098         for (int i = 0; i < GetPresetCount(); i++) {
01099             Preset* p = GetPreset(i);
01100             if (p == NULL) continue;
01101             for (int j = p->GetRegionCount() - 1; j >= 0 ; j--) {
01102                 if (p->GetRegion(j) && p->GetRegion(j)->pInstrument == pInstrument) {
01103                     p->GetRegion(j)->pInstrument = NULL;
01104                 }
01105             }
01106         }
01107 
01108         for (int i = 0; i < GetInstrumentCount(); i++) {
01109             if (GetInstrument(i) == pInstrument) {
01110                 Instruments[i] = NULL;
01111                 delete pInstrument;
01112             }
01113         }
01114     }
01115 
01116     int File::GetSampleCount() {
01117         return Samples.size() - 1; // exclude terminal sample (EOS)
01118     }
01119 
01120     Sample* File::GetSample(int idx) {
01121         if (idx < 0 || idx >= GetSampleCount()) {
01122             throw Exception("Sample index out of bounds");
01123         }
01124 
01125         return Samples[idx];
01126     }
01127 
01128     void File::DeleteSample(Sample* pSample) {
01129         // Sanity check
01130         for (int i = GetInstrumentCount() - 1; i >= 0; i--) {
01131             Instrument* pInstr = GetInstrument(i);
01132             if (pInstr == NULL) continue;
01133 
01134             for (int j = pInstr->GetRegionCount() - 1; j >= 0 ; j--) {
01135                 if (pInstr->GetRegion(j) && pInstr->GetRegion(j)->GetSample() == pSample) {
01136                     std::cerr << "Deleting sample which is still in use" << std::endl;
01137                 }
01138             }
01139         }
01141 
01142         for (int i = 0; i < GetSampleCount(); i++) {
01143             if (Samples[i] == pSample) {
01144                 delete pSample;
01145                 Samples[i] = NULL;
01146                 return;
01147             }
01148         }
01149 
01150         throw Exception("Unknown sample: " + pSample->Name);
01151     }
01152 
01153     bool File::HasSamples() {
01154         for (int i = 0; i < GetSampleCount(); i++) {
01155             if (Samples[i] != NULL) return true;
01156         }
01157 
01158         return false;
01159     }
01160 
01170     Sample::buffer_t Sample::LoadSampleData() {
01171         return LoadSampleDataWithNullSamplesExtension(GetTotalFrameCount(), 0); // 0 amount of NullSamples
01172     }
01173 
01192     Sample::buffer_t Sample::LoadSampleData(unsigned long SampleCount) {
01193         return LoadSampleDataWithNullSamplesExtension(SampleCount, 0); // 0 amount of NullSamples
01194     }
01195 
01215     Sample::buffer_t Sample::LoadSampleDataWithNullSamplesExtension(uint NullSamplesCount) {
01216         return LoadSampleDataWithNullSamplesExtension(GetTotalFrameCount(), NullSamplesCount);
01217     }
01218 
01247     Sample::buffer_t Sample::LoadSampleDataWithNullSamplesExtension(unsigned long SampleCount, uint NullSamplesCount) {
01248         if (SampleCount > GetTotalFrameCount()) SampleCount = GetTotalFrameCount();
01249         if (RAMCache.pStart) delete[] (int8_t*) RAMCache.pStart;
01250         unsigned long allocationsize = (SampleCount + NullSamplesCount) * GetFrameSize();
01251         SetPos(0); // reset read position to begin of sample
01252         RAMCache.pStart            = new int8_t[allocationsize];
01253         RAMCache.Size              = Read(RAMCache.pStart, SampleCount) * GetFrameSize();
01254         RAMCache.NullExtensionSize = allocationsize - RAMCache.Size;
01255         // fill the remaining buffer space with silence samples
01256         memset((int8_t*)RAMCache.pStart + RAMCache.Size, 0, RAMCache.NullExtensionSize);
01257         return GetCache();
01258     }
01259 
01270     Sample::buffer_t Sample::GetCache() {
01271         // return a copy of the buffer_t structure
01272         buffer_t result;
01273         result.Size              = this->RAMCache.Size;
01274         result.pStart            = this->RAMCache.pStart;
01275         result.NullExtensionSize = this->RAMCache.NullExtensionSize;
01276         return result;
01277     }
01278 
01285     void Sample::ReleaseSampleData() {
01286         if (RAMCache.pStart) delete[] (int8_t*) RAMCache.pStart;
01287         RAMCache.pStart = NULL;
01288         RAMCache.Size   = 0;
01289         RAMCache.NullExtensionSize = 0;
01290     }
01291 
01301     unsigned long Sample::SetPos(unsigned long SampleCount) {
01302         pCkSmpl->SetPos((Start * 2) + (SampleCount * 2), RIFF::stream_start);
01303         if(pCkSm24) pCkSm24->SetPos(Start + SampleCount, RIFF::stream_start);
01304         return SampleCount;
01305     }
01306 
01310     unsigned long Sample::GetPos() {
01311         return (pCkSmpl->GetPos() - (Start * 2)) / 2;
01312     }
01313 
01330     unsigned long Sample::Read(void* pBuffer, unsigned long SampleCount) {
01331         // TODO: startAddrsCoarseOffset, endAddrsCoarseOffset
01332         if (SampleCount == 0) return 0;
01333         long pos = GetPos();
01334         if (pos + SampleCount > GetTotalFrameCount()) SampleCount = GetTotalFrameCount() - pos;
01335 
01336         if (GetFrameSize() / GetChannelCount() == 3 /* 24 bit */) {
01337             uint8_t* pBuf = (uint8_t*)pBuffer;
01338             if (SampleType == MONO_SAMPLE || SampleType == ROM_MONO_SAMPLE) {
01339                 pCkSmpl->Read(pBuf, SampleCount, 2);
01340                 pCkSm24->Read(pBuf + SampleCount * 2, SampleCount, 1);
01341                 for (int i = SampleCount - 1; i >= 0; i--) {
01342                     pBuf[i*3] = pBuf[(SampleCount * 2) + i];
01343                     pBuf[i*3 + 2] = pBuf[i*2 + 1];
01344                     pBuf[i*3 + 1] = pBuf[i*2];
01345                 }
01346             } else if (SampleType == LEFT_SAMPLE || SampleType == ROM_LEFT_SAMPLE) {
01347                 pCkSmpl->Read(pBuf, SampleCount, 2);
01348                 pCkSm24->Read(pBuf + SampleCount * 2, SampleCount, 1);
01349                 for (int i = SampleCount - 1; i >= 0; i--) {
01350                     pBuf[i*6] = pBuf[(SampleCount * 2) + i];
01351                     pBuf[i*6 + 2] = pBuf[i*2 + 1];
01352                     pBuf[i*6 + 1] = pBuf[i*2];
01353                     pBuf[i*6 + 3] = pBuf[i*6 + 4] = pBuf[i*6 + 5] = 0;
01354                 }
01355             } else if (SampleType == RIGHT_SAMPLE || SampleType == ROM_RIGHT_SAMPLE) {
01356                 pCkSmpl->Read(pBuf, SampleCount, 2);
01357                 pCkSm24->Read(pBuf + SampleCount * 2, SampleCount, 1);
01358                 for (int i = SampleCount - 1; i >= 0; i--) {
01359                     pBuf[i*6 + 3] = pBuf[(SampleCount * 2) + i];
01360                     pBuf[i*6 + 5] = pBuf[i*2 + 1];
01361                     pBuf[i*6 + 4] = pBuf[i*2];
01362                     pBuf[i*6] = pBuf[i*6 + 1] = pBuf[i*6 + 2] = 0;
01363                 }
01364             }
01365         } else {
01366             if (SampleType == MONO_SAMPLE || SampleType == ROM_MONO_SAMPLE) {
01367                 return pCkSmpl->Read(pBuffer, SampleCount, 2);
01368             }
01369 
01370             int16_t* pBuf = (int16_t*)pBuffer;
01371             if (SampleType == LEFT_SAMPLE || SampleType == ROM_LEFT_SAMPLE) {
01372                 pCkSmpl->Read(pBuf, SampleCount, 2);
01373                 for (int i = SampleCount - 1; i >= 0; i--) {
01374                     pBuf[i*2] = pBuf[i];
01375                     pBuf[i*2 + 1] = 0;
01376                 }
01377             } else if (SampleType == RIGHT_SAMPLE || SampleType == ROM_RIGHT_SAMPLE) {
01378                 pCkSmpl->Read(pBuf, SampleCount, 2);
01379                 for (int i = SampleCount - 1; i >= 0; i--) {
01380                     pBuf[i*2] = 0;
01381                     pBuf[i*2 + 1] = pBuf[i];
01382                 }
01383             }
01384         }
01385 
01386         if (pCkSmpl->GetPos() > (End * 2)) {
01387             std::cerr << "Read after the sample end. This is a BUG!" << std::endl;
01388             std::cerr << "Current position: " << GetPos() << std::endl;
01389             std::cerr << "Total number of frames: " << GetTotalFrameCount() << std::endl << std::endl;
01390         }
01391         return SampleCount;
01392     }
01393 
01394 
01395 // *************** functions ***************
01396 // *
01397 
01401     String libraryName() {
01402         return PACKAGE;
01403     }
01404 
01408     String libraryVersion() {
01409         return VERSION;
01410     }
01411 
01412 } // namespace sf2

Generated on Sun May 1 03:22:46 2011 for libgig by  doxygen 1.5.2