void VGMColl::UnpackSampColl(DLSFile& dls, VGMSampColl* sampColl, vector<VGMSamp*>& finalSamps) { assert(sampColl != NULL); size_t nSamples = sampColl->samples.size(); for (size_t i=0; i<nSamples; i++) { VGMSamp* samp = sampColl->samples[i]; uint32_t bufSize; if (samp->ulUncompressedSize) bufSize = samp->ulUncompressedSize; else bufSize = (uint32_t)ceil((double)samp->dataLength * samp->GetCompressionRatio()); //bool bOddBufSize = bufSize % 2; //if (bOddBufSize) //if the buffer size is odd, we must align it to be even for the RIFF format // bufSize++; uint8_t* uncompSampBuf = new uint8_t[bufSize]; //create a new memory space for the uncompressed wave samp->ConvertToStdWave(uncompSampBuf); //and uncompress into that space //if (bOddBufSize) // uncompSampBuf[bufSize] = 0; //set the last (should be unused) byte to 0; uint16_t blockAlign = samp->bps / 8*samp->channels; dls.AddWave(1, samp->channels, samp->rate, samp->rate*blockAlign, blockAlign, samp->bps, bufSize, uncompSampBuf, wstring2string(samp->name)); finalSamps.push_back(samp); } }
bool VGMColl::OnSaveAllDLS() { wstring dirpath = pRoot->UI_GetSaveDirPath(); if (dirpath.length() != 0) { DLSFile dlsfile; wstring filepath = dirpath + L"\\" + ConvertToSafeFileName(this->name) + L".dls"; if (CreateDLSFile(dlsfile)) { if (!dlsfile.SaveDLSFile(filepath)) pRoot->AddLogItem(new LogItem(std::wstring(L"Failed to save DLS file"), LOG_LEVEL_ERR, L"VGMColl")); } else pRoot->AddLogItem(new LogItem(std::wstring(L"Failed to save DLS file"), LOG_LEVEL_ERR, L"VGMColl")); if (this->seq != nullptr) { filepath = dirpath + L"\\" + ConvertToSafeFileName(this->name) + L".mid"; if (!this->seq->SaveAsMidi(filepath)) pRoot->AddLogItem(new LogItem(std::wstring(L"Failed to save MIDI file"), LOG_LEVEL_ERR, L"VGMColl")); } } return true; }
bool VGMColl::OnSaveAllDLS() { wstring dirpath = pRoot->UI_GetSaveDirPath(); if (dirpath.length() != 0) { DLSFile dlsfile; wstring filepath = dirpath + L"\\" + ConvertToSafeFileName(this->name) + L".dls"; if (CreateDLSFile(dlsfile)) { if (!dlsfile.SaveDLSFile(filepath)) Alert(L"Failed to save DLS file."); } else Alert(L"Failed to save DLS file."); filepath = dirpath + L"\\" + ConvertToSafeFileName(this->name) + L".mid"; if (!this->seq->SaveAsMidi(filepath)) Alert(L"Failed to save MIDI file."); } return true; }
void VGMColl::UnpackSampColl(DLSFile &dls, VGMSampColl *sampColl, vector<VGMSamp *> &finalSamps) { assert(sampColl != NULL); size_t nSamples = sampColl->samples.size(); for (size_t i = 0; i < nSamples; i++) { VGMSamp *samp = sampColl->samples[i]; uint32_t bufSize; if (samp->ulUncompressedSize) bufSize = samp->ulUncompressedSize; else bufSize = (uint32_t) ceil((double) samp->dataLength * samp->GetCompressionRatio()); uint8_t *uncompSampBuf = new uint8_t[bufSize]; //create a new memory space for the uncompressed wave samp->ConvertToStdWave(uncompSampBuf); //and uncompress into that space uint16_t blockAlign = samp->bps / 8 * samp->channels; dls.AddWave(1, samp->channels, samp->rate, samp->rate * blockAlign, blockAlign, samp->bps, bufSize, uncompSampBuf, wstring2string(samp->name)); finalSamps.push_back(samp); } }
bool VGMColl::MainDLSCreation(DLSFile &dls) { vector<VGMSamp *> finalSamps; //we have to collect the finalSampColls in case sampcolls is empty but there are multiple instrSets with //embedded sampcolls vector<VGMSampColl *> finalSampColls; if (!instrsets.size() /*|| !sampcolls.size()*/) return false; // if there are independent SampColl(s) in the collection if (sampcolls.size()) { for (uint32_t sam = 0; sam < sampcolls.size(); sam++) { finalSampColls.push_back(sampcolls[sam]); UnpackSampColl(dls, sampcolls[sam], finalSamps); } } // otherwise, the SampColl(s) are children of the InstrSet(s) else { for (uint32_t i = 0; i < instrsets.size(); i++) { finalSampColls.push_back(instrsets[i]->sampColl); UnpackSampColl(dls, instrsets[i]->sampColl, finalSamps); } } if (finalSamps.size() == 0) return false; for (size_t inst = 0; inst < instrsets.size(); inst++) { VGMInstrSet *set = instrsets[inst]; size_t nInstrs = set->aInstrs.size(); for (size_t i = 0; i < nInstrs; i++) { VGMInstr *vgminstr = set->aInstrs[i]; size_t nRgns = vgminstr->aRgns.size(); std::string name = wstring2string(vgminstr->name); DLSInstr *newInstr = dls.AddInstr(vgminstr->bank, vgminstr->instrNum, name); for (uint32_t j = 0; j < nRgns; j++) { VGMRgn *rgn = vgminstr->aRgns[j]; // if (rgn->sampNum+1 > sampColl->samples.size()) //does thereferenced sample exist? // continue; // Determine the SampColl associated with this rgn. If there's an explicit pointer to it, use that. VGMSampColl *sampColl = rgn->sampCollPtr; if (!sampColl) { // If rgn is of an InstrSet with an embedded SampColl, use that SampColl. if (((VGMInstrSet *) rgn->vgmfile)->sampColl) sampColl = ((VGMInstrSet *) rgn->vgmfile)->sampColl; // If that does not exist, assume the first SampColl else sampColl = finalSampColls[0]; } // Determine the sample number within the rgn's associated SampColl size_t realSampNum; // If a sample offset is provided, then find the sample number based on this offset. // see sampOffset declaration in header file for more info. if (rgn->sampOffset != -1) { bool bFoundIt = false; for (uint32_t s = 0; s < sampColl->samples.size(); s++) { //for every sample if (rgn->sampOffset == sampColl->samples[s]->dwOffset - sampColl->dwOffset - sampColl->sampDataOffset) { realSampNum = s; //samples[m]->loop.loopStart = parInstrSet->aInstrs[i]->aRgns[k]->loop.loopStart; //samples[m]->loop.loopLength = (samples[m]->dataLength) - (parInstrSet->aInstrs[i]->aRgns[k]->loop.loopStart); //[aInstrs[i]->aRegions[k]->sample_num]->dwUncompSize/2) - ((aInstrs[i]->aRegions[k]->loop_point*28)/16); //to end of sample bFoundIt = true; break; } } if (!bFoundIt) { std::wstring message = FormatString<wstring>(L"Could not match rgn with sampOffset %X to a sample with that offset.\n (InstrSet %d, Instr %d, Rgn %d)", rgn->sampOffset, inst, i, j); pRoot->AddLogItem(new LogItem(std::wstring(message.c_str()), LOG_LEVEL_ERR, L"VGMColl")); realSampNum = 0; } } // Otherwise, the sample number should be explicitly defined in the rgn. else realSampNum = rgn->sampNum; // Determine the sampCollNum (index into our finalSampColls vector) unsigned int sampCollNum; for (unsigned int k = 0; k < finalSampColls.size(); k++) { if (finalSampColls[k] == sampColl) sampCollNum = k; } // now we add the number of samples from the preceding SampColls to the value to get the real sampNum // in the final DLS file. for (unsigned int k = 0; k < sampCollNum; k++) realSampNum += finalSampColls[k]->samples.size(); // For collections with multiple SampColls // If a SampColl ptr is given, find the SampColl and adjust the sample number of the region // to compensate for all preceding SampColl samples. //if (rgn->sampCollNum == -1) //if a sampCollPtr is defined //{ // // find the sampColl's index in samplecolls (the sampCollNum, effectively) // for (uint32_t i=0; i < finalSampColls.size(); i++) // { // if (finalSampColls[i] == sampColl) // rgn->sampCollNum = i; // } //} //if (rgn->sampCollNum != -1) //if a sampCollNum is defined //{ //then sampNum represents the sample number in the specific sample collection // for (int k=0; k < rgn->sampCollNum; k++) // realSampNum += finalSampColls[k]->samples.size(); //so now we add all previous sample collection samples to the value to get the real (absolute) sampNum //} DLSRgn *newRgn = newInstr->AddRgn(); newRgn->SetRanges(rgn->keyLow, rgn->keyHigh, rgn->velLow, rgn->velHigh); newRgn->SetWaveLinkInfo(0, 0, 1, (uint32_t) realSampNum); if (realSampNum >= finalSamps.size()) { wchar_t log[256]; swprintf(log, 256, L"Sample %u does not exist.", realSampNum); pRoot->AddLogItem(new LogItem(log, LOG_LEVEL_ERR, L"VGMColl")); realSampNum = finalSamps.size() - 1; } VGMSamp *samp = finalSamps[realSampNum];//sampColl->samples[rgn->sampNum]; DLSWsmp *newWsmp = newRgn->AddWsmp(); // This is a really loopy way of determining the loop information, pardon the pun. However, it works. // There might be a way to simplify this, but I don't want to test out whether another method breaks anything just yet // Use the sample's loopStatus to determine if a loop occurs. If it does, see if the sample provides loop info // (gathered during ADPCM > PCM conversion. If the sample doesn't provide loop offset info, then use the region's // loop info. if (samp->bPSXLoopInfoPrioritizing) { if (samp->loop.loopStatus != -1) { if (samp->loop.loopStart != 0 || samp->loop.loopLength != 0) newWsmp->SetLoopInfo(samp->loop, samp); else { rgn->loop.loopStatus = samp->loop.loopStatus; newWsmp->SetLoopInfo(rgn->loop, samp); } } else throw; } // The normal method: First, we check if the rgn has loop info defined. // If it doesn't, then use the sample's loop info. else if (rgn->loop.loopStatus == -1) { if (samp->loop.loopStatus != -1) newWsmp->SetLoopInfo(samp->loop, samp); else throw; } else newWsmp->SetLoopInfo(rgn->loop, samp); uint8_t realUnityKey; if (rgn->unityKey == -1) realUnityKey = samp->unityKey; else realUnityKey = rgn->unityKey; if (realUnityKey == -1) realUnityKey = 0x3C; short realFineTune; if (rgn->fineTune == 0) realFineTune = samp->fineTune; else realFineTune = rgn->fineTune; long realAttenuation; if (rgn->volume == -1 && samp->volume == -1) realAttenuation = 0; else if (rgn->volume == -1) realAttenuation = (long) (-(ConvertLogScaleValToAtten(samp->volume) * DLS_DECIBEL_UNIT * 10)); else realAttenuation = (long) (-(ConvertLogScaleValToAtten(rgn->volume) * DLS_DECIBEL_UNIT * 10)); long convAttack = (long) roundi(SecondsToTimecents(rgn->attack_time) * 65536); long convDecay = (long) roundi(SecondsToTimecents(rgn->decay_time) * 65536); long convSustainLev; if (rgn->sustain_level == -1) convSustainLev = 0x03e80000; //sustain at full if no sustain level provided else { //the DLS envelope is a range from 0 to -96db. double attenInDB = ConvertLogScaleValToAtten(rgn->sustain_level); convSustainLev = (long) (((96.0 - attenInDB) / 96.0) * 0x03e80000); } long convRelease = (long) roundi(SecondsToTimecents(rgn->release_time) * 65536); DLSArt *newArt = newRgn->AddArt(); newArt->AddPan(ConvertPercentPanTo10thPercentUnits(rgn->pan) * 65536); newArt->AddADSR(convAttack, 0, convDecay, convSustainLev, convRelease, 0); newWsmp->SetPitchInfo(realUnityKey, realFineTune, realAttenuation); } } } return true; }