--- libgig/trunk/src/gig.cpp 2019/02/28 17:49:07 3488 +++ libgig/trunk/src/gig.cpp 2019/10/02 16:30:29 3623 @@ -1740,6 +1740,7 @@ VCFType = vcf_type_lowpass; memset(DimensionUpperLimits, 127, 8); } + // chunk for own format extensions, these will *NOT* work with Gigasampler/GigaStudio ! RIFF::Chunk* lsde = _3ewl->GetSubChunk(CHUNK_ID_LSDE); if (lsde) { // format extension for EG behavior options @@ -1765,6 +1766,28 @@ SustainReleaseTrigger = sust_rel_trg_none; NoNoteOffReleaseTrigger = false; } + // format extension for LFOs' wave form, phase displacement and for + // LFO3's flip phase + if (lsde && lsde->GetSize() > 4) { + lsde->SetPos(4); + LFO1WaveForm = static_cast( lsde->ReadUint16() ); + LFO2WaveForm = static_cast( lsde->ReadUint16() ); + LFO3WaveForm = static_cast( lsde->ReadUint16() ); + lsde->ReadUint16(); // unused 16 bits, reserved for potential future use + LFO1Phase = (double) GIG_EXP_DECODE( lsde->ReadInt32() ); + LFO2Phase = (double) GIG_EXP_DECODE( lsde->ReadInt32() ); + LFO3Phase = (double) GIG_EXP_DECODE( lsde->ReadInt32() ); + const uint32_t flags = lsde->ReadInt32(); + LFO3FlipPhase = flags & 1; + } else { + LFO1WaveForm = lfo_wave_sine; + LFO2WaveForm = lfo_wave_sine; + LFO3WaveForm = lfo_wave_sine; + LFO1Phase = 0.0; + LFO2Phase = 0.0; + LFO3Phase = 0.0; + LFO3FlipPhase = false; + } pVelocityAttenuationTable = GetVelocityTable(VelocityResponseCurve, VelocityResponseDepth, @@ -1890,7 +1913,9 @@ SRLZ(EG1ControllerAttackInfluence); SRLZ(EG1ControllerDecayInfluence); SRLZ(EG1ControllerReleaseInfluence); + SRLZ(LFO1WaveForm); SRLZ(LFO1Frequency); + SRLZ(LFO1Phase); SRLZ(LFO1InternalDepth); SRLZ(LFO1ControlDepth); SRLZ(LFO1Controller); @@ -1908,7 +1933,9 @@ SRLZ(EG2ControllerAttackInfluence); SRLZ(EG2ControllerDecayInfluence); SRLZ(EG2ControllerReleaseInfluence); + SRLZ(LFO2WaveForm); SRLZ(LFO2Frequency); + SRLZ(LFO2Phase); SRLZ(LFO2InternalDepth); SRLZ(LFO2ControlDepth); SRLZ(LFO2Controller); @@ -1916,10 +1943,13 @@ SRLZ(LFO2Sync); SRLZ(EG3Attack); SRLZ(EG3Depth); + SRLZ(LFO3WaveForm); SRLZ(LFO3Frequency); + SRLZ(LFO3Phase); SRLZ(LFO3InternalDepth); SRLZ(LFO3ControlDepth); SRLZ(LFO3Controller); + SRLZ(LFO3FlipPhase); SRLZ(LFO3Sync); SRLZ(VCFEnabled); SRLZ(VCFType); @@ -2267,19 +2297,17 @@ // chunk for own format extensions, these will *NOT* work with // Gigasampler/GigaStudio ! RIFF::Chunk* lsde = pParentList->GetSubChunk(CHUNK_ID_LSDE); - const int lsdeSize = 4; // NOTE: we reserved the 3rd byte for a potential future EG3 option - if (!lsde) { - // only add this "LSDE" chunk if either EG options or release - // trigger options deviate from their default behaviour - eg_opt_t defaultOpt; - if (memcmp(&EG1Options, &defaultOpt, sizeof(eg_opt_t)) || - memcmp(&EG2Options, &defaultOpt, sizeof(eg_opt_t)) || - SustainReleaseTrigger || NoNoteOffReleaseTrigger) - { - lsde = pParentList->AddSubChunk(CHUNK_ID_LSDE, lsdeSize); - // move LSDE chunk to the end of parent list - pParentList->MoveSubChunk(lsde, (RIFF::Chunk*)NULL); - } + const int lsdeSize = + 3 /* EG cancel options */ + + 1 /* sustain pedal up on release trigger option */ + + 8 /* LFOs' wave forms */ + 12 /* LFOs' phase */ + 4 /* flags (LFO3FlipPhase) */; + if (!lsde && UsesAnyGigFormatExtension()) { + // only add this "LSDE" chunk if there is some (format extension) + // setting effective that would require our "LSDE" format extension + // chunk to be stored + lsde = pParentList->AddSubChunk(CHUNK_ID_LSDE, lsdeSize); + // move LSDE chunk to the end of parent list + pParentList->MoveSubChunk(lsde, (RIFF::Chunk*)NULL); } if (lsde) { if (lsde->GetNewSize() < lsdeSize) @@ -2297,9 +2325,52 @@ } // format extension for release trigger options pData[3] = static_cast(SustainReleaseTrigger) | (NoNoteOffReleaseTrigger ? (1<<7) : 0); + // format extension for LFOs' wave form, phase displacement and for + // LFO3's flip phase + store16(&pData[4], LFO1WaveForm); + store16(&pData[6], LFO2WaveForm); + store16(&pData[8], LFO3WaveForm); + //NOTE: 16 bits reserved here for potential future use ! + const int32_t lfo1Phase = (int32_t) GIG_EXP_ENCODE(LFO1Phase); + const int32_t lfo2Phase = (int32_t) GIG_EXP_ENCODE(LFO2Phase); + const int32_t lfo3Phase = (int32_t) GIG_EXP_ENCODE(LFO3Phase); + store32(&pData[12], lfo1Phase); + store32(&pData[16], lfo2Phase); + store32(&pData[20], lfo3Phase); + const int32_t flags = LFO3FlipPhase ? 1 : 0; + store32(&pData[24], flags); + + // compile time sanity check: is our last store access here + // consistent with the initial lsdeSize value assignment? + static_assert(lsdeSize == 28, "Inconsistency in assumed 'LSDE' RIFF chunk size"); } } + /** + * Returns @c true in case this DimensionRegion object uses any gig format + * extension, that is whether this DimensionRegion object currently has any + * setting effective that would require our "LSDE" RIFF chunk to be stored + * to the gig file. + * + * Right now this is a private method. It is considerable though this method + * to become (in slightly modified form) a public API method in future, i.e. + * to allow instrument editors to visualize and/or warn the user of any + * format extension being used. Right now this method really just serves to + * answer the question whether an LSDE chunk is required, for the public API + * purpose this method would also need to check whether any other setting + * stored to the regular value '3ewa' chunk, is actually a format extension + * as well. + */ + bool DimensionRegion::UsesAnyGigFormatExtension() const { + eg_opt_t defaultOpt; + return memcmp(&EG1Options, &defaultOpt, sizeof(eg_opt_t)) || + memcmp(&EG2Options, &defaultOpt, sizeof(eg_opt_t)) || + SustainReleaseTrigger || NoNoteOffReleaseTrigger || + LFO1WaveForm || LFO2WaveForm || LFO3WaveForm || + LFO1Phase || LFO2Phase || LFO3Phase || + LFO3FlipPhase; + } + double* DimensionRegion::GetReleaseVelocityTable(curve_type_t releaseVelocityResponseCurve, uint8_t releaseVelocityResponseDepth) { curve_type_t curveType = releaseVelocityResponseCurve; uint8_t depth = releaseVelocityResponseDepth;