Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed not releasing a pipe after fast switching between vave-based tremulant samples and regular pipe samples https://github.com/GrandOrgue/grandorgue/issues/2004 #2041

Merged
merged 4 commits into from
Dec 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
- Fixed not releasing a pipe after fast switching between vave-based tremulant samples and regular pipe samples https://github.com/GrandOrgue/grandorgue/issues/2004
- Removed support of MacOs 12
- Fixed hang if there were lots of unused ODF entries https://github.com/GrandOrgue/grandorgue/issues/1918
# 3.15.3 (2024-11-23)
Expand Down
64 changes: 46 additions & 18 deletions src/grandorgue/sound/GOSoundFader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,39 +32,67 @@ void GOSoundFader::Process(
unsigned nFrames, float *buffer, float externalVolume) {
// setup process

// Consider the velocity volume as part of the external volume
externalVolume *= m_VelocityVolume;

float startTargetVolumePoint = m_LastTargetVolumePoint;

// Calculate new m_LastTargetVolumePoint
// the target volume will be changed from startTargetVolumePoint to
// m_LastTargetVolumePoint during the nFrames
float targetVolumeDeltaPerFrame
= m_IncreasingDeltaPerFrame + m_DecreasingDeltaPerFrame;

if (targetVolumeDeltaPerFrame != 0.0f) {
m_LastTargetVolumePoint = std::clamp(
startTargetVolumePoint + targetVolumeDeltaPerFrame * nFrames,
0.0f,
m_TargetVolume);
unsigned framesLeftAfterIncreasing = nFrames;

// increasing section
if (m_IncreasingDeltaPerFrame > 0.0f) {
// we are increasing now
float newTargetVolumePoint
= m_LastTargetVolumePoint + m_IncreasingDeltaPerFrame * nFrames;

if (newTargetVolumePoint < m_TargetVolume) {
framesLeftAfterIncreasing = 0; // we are increase during the whole period
m_LastTargetVolumePoint = newTargetVolumePoint;
} else {
// we reach m_TargetVolume inside this nFrames period

if (m_LastTargetVolumePoint >= m_TargetVolume)
// target volume is reached. Stop increasing
// stop increasing
m_IncreasingDeltaPerFrame = 0.0f;
else if (m_LastTargetVolumePoint <= 0.0f)
// Decreasing is finished. Stop it.

// calculate how many frames left after increasing
framesLeftAfterIncreasing = nFrames
- unsigned((m_TargetVolume - m_LastTargetVolumePoint)
/ m_IncreasingDeltaPerFrame);

m_LastTargetVolumePoint = m_TargetVolume;
}
}

// decreasing section
if (framesLeftAfterIncreasing && m_DecreasingDeltaPerFrame > 0.0f) {
// decrease the volume
float newTargetVolumePoint = m_LastTargetVolumePoint
- m_DecreasingDeltaPerFrame * framesLeftAfterIncreasing;

if (newTargetVolumePoint > 0.0f) {
m_LastTargetVolumePoint = newTargetVolumePoint;
} else {
// stop decreasing
m_DecreasingDeltaPerFrame = 0.0f;
m_LastTargetVolumePoint = 0.0f;
}
}

if (m_LastExternalVolumePoint < 0.0f) // The first Process() call
m_LastExternalVolumePoint = externalVolume;
// Calculate the external volume
float targetExternalVolume = m_VelocityVolume * externalVolume;

if (m_LastExternalVolumePoint < 0.0f)
m_LastExternalVolumePoint = targetExternalVolume;

float startExternalVolumePoint = m_LastExternalVolumePoint;

// Calculate new m_LastExternalVolumePoint
// the target volume will be changed from startExternalVolumePoint to
// m_LastExternalVolumePoint during the nFrames period
if (externalVolume != startExternalVolumePoint)
m_LastExternalVolumePoint += (externalVolume - startExternalVolumePoint)
if (targetExternalVolume != startExternalVolumePoint)
m_LastExternalVolumePoint
+= (targetExternalVolume - startExternalVolumePoint)
// Assume that external volume is to be reached in MAX_FRAME_SIZE frames
* std::max(nFrames, EXTERNAL_VOLUME_CHANGE_FRAMES)
/ EXTERNAL_VOLUME_CHANGE_FRAMES;
Expand Down
17 changes: 16 additions & 1 deletion src/grandorgue/sound/GOSoundFader.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
#ifndef GOSOUNDFADER_H_
#define GOSOUNDFADER_H_

#include <assert.h>

/**
* This class is responsible for smoothly changing a volume of samples.
*
Expand Down Expand Up @@ -71,7 +73,20 @@ class GOSoundFader {
inline void StartDecreasingVolume(unsigned nFrames) {
// maybe m_TargetVolume has not yet been reached, but the velocity of
// decreasing should be the same as it has reached
m_DecreasingDeltaPerFrame = -(m_TargetVolume / nFrames);
m_DecreasingDeltaPerFrame = m_TargetVolume / nFrames;
if (m_IncreasingDeltaPerFrame > 0.0f) {
/*
The increasing has not yet finished. We are starting a "virtual"
decreasing from m_TargetVolume to 0.
The increasing processus will continue until it meet the "virtual"
decreasing one at the new m_TargetVolume. Let's calculate it
*/
assert(m_LastTargetVolumePoint < m_TargetVolume);
m_TargetVolume = (m_TargetVolume - m_LastTargetVolumePoint)
* m_IncreasingDeltaPerFrame
/ (m_IncreasingDeltaPerFrame + m_DecreasingDeltaPerFrame)
+ m_LastTargetVolumePoint;
}
}

inline float GetVelocityVolume() const { return m_VelocityVolume; }
Expand Down
Loading