public AnalyticADSREnvelope( IAnalyticStream stream, double timeToPeak, double timeToSustain, double sustainAmplitude, double sustainDecayTime, double releaseDecayTime) : base(stream) { this.sustainAmplitude = sustainAmplitude; sustainDecaySamples = (int)(SamplingRate * sustainDecayTime); releaseDecaySamples = (int)(SamplingRate * releaseDecayTime); attackUpSamples = (int)(SamplingRate * timeToPeak); attackUpEndSample = attackUpSamples; attackDownSamples = (int)(SamplingRate * timeToSustain); attackDownEndSample = attackUpEndSample + attackDownSamples; sustainEndSample = int.MaxValue; attackUpGrowthRate = Math.Pow(1.0 / ENVELOPE_CUTOFF, 1.0 / attackUpSamples); attackDownDecayRate = Math.Pow(sustainAmplitude, 1.0 / attackDownSamples); sustainDecayRate = Math.Exp(-1.0 / sustainDecaySamples); releaseDecayRate = Math.Exp(-1.0 / releaseDecaySamples); immediateDecayRate = Math.Pow(ENVELOPE_CUTOFF, 1 / (SamplingRate * 0.01)); //Start at a small envelope for exponential growth currentEnvelope = ENVELOPE_CUTOFF; envelopeState = EnvelopeState.AttackUp; }
/// <summary> /// Start the channel. /// </summary> /// <param name="noteDuration">Note duration.</param> private void Start(int noteDuration) { State = EnvelopeState.Attack; Velocity = -92544; _pos = 0; _prevLeft = _prevRight = 0; NoteDuration = noteDuration; }
/// <summary> /// Calculate the coefficient of a particular segment. /// </summary> /// <param name="state">The envelope state.</param> /// <param name="time">The envelope time.</param> private void CalcCoef(EnvelopeState state, float time) { double numSamples = ATKSettings.SampleRate * (time * 0.001); // It would have to be casted as double anyway switch (state) { case EnvelopeState.ATTACK: this.attackCoef = Math.Exp(-Math.Log((1.0 + this.attackTCO) / this.attackTCO) / numSamples); this.attackOffset = (1.0 + this.attackTCO) * (1.0 - this.attackCoef); break; case EnvelopeState.DECAY: this.decayCoef = Math.Exp(-Math.Log((1.0 + this.attackTCO) / this.attackTCO) / numSamples); this.decayOffset = (this.SustainLevel - this.decayTCO) * (1.0 - this.decayCoef); break; case EnvelopeState.RELEASE: this.releaseCoef = Math.Exp(-Math.Log((1.0 + this.attackTCO) / this.attackTCO) / numSamples); this.releaseOffset = -this.releaseTCO * (1.0 - this.releaseCoef); break; default: Trace.TraceWarning("[ATK] Coefficient not calculated. " + state + " is not a proper envelope state."); break; } }
/// <summary> /// Step the envelope. /// </summary> public void StepEnvelope() { switch (State) { case EnvelopeState.Attack: { Velocity = _attack * Velocity / 0xFF; if (Velocity == 0) { State = EnvelopeState.Decay; } break; } case EnvelopeState.Decay: { Velocity -= _decay; if (Velocity <= _sustain) { State = EnvelopeState.Sustain; Velocity = _sustain; } break; } case EnvelopeState.Release: { Velocity -= _release; if (Velocity < -92544) { Velocity = -92544; } break; } } }
/// <summary> /// 現在のエンベロープの状態に基づき、エンベロープ値を出力します。 /// </summary> /// <param name="time">エンベロープの開始時間値。</param> /// <param name="envelopes">出力が格納される実数の配列。</param> /// <param name="offset">代入が開始される配列のインデックス。</param> /// <param name="count">代入される実数値の数。</param> public void Generate(int time, float[] envelopes, int count) { float res; for (int i = 0; i < count; i++, time++) { if (this.State == EnvelopeState.Attack) { res = (time < this.attackTime) ? time * this.da : (time < this.t2) ? 1.0f : (time < this.t3) ? 1.0f - (time - this.t2) * this.dd : this.sustainLevel; } else if (this.State == EnvelopeState.Release) { if (time < this.t5) { res = this.sustainLevel - (time - this.releaseStartTime) * this.dr; } else { res = 0.0f; this.state = EnvelopeState.Silence; } } else { res = 0.0f; } envelopes[i] = res; } }
public override void Seek(int position) { position = GeneralMath.Clamp(position, 0, ChannelSamples); stream.Seek(position); this.position = position; if (position < attackUpEndSample) { envelopeState = EnvelopeState.AttackUp; currentEnvelope = ENVELOPE_CUTOFF * Math.Pow(1.0 / ENVELOPE_CUTOFF, position / (double)attackUpSamples); } else if (position < attackDownEndSample) { envelopeState = EnvelopeState.AttackDown; currentEnvelope = Math.Pow(sustainAmplitude, (position - attackUpEndSample) / (double)attackDownSamples); } else if (position < sustainEndSample) { envelopeState = EnvelopeState.Sustain; currentEnvelope = sustainAmplitude * Math.Pow(sustainDecayRate, (position - attackDownEndSample)); } else { envelopeState = EnvelopeState.Released; currentEnvelope = sustainAmplitude * Math.Pow(sustainDecayRate, sustainEndSample - attackDownEndSample) * Math.Pow(releaseDecayRate, position - sustainEndSample); } }
public virtual void Release() { if (State < EnvelopeState.Releasing) { State = EnvelopeState.Releasing; } }
public void UpdateEnvelope() { switch (CurrentEnvelopeState) { case EnvelopeState.Attack: { var envelopeTime = (GetCurrentMs() - EnvelopeStartTime) / (float)AttackMs; if (envelopeTime >= 1) { envelopeTime = 1; CurrentEnvelopeState = EnvelopeState.Decay; EnvelopeStartTime = GetCurrentMs(); } CurrentEnvelopeValue = AttackResponse.Evaluate(envelopeTime); break; } case EnvelopeState.Decay: { var envelopeTime = (GetCurrentMs() - EnvelopeStartTime) / (float)DecayMs; if (envelopeTime >= 1) { envelopeTime = 1; CurrentEnvelopeState = EnvelopeState.Off; EnvelopeStartTime = 0; } CurrentEnvelopeValue = DecayResponse.Evaluate(envelopeTime); break; } } CurveIntensity = CurrentEnvelopeValue * IntensityMultiplier; }
public SampleSourceWithADSR(ISampleSource sampleSource, SoundVoice voice, VoiceADSREnvelope envelope) { this.sampleSource = sampleSource; this.voice = voice; envelopeState = new EnvelopeState(envelope); tracing = sceSasCore.log.TraceEnabled; }
public void SetEnvelopePhase7_2074ED8() { if (State != EnvelopeState.Zero) { UpdateEnvelopePlan(0, release); State = EnvelopeState.Seven; } }
void Start(int noteLength) { State = EnvelopeState.Attack; Velocity = -92544; pos = 0; prevLeft = prevRight = 0; NoteLength = noteLength; }
public void Stop() { State = EnvelopeState.Dead; if (Owner != null) { Owner.Channels.Remove(this); } Owner = null; }
/// <summary> /// このインスタンスにおけるすべてのパラメータを既定値に戻します。 /// </summary> public void Reset() { this.attackTime = (int)(0.05f * this.samplingFreq); this.peakTime = (int)(0.0f * this.samplingFreq); this.decayTime = (int)(0.0f * this.samplingFreq); this.sustainLevel = 1.0f; this.releaseTime = (int)(0.05f * this.samplingFreq); this.state = EnvelopeState.Silence; }
public Envelope(EnvelopeState <TMessage> state) { SubscriberKey = state.SubscriberKey; _id = state.Id; _retriesRemaining = state.RetriesRemaining; _message = state.Message; RetryPolicy = state.RetryPolicyState.GetRetryPolicy(); AcknowledgmentId = state.AcknowledgmentId; }
public ADSREnvelope( IBGCStream stream, double timeToPeak, double timeToSustain, double timeToRelease, double sustainAmplitude, double sustainDecayTime, double releaseDecayTime) : base(stream) { Debug.Assert(stream.Channels == 1); Debug.Assert(timeToPeak >= 0.0); Debug.Assert(timeToSustain >= 0.0); Debug.Assert(timeToRelease >= 0.0); Debug.Assert(sustainDecayTime >= 0.0); Debug.Assert(releaseDecayTime >= 0.0); this.sustainAmplitude = sustainAmplitude; sustainDecaySamples = (int)(SamplingRate * sustainDecayTime); releaseDecaySamples = (int)(SamplingRate * releaseDecayTime); attackUpSamples = (int)(SamplingRate * timeToPeak); attackUpEndSample = attackUpSamples; attackDownSamples = (int)(SamplingRate * timeToSustain); attackDownEndSample = attackUpEndSample + attackDownSamples; int sustainSamples = (int)(SamplingRate * timeToRelease); sustainEndSample = attackDownEndSample + sustainSamples; attackUpGrowthRate = Math.Pow(1.0 / ENVELOPE_CUTOFF, 1.0 / attackUpSamples); attackDownDecayRate = Math.Pow(sustainAmplitude, 1.0 / attackDownSamples); sustainDecayRate = Math.Exp(-1.0 / sustainDecaySamples); releaseDecayRate = Math.Exp(-1.0 / releaseDecaySamples); immediateDecayRate = Math.Pow(ENVELOPE_CUTOFF, 1 / (SamplingRate * 0.01)); //Start at a small envelope for exponential growth currentEnvelope = ENVELOPE_CUTOFF; envelopeState = EnvelopeState.AttackUp; double releaseBeginAmplitude = sustainAmplitude * Math.Pow(sustainDecayRate, sustainSamples); if (releaseBeginAmplitude < ENVELOPE_CUTOFF) { ChannelSamples = attackDownEndSample + (int)Math.Ceiling( Math.Log(ENVELOPE_CUTOFF / sustainAmplitude) / Math.Log(sustainDecayRate)); } else { ChannelSamples = sustainEndSample + (int)Math.Ceiling( Math.Log(ENVELOPE_CUTOFF / releaseBeginAmplitude) / Math.Log(releaseDecayRate)); } }
/// <summary> /// エンベロープの状態をアタック状態に変更します。 /// </summary> public void Attack() { this.state = EnvelopeState.Attack; //precalc this.t2 = this.attackTime + this.peakTime; this.t3 = t2 + this.decayTime; this.da = 1.0f / this.attackTime; this.dd = (1.0f - this.sustainLevel) / this.decayTime; }
public void StartEnvelope() { // Start time = current time in Ms EnvelopeStartTime = GetCurrentMs(); // set state to attack CurrentEnvelopeState = EnvelopeState.Attack; Trigger = false; }
/// <summary> /// Trigger the gate /// </summary> /// <param name="gate">If true, enter attack phase, if false enter release phase (unless already idle)</param> public void Gate(bool gate) { if (gate) { state = EnvelopeState.Attack; } else if (state != EnvelopeState.Idle) { state = EnvelopeState.Release; } }
/// <summary> /// Controls the activation of the envelope. /// </summary> /// <param name="isActive">If true, sets the envelope to attack. If false, sets the envelope to release.</param> public void Gate(bool isActive) { if (isActive) { State = EnvelopeState.Attack; } else if (State != EnvelopeState.Idle) { State = EnvelopeState.Release; } }
/// <summary> /// エンベロープの状態をリリース状態に変更します。 /// </summary> /// <param name="time">リリースが開始された時間値。</param> public void Release(int time) { if (this.state == EnvelopeState.Attack) { this.state = EnvelopeState.Release; this.releaseStartTime = time; //precalc this.t5 = time + this.releaseTime; this.dr = this.sustainLevel / this.releaseTime; } }
public void TriggerRelease(bool immediate = false) { if (immediate) { envelopeState = EnvelopeState.ImmediateRelease; } else { if (envelopeState != EnvelopeState.ImmediateRelease) { envelopeState = EnvelopeState.Released; } } }
/// <summary> /// Генерация нового значения огибающей. /// </summary> /// <returns></returns> public double Process() { switch (state) { case EnvelopeState.Idle: break; case EnvelopeState.Attack: currValue = attackBase + currValue * attackCoef; if (currValue >= 1f) { currValue = 1f; if (decayCoef != 0) { state = EnvelopeState.Decay; } else { state = EnvelopeState.Sustain; } } break; case EnvelopeState.Decay: currValue = decayBase + currValue * decayCoef; if (currValue <= sustainLevel) { currValue = sustainLevel; state = EnvelopeState.Sustain; } break; case EnvelopeState.Sustain: currValue = sustainLevel; break; case EnvelopeState.Release: currValue = releaseBase + currValue * releaseCoef; if (currValue <= 0) { currValue = 0; state = EnvelopeState.Idle; OnSoundStop(); } break; } return(currValue); }
/// <summary> /// Update is called every frame by the shake. /// </summary> public void Update(float deltaTime) { if (IsFinished) { return; } if (state == EnvelopeState.Increase) { if (pars.attack > 0) { amplitude += deltaTime * pars.attack; } if (amplitude > targetAmplitude || pars.attack <= 0) { amplitude = targetAmplitude; state = EnvelopeState.Sustain; if (controlMode == EnvelopeControlMode.Auto) { sustainEndTime = Time.time + pars.sustain; } } } else { if (state == EnvelopeState.Decrease) { if (pars.decay > 0) { amplitude -= deltaTime * pars.decay; } if (amplitude < targetAmplitude || pars.decay <= 0) { amplitude = targetAmplitude; state = EnvelopeState.Sustain; } } else { if (controlMode == EnvelopeControlMode.Auto && Time.time > sustainEndTime) { SetTarget(0); } } } amplitude = Mathf.Clamp01(amplitude); Intensity = Power.Evaluate(amplitude, pars.degree); }
/// <summary> /// Метод, начинающий стадию атаки. /// </summary> public void TriggerAttack() { if (attackCoef != 0) { currValue = 0; state = EnvelopeState.Attack; } else if (decayCoef != 0) { currValue = 1; state = EnvelopeState.Decay; } else { state = EnvelopeState.Sustain; } }
public override void Release() { if (State < EnvelopeState.Releasing) { if (_adsr.R == 0) { _velocity = 0; Stop(); } else if (_velocity == 0) { Stop(); } else { _nextState = EnvelopeState.Releasing; } } }
private int StateEndSample(EnvelopeState state) { switch (state) { case EnvelopeState.AttackUp: return(attackUpEndSample); case EnvelopeState.AttackDown: return(attackDownEndSample); case EnvelopeState.Sustain: return(sustainEndSample); case EnvelopeState.Released: return(int.MaxValue); case EnvelopeState.ImmediateRelease: return(int.MaxValue); default: Debug.LogError($"Unexpected EnvelopeState: {state}"); goto case EnvelopeState.ImmediateRelease; } }
private double EnvelopeRate(EnvelopeState state) { switch (state) { case EnvelopeState.AttackUp: return(attackUpGrowthRate); case EnvelopeState.AttackDown: return(attackDownDecayRate); case EnvelopeState.Sustain: return(sustainDecayRate); case EnvelopeState.Released: return(releaseDecayRate); case EnvelopeState.ImmediateRelease: return(immediateDecayRate); default: Debug.LogError($"Unexpected EnvelopeState: {state}"); goto case EnvelopeState.ImmediateRelease; } }
private void DetermineEnvelopeStartingPoint() { State = EnvelopeState.Two; // This isn't actually placed in this func bool atLeastOneThingIsValid = CMDB1___sub_2074CA0(); // Neither is this if (atLeastOneThingIsValid) { if (attack != 0) { velocity = attackVolume << 23; State = EnvelopeState.Hold; UpdateEnvelopePlan(0x7F, attack); } else { velocity = 0x7F << 23; if (hold != 0) { UpdateEnvelopePlan(0x7F, hold); State = EnvelopeState.Decay; } else if (decay != 0) { UpdateEnvelopePlan(sustain, decay); State = EnvelopeState.Decay2; } else { UpdateEnvelopePlan(0, release); State = EnvelopeState.Six; } } // Unk1E = 1 } else if (State != EnvelopeState.One) // What should it be? { State = EnvelopeState.Zero; velocity = 0x7F << 23; } }
/// <summary> /// Read the next volume multiplier from the envelope generator /// </summary> /// <returns>A volume multiplier</returns> public float Process() { switch (state) { case EnvelopeState.Idle: break; case EnvelopeState.Attack: output = attackBase + output * attackCoef; if (output >= 1.0f) { output = 1.0f; state = EnvelopeState.Decay; } break; case EnvelopeState.Decay: output = decayBase + output * decayCoef; if (output <= sustainLevel) { output = sustainLevel; state = EnvelopeState.Sustain; } break; case EnvelopeState.Sustain: break; case EnvelopeState.Release: output = releaseBase + output * releaseCoef; if (output <= 0.0) { output = 0.0f; state = EnvelopeState.Idle; } break; } return(output); }
// Returns whether the note is active or not public virtual bool TickNote() { if (State < EnvelopeState.Releasing) { if (Note.Duration > 0) { Note.Duration--; if (Note.Duration == 0) { State = EnvelopeState.Releasing; return(false); } return(true); } else { return(true); } } else { return(false); } }
public override void Reset () { base.Reset(); State = EnvelopeState.Off; }
/// <summary> /// エンベロープの状態をサイレンス状態に変更します。 /// </summary> public void Silence() { this.state = EnvelopeState.Silence; }
public override float Next () { switch (state) { case EnvelopeState.Off: break; case EnvelopeState.Attack: phase += AudioProperties.Interval * attack; output = Mathf.Lerp(0.0f, 1.0f, phase); if (phase >= 1.0f) { State = EnvelopeState.Decay; } break; case EnvelopeState.Decay: phase += AudioProperties.Interval * decay; output = Mathf.Lerp(1.0f, sustain, phase); if (phase >= 1.0f) { State = EnvelopeState.Sustain; } break; case EnvelopeState.Sustain: output = sustain; break; case EnvelopeState.Release: phase += AudioProperties.Interval * release; output = Mathf.Lerp(releaseOutput, 0.0f, phase); if (phase >= 1.0) { State = EnvelopeState.Off; } break; } return output; }
/// <summary> /// Trigger the gate /// </summary> /// <param name="gate">If true, enter attack phase, if false enter release phase (unless already idle)</param> public void Gate(bool gate) { if (gate) state = EnvelopeState.Attack; else if (state != EnvelopeState.Idle) state = EnvelopeState.Release; }
/// <summary> /// Read the next volume multiplier from the envelope generator /// </summary> /// <returns>A volume multiplier</returns> public float Process() { switch (state) { case EnvelopeState.Idle: break; case EnvelopeState.Attack: output = attackBase + output * attackCoef; if (output >= 1.0f) { output = 1.0f; state = EnvelopeState.Decay; } break; case EnvelopeState.Decay: output = decayBase + output * decayCoef; if (output <= sustainLevel) { output = sustainLevel; state = EnvelopeState.Sustain; } break; case EnvelopeState.Sustain: break; case EnvelopeState.Release: output = releaseBase + output * releaseCoef; if (output <= 0.0) { output = 0.0f; state = EnvelopeState.Idle; } break; } return output; }
/// <summary> /// 現在のエンベロープの状態に基づき、エンベロープ値を出力します。 /// </summary> /// <param name="time">エンベロープの開始時間値。</param> /// <param name="envelopes">出力が格納される実数の配列。</param> /// <param name="offset">代入が開始される配列のインデックス。</param> /// <param name="count">代入される実数値の数。</param> public void Generate(int time, float[] envelopes, int count) { float res; for (int i = 0; i < count; i++, time++) { if (this.State == EnvelopeState.Attack) res = (time < this.attackTime) ? time * this.da : (time < this.t2) ? 1.0f : (time < this.t3) ? 1.0f - (time - this.t2) * this.dd : this.sustainLevel; else if (this.State == EnvelopeState.Release) if (time < this.t5) res = this.sustainLevel - (time - this.releaseStartTime) * this.dr; else { res = 0.0f; this.state = EnvelopeState.Silence; } else res = 0.0f; envelopes[i] = res; } }
/// <summary> /// Reset to idle state /// </summary> public void Reset() { state = EnvelopeState.Idle; output = 0.0f; }
public void Start () { State = EnvelopeState.Attack; }
public void Stop () { if (State != EnvelopeState.Off) { State = EnvelopeState.Release; } }