Exemple #1
0
        public void Start(RegionPair region, int channel, int key, int velocity)
        {
            this.exclusiveClass = region.ExclusiveClass;
            this.channel        = channel;
            this.key            = key;
            this.velocity       = velocity;

            if (velocity > 0)
            {
                // According to the Polyphone's implementation, the initial attenuation should be reduced to 40%.
                // I'm not sure why, but this indeed improves the loudness variability.
                var sampleAttenuation = 0.4F * region.InitialAttenuation;
                var filterAttenuation = 0.5F * region.InitialFilterQ;
                var decibels          = 2 * SoundFontMath.LinearToDecibels(velocity / 127F) - sampleAttenuation - filterAttenuation;
                noteGain = SoundFontMath.DecibelsToLinear(decibels);
            }
            else
            {
                noteGain = 0F;
            }

            cutoff    = region.InitialFilterCutoffFrequency;
            resonance = SoundFontMath.DecibelsToLinear(region.InitialFilterQ);

            vibLfoToPitch = 0.01F * region.VibratoLfoToPitch;
            modLfoToPitch = 0.01F * region.ModulationLfoToPitch;
            modEnvToPitch = 0.01F * region.ModulationEnvelopeToPitch;

            modLfoToCutoff = region.ModulationLfoToFilterCutoffFrequency;
            modEnvToCutoff = region.ModulationEnvelopeToFilterCutoffFrequency;
            dynamicCutoff  = modLfoToCutoff != 0 || modEnvToCutoff != 0;

            modLfoToVolume = region.ModulationLfoToVolume;
            dynamicVolume  = modLfoToVolume > 0.05F;

            instrumentPan    = SoundFontMath.Clamp(region.Pan, -50F, 50F);
            instrumentReverb = 0.01F * region.ReverbEffectsSend;
            instrumentChorus = 0.01F * region.ChorusEffectsSend;

            volEnv.Start(region, key, velocity);
            modEnv.Start(region, key, velocity);
            vibLfo.StartVibrato(region, key, velocity);
            modLfo.StartModulation(region, key, velocity);
            oscillator.Start(synthesizer.SoundFont.WaveDataArray, region);
            filter.ClearBuffer();
            filter.SetLowPassFilter(cutoff, resonance);

            smoothedCutoff = cutoff;

            voiceState  = VoiceState.Playing;
            voiceLength = 0;
        }
        public void Start(float delay, float attack, float hold, float decay, float sustain, float release)
        {
            attackSlope = 1 / attack;
            decaySlope = -9.226 / decay;
            releaseSlope = -9.226 / release;

            attackStartTime = delay;
            holdStartTime = attackStartTime + attack;
            decayStartTime = holdStartTime + hold;
            releaseStartTime = 0;

            sustainLevel = SoundFontMath.Clamp(sustain, 0F, 1F);
            releaseLevel = 0;

            processedSampleCount = 0;
            stage = Stage.Delay;
            value = 0;

            Process(0);
        }
Exemple #3
0
        public bool Process()
        {
            if (noteGain < SoundFontMath.NonAudible)
            {
                return(false);
            }

            var channelInfo = synthesizer.Channels[channel];

            ReleaseIfNecessary(channelInfo);

            if (!volEnv.Process())
            {
                return(false);
            }

            modEnv.Process();
            vibLfo.Process();
            modLfo.Process();

            var vibPitchChange     = (0.01F * channelInfo.Modulation + vibLfoToPitch) * vibLfo.Value;
            var modPitchChange     = modLfoToPitch * modLfo.Value + modEnvToPitch * modEnv.Value;
            var channelPitchChange = channelInfo.Tune + channelInfo.PitchBend;
            var pitch = key + vibPitchChange + modPitchChange + channelPitchChange;

            if (!oscillator.Process(block, pitch))
            {
                return(false);
            }

            if (dynamicCutoff)
            {
                var cents     = modLfoToCutoff * modLfo.Value + modEnvToCutoff * modEnv.Value;
                var factor    = SoundFontMath.CentsToMultiplyingFactor(cents);
                var newCutoff = factor * cutoff;

                // The cutoff change is limited within x0.5 and x2 to reduce pop noise.
                var lowerLimit = 0.5F * smoothedCutoff;
                var upperLimit = 2F * smoothedCutoff;
                if (newCutoff < lowerLimit)
                {
                    smoothedCutoff = lowerLimit;
                }
                else if (newCutoff > upperLimit)
                {
                    smoothedCutoff = upperLimit;
                }
                else
                {
                    smoothedCutoff = newCutoff;
                }

                filter.SetLowPassFilter(smoothedCutoff, resonance);
            }
            filter.Process(block);

            previousMixGainLeft  = currentMixGainLeft;
            previousMixGainRight = currentMixGainRight;
            previousReverbSend   = currentReverbSend;
            previousChorusSend   = currentChorusSend;

            // According to the GM spec, the following value should be squared.
            var ve          = channelInfo.Volume * channelInfo.Expression;
            var channelGain = ve * ve;

            var mixGain = noteGain * channelGain * volEnv.Value;

            if (dynamicVolume)
            {
                var decibels = modLfoToVolume * modLfo.Value;
                mixGain *= SoundFontMath.DecibelsToLinear(decibels);
            }

            var angle = (MathF.PI / 200F) * (channelInfo.Pan + instrumentPan + 50F);

            if (angle <= 0F)
            {
                currentMixGainLeft  = mixGain;
                currentMixGainRight = 0F;
            }
            else if (angle >= SoundFontMath.HalfPi)
            {
                currentMixGainLeft  = 0F;
                currentMixGainRight = mixGain;
            }
            else
            {
                currentMixGainLeft  = mixGain * MathF.Cos(angle);
                currentMixGainRight = mixGain * MathF.Sin(angle);
            }

            currentReverbSend = SoundFontMath.Clamp(channelInfo.ReverbSend + instrumentReverb, 0F, 1F);
            currentChorusSend = SoundFontMath.Clamp(channelInfo.ChorusSend + instrumentChorus, 0F, 1F);

            if (voiceLength == 0)
            {
                previousMixGainLeft  = currentMixGainLeft;
                previousMixGainRight = currentMixGainRight;
                previousReverbSend   = currentReverbSend;
                previousChorusSend   = currentChorusSend;
            }

            voiceLength += synthesizer.BlockSize;

            return(true);
        }