454 |
} |
} |
455 |
|
|
456 |
/** |
/** |
457 |
|
* Make a (semi) deep copy of the Sample object given by @a orig (without |
458 |
|
* the actual waveform data) and assign it to this object. |
459 |
|
* |
460 |
|
* Discussion: copying .gig samples is a bit tricky. It requires three |
461 |
|
* steps: |
462 |
|
* 1. Copy sample's meta informations (done by CopyAssignMeta()) including |
463 |
|
* its new sample waveform data size. |
464 |
|
* 2. Saving the file (done by File::Save()) so that it gains correct size |
465 |
|
* and layout for writing the actual wave form data directly to disc |
466 |
|
* in next step. |
467 |
|
* 3. Copy the waveform data with disk streaming (done by CopyAssignWave()). |
468 |
|
* |
469 |
|
* @param orig - original Sample object to be copied from |
470 |
|
*/ |
471 |
|
void Sample::CopyAssignMeta(const Sample* orig) { |
472 |
|
// handle base classes |
473 |
|
DLS::Sample::CopyAssignCore(orig); |
474 |
|
|
475 |
|
// handle actual own attributes of this class |
476 |
|
Manufacturer = orig->Manufacturer; |
477 |
|
Product = orig->Product; |
478 |
|
SamplePeriod = orig->SamplePeriod; |
479 |
|
MIDIUnityNote = orig->MIDIUnityNote; |
480 |
|
FineTune = orig->FineTune; |
481 |
|
SMPTEFormat = orig->SMPTEFormat; |
482 |
|
SMPTEOffset = orig->SMPTEOffset; |
483 |
|
Loops = orig->Loops; |
484 |
|
LoopID = orig->LoopID; |
485 |
|
LoopType = orig->LoopType; |
486 |
|
LoopStart = orig->LoopStart; |
487 |
|
LoopEnd = orig->LoopEnd; |
488 |
|
LoopSize = orig->LoopSize; |
489 |
|
LoopFraction = orig->LoopFraction; |
490 |
|
LoopPlayCount = orig->LoopPlayCount; |
491 |
|
|
492 |
|
// schedule resizing this sample to the given sample's size |
493 |
|
Resize(orig->GetSize()); |
494 |
|
} |
495 |
|
|
496 |
|
/** |
497 |
|
* Should be called after CopyAssignMeta() and File::Save() sequence. |
498 |
|
* Read more about it in the discussion of CopyAssignMeta(). This method |
499 |
|
* copies the actual waveform data by disk streaming. |
500 |
|
* |
501 |
|
* @e CAUTION: this method is currently not thread safe! During this |
502 |
|
* operation the sample must not be used for other purposes by other |
503 |
|
* threads! |
504 |
|
* |
505 |
|
* @param orig - original Sample object to be copied from |
506 |
|
*/ |
507 |
|
void Sample::CopyAssignWave(const Sample* orig) { |
508 |
|
const int iReadAtOnce = 32*1024; |
509 |
|
char* buf = new char[iReadAtOnce * orig->FrameSize]; |
510 |
|
Sample* pOrig = (Sample*) orig; //HACK: remove constness for now |
511 |
|
unsigned long restorePos = pOrig->GetPos(); |
512 |
|
pOrig->SetPos(0); |
513 |
|
SetPos(0); |
514 |
|
for (unsigned long n = pOrig->Read(buf, iReadAtOnce); n; |
515 |
|
n = pOrig->Read(buf, iReadAtOnce)) |
516 |
|
{ |
517 |
|
Write(buf, n); |
518 |
|
} |
519 |
|
pOrig->SetPos(restorePos); |
520 |
|
delete [] buf; |
521 |
|
} |
522 |
|
|
523 |
|
/** |
524 |
* Apply sample and its settings to the respective RIFF chunks. You have |
* Apply sample and its settings to the respective RIFF chunks. You have |
525 |
* to call File::Save() to make changes persistent. |
* to call File::Save() to make changes persistent. |
526 |
* |
* |
875 |
/** |
/** |
876 |
* Returns the current position in the sample (in sample points). |
* Returns the current position in the sample (in sample points). |
877 |
*/ |
*/ |
878 |
unsigned long Sample::GetPos() { |
unsigned long Sample::GetPos() const { |
879 |
if (Compressed) return SamplePos; |
if (Compressed) return SamplePos; |
880 |
else return pCkData->GetPos() / FrameSize; |
else return pCkData->GetPos() / FrameSize; |
881 |
} |
} |
1675 |
* @param orig - original DimensionRegion object to be copied from |
* @param orig - original DimensionRegion object to be copied from |
1676 |
*/ |
*/ |
1677 |
void DimensionRegion::CopyAssign(const DimensionRegion* orig) { |
void DimensionRegion::CopyAssign(const DimensionRegion* orig) { |
1678 |
|
CopyAssign(orig, NULL); |
1679 |
|
} |
1680 |
|
|
1681 |
|
/** |
1682 |
|
* Make a (semi) deep copy of the DimensionRegion object given by @a orig |
1683 |
|
* and assign it to this object. |
1684 |
|
* |
1685 |
|
* @param orig - original DimensionRegion object to be copied from |
1686 |
|
* @param mSamples - crosslink map between the foreign file's samples and |
1687 |
|
* this file's samples |
1688 |
|
*/ |
1689 |
|
void DimensionRegion::CopyAssign(const DimensionRegion* orig, const std::map<Sample*,Sample*>* mSamples) { |
1690 |
// delete all allocated data first |
// delete all allocated data first |
1691 |
if (VelocityTable) delete [] VelocityTable; |
if (VelocityTable) delete [] VelocityTable; |
1692 |
if (pSampleLoops) delete [] pSampleLoops; |
if (pSampleLoops) delete [] pSampleLoops; |
1694 |
// backup parent list pointer |
// backup parent list pointer |
1695 |
RIFF::List* p = pParentList; |
RIFF::List* p = pParentList; |
1696 |
|
|
1697 |
|
gig::Sample* pOriginalSample = pSample; |
1698 |
|
gig::Region* pOriginalRegion = pRegion; |
1699 |
|
|
1700 |
//NOTE: copy code copied from assignment constructor above, see comment there as well |
//NOTE: copy code copied from assignment constructor above, see comment there as well |
1701 |
|
|
1702 |
*this = *orig; // default memberwise shallow copy of all parameters |
*this = *orig; // default memberwise shallow copy of all parameters |
1703 |
pParentList = p; // restore the chunk pointer |
pParentList = p; // restore the chunk pointer |
1704 |
|
|
1705 |
|
// only take the raw sample reference & parent region reference if the |
1706 |
|
// two DimensionRegion objects are part of the same file |
1707 |
|
if (pOriginalRegion->GetParent()->GetParent() != orig->pRegion->GetParent()->GetParent()) { |
1708 |
|
pRegion = pOriginalRegion; |
1709 |
|
pSample = pOriginalSample; |
1710 |
|
} |
1711 |
|
|
1712 |
|
if (mSamples && mSamples->count(orig->pSample)) { |
1713 |
|
pSample = mSamples->find(orig->pSample)->second; |
1714 |
|
} |
1715 |
|
|
1716 |
// deep copy of owned structures |
// deep copy of owned structures |
1717 |
if (orig->VelocityTable) { |
if (orig->VelocityTable) { |
3065 |
* @param orig - original Region object to be copied from |
* @param orig - original Region object to be copied from |
3066 |
*/ |
*/ |
3067 |
void Region::CopyAssign(const Region* orig) { |
void Region::CopyAssign(const Region* orig) { |
3068 |
|
CopyAssign(orig, NULL); |
3069 |
|
} |
3070 |
|
|
3071 |
|
/** |
3072 |
|
* Make a (semi) deep copy of the Region object given by @a orig and |
3073 |
|
* assign it to this object |
3074 |
|
* |
3075 |
|
* @param mSamples - crosslink map between the foreign file's samples and |
3076 |
|
* this file's samples |
3077 |
|
*/ |
3078 |
|
void Region::CopyAssign(const Region* orig, const std::map<Sample*,Sample*>* mSamples) { |
3079 |
// handle base classes |
// handle base classes |
3080 |
DLS::Region::CopyAssign(orig); |
DLS::Region::CopyAssign(orig); |
3081 |
|
|
3082 |
|
if (mSamples && mSamples->count((gig::Sample*)orig->pSample)) { |
3083 |
|
pSample = mSamples->find((gig::Sample*)orig->pSample)->second; |
3084 |
|
} |
3085 |
|
|
3086 |
// handle own member variables |
// handle own member variables |
3087 |
for (int i = Dimensions - 1; i >= 0; --i) { |
for (int i = Dimensions - 1; i >= 0; --i) { |
3088 |
DeleteDimension(&pDimensionDefinitions[i]); |
DeleteDimension(&pDimensionDefinitions[i]); |
3097 |
for (int i = 0; i < 256; i++) { |
for (int i = 0; i < 256; i++) { |
3098 |
if (pDimensionRegions[i] && orig->pDimensionRegions[i]) { |
if (pDimensionRegions[i] && orig->pDimensionRegions[i]) { |
3099 |
pDimensionRegions[i]->CopyAssign( |
pDimensionRegions[i]->CopyAssign( |
3100 |
orig->pDimensionRegions[i] |
orig->pDimensionRegions[i], |
3101 |
|
mSamples |
3102 |
); |
); |
3103 |
} |
} |
3104 |
} |
} |
3570 |
* @param orig - original Instrument object to be copied from |
* @param orig - original Instrument object to be copied from |
3571 |
*/ |
*/ |
3572 |
void Instrument::CopyAssign(const Instrument* orig) { |
void Instrument::CopyAssign(const Instrument* orig) { |
3573 |
|
CopyAssign(orig, NULL); |
3574 |
|
} |
3575 |
|
|
3576 |
|
/** |
3577 |
|
* Make a (semi) deep copy of the Instrument object given by @a orig |
3578 |
|
* and assign it to this object. |
3579 |
|
* |
3580 |
|
* @param orig - original Instrument object to be copied from |
3581 |
|
* @param mSamples - crosslink map between the foreign file's samples and |
3582 |
|
* this file's samples |
3583 |
|
*/ |
3584 |
|
void Instrument::CopyAssign(const Instrument* orig, const std::map<Sample*,Sample*>* mSamples) { |
3585 |
// handle base class |
// handle base class |
3586 |
// (without copying DLS region stuff) |
// (without copying DLS region stuff) |
3587 |
DLS::Instrument::CopyAssignCore(orig); |
DLS::Instrument::CopyAssignCore(orig); |
3610 |
Region* dstRgn = AddRegion(); |
Region* dstRgn = AddRegion(); |
3611 |
//NOTE: Region does semi-deep copy ! |
//NOTE: Region does semi-deep copy ! |
3612 |
dstRgn->CopyAssign( |
dstRgn->CopyAssign( |
3613 |
static_cast<gig::Region*>(*it) |
static_cast<gig::Region*>(*it), |
3614 |
|
mSamples |
3615 |
); |
); |
3616 |
} |
} |
3617 |
} |
} |
3820 |
SamplesIterator++; |
SamplesIterator++; |
3821 |
return static_cast<gig::Sample*>( (SamplesIterator != pSamples->end()) ? *SamplesIterator : NULL ); |
return static_cast<gig::Sample*>( (SamplesIterator != pSamples->end()) ? *SamplesIterator : NULL ); |
3822 |
} |
} |
3823 |
|
|
3824 |
|
/** |
3825 |
|
* Returns Sample object of @a index. |
3826 |
|
* |
3827 |
|
* @returns sample object or NULL if index is out of bounds |
3828 |
|
*/ |
3829 |
|
Sample* File::GetSample(uint index) { |
3830 |
|
if (!pSamples) LoadSamples(); |
3831 |
|
if (!pSamples) return NULL; |
3832 |
|
DLS::File::SampleList::iterator it = pSamples->begin(); |
3833 |
|
for (int i = 0; i < index; ++i) { |
3834 |
|
++it; |
3835 |
|
if (it == pSamples->end()) return NULL; |
3836 |
|
} |
3837 |
|
if (it == pSamples->end()) return NULL; |
3838 |
|
return static_cast<gig::Sample*>( *it ); |
3839 |
|
} |
3840 |
|
|
3841 |
/** @brief Add a new sample. |
/** @brief Add a new sample. |
3842 |
* |
* |
4055 |
instr->CopyAssign(orig); |
instr->CopyAssign(orig); |
4056 |
return instr; |
return instr; |
4057 |
} |
} |
4058 |
|
|
4059 |
|
/** @brief Add content of another existing file. |
4060 |
|
* |
4061 |
|
* Duplicates the samples, groups and instruments of the original file |
4062 |
|
* given by @a pFile and adds them to @c this File. In case @c this File is |
4063 |
|
* a new one that you haven't saved before, then you have to call |
4064 |
|
* SetFileName() before calling AddContentOf(), because this method will |
4065 |
|
* automatically save this file during operation, which is required for |
4066 |
|
* writing the sample waveform data by disk streaming. |
4067 |
|
* |
4068 |
|
* @param pFile - original file whose's content shall be copied from |
4069 |
|
*/ |
4070 |
|
void File::AddContentOf(File* pFile) { |
4071 |
|
static int iCallCount = -1; |
4072 |
|
iCallCount++; |
4073 |
|
std::map<Group*,Group*> mGroups; |
4074 |
|
std::map<Sample*,Sample*> mSamples; |
4075 |
|
|
4076 |
|
// clone sample groups |
4077 |
|
for (int i = 0; pFile->GetGroup(i); ++i) { |
4078 |
|
Group* g = AddGroup(); |
4079 |
|
g->Name = |
4080 |
|
"COPY" + ToString(iCallCount) + "_" + pFile->GetGroup(i)->Name; |
4081 |
|
mGroups[pFile->GetGroup(i)] = g; |
4082 |
|
} |
4083 |
|
|
4084 |
|
// clone samples (not waveform data here yet) |
4085 |
|
for (int i = 0; pFile->GetSample(i); ++i) { |
4086 |
|
Sample* s = AddSample(); |
4087 |
|
s->CopyAssignMeta(pFile->GetSample(i)); |
4088 |
|
mGroups[pFile->GetSample(i)->GetGroup()]->AddSample(s); |
4089 |
|
mSamples[pFile->GetSample(i)] = s; |
4090 |
|
} |
4091 |
|
|
4092 |
|
//BUG: For some reason this method only works with this additional |
4093 |
|
// Save() call in between here. |
4094 |
|
// |
4095 |
|
// Important: The correct one of the 2 Save() methods has to be called |
4096 |
|
// here, depending on whether the file is completely new or has been |
4097 |
|
// saved to disk already, otherwise it will result in data corruption. |
4098 |
|
if (pRIFF->IsNew()) |
4099 |
|
Save(GetFileName()); |
4100 |
|
else |
4101 |
|
Save(); |
4102 |
|
|
4103 |
|
// clone instruments |
4104 |
|
// (passing the crosslink table here for the cloned samples) |
4105 |
|
for (int i = 0; pFile->GetInstrument(i); ++i) { |
4106 |
|
Instrument* instr = AddInstrument(); |
4107 |
|
instr->CopyAssign(pFile->GetInstrument(i), &mSamples); |
4108 |
|
} |
4109 |
|
|
4110 |
|
// Mandatory: file needs to be saved to disk at this point, so this |
4111 |
|
// file has the correct size and data layout for writing the samples' |
4112 |
|
// waveform data to disk. |
4113 |
|
Save(); |
4114 |
|
|
4115 |
|
// clone samples' waveform data |
4116 |
|
// (using direct read & write disk streaming) |
4117 |
|
for (int i = 0; pFile->GetSample(i); ++i) { |
4118 |
|
mSamples[pFile->GetSample(i)]->CopyAssignWave(pFile->GetSample(i)); |
4119 |
|
} |
4120 |
|
} |
4121 |
|
|
4122 |
/** @brief Delete an instrument. |
/** @brief Delete an instrument. |
4123 |
* |
* |