diff --git a/src/mumble/AudioConfigDialog.cpp b/src/mumble/AudioConfigDialog.cpp index 0ef432dc978..07871cfceab 100644 --- a/src/mumble/AudioConfigDialog.cpp +++ b/src/mumble/AudioConfigDialog.cpp @@ -866,22 +866,22 @@ void AudioOutputDialog::on_qsbMinimumDistance_valueChanged(double value) { qsMinDistance->setValue(value * 10); // Ensure that max distance is always a least 1m larger than min distance - qsMaxDistance->setValue(std::max(qsMaxDistance->value(), static_cast< int >(value * 10) + 1)); + qsMaxDistance->setValue(std::max(qsMaxDistance->value(), static_cast< int >(value * 10) + 10)); } void AudioOutputDialog::on_qsMaxDistance_valueChanged(int value) { QSignalBlocker blocker(qsbMaximumDistance); qsbMaximumDistance->setValue(value / 10.0f); - // Ensure that max distance is always a least 1m larger than min distance + // Ensure that min distance is always a least 1m less than max distance qsbMinimumDistance->setValue(std::min(qsbMinimumDistance->value(), (value / 10.0) - 1)); } void AudioOutputDialog::on_qsbMaximumDistance_valueChanged(double value) { QSignalBlocker blocker(qsMaxDistance); qsMaxDistance->setValue(value * 10); - // Ensure that max distance is always a least 1m larger than min distance - qsMinDistance->setValue(std::min(qsMinDistance->value(), static_cast< int >(value * 10) - 1)); + // Ensure that min distance is always a least 1m less than max distance + qsMinDistance->setValue(std::min(qsMinDistance->value(), static_cast< int >(value * 10) - 10)); } void AudioOutputDialog::on_qsMinimumVolume_valueChanged(int value) { diff --git a/src/mumble/AudioOutput.cpp b/src/mumble/AudioOutput.cpp index 3994491d15b..d8e80e9073a 100644 --- a/src/mumble/AudioOutput.cpp +++ b/src/mumble/AudioOutput.cpp @@ -100,18 +100,30 @@ AudioOutput::~AudioOutput() { float AudioOutput::calcGain(float dotproduct, float distance) { // dotproduct is in the range [-1, 1], thus we renormalize it to the range [0, 1] float dotfactor = (dotproduct + 1.0f) / 2.0f; - float att; + // Volume on the ear opposite to the sound should never reach 0 in the real world. + // Therefore, we define the minimum volume as 1/4th of the theoretical maximum (ignoring + // the sound direction but taking distance into account) for _any_ ear. + const float offset = (1.0f - dotfactor) * 0.25f; + dotfactor += offset; + + float att; - // No distance attenuation - if (Global::get().s.fAudioMaxDistVolume > 0.99f) { - att = qMin(1.0f, dotfactor + Global::get().s.fAudioBloom); + if (distance < 0.01f) { + // Listener is "inside" source -> no attenuation + // Without this extra check, we would have a dotfactor of 0.5 + // despite being numerically inside the source leading to a loss + // of volume. + att = 1.0f; + } else if (Global::get().s.fAudioMaxDistVolume > 0.99f) { + // User selected no distance attenuation + att = std::min(1.0f, dotfactor + Global::get().s.fAudioBloom); } else if (distance < Global::get().s.fAudioMinDistance) { // Fade in blooming as soon as the sound source enters fAudioMinDistance and increase it to its full // capability when the audio source is at the same position as the local player float bloomfac = Global::get().s.fAudioBloom * (1.0f - distance / Global::get().s.fAudioMinDistance); - att = qMin(1.0f, bloomfac + dotfactor); + att = std::min(1.0f, bloomfac + dotfactor); } else { float datt; @@ -119,8 +131,9 @@ float AudioOutput::calcGain(float dotproduct, float distance) { datt = Global::get().s.fAudioMaxDistVolume; } else { float mvol = Global::get().s.fAudioMaxDistVolume; - if (mvol < 0.01f) - mvol = 0.01f; + if (mvol < 0.005f) { + mvol = 0.005f; + } float drel = (distance - Global::get().s.fAudioMinDistance) / (Global::get().s.fAudioMaxDistance - Global::get().s.fAudioMinDistance); @@ -660,21 +673,30 @@ bool AudioOutput::mix(void *outbuff, unsigned int frameCount) { } } + const bool isAudible = + (Global::get().s.fAudioMaxDistVolume > 0) || (len < Global::get().s.fAudioMaxDistance); + for (unsigned int s = 0; s < nchan; ++s) { const float dot = bSpeakerPositional[s] ? connectionVec.x * speaker[s * 3 + 0] + connectionVec.y * speaker[s * 3 + 1] + connectionVec.z * speaker[s * 3 + 2] : 1.0f; - // Volume on the ear opposite to the sound should never reach 0 in the real world. - // The gain is multiplied by 19/20 and 1/20 is added. This will have the effect - // of bringing the lowest value up to 1/20, while keeping the highest value at 1. - // E.g. calcGain() = 1; 1 * 19/20 + 1/20 = 0.95 + 0.05 = 1 - // calcGain() = 0; 0 * 19/20 + 1/20 = 0 + 0.05 = 0.05 - const float str = svol[s] * (1 / 20.0 + (19 / 20.0) * calcGain(dot, len)) * volumeAdjustment; + float channelVol; + if (isAudible) { + // In the current contex, we know that sound reaches at least one ear. + channelVol = svol[s] * calcGain(dot, len) * volumeAdjustment; + } else { + // The user has set the minimum positional volume to 0 and this sound source + // is exceeding the positional volume range. This means that the sound is completely + // inaudible at the current position. We therefore set the volume the to 0, + // making sure the user really can not hear any audio from that source. + channelVol = 0; + } + float *RESTRICT o = output + s; - const float old = (buffer->pfVolume[s] >= 0.0f) ? buffer->pfVolume[s] : str; - const float inc = (str - old) / static_cast< float >(frameCount); - buffer->pfVolume[s] = str; + const float old = (buffer->pfVolume[s] >= 0.0f) ? buffer->pfVolume[s] : channelVol; + const float inc = (channelVol - old) / static_cast< float >(frameCount); + buffer->pfVolume[s] = channelVol; // Calculates the ITD offset of the audio data this frame. // Interaural Time Delay (ITD) is a small time delay between your ears @@ -692,10 +714,10 @@ bool AudioOutput::mix(void *outbuff, unsigned int frameCount) { const float incOffset = (offset - oldOffset) / static_cast< float >(frameCount); buffer->piOffset[s] = offset; /* - qWarning("%d: Pos %f %f %f : Dot %f Len %f Str %f", s, speaker[s*3+0], - speaker[s*3+1], speaker[s*3+2], dot, len, str); + qWarning("%d: Pos %f %f %f : Dot %f Len %f ChannelVol %f", s, speaker[s*3+0], + speaker[s*3+1], speaker[s*3+2], dot, len, channelVol); */ - if ((old >= 0.00000001f) || (str >= 0.00000001f)) { + if ((old >= 0.00000001f) || (channelVol >= 0.00000001f)) { for (unsigned int i = 0; i < frameCount; ++i) { unsigned int currentOffset = oldOffset + incOffset * i; if (speech && speech->bStereo) { @@ -714,8 +736,8 @@ bool AudioOutput::mix(void *outbuff, unsigned int frameCount) { // Mix the current audio source into the output by adding it to the elements of the output buffer after // having applied a volume adjustment for (unsigned int s = 0; s < nchan; ++s) { - const float str = svol[s] * volumeAdjustment; - float *RESTRICT o = output + s; + const float channelVol = svol[s] * volumeAdjustment; + float *RESTRICT o = output + s; if (buffer->bStereo) { // Linear-panning stereo stream according to the projection of fSpeaker vector on left-right // direction. @@ -723,10 +745,10 @@ bool AudioOutput::mix(void *outbuff, unsigned int frameCount) { for (unsigned int i = 0; i < frameCount; ++i) o[i * nchan] += (pfBuffer[2 * i] * fStereoPanningFactor[2 * s + 0] + pfBuffer[2 * i + 1] * fStereoPanningFactor[2 * s + 1]) - * str; + * channelVol; } else { for (unsigned int i = 0; i < frameCount; ++i) - o[i * nchan] += pfBuffer[i] * str; + o[i * nchan] += pfBuffer[i] * channelVol; } } } diff --git a/src/mumble/ManualPlugin.cpp b/src/mumble/ManualPlugin.cpp index 5c811e97af5..bf7260aa635 100644 --- a/src/mumble/ManualPlugin.cpp +++ b/src/mumble/ManualPlugin.cpp @@ -23,7 +23,7 @@ static QPointer< Manual > mDlg = nullptr; static bool bLinkable = false; static bool bActive = true; -static int iAzimuth = 180; +static int iAzimuth = 0; static int iElevation = 0; static const QString defaultContext = QString::fromLatin1("Mumble"); @@ -52,8 +52,8 @@ Manual::Manual(QWidget *p) : QDialog(p) { // The center of the indicator's circle will represent the current position indicator.addEllipse(QRectF(-indicatorDiameter / 2, -indicatorDiameter / 2, indicatorDiameter, indicatorDiameter)); // A line will indicate the indicator's orientation (azimuth) - indicator.moveTo(0, indicatorDiameter / 2); - indicator.lineTo(0, indicatorDiameter); + indicator.moveTo(0, -indicatorDiameter / 2); + indicator.lineTo(0, -indicatorDiameter); m_qgiPosition = m_qgsScene->addPath(indicator);