--- linuxsampler/trunk/src/engines/gig/Voice.cpp 2004/12/13 00:46:42 319 +++ linuxsampler/trunk/src/engines/gig/Voice.cpp 2005/02/09 01:22:18 361 @@ -58,9 +58,14 @@ pLFO2 = NULL; pLFO3 = NULL; KeyGroup = 0; - + SynthesisMode = 0; // set all mode bits to 0 first // select synthesis implementation (currently either pure C++ or MMX+SSE(1)) + #if ARCH_X86 SYNTHESIS_MODE_SET_IMPLEMENTATION(SynthesisMode, Features::supportsMMX() && Features::supportsSSE()); + #else + SYNTHESIS_MODE_SET_IMPLEMENTATION(SynthesisMode, false); + #endif + SYNTHESIS_MODE_SET_PROFILING(SynthesisMode, true); } Voice::~Voice() { @@ -114,7 +119,9 @@ * @param iLayer - layer number this voice refers to (only if this is a layered sound of course) * @param ReleaseTriggerVoice - if this new voice is a release trigger voice (optional, default = false) * @param VoiceStealing - wether the voice is allowed to steal voices for further subvoices - * @returns 0 on success, a value < 0 if something failed + * @returns 0 on success, a value < 0 if the voice wasn't triggered + * (either due to an error or e.g. because no region is + * defined for the given key) */ int Voice::Trigger(Pool::Iterator& itNoteOnEvent, int PitchBend, ::gig::Instrument* pInstrument, int iLayer, bool ReleaseTriggerVoice, bool VoiceStealing) { if (!pInstrument) { @@ -135,8 +142,7 @@ itChildVoice = Pool::Iterator(); if (!pRegion) { - std::cerr << "gig::Voice: No Region defined for MIDI key " << MIDIKey << std::endl << std::flush; - KillImmediately(); + dmsg(4, ("gig::Voice: No Region defined for MIDI key %d\n", MIDIKey)); return -1; } @@ -144,7 +150,7 @@ // get current dimension values to select the right dimension region //FIXME: controller values for selecting the dimension region here are currently not sample accurate - uint DimValues[5] = {0,0,0,0,0}; + uint DimValues[8] = { 0 }; for (int i = pRegion->Dimensions - 1; i >= 0; i--) { switch (pRegion->pDimensionDefinitions[i].dimension) { case ::gig::dimension_samplechannel: @@ -168,7 +174,7 @@ DimValues[i] = (uint) ReleaseTriggerVoice; break; case ::gig::dimension_keyboard: - DimValues[i] = (uint) itNoteOnEvent->Param.Note.Key; + DimValues[i] = (uint) pEngine->CurrentKeyDimension; break; case ::gig::dimension_modwheel: DimValues[i] = pEngine->ControllerTable[1]; @@ -246,9 +252,10 @@ std::cerr << "gig::Voice::Trigger() Error: Unknown dimension\n" << std::flush; } } - pDimRgn = pRegion->GetDimensionRegionByValue(DimValues[4],DimValues[3],DimValues[2],DimValues[1],DimValues[0]); + pDimRgn = pRegion->GetDimensionRegionByValue(DimValues); pSample = pDimRgn->pSample; // sample won't change until the voice is finished + if (!pSample || !pSample->SamplesTotal) return -1; // no need to continue if sample is silent // select channel mode (mono or stereo) SYNTHESIS_MODE_SET_CHANNELS(SynthesisMode, pSample->Channels == 2); @@ -308,7 +315,7 @@ // calculate initial pitch value { - double pitchbasecents = pDimRgn->FineTune * 10 + (int) pEngine->ScaleTuning[MIDIKey % 12]; + double pitchbasecents = pDimRgn->FineTune + (int) pEngine->ScaleTuning[MIDIKey % 12]; if (pDimRgn->PitchTrack) pitchbasecents += (MIDIKey - (int) pDimRgn->UnityNote) * 100; this->PitchBase = RTMath::CentsToFreqRatio(pitchbasecents) * (double(pSample->SamplesPerSecond) / double(pEngine->pAudioOutputDevice->SampleRate())); this->PitchBend = RTMath::CentsToFreqRatio(((double) PitchBend / 8192.0) * 200.0); // pitchbend wheel +-2 semitones = 200 cents @@ -693,12 +700,19 @@ } DiskStreamRef.pStream->IncrementReadPos(pSample->Channels * (int(Pos) - MaxRAMPos)); Pos -= int(Pos); + RealSampleWordsLeftToRead = -1; // -1 means no silence has been added yet } + const int sampleWordsLeftToRead = DiskStreamRef.pStream->GetReadSpace(); + // add silence sample at the end if we reached the end of the stream (for the interpolator) - if (DiskStreamRef.State == Stream::state_end && DiskStreamRef.pStream->GetReadSpace() < (pEngine->MaxSamplesPerCycle << MAX_PITCH) / pSample->Channels) { - DiskStreamRef.pStream->WriteSilence((pEngine->MaxSamplesPerCycle << MAX_PITCH) / pSample->Channels); - this->PlaybackState = playback_state_end; + if (DiskStreamRef.State == Stream::state_end) { + const int maxSampleWordsPerCycle = (pEngine->MaxSamplesPerCycle << MAX_PITCH) * pSample->Channels + 6; // +6 for the interpolator algorithm + if (sampleWordsLeftToRead <= maxSampleWordsPerCycle) { + // remember how many sample words there are before any silence has been added + if (RealSampleWordsLeftToRead < 0) RealSampleWordsLeftToRead = sampleWordsLeftToRead; + DiskStreamRef.pStream->WriteSilence(maxSampleWordsPerCycle - sampleWordsLeftToRead); + } } sample_t* ptr = DiskStreamRef.pStream->GetReadPtr(); // get the current read_ptr within the ringbuffer where we read the samples from @@ -706,8 +720,16 @@ // render current audio fragment Synthesize(Samples, ptr, Delay); - DiskStreamRef.pStream->IncrementReadPos(int(Pos) * pSample->Channels); - Pos -= int(Pos); + const int iPos = (int) Pos; + const int readSampleWords = iPos * pSample->Channels; // amount of sample words actually been read + DiskStreamRef.pStream->IncrementReadPos(readSampleWords); + Pos -= iPos; // just keep fractional part of Pos + + // change state of voice to 'end' if we really reached the end of the sample data + if (RealSampleWordsLeftToRead >= 0) { + RealSampleWordsLeftToRead -= readSampleWords; + if (RealSampleWordsLeftToRead <= 0) this->PlaybackState = playback_state_end; + } } break; @@ -926,6 +948,7 @@ float prev_cutoff = pEngine->pSynthesisParameters[Event::destination_vcfc][0]; float prev_res = pEngine->pSynthesisParameters[Event::destination_vcfr][0]; FilterLeft.SetParameters(&bqbase, &bqmain, prev_cutoff, prev_res, pEngine->SampleRate); + FilterRight.SetParameters(&bqbase, &bqmain, prev_cutoff, prev_res, pEngine->SampleRate); pEngine->pBasicFilterParameters[0] = bqbase; pEngine->pMainFilterParameters[0] = bqmain; @@ -939,24 +962,25 @@ prev_cutoff = pEngine->pSynthesisParameters[Event::destination_vcfc][i]; prev_res = pEngine->pSynthesisParameters[Event::destination_vcfr][i]; FilterLeft.SetParameters(&bqbase, &bqmain, prev_cutoff, prev_res, pEngine->SampleRate); + FilterRight.SetParameters(&bqbase, &bqmain, prev_cutoff, prev_res, pEngine->SampleRate); } } //same as 'pEngine->pBasicFilterParameters[i] = bqbase;' bq = (float*) &pEngine->pBasicFilterParameters[i]; - bq[0] = bqbase.a1; - bq[1] = bqbase.a2; - bq[2] = bqbase.b0; - bq[3] = bqbase.b1; - bq[4] = bqbase.b2; + bq[0] = bqbase.b0; + bq[1] = bqbase.b1; + bq[2] = bqbase.b2; + bq[3] = bqbase.a1; + bq[4] = bqbase.a2; // same as 'pEngine->pMainFilterParameters[i] = bqmain;' bq = (float*) &pEngine->pMainFilterParameters[i]; - bq[0] = bqmain.a1; - bq[1] = bqmain.a2; - bq[2] = bqmain.b0; - bq[3] = bqmain.b1; - bq[4] = bqmain.b2; + bq[0] = bqmain.b0; + bq[1] = bqmain.b1; + bq[2] = bqmain.b2; + bq[3] = bqmain.a1; + bq[4] = bqmain.a2; } } @@ -968,18 +992,8 @@ * @param pSrc - pointer to input sample data * @param Skip - number of sample points to skip in output buffer */ - void Voice::Synthesize(uint Samples, sample_t* pSrc, int Skip) { - UpdateSynthesisMode(); - SynthesizeFragment_Fn* f = (SynthesizeFragment_Fn*) SynthesizeFragmentFnPtr; - f(*this, Samples, pSrc, Skip); - } - - /** - * Determine the respective synthesis function for the given synthesis - * mode. - */ - void Voice::UpdateSynthesisMode() { - SynthesizeFragmentFnPtr = GetSynthesisFunction(SynthesisMode); + void Voice::Synthesize(uint Samples, sample_t* pSrc, uint Skip) { + RunSynthesisFunction(SynthesisMode, *this, Samples, pSrc, Skip); } /**