예제 #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;
        }
예제 #2
0
        public static void Start(this ModulationEnvelope envelope, RegionPair region, int key, int velocity)
        {
            // According to the implementation of TinySoundFont, the attack time should be adjusted by the velocity.

            var delay   = region.DelayModulationEnvelope;
            var attack  = region.AttackModulationEnvelope * ((145 - velocity) / 144F);
            var hold    = region.HoldModulationEnvelope * SoundFontMath.KeyNumberToMultiplyingFactor(region.KeyNumberToModulationEnvelopeHold, key);
            var decay   = region.DecayModulationEnvelope * SoundFontMath.KeyNumberToMultiplyingFactor(region.KeyNumberToModulationEnvelopeDecay, key);
            var sustain = 1F - region.SustainModulationEnvelope / 100F;
            var release = region.ReleaseModulationEnvelope;

            envelope.Start(delay, attack, hold, decay, sustain, release);
        }
예제 #3
0
        public static void Start(this VolumeEnvelope envelope, RegionPair region, int key, int velocity)
        {
            // If the release time is shorter than 10 ms, it will be clamped to 10 ms to avoid pop noise.

            var delay   = region.DelayVolumeEnvelope;
            var attack  = region.AttackVolumeEnvelope;
            var hold    = region.HoldVolumeEnvelope * SoundFontMath.KeyNumberToMultiplyingFactor(region.KeyNumberToVolumeEnvelopeHold, key);
            var decay   = region.DecayVolumeEnvelope * SoundFontMath.KeyNumberToMultiplyingFactor(region.KeyNumberToVolumeEnvelopeDecay, key);
            var sustain = SoundFontMath.DecibelsToLinear(-region.SustainVolumeEnvelope);
            var release = Math.Max(region.ReleaseVolumeEnvelope, 0.01F);

            envelope.Start(delay, attack, hold, decay, sustain, release);
        }
예제 #4
0
        /// <summary>
        /// Starts a note.
        /// </summary>
        /// <param name="channel">The channel of the note.</param>
        /// <param name="key">The key of the note.</param>
        /// <param name="velocity">The velocity of the note.</param>
        public void NoteOn(int channel, int key, int velocity)
        {
            if (velocity == 0)
            {
                NoteOff(channel, key);
                return;
            }

            if (!(0 <= channel && channel < channels.Length))
            {
                return;
            }

            var channelInfo = channels[channel];

            var presetId = (channelInfo.BankNumber << 16) | channelInfo.PatchNumber;

            Preset preset;

            if (!presetLookup.TryGetValue(presetId, out preset))
            {
                // Try fallback to the GM sound set.
                if (!presetLookup.TryGetValue(channelInfo.PatchNumber, out preset))
                {
                    // No corresponding preset was found. Use the default one...
                    preset = defaultPreset;
                }
            }

            foreach (var presetRegion in preset.RegionArray)
            {
                if (presetRegion.Contains(key, velocity))
                {
                    foreach (var instrumentRegion in presetRegion.Instrument.RegionArray)
                    {
                        if (instrumentRegion.Contains(key, velocity))
                        {
                            var regionPair = new RegionPair(presetRegion, instrumentRegion);

                            var voice = voices.RequestNew(instrumentRegion, channel);
                            if (voice != null)
                            {
                                voice.Start(regionPair, channel, key, velocity);
                            }
                        }
                    }
                }
            }
        }
예제 #5
0
        public static void Start(this Oscillator oscillator, short[] data, RegionPair region)
        {
            var sampleRate  = region.Instrument.Sample.SampleRate;
            var loopMode    = region.SampleModes;
            var start       = region.SampleStart;
            var end         = region.SampleEnd;
            var startLoop   = region.SampleStartLoop;
            var endLoop     = region.SampleEndLoop;
            var rootKey     = region.RootKey;
            var coarseTune  = region.CoarseTune;
            var fineTune    = region.FineTune;
            var scaleTuning = region.ScaleTuning;

            oscillator.Start(data, loopMode, sampleRate, start, end, startLoop, endLoop, rootKey, coarseTune, fineTune, scaleTuning);
        }
예제 #6
0
 public static void StartModulation(this Lfo lfo, RegionPair region, int key, int velocity)
 {
     lfo.Start(region.DelayModulationLfo, region.FrequencyModulationLfo);
 }
예제 #7
0
 public static void StartVibrato(this Lfo lfo, RegionPair region, int key, int velocity)
 {
     lfo.Start(region.DelayVibratoLfo, region.FrequencyVibratoLfo);
 }