Example #1
0
void VGMColl::UnpackSampColl(SynthFile& synthfile, 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;
		SynthWave* wave = synthfile.AddWave(1, samp->channels, samp->rate, samp->rate*blockAlign, blockAlign,
			samp->bps, bufSize, uncompSampBuf, wstring2string(samp->name));
		finalSamps.push_back(samp);

		// If we don't have any loop information, then don't create a sampInfo structure for the Wave
		if (samp->loop.loopStatus == -1)
			return;

		SynthSampInfo* sampInfo = wave->AddSampInfo();
		if (samp->bPSXLoopInfoPrioritizing)
		{
			if (samp->loop.loopStart != 0 || samp->loop.loopLength != 0)
				sampInfo->SetLoopInfo(samp->loop, samp);
		}
		else
			sampInfo->SetLoopInfo(samp->loop, samp);

		double attenuation = (samp->volume != -1) ? ConvertLogScaleValToAtten(samp->volume) : 0;
		uint8_t unityKey = (samp->unityKey != -1) ? samp->unityKey : 0x3C;
		short fineTune = samp->fineTune;
		sampInfo->SetPitchInfo(unityKey, fineTune, attenuation);
	}
}
Example #2
0
SynthFile *VGMColl::CreateSynthFile() {
  SynthFile *synthfile = new SynthFile("SynthFile"/**this->instrsets[0]->GetName()*/);


  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()*/) {
    delete synthfile;
    return NULL;
  }

  // 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(*synthfile, 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(*synthfile, instrsets[i]->sampColl, finalSamps);
    }
  }

  if (finalSamps.size() == 0) {
    delete synthfile;
    return NULL;
  }


  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();
      if (nRgns == 0)                                //do not write an instrument if it has no regions
        continue;
      SynthInstr *newInstr = synthfile->AddInstr(vgminstr->bank, vgminstr->instrNum);
      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 = finalSampColls.size();
        for (uint32_t i = 0; i < finalSampColls.size(); i++) {
          if (finalSampColls[i] == sampColl)
            sampCollNum = i;
        }
        if (sampCollNum == finalSampColls.size()) {
          pRoot->AddLogItem(new LogItem(L"SampColl does not exist.", LOG_LEVEL_ERR, L"VGMColl"));
          return NULL;
        }
        //   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 (uint32_t k = 0; k < sampCollNum; k++)
          realSampNum += finalSampColls[k]->samples.size();

        SynthRgn *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];
        SynthSampInfo *sampInfo = newRgn->AddSampInfo();

        // 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)
              sampInfo->SetLoopInfo(samp->loop, samp);
            else {
              rgn->loop.loopStatus = samp->loop.loopStatus;
              sampInfo->SetLoopInfo(rgn->loop, samp);
            }
          }
          else {
            delete synthfile;
            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)
            sampInfo->SetLoopInfo(samp->loop, samp);
          else {
            delete synthfile;
            throw;
          }
        }
        else
          sampInfo->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;

        double attenuation;
        if (rgn->volume != -1)
          attenuation = ConvertLogScaleValToAtten(rgn->volume);
        else if (samp->volume != -1)
          attenuation = ConvertLogScaleValToAtten(samp->volume);
        else
          attenuation = 0;

        double sustainLevAttenDb;
        if (rgn->sustain_level == -1)
          sustainLevAttenDb = 0.0;
        else
          sustainLevAttenDb = ConvertPercentAmplitudeToAttenDB_SF2(rgn->sustain_level);

        SynthArt *newArt = newRgn->AddArt();
        newArt->AddPan(rgn->pan);
        newArt->AddADSR(rgn->attack_time, (Transform) rgn->attack_transform, rgn->decay_time,
                        sustainLevAttenDb, rgn->sustain_time, rgn->release_time, (Transform) rgn->release_transform);

        sampInfo->SetPitchInfo(realUnityKey, realFineTune, attenuation);
      }
    }
  }
  return synthfile;
}