/[svn]/libgig/trunk/src/gig.cpp
ViewVC logotype

Diff of /libgig/trunk/src/gig.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 2557 by schoenebeck, Sat May 17 23:31:20 2014 UTC revision 2593 by schoenebeck, Wed Jun 4 01:59:56 2014 UTC
# Line 3056  namespace { Line 3056  namespace {
3056              memset(_3lnk->LoadChunkData(), 0, _3lnkChunkSize);              memset(_3lnk->LoadChunkData(), 0, _3lnkChunkSize);
3057    
3058              // move 3prg to last position              // move 3prg to last position
3059              pCkRegion->MoveSubChunk(pCkRegion->GetSubList(LIST_TYPE_3PRG), 0);              pCkRegion->MoveSubChunk(pCkRegion->GetSubList(LIST_TYPE_3PRG), (RIFF::Chunk*)NULL);
3060          }          }
3061    
3062          // update dimension definitions in '3lnk' chunk          // update dimension definitions in '3lnk' chunk
# Line 3743  namespace { Line 3743  namespace {
3743              }              }
3744              bitpos += pDimensionDefinitions[i].bits;              bitpos += pDimensionDefinitions[i].bits;
3745          }          }
3746          DimensionRegion* dimreg = pDimensionRegions[dimregidx];          DimensionRegion* dimreg = pDimensionRegions[dimregidx & 255];
3747            if (!dimreg) return NULL;
3748          if (veldim != -1) {          if (veldim != -1) {
3749              // (dimreg is now the dimension region for the lowest velocity)              // (dimreg is now the dimension region for the lowest velocity)
3750              if (dimreg->VelocityTable) // custom defined zone ranges              if (dimreg->VelocityTable) // custom defined zone ranges
3751                  bits = dimreg->VelocityTable[DimValues[veldim]];                  bits = dimreg->VelocityTable[DimValues[veldim] & 127];
3752              else // normal split type              else // normal split type
3753                  bits = uint8_t(DimValues[veldim] / pDimensionDefinitions[veldim].zone_size);                  bits = uint8_t((DimValues[veldim] & 127) / pDimensionDefinitions[veldim].zone_size);
3754    
3755              dimregidx |= bits << velbitpos;              const uint8_t limiter_mask = (1 << pDimensionDefinitions[veldim].bits) - 1;
3756              dimreg = pDimensionRegions[dimregidx];              dimregidx |= (bits & limiter_mask) << velbitpos;
3757                dimreg = pDimensionRegions[dimregidx & 255];
3758          }          }
3759          return dimreg;          return dimreg;
3760      }      }
# Line 4023  namespace { Line 4025  namespace {
4025          }          }
4026      }      }
4027    
4028    // *************** Script ***************
4029    // *
4030    
4031        Script::Script(ScriptGroup* group, RIFF::Chunk* ckScri) {
4032            pGroup = group;
4033            pChunk = ckScri;
4034            if (ckScri) { // object is loaded from file ...
4035                // read header
4036                uint32_t headerSize = ckScri->ReadUint32();
4037                Compression = (Compression_t) ckScri->ReadUint32();
4038                Encoding    = (Encoding_t) ckScri->ReadUint32();
4039                Language    = (Language_t) ckScri->ReadUint32();
4040                Bypass      = (Language_t) ckScri->ReadUint32() & 1;
4041                crc         = ckScri->ReadUint32();
4042                uint32_t nameSize = ckScri->ReadUint32();
4043                Name.resize(nameSize, ' ');
4044                for (int i = 0; i < nameSize; ++i)
4045                    Name[i] = ckScri->ReadUint8();
4046                // to handle potential future extensions of the header
4047                ckScri->SetPos(headerSize - 6*sizeof(int32_t) + nameSize, RIFF::stream_curpos);
4048                // read actual script data
4049                uint32_t scriptSize = ckScri->GetSize() - ckScri->GetPos();
4050                data.resize(scriptSize);
4051                for (int i = 0; i < scriptSize; ++i)
4052                    data[i] = ckScri->ReadUint8();
4053            } else { // this is a new script object, so just initialize it as such ...
4054                Compression = COMPRESSION_NONE;
4055                Encoding = ENCODING_ASCII;
4056                Language = LANGUAGE_NKSP;
4057                Bypass   = false;
4058                crc      = 0;
4059                Name     = "Unnamed Script";
4060            }
4061        }
4062    
4063        Script::~Script() {
4064        }
4065    
4066        /**
4067         * Returns the current script (i.e. as source code) in text format.
4068         */
4069        String Script::GetScriptAsText() {
4070            String s;
4071            s.resize(data.size(), ' ');
4072            memcpy(&s[0], &data[0], data.size());
4073            return s;
4074        }
4075    
4076        /**
4077         * Replaces the current script with the new script source code text given
4078         * by @a text.
4079         *
4080         * @param text - new script source code
4081         */
4082        void Script::SetScriptAsText(const String& text) {
4083            data.resize(text.size());
4084            memcpy(&data[0], &text[0], text.size());
4085        }
4086    
4087        void Script::UpdateChunks() {
4088            // recalculate CRC32 check sum
4089            __resetCRC(crc);
4090            __calculateCRC(&data[0], data.size(), crc);
4091            __encodeCRC(crc);
4092            // make sure chunk exists and has the required size
4093            const int chunkSize = 7*sizeof(int32_t) + Name.size() + data.size();
4094            if (!pChunk) pChunk = pGroup->pList->AddSubChunk(CHUNK_ID_SCRI, chunkSize);
4095            else pChunk->Resize(chunkSize);
4096            // fill the chunk data to be written to disk
4097            uint8_t* pData = (uint8_t*) pChunk->LoadChunkData();
4098            int pos = 0;
4099            store32(&pData[pos], 6*sizeof(int32_t) + Name.size()); // total header size
4100            pos += sizeof(int32_t);
4101            store32(&pData[pos], Compression);
4102            pos += sizeof(int32_t);
4103            store32(&pData[pos], Encoding);
4104            pos += sizeof(int32_t);
4105            store32(&pData[pos], Language);
4106            pos += sizeof(int32_t);
4107            store32(&pData[pos], Bypass ? 1 : 0);
4108            pos += sizeof(int32_t);
4109            store32(&pData[pos], crc);
4110            pos += sizeof(int32_t);
4111            store32(&pData[pos], Name.size());
4112            pos += sizeof(int32_t);
4113            for (int i = 0; i < Name.size(); ++i, ++pos)
4114                pData[pos] = Name[i];
4115            for (int i = 0; i < data.size(); ++i, ++pos)
4116                pData[pos] = data[i];
4117        }
4118    
4119        /**
4120         * Move this script from its current ScriptGroup to another ScriptGroup
4121         * given by @a pGroup.
4122         *
4123         * @param pGroup - script's new group
4124         */
4125        void Script::SetGroup(ScriptGroup* pGroup) {
4126            if (this->pGroup = pGroup) return;
4127            if (pChunk)
4128                pChunk->GetParent()->MoveSubChunk(pChunk, pGroup->pList);
4129            this->pGroup = pGroup;
4130        }
4131    
4132        void Script::RemoveAllScriptReferences() {
4133            File* pFile = pGroup->pFile;
4134            for (int i = 0; pFile->GetInstrument(i); ++i) {
4135                Instrument* instr = pFile->GetInstrument(i);
4136                instr->RemoveScript(this);
4137            }
4138        }
4139    
4140    // *************** ScriptGroup ***************
4141    // *
4142    
4143        ScriptGroup::ScriptGroup(File* file, RIFF::List* lstRTIS) {
4144            pFile = file;
4145            pList = lstRTIS;
4146            pScripts = NULL;
4147            if (lstRTIS) {
4148                RIFF::Chunk* ckName = lstRTIS->GetSubChunk(CHUNK_ID_LSNM);
4149                ::LoadString(ckName, Name);
4150            } else {
4151                Name = "Default Group";
4152            }
4153        }
4154    
4155        ScriptGroup::~ScriptGroup() {
4156            if (pScripts) {
4157                std::list<Script*>::iterator iter = pScripts->begin();
4158                std::list<Script*>::iterator end  = pScripts->end();
4159                while (iter != end) {
4160                    delete *iter;
4161                    ++iter;
4162                }
4163                delete pScripts;
4164            }
4165        }
4166    
4167        void ScriptGroup::UpdateChunks() {
4168            if (pScripts) {
4169                if (!pList)
4170                    pList = pFile->pRIFF->GetSubList(LIST_TYPE_3LS)->AddSubList(LIST_TYPE_RTIS);
4171    
4172                // now store the name of this group as <LSNM> chunk as subchunk of the <RTIS> list chunk
4173                ::SaveString(CHUNK_ID_LSNM, NULL, pList, Name, String("Unnamed Group"), true, 64);
4174    
4175                for (std::list<Script*>::iterator it = pScripts->begin();
4176                     it != pScripts->end(); ++it)
4177                {
4178                    (*it)->UpdateChunks();
4179                }
4180            }
4181        }
4182    
4183        /** @brief Get instrument script.
4184         *
4185         * Returns the real-time instrument script with the given index.
4186         *
4187         * @param index - number of the sought script (0..n)
4188         * @returns sought script or NULL if there's no such script
4189         */
4190        Script* ScriptGroup::GetScript(uint index) {
4191            if (!pScripts) LoadScripts();
4192            std::list<Script*>::iterator it = pScripts->begin();
4193            for (uint i = 0; it != pScripts->end(); ++i, ++it)
4194                if (i == index) return *it;
4195            return NULL;
4196        }
4197    
4198        /** @brief Add new instrument script.
4199         *
4200         * Adds a new real-time instrument script to the file. The script is not
4201         * actually used / executed unless it is referenced by an instrument to be
4202         * used. This is similar to samples, which you can add to a file, without
4203         * an instrument necessarily actually using it.
4204         *
4205         * You have to call Save() to make this persistent to the file.
4206         *
4207         * @return new empty script object
4208         */
4209        Script* ScriptGroup::AddScript() {
4210            if (!pScripts) LoadScripts();
4211            Script* pScript = new Script(this, NULL);
4212            pScripts->push_back(pScript);
4213            return pScript;
4214        }
4215    
4216        /** @brief Delete an instrument script.
4217         *
4218         * This will delete the given real-time instrument script. References of
4219         * instruments that are using that script will be removed accordingly.
4220         *
4221         * You have to call Save() to make this persistent to the file.
4222         *
4223         * @param pScript - script to delete
4224         * @throws gig::Exception if given script could not be found
4225         */
4226        void ScriptGroup::DeleteScript(Script* pScript) {
4227            if (!pScripts) LoadScripts();
4228            std::list<Script*>::iterator iter =
4229                find(pScripts->begin(), pScripts->end(), pScript);
4230            if (iter == pScripts->end())
4231                throw gig::Exception("Could not delete script, could not find given script");
4232            pScripts->erase(iter);
4233            pScript->RemoveAllScriptReferences();
4234            if (pScript->pChunk)
4235                pScript->pChunk->GetParent()->DeleteSubChunk(pScript->pChunk);
4236            delete pScript;
4237        }
4238    
4239        void ScriptGroup::LoadScripts() {
4240            if (pScripts) return;
4241            pScripts = new std::list<Script*>;
4242            if (!pList) return;
4243    
4244            for (RIFF::Chunk* ck = pList->GetFirstSubChunk(); ck;
4245                 ck = pList->GetNextSubChunk())
4246            {
4247                if (ck->GetChunkID() == CHUNK_ID_SCRI) {
4248                    pScripts->push_back(new Script(this, ck));
4249                }
4250            }
4251        }
4252    
4253  // *************** Instrument ***************  // *************** Instrument ***************
4254  // *  // *
4255    
# Line 4045  namespace { Line 4272  namespace {
4272          DimensionKeyRange.high = 0;          DimensionKeyRange.high = 0;
4273          pMidiRules = new MidiRule*[3];          pMidiRules = new MidiRule*[3];
4274          pMidiRules[0] = NULL;          pMidiRules[0] = NULL;
4275            pScriptRefs = NULL;
4276    
4277          // Loading          // Loading
4278          RIFF::List* lart = insList->GetSubList(LIST_TYPE_LART);          RIFF::List* lart = insList->GetSubList(LIST_TYPE_LART);
# Line 4105  namespace { Line 4333  namespace {
4333              }              }
4334          }          }
4335    
4336            // own gig format extensions
4337            RIFF::List* lst3LS = insList->GetSubList(LIST_TYPE_3LS);
4338            if (lst3LS) {
4339                RIFF::Chunk* ckSCSL = lst3LS->GetSubChunk(CHUNK_ID_SCSL);
4340                if (ckSCSL) {
4341                    int slotCount = ckSCSL->ReadUint32();
4342                    int slotSize  = ckSCSL->ReadUint32();
4343                    int unknownSpace = slotSize - 2*sizeof(uint32_t); // in case of future extensions
4344                    for (int i = 0; i < slotCount; ++i) {
4345                        _ScriptPooolEntry e;
4346                        e.fileOffset = ckSCSL->ReadUint32();
4347                        e.bypass     = ckSCSL->ReadUint32() & 1;
4348                        if (unknownSpace) ckSCSL->SetPos(unknownSpace, RIFF::stream_curpos); // in case of future extensions
4349                        scriptPoolFileOffsets.push_back(e);
4350                    }
4351                }
4352            }
4353    
4354          __notify_progress(pProgress, 1.0f); // notify done          __notify_progress(pProgress, 1.0f); // notify done
4355      }      }
4356    
# Line 4125  namespace { Line 4371  namespace {
4371              delete pMidiRules[i];              delete pMidiRules[i];
4372          }          }
4373          delete[] pMidiRules;          delete[] pMidiRules;
4374            if (pScriptRefs) delete pScriptRefs;
4375      }      }
4376    
4377      /**      /**
# Line 4180  namespace { Line 4427  namespace {
4427                  pMidiRules[i]->UpdateChunks(pData);                  pMidiRules[i]->UpdateChunks(pData);
4428              }              }
4429          }          }
4430    
4431            // own gig format extensions
4432           if (pScriptRefs) {
4433               RIFF::List* lst3LS = pCkInstrument->GetSubList(LIST_TYPE_3LS);
4434               if (!lst3LS) lst3LS = pCkInstrument->AddSubList(LIST_TYPE_3LS);
4435               const int totalSize = pScriptRefs->size() * 2*sizeof(uint32_t);
4436               RIFF::Chunk* ckSCSL = lst3LS->GetSubChunk(CHUNK_ID_SCSL);
4437               if (!ckSCSL) ckSCSL = lst3LS->AddSubChunk(CHUNK_ID_SCSL, totalSize);
4438               else ckSCSL->Resize(totalSize);
4439               uint8_t* pData = (uint8_t*) ckSCSL->LoadChunkData();
4440               for (int i = 0, pos = 0; i < pScriptRefs->size(); ++i) {
4441                   int fileOffset =
4442                        (*pScriptRefs)[i].script->pChunk->GetFilePos() -
4443                        (*pScriptRefs)[i].script->pChunk->GetPos() -
4444                        CHUNK_HEADER_SIZE;
4445                   store32(&pData[pos], fileOffset);
4446                   pos += sizeof(uint32_t);
4447                   store32(&pData[pos], (*pScriptRefs)[i].bypass ? 1 : 0);
4448                   pos += sizeof(uint32_t);
4449               }
4450           }
4451      }      }
4452    
4453      /**      /**
# Line 4311  namespace { Line 4579  namespace {
4579          pMidiRules[i] = 0;          pMidiRules[i] = 0;
4580      }      }
4581    
4582        void Instrument::LoadScripts() {
4583            if (pScriptRefs) return;
4584            pScriptRefs = new std::vector<_ScriptPooolRef>;
4585            if (scriptPoolFileOffsets.empty()) return;
4586            File* pFile = (File*) GetParent();
4587            for (uint k = 0; k < scriptPoolFileOffsets.size(); ++k) {
4588                uint32_t offset = scriptPoolFileOffsets[k].fileOffset;
4589                for (uint i = 0; pFile->GetScriptGroup(i); ++i) {
4590                    ScriptGroup* group = pFile->GetScriptGroup(i);
4591                    for (uint s = 0; group->GetScript(s); ++s) {
4592                        Script* script = group->GetScript(s);
4593                        if (script->pChunk) {
4594                            script->pChunk->SetPos(0);
4595                            if (script->pChunk->GetFilePos() -
4596                                script->pChunk->GetPos() -
4597                                CHUNK_HEADER_SIZE == offset)
4598                            {
4599                                _ScriptPooolRef ref;
4600                                ref.script = script;
4601                                ref.bypass = scriptPoolFileOffsets[k].bypass;
4602                                pScriptRefs->push_back(ref);
4603                                break;
4604                            }
4605                        }
4606                    }
4607                }
4608            }
4609            // we don't need that anymore
4610            scriptPoolFileOffsets.clear();
4611        }
4612    
4613        /** @brief Get instrument script (gig format extension).
4614         *
4615         * Returns the real-time instrument script of instrument script slot
4616         * @a index.
4617         *
4618         * @note This is an own format extension which did not exist i.e. in the
4619         * GigaStudio 4 software. It will currently only work with LinuxSampler and
4620         * gigedit.
4621         *
4622         * @param index - instrument script slot index
4623         * @returns script or NULL if index is out of bounds
4624         */
4625        Script* Instrument::GetScriptOfSlot(uint index) {
4626            LoadScripts();
4627            if (index >= pScriptRefs->size()) return NULL;
4628            return pScriptRefs->at(index).script;
4629        }
4630    
4631        /** @brief Add new instrument script slot (gig format extension).
4632         *
4633         * Add the given real-time instrument script reference to this instrument,
4634         * which shall be executed by the sampler for for this instrument. The
4635         * script will be added to the end of the script list of this instrument.
4636         * The positions of the scripts in the Instrument's Script list are
4637         * relevant, because they define in which order they shall be executed by
4638         * the sampler. For this reason it is also legal to add the same script
4639         * twice to an instrument, for example you might have a script called
4640         * "MyFilter" which performs an event filter task, and you might have
4641         * another script called "MyNoteTrigger" which triggers new notes, then you
4642         * might for example have the following list of scripts on the instrument:
4643         *
4644         * 1. Script "MyFilter"
4645         * 2. Script "MyNoteTrigger"
4646         * 3. Script "MyFilter"
4647         *
4648         * Which would make sense, because the 2nd script launched new events, which
4649         * you might need to filter as well.
4650         *
4651         * There are two ways to disable / "bypass" scripts. You can either disable
4652         * a script locally for the respective script slot on an instrument (i.e. by
4653         * passing @c false to the 2nd argument of this method, or by calling
4654         * SetScriptBypassed()). Or you can disable a script globally for all slots
4655         * and all instruments by setting Script::Bypass.
4656         *
4657         * @note This is an own format extension which did not exist i.e. in the
4658         * GigaStudio 4 software. It will currently only work with LinuxSampler and
4659         * gigedit.
4660         *
4661         * @param pScript - script that shall be executed for this instrument
4662         * @param bypass  - if enabled, the sampler shall skip executing this
4663         *                  script (in the respective list position)
4664         * @see SetScriptBypassed()
4665         */
4666        void Instrument::AddScriptSlot(Script* pScript, bool bypass) {
4667            LoadScripts();
4668            _ScriptPooolRef ref = { pScript, bypass };
4669            pScriptRefs->push_back(ref);
4670        }
4671    
4672        /** @brief Flip two script slots with each other (gig format extension).
4673         *
4674         * Swaps the position of the two given scripts in the Instrument's Script
4675         * list. The positions of the scripts in the Instrument's Script list are
4676         * relevant, because they define in which order they shall be executed by
4677         * the sampler.
4678         *
4679         * @note This is an own format extension which did not exist i.e. in the
4680         * GigaStudio 4 software. It will currently only work with LinuxSampler and
4681         * gigedit.
4682         *
4683         * @param index1 - index of the first script slot to swap
4684         * @param index2 - index of the second script slot to swap
4685         */
4686        void Instrument::SwapScriptSlots(uint index1, uint index2) {
4687            LoadScripts();
4688            if (index1 >= pScriptRefs->size() || index2 >= pScriptRefs->size())
4689                return;
4690            _ScriptPooolRef tmp = (*pScriptRefs)[index1];
4691            (*pScriptRefs)[index1] = (*pScriptRefs)[index2];
4692            (*pScriptRefs)[index2] = tmp;
4693        }
4694    
4695        /** @brief Remove script slot.
4696         *
4697         * Removes the script slot with the given slot index.
4698         *
4699         * @param index - index of script slot to remove
4700         */
4701        void Instrument::RemoveScriptSlot(uint index) {
4702            LoadScripts();
4703            if (index >= pScriptRefs->size()) return;
4704            pScriptRefs->erase( pScriptRefs->begin() + index );
4705        }
4706    
4707        /** @brief Remove reference to given Script (gig format extension).
4708         *
4709         * This will remove all script slots on the instrument which are referencing
4710         * the given script.
4711         *
4712         * @note This is an own format extension which did not exist i.e. in the
4713         * GigaStudio 4 software. It will currently only work with LinuxSampler and
4714         * gigedit.
4715         *
4716         * @param pScript - script reference to remove from this instrument
4717         * @see RemoveScriptSlot()
4718         */
4719        void Instrument::RemoveScript(Script* pScript) {
4720            LoadScripts();
4721            for (int i = pScriptRefs->size() - 1; i >= 0; --i) {
4722                if ((*pScriptRefs)[i].script == pScript) {
4723                    pScriptRefs->erase( pScriptRefs->begin() + i );
4724                }
4725            }
4726        }
4727    
4728        /** @brief Instrument's amount of script slots.
4729         *
4730         * This method returns the amount of script slots this instrument currently
4731         * uses.
4732         *
4733         * A script slot is a reference of a real-time instrument script to be
4734         * executed by the sampler. The scripts will be executed by the sampler in
4735         * sequence of the slots. One (same) script may be referenced multiple
4736         * times in different slots.
4737         *
4738         * @note This is an own format extension which did not exist i.e. in the
4739         * GigaStudio 4 software. It will currently only work with LinuxSampler and
4740         * gigedit.
4741         */
4742        uint Instrument::ScriptSlotCount() const {
4743            return pScriptRefs ? pScriptRefs->size() : scriptPoolFileOffsets.size();
4744        }
4745    
4746        /** @brief Whether script execution shall be skipped.
4747         *
4748         * Defines locally for the Script reference slot in the Instrument's Script
4749         * list, whether the script shall be skipped by the sampler regarding
4750         * execution.
4751         *
4752         * It is also possible to ignore exeuction of the script globally, for all
4753         * slots and for all instruments by setting Script::Bypass.
4754         *
4755         * @note This is an own format extension which did not exist i.e. in the
4756         * GigaStudio 4 software. It will currently only work with LinuxSampler and
4757         * gigedit.
4758         *
4759         * @param index - index of the script slot on this instrument
4760         * @see Script::Bypass
4761         */
4762        bool Instrument::IsScriptSlotBypassed(uint index) {
4763            if (index >= ScriptSlotCount()) return false;
4764            return pScriptRefs ? pScriptRefs->at(index).bypass
4765                               : scriptPoolFileOffsets.at(index).bypass;
4766            
4767        }
4768    
4769        /** @brief Defines whether execution shall be skipped.
4770         *
4771         * You can call this method to define locally whether or whether not the
4772         * given script slot shall be executed by the sampler.
4773         *
4774         * @note This is an own format extension which did not exist i.e. in the
4775         * GigaStudio 4 software. It will currently only work with LinuxSampler and
4776         * gigedit.
4777         *
4778         * @param index - script slot index on this instrument
4779         * @param bBypass - if true, the script slot will be skipped by the sampler
4780         * @see Script::Bypass
4781         */
4782        void Instrument::SetScriptSlotBypassed(uint index, bool bBypass) {
4783            if (index >= ScriptSlotCount()) return;
4784            if (pScriptRefs)
4785                pScriptRefs->at(index).bypass = bBypass;
4786            else
4787                scriptPoolFileOffsets.at(index).bypass = bBypass;
4788        }
4789    
4790      /**      /**
4791       * Make a (semi) deep copy of the Instrument object given by @a orig       * Make a (semi) deep copy of the Instrument object given by @a orig
4792       * and assign it to this object.       * and assign it to this object.
# Line 4344  namespace { Line 4820  namespace {
4820          PitchbendRange = orig->PitchbendRange;          PitchbendRange = orig->PitchbendRange;
4821          PianoReleaseMode = orig->PianoReleaseMode;          PianoReleaseMode = orig->PianoReleaseMode;
4822          DimensionKeyRange = orig->DimensionKeyRange;          DimensionKeyRange = orig->DimensionKeyRange;
4823            scriptPoolFileOffsets = orig->scriptPoolFileOffsets;
4824            pScriptRefs = orig->pScriptRefs;
4825                    
4826          // free old midi rules          // free old midi rules
4827          for (int i = 0 ; pMidiRules[i] ; i++) {          for (int i = 0 ; pMidiRules[i] ; i++) {
# Line 4529  namespace { Line 5007  namespace {
5007          bAutoLoad = true;          bAutoLoad = true;
5008          *pVersion = VERSION_3;          *pVersion = VERSION_3;
5009          pGroups = NULL;          pGroups = NULL;
5010            pScriptGroups = NULL;
5011          pInfo->SetFixedStringLengths(_FileFixedStringLengths);          pInfo->SetFixedStringLengths(_FileFixedStringLengths);
5012          pInfo->ArchivalLocation = String(256, ' ');          pInfo->ArchivalLocation = String(256, ' ');
5013    
# Line 4544  namespace { Line 5023  namespace {
5023      File::File(RIFF::File* pRIFF) : DLS::File(pRIFF) {      File::File(RIFF::File* pRIFF) : DLS::File(pRIFF) {
5024          bAutoLoad = true;          bAutoLoad = true;
5025          pGroups = NULL;          pGroups = NULL;
5026            pScriptGroups = NULL;
5027          pInfo->SetFixedStringLengths(_FileFixedStringLengths);          pInfo->SetFixedStringLengths(_FileFixedStringLengths);
5028      }      }
5029    
# Line 4557  namespace { Line 5037  namespace {
5037              }              }
5038              delete pGroups;              delete pGroups;
5039          }          }
5040            if (pScriptGroups) {
5041                std::list<ScriptGroup*>::iterator iter = pScriptGroups->begin();
5042                std::list<ScriptGroup*>::iterator end  = pScriptGroups->end();
5043                while (iter != end) {
5044                    delete *iter;
5045                    ++iter;
5046                }
5047                delete pScriptGroups;
5048            }
5049      }      }
5050    
5051      Sample* File::GetFirstSample(progress_t* pProgress) {      Sample* File::GetFirstSample(progress_t* pProgress) {
# Line 5069  namespace { Line 5558  namespace {
5558          }          }
5559      }      }
5560    
5561        /** @brief Get instrument script group (by index).
5562         *
5563         * Returns the real-time instrument script group with the given index.
5564         *
5565         * @param index - number of the sought group (0..n)
5566         * @returns sought script group or NULL if there's no such group
5567         */
5568        ScriptGroup* File::GetScriptGroup(uint index) {
5569            if (!pScriptGroups) LoadScriptGroups();
5570            std::list<ScriptGroup*>::iterator it = pScriptGroups->begin();
5571            for (uint i = 0; it != pScriptGroups->end(); ++i, ++it)
5572                if (i == index) return *it;
5573            return NULL;
5574        }
5575    
5576        /** @brief Get instrument script group (by name).
5577         *
5578         * Returns the first real-time instrument script group found with the given
5579         * group name. Note that group names may not necessarily be unique.
5580         *
5581         * @param name - name of the sought script group
5582         * @returns sought script group or NULL if there's no such group
5583         */
5584        ScriptGroup* File::GetScriptGroup(const String& name) {
5585            if (!pScriptGroups) LoadScriptGroups();
5586            std::list<ScriptGroup*>::iterator it = pScriptGroups->begin();
5587            for (uint i = 0; it != pScriptGroups->end(); ++i, ++it)
5588                if ((*it)->Name == name) return *it;
5589            return NULL;
5590        }
5591    
5592        /** @brief Add new instrument script group.
5593         *
5594         * Adds a new, empty real-time instrument script group to the file.
5595         *
5596         * You have to call Save() to make this persistent to the file.
5597         *
5598         * @return new empty script group
5599         */
5600        ScriptGroup* File::AddScriptGroup() {
5601            if (!pScriptGroups) LoadScriptGroups();
5602            ScriptGroup* pScriptGroup = new ScriptGroup(this, NULL);
5603            pScriptGroups->push_back(pScriptGroup);
5604            return pScriptGroup;
5605        }
5606    
5607        /** @brief Delete an instrument script group.
5608         *
5609         * This will delete the given real-time instrument script group and all its
5610         * instrument scripts it contains. References inside instruments that are
5611         * using the deleted scripts will be removed from the respective instruments
5612         * accordingly.
5613         *
5614         * You have to call Save() to make this persistent to the file.
5615         *
5616         * @param pScriptGroup - script group to delete
5617         * @throws gig::Exception if given script group could not be found
5618         */
5619        void File::DeleteScriptGroup(ScriptGroup* pScriptGroup) {
5620            if (!pScriptGroups) LoadScriptGroups();
5621            std::list<ScriptGroup*>::iterator iter =
5622                find(pScriptGroups->begin(), pScriptGroups->end(), pScriptGroup);
5623            if (iter == pScriptGroups->end())
5624                throw gig::Exception("Could not delete script group, could not find given script group");
5625            pScriptGroups->erase(iter);
5626            for (int i = 0; pScriptGroup->GetScript(i); ++i)
5627                pScriptGroup->DeleteScript(pScriptGroup->GetScript(i));
5628            if (pScriptGroup->pList)
5629                pScriptGroup->pList->GetParent()->DeleteSubChunk(pScriptGroup->pList);
5630            delete pScriptGroup;
5631        }
5632    
5633        void File::LoadScriptGroups() {
5634            if (pScriptGroups) return;
5635            pScriptGroups = new std::list<ScriptGroup*>;
5636            RIFF::List* lstLS = pRIFF->GetSubList(LIST_TYPE_3LS);
5637            if (lstLS) {
5638                for (RIFF::List* lst = lstLS->GetFirstSubList(); lst;
5639                     lst = lstLS->GetNextSubList())
5640                {
5641                    if (lst->GetListType() == LIST_TYPE_RTIS) {
5642                        pScriptGroups->push_back(new ScriptGroup(this, lst));
5643                    }
5644                }
5645            }
5646        }
5647    
5648      /**      /**
5649       * Apply all the gig file's current instruments, samples, groups and settings       * Apply all the gig file's current instruments, samples, groups and settings
5650       * to the respective RIFF chunks. You have to call Save() to make changes       * to the respective RIFF chunks. You have to call Save() to make changes
# Line 5084  namespace { Line 5660  namespace {
5660    
5661          b64BitWavePoolOffsets = pVersion && pVersion->major == 3;          b64BitWavePoolOffsets = pVersion && pVersion->major == 3;
5662    
5663            // update own gig format extension chunks
5664            // (not part of the GigaStudio 4 format)
5665            //
5666            // This must be performed before writing the chunks for instruments,
5667            // because the instruments' script slots will write the file offsets
5668            // of the respective instrument script chunk as reference.
5669            if (pScriptGroups) {
5670                RIFF::List* lst3LS = pRIFF->GetSubList(LIST_TYPE_3LS);
5671                if (pScriptGroups->empty()) {
5672                    if (lst3LS) pRIFF->DeleteSubChunk(lst3LS);
5673                } else {
5674                    if (!lst3LS) lst3LS = pRIFF->AddSubList(LIST_TYPE_3LS);
5675    
5676                    // Update instrument script (group) chunks.
5677    
5678                    for (std::list<ScriptGroup*>::iterator it = pScriptGroups->begin();
5679                         it != pScriptGroups->end(); ++it)
5680                    {
5681                        (*it)->UpdateChunks();
5682                    }
5683                }
5684            }
5685    
5686          // first update base class's chunks          // first update base class's chunks
5687          DLS::File::UpdateChunks();          DLS::File::UpdateChunks();
5688    

Legend:
Removed from v.2557  
changed lines
  Added in v.2593

  ViewVC Help
Powered by ViewVC