SF2InfoListChunk::SF2InfoListChunk(string name) : LISTChunk("INFO") { // Create a date string time_t current_time = time(NULL); char* c_time_string = ctime(¤t_time); // Add the child info chunks Chunk* ifilCk = new Chunk("ifil"); sfVersionTag versionTag; //soundfont version 2.01 versionTag.wMajor = 2; versionTag.wMinor = 1; ifilCk->SetData(&versionTag, sizeof(versionTag)); AddChildChunk(ifilCk); AddChildChunk(new SF2StringChunk("isng", "EMU8000")); AddChildChunk(new SF2StringChunk("INAM", name)); AddChildChunk(new SF2StringChunk("ICRD", string(c_time_string))); AddChildChunk(new SF2StringChunk("ISFT", string("VGMTrans " + string(VERSION)) )); }
SF2File::SF2File(SynthFile* synthfile) : RiffFile(synthfile->name, "sfbk") { // convert wstring to stringstream //char* c_name = new char[name.length()+1]; //wcstombs(c_name, name.c_str(), name.length()+1); //stringstream mbs_name; //mbs_name << c_name; //delete c_name; //*********** // INFO chunk //*********** AddChildChunk(new SF2InfoListChunk(name)); // sdta chunk and its child smpl chunk containing all samples LISTChunk* sdtaCk = new LISTChunk("sdta"); Chunk* smplCk = new Chunk("smpl"); // Concatanate all of the samples together and add the result to the smpl chunk data size_t numWaves = synthfile->vWaves.size(); smplCk->size = 0; for (size_t i = 0; i < numWaves; i++) { SynthWave* wave = synthfile->vWaves[i]; wave->ConvertTo16bitSigned(); smplCk->size += wave->dataSize + (46*2); // plus the 46 padding samples required by sf2 spec } smplCk->data = new uint8_t[smplCk->size]; uint32_t bufPtr = 0; for (size_t i = 0; i < numWaves; i++) { SynthWave* wave = synthfile->vWaves[i]; memcpy(smplCk->data + bufPtr, wave->data, wave->dataSize); memset(smplCk->data + bufPtr + wave->dataSize, 0, 46*2); bufPtr += wave->dataSize + (46*2); // plus the 46 padding samples required by sf2 spec } sdtaCk->AddChildChunk(smplCk); this->AddChildChunk(sdtaCk); //*********** // pdta chunk //*********** LISTChunk* pdtaCk = new LISTChunk("pdta"); //*********** // phdr chunk //*********** Chunk* phdrCk = new Chunk("phdr"); size_t numInstrs = synthfile->vInstrs.size(); phdrCk->size = (uint32_t)((numInstrs+1) * sizeof(sfPresetHeader)); phdrCk->data = new uint8_t[phdrCk->size]; for (size_t i = 0; i < numInstrs; i++) { SynthInstr* instr = synthfile->vInstrs[i]; sfPresetHeader presetHdr; memset(&presetHdr, 0, sizeof(sfPresetHeader)); memcpy(presetHdr.achPresetName, instr->name.c_str(), min((unsigned long)instr->name.length(), (unsigned long)20)); presetHdr.wPreset = (uint16_t)instr->ulInstrument; presetHdr.wBank = (uint16_t)instr->ulBank; presetHdr.wPresetBagNdx = (uint16_t)i; presetHdr.dwLibrary = 0; presetHdr.dwGenre = 0; presetHdr.dwMorphology = 0; memcpy(phdrCk->data + (i*sizeof(sfPresetHeader)), &presetHdr, sizeof(sfPresetHeader)); } // add terminal sfPresetBag sfPresetHeader presetHdr; memset(&presetHdr, 0, sizeof(sfPresetHeader)); presetHdr.wPresetBagNdx = (uint16_t)numInstrs; memcpy(phdrCk->data + (numInstrs*sizeof(sfPresetHeader)), &presetHdr, sizeof(sfPresetHeader)); pdtaCk->AddChildChunk(phdrCk); //*********** // pbag chunk //*********** Chunk* pbagCk = new Chunk("pbag"); const size_t ITEMS_IN_PGEN = 2; pbagCk->size = (uint32_t)((numInstrs+1) * sizeof(sfPresetBag)); pbagCk->data = new uint8_t[pbagCk->size]; for (size_t i = 0; i < numInstrs; i++) { SynthInstr* instr = synthfile->vInstrs[i]; sfPresetBag presetBag; memset(&presetBag, 0, sizeof(sfPresetBag)); presetBag.wGenNdx = (uint16_t)(i*ITEMS_IN_PGEN); presetBag.wModNdx = 0; memcpy(pbagCk->data + (i*sizeof(sfPresetBag)), &presetBag, sizeof(sfPresetBag)); } // add terminal sfPresetBag sfPresetBag presetBag; memset(&presetBag, 0, sizeof(sfPresetBag)); presetBag.wGenNdx = (uint16_t)(numInstrs * ITEMS_IN_PGEN); memcpy(pbagCk->data + (numInstrs*sizeof(sfPresetBag)), &presetBag, sizeof(sfPresetBag)); pdtaCk->AddChildChunk(pbagCk); //*********** // pmod chunk //*********** Chunk* pmodCk = new Chunk("pmod"); // create the terminal field sfModList modList; memset(&modList, 0, sizeof(sfModList)); pmodCk->SetData(&modList, sizeof(sfModList)); //modList.sfModSrcOper = cc1_Mod; //modList.sfModDestOper = startAddrsOffset; //modList.modAmount = 0; //modList.sfModAmtSrcOper = cc1_Mod; //modList.sfModTransOper = linear; pdtaCk->AddChildChunk(pmodCk); //*********** // pgen chunk //*********** Chunk* pgenCk = new Chunk("pgen"); //pgenCk->size = (synthfile->vInstrs.size()+1) * sizeof(sfGenList); pgenCk->size = (uint32_t)((synthfile->vInstrs.size() * sizeof(sfGenList) * ITEMS_IN_PGEN) + sizeof(sfGenList)); pgenCk->data = new uint8_t[pgenCk->size]; uint32_t dataPtr = 0; for (size_t i = 0; i < numInstrs; i++) { SynthInstr* instr = synthfile->vInstrs[i]; sfGenList genList; memset(&genList, 0, sizeof(sfGenList)); // reverbEffectsSend genList.sfGenOper = reverbEffectsSend; genList.genAmount.shAmount= 700; memcpy(pgenCk->data + dataPtr, &genList, sizeof(sfGenList)); dataPtr += sizeof(sfGenList); genList.sfGenOper = instrument; genList.genAmount.wAmount = (uint16_t)i; memcpy(pgenCk->data + dataPtr, &genList, sizeof(sfGenList)); dataPtr += sizeof(sfGenList); } // add terminal sfGenList sfGenList genList; memset(&genList, 0, sizeof(sfGenList)); memcpy(pgenCk->data + dataPtr, &genList, sizeof(sfGenList)); pdtaCk->AddChildChunk(pgenCk); //*********** // inst chunk //*********** Chunk* instCk = new Chunk("inst"); instCk->size = (uint32_t)((synthfile->vInstrs.size()+1) * sizeof(sfInst)); instCk->data = new uint8_t[instCk->size]; size_t rgnCounter = 0; for (size_t i = 0; i < numInstrs; i++) { SynthInstr* instr = synthfile->vInstrs[i]; sfInst inst; memset(&inst, 0, sizeof(sfInst)); memcpy(inst.achInstName, instr->name.c_str(), min((unsigned long)instr->name.length(), (unsigned long)20)); inst.wInstBagNdx = (uint16_t)rgnCounter; rgnCounter += instr->vRgns.size(); memcpy(instCk->data + (i*sizeof(sfInst)), &inst, sizeof(sfInst)); } // add terminal sfInst sfInst inst; memset(&inst, 0, sizeof(sfInst)); inst.wInstBagNdx = (uint16_t)rgnCounter; memcpy(instCk->data + (numInstrs*sizeof(sfInst)), &inst, sizeof(sfInst)); pdtaCk->AddChildChunk(instCk); //*********** // ibag chunk - stores all zones (regions) for instruments //*********** Chunk* ibagCk = new Chunk("ibag"); size_t numRgns = 0; for (size_t i = 0; i < numInstrs; i++) numRgns += synthfile->vInstrs[i]->vRgns.size(); ibagCk->size = (uint32_t)((numRgns+1) * sizeof(sfInstBag)); ibagCk->data = new uint8_t[ibagCk->size]; rgnCounter = 0; int instGenCounter = 0; for (size_t i = 0; i < numInstrs; i++) { SynthInstr* instr = synthfile->vInstrs[i]; size_t numRgns = instr->vRgns.size(); for (size_t j = 0; j < numRgns; j++) { SynthRgn* rgn = instr->vRgns[j]; sfInstBag instBag; memset(&instBag, 0, sizeof(sfInstBag)); instBag.wInstGenNdx = instGenCounter; instGenCounter += 11; instBag.wInstModNdx = 0; memcpy(ibagCk->data + (rgnCounter++*sizeof(sfInstBag)), &instBag, sizeof(sfInstBag)); } } // add terminal sfInstBag sfInstBag instBag; memset(&instBag, 0, sizeof(sfInstBag)); instBag.wInstGenNdx = instGenCounter; instBag.wInstModNdx = 0; memcpy(ibagCk->data + (rgnCounter*sizeof(sfInstBag)), &instBag, sizeof(sfInstBag)); pdtaCk->AddChildChunk(ibagCk); //*********** // imod chunk //*********** Chunk* imodCk = new Chunk("imod"); // create the terminal field memset(&modList, 0, sizeof(sfModList)); imodCk->SetData(&modList, sizeof(sfModList)); pdtaCk->AddChildChunk(imodCk); //*********** // igen chunk //*********** Chunk* igenCk = new Chunk("igen"); igenCk->size = (uint32_t)((numRgns * sizeof(sfInstGenList) * 11) + sizeof(sfInstGenList)); igenCk->data = new uint8_t[igenCk->size]; dataPtr = 0; for (size_t i = 0; i < numInstrs; i++) { SynthInstr* instr = synthfile->vInstrs[i]; size_t numRgns = instr->vRgns.size(); for (size_t j = 0; j < numRgns; j++) { SynthRgn* rgn = instr->vRgns[j]; sfInstGenList instGenList; // Key range - (if exists) this must be the first chunk instGenList.sfGenOper = keyRange; instGenList.genAmount.ranges.byLo = (uint8_t)rgn->usKeyLow; instGenList.genAmount.ranges.byHi = (uint8_t)rgn->usKeyHigh; memcpy(igenCk->data + dataPtr, &instGenList, sizeof(sfInstGenList)); dataPtr += sizeof(sfInstGenList); if (rgn->usVelHigh) // 0 means 'not set', fixes TriAce instruments { // Velocity range (if exists) this must be the next chunk instGenList.sfGenOper = velRange; instGenList.genAmount.ranges.byLo = (uint8_t)rgn->usVelLow; instGenList.genAmount.ranges.byHi = (uint8_t)rgn->usVelHigh; memcpy(igenCk->data + dataPtr, &instGenList, sizeof(sfInstGenList)); dataPtr += sizeof(sfInstGenList); } // initialAttenuation instGenList.sfGenOper = initialAttenuation; instGenList.genAmount.shAmount= (int16_t)(rgn->sampinfo->attenuation * 10); memcpy(igenCk->data + dataPtr, &instGenList, sizeof(sfInstGenList)); dataPtr += sizeof(sfInstGenList); // pan instGenList.sfGenOper = pan; instGenList.genAmount.shAmount= (int16_t)ConvertPercentPanTo10thPercentUnits(rgn->art->pan); memcpy(igenCk->data + dataPtr, &instGenList, sizeof(sfInstGenList)); dataPtr += sizeof(sfInstGenList); // sampleModes instGenList.sfGenOper = sampleModes; instGenList.genAmount.wAmount = rgn->sampinfo->cSampleLoops; memcpy(igenCk->data + dataPtr, &instGenList, sizeof(sfInstGenList)); dataPtr += sizeof(sfInstGenList); // overridingRootKey instGenList.sfGenOper = overridingRootKey; instGenList.genAmount.wAmount = rgn->sampinfo->usUnityNote; memcpy(igenCk->data + dataPtr, &instGenList, sizeof(sfInstGenList)); dataPtr += sizeof(sfInstGenList); // attackVolEnv instGenList.sfGenOper = attackVolEnv; instGenList.genAmount.shAmount = (rgn->art->attack_time == 0) ? -32768 : roundi(SecondsToTimecents(rgn->art->attack_time)); memcpy(igenCk->data + dataPtr, &instGenList, sizeof(sfInstGenList)); dataPtr += sizeof(sfInstGenList); // decayVolEnv instGenList.sfGenOper = decayVolEnv; instGenList.genAmount.shAmount = (rgn->art->decay_time == 0) ? -32768 : roundi(SecondsToTimecents(rgn->art->decay_time)); memcpy(igenCk->data + dataPtr, &instGenList, sizeof(sfInstGenList)); dataPtr += sizeof(sfInstGenList); // sustainVolEnv instGenList.sfGenOper = sustainVolEnv; if (rgn->art->sustain_lev > 100.0) rgn->art->sustain_lev = 100.0; instGenList.genAmount.shAmount = (int16_t)(rgn->art->sustain_lev * 10); memcpy(igenCk->data + dataPtr, &instGenList, sizeof(sfInstGenList)); dataPtr += sizeof(sfInstGenList); // releaseVolEnv instGenList.sfGenOper = releaseVolEnv; instGenList.genAmount.shAmount = (rgn->art->release_time == 0) ? -32768 : roundi(SecondsToTimecents(rgn->art->release_time)); memcpy(igenCk->data + dataPtr, &instGenList, sizeof(sfInstGenList)); dataPtr += sizeof(sfInstGenList); // reverbEffectsSend //instGenList.sfGenOper = reverbEffectsSend; //instGenList.genAmount.shAmount = 800; //memcpy(pgenCk->data + dataPtr, &instGenList, sizeof(sfInstGenList)); //dataPtr += sizeof(sfInstGenList); // sampleID - this is the terminal chunk instGenList.sfGenOper = sampleID; instGenList.genAmount.wAmount = (uint16_t)(rgn->tableIndex); memcpy(igenCk->data + dataPtr, &instGenList, sizeof(sfInstGenList)); dataPtr += sizeof(sfInstGenList); //int numConnBlocks = rgn->art->vConnBlocks.size(); //for (int k = 0; k < numConnBlocks; k++) //{ // SynthConnectionBlock* connBlock = rgn->art->vConnBlocks[k]; // connBlock-> //} } } // add terminal sfInstBag sfInstGenList instGenList; memset(&instGenList, 0, sizeof(sfInstGenList)); memcpy(igenCk->data + dataPtr, &instGenList, sizeof(sfInstGenList)); //memset(ibagCk->data + (numRgns*sizeof(sfInstBag)), 0, sizeof(sfInstBag)); //igenCk->SetData(&genList, sizeof(sfGenList)); pdtaCk->AddChildChunk(igenCk); //*********** // shdr chunk //*********** Chunk* shdrCk = new Chunk("shdr"); size_t numSamps = synthfile->vWaves.size(); shdrCk->size = (uint32_t)((numSamps+1) * sizeof(sfSample)); shdrCk->data = new uint8_t[shdrCk->size]; uint32_t sampOffset = 0; for (size_t i = 0; i < numSamps; i++) { SynthWave* wave = synthfile->vWaves[i]; sfSample samp; memset(&samp, 0, sizeof(sfSample)); memcpy(samp.achSampleName, wave->name.c_str(), min((unsigned long)wave->name.length(), (unsigned long)20)); samp.dwStart = sampOffset; samp.dwEnd = samp.dwStart + (wave->dataSize / sizeof(uint16_t)); sampOffset = samp.dwEnd + 46; // plus the 46 padding samples required by sf2 spec // Search through all regions for an associated sampInfo structure with this sample SynthSampInfo* sampInfo = NULL; for (size_t j = 0; j < numInstrs; j++) { SynthInstr* instr = synthfile->vInstrs[j]; size_t numRgns = instr->vRgns.size(); for (size_t k = 0; k < numRgns; k++) { SynthRgn* rgn = instr->vRgns[k]; if (rgn->tableIndex == i && rgn->sampinfo != NULL) { sampInfo = rgn->sampinfo; break; } } if (sampInfo != NULL) break; } // If we didn't find a rgn association, then it should be in the SynthWave structure. if (sampInfo == NULL) sampInfo = wave->sampinfo; assert (sampInfo != NULL); samp.dwStartloop = samp.dwStart + sampInfo->ulLoopStart; samp.dwEndloop = samp.dwStartloop + sampInfo->ulLoopLength; samp.dwSampleRate = wave->dwSamplesPerSec; samp.byOriginalKey = (uint8_t)(sampInfo->usUnityNote); samp.chCorrection = (char)(sampInfo->sFineTune); samp.wSampleLink = 0; samp.sfSampleType = monoSample; memcpy(shdrCk->data + (i*sizeof(sfSample)), &samp, sizeof(sfSample)); } // add terminal sfSample memset(shdrCk->data + (numSamps*sizeof(sfSample)), 0, sizeof(sfSample)); pdtaCk->AddChildChunk(shdrCk); this->AddChildChunk(pdtaCk); }