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 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); }
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); }
/// <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); } } } } } }
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); }
public static void StartModulation(this Lfo lfo, RegionPair region, int key, int velocity) { lfo.Start(region.DelayModulationLfo, region.FrequencyModulationLfo); }
public static void StartVibrato(this Lfo lfo, RegionPair region, int key, int velocity) { lfo.Start(region.DelayVibratoLfo, region.FrequencyVibratoLfo); }