1
0
mirror of https://github.com/qTox/qTox.git synced 2024-03-22 14:00:36 +08:00

refactor(avform): simplify and standardize sliders, use RMS for volume

Also improve usefulness of volume bar by including gain, clipping, and activation threshold. Remove magic numbers. Clear volumue display when mic is disabled.

Fix #4893
This commit is contained in:
Anthony Bilinski 2018-04-10 22:39:50 -07:00
parent f6622e4092
commit 1583991fb4
No known key found for this signature in database
GPG Key ID: 2AA8E0DA1B31FB3C
8 changed files with 116 additions and 100 deletions

View File

@ -62,6 +62,8 @@ public:
virtual qreal outputVolume() const = 0; virtual qreal outputVolume() const = 0;
virtual void setOutputVolume(qreal volume) = 0; virtual void setOutputVolume(qreal volume) = 0;
virtual qreal maxOutputVolume() const = 0;
virtual qreal minOutputVolume() const = 0;
virtual qreal minInputGain() const = 0; virtual qreal minInputGain() const = 0;
virtual void setMinInputGain(qreal dB) = 0; virtual void setMinInputGain(qreal dB) = 0;
@ -73,10 +75,7 @@ public:
virtual void setInputGain(qreal dB) = 0; virtual void setInputGain(qreal dB) = 0;
virtual qreal minInputThreshold() const = 0; virtual qreal minInputThreshold() const = 0;
virtual void setMinInputThreshold(qreal dB) = 0;
virtual qreal maxInputThreshold() const = 0; virtual qreal maxInputThreshold() const = 0;
virtual void setMaxInputThreshold(qreal dB) = 0;
virtual qreal getInputThreshold() const = 0; virtual qreal getInputThreshold() const = 0;
virtual void setInputThreshold(qreal percent) = 0; virtual void setInputThreshold(qreal percent) = 0;
@ -109,8 +108,9 @@ protected:
// Public default audio settings // Public default audio settings
static constexpr uint32_t AUDIO_SAMPLE_RATE = 48000; static constexpr uint32_t AUDIO_SAMPLE_RATE = 48000;
static constexpr uint32_t AUDIO_FRAME_DURATION = 20; static constexpr uint32_t AUDIO_FRAME_DURATION = 20;
static constexpr uint32_t AUDIO_FRAME_SAMPLE_COUNT = static constexpr uint32_t AUDIO_FRAME_SAMPLE_COUNT_PER_CHANNEL =
AUDIO_FRAME_DURATION * AUDIO_SAMPLE_RATE / 1000; AUDIO_FRAME_DURATION * AUDIO_SAMPLE_RATE / 1000;
uint32_t AUDIO_FRAME_SAMPLE_COUNT_TOTAL = 0;
signals: signals:
void frameAvailable(const int16_t* pcm, size_t sample_count, uint8_t channels, void frameAvailable(const int16_t* pcm, size_t sample_count, uint8_t channels,

View File

@ -32,6 +32,18 @@
#include <cassert> #include <cassert>
namespace {
void applyGain(int16_t* buffer, uint32_t bufferSize, qreal gainFactor)
{
for (quint32 i = 0; i < bufferSize; ++i) {
// gain amplification with clipping to 16-bit boundaries
buffer[i] = qBound<int16_t>(std::numeric_limits<int16_t>::min(),
qRound(buffer[i] * gainFactor),
std::numeric_limits<int16_t>::max());
}
}
}
/** /**
* @class OpenAL * @class OpenAL
* @brief Provides the OpenAL audio backend * @brief Provides the OpenAL audio backend
@ -181,7 +193,7 @@ void OpenAL::setMaxInputGain(qreal dB)
/** /**
* @brief The minimum threshold value for an input device. * @brief The minimum threshold value for an input device.
* *
* @return minimum threshold percentage * @return minimum normalized threshold
*/ */
qreal OpenAL::minInputThreshold() const qreal OpenAL::minInputThreshold() const
{ {
@ -190,20 +202,9 @@ qreal OpenAL::minInputThreshold() const
} }
/** /**
* @brief Set the minimum allowed threshold percentage * @brief The maximum normalized threshold value for an input device.
* *
* @note Default is 0%; usually you don't need to alter this value; * @return maximum normalized threshold
*/
void OpenAL::setMinInputThreshold(qreal percent)
{
QMutexLocker locker(&audioLock);
minInThreshold = percent;
}
/**
* @brief The maximum threshold value for an input device.
*
* @return maximum threshold percentage
*/ */
qreal OpenAL::maxInputThreshold() const qreal OpenAL::maxInputThreshold() const
{ {
@ -211,17 +212,6 @@ qreal OpenAL::maxInputThreshold() const
return maxInThreshold; return maxInThreshold;
} }
/**
* @brief Set the maximum allowed threshold percentage
*
* @note Default is 40%; usually you don't need to alter this value.
*/
void OpenAL::setMaxInputThreshold(qreal percent)
{
QMutexLocker locker(&audioLock);
maxInThreshold = percent;
}
void OpenAL::reinitInput(const QString& inDevDesc) void OpenAL::reinitInput(const QString& inDevDesc)
{ {
QMutexLocker locker(&audioLock); QMutexLocker locker(&audioLock);
@ -311,15 +301,15 @@ bool OpenAL::initInput(const QString& deviceName, uint32_t channels)
// TODO: Try to actually detect if our audio source is stereo // TODO: Try to actually detect if our audio source is stereo
this->channels = channels; this->channels = channels;
int stereoFlag = channels == 1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16; int stereoFlag = channels == 1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16;
const uint32_t sampleRate = AUDIO_SAMPLE_RATE;
const uint16_t frameDuration = AUDIO_FRAME_DURATION;
const int bytesPerSample = 2; const int bytesPerSample = 2;
const int safetyFactor = 2; const int safetyFactor = 2; // internal OpenAL ring buffer. must be larger than our inputBuffer to avoid the ring
const ALCsizei bufSize = AUDIO_FRAME_SAMPLE_COUNT * channels * bytesPerSample * safetyFactor; // from overwriting itself between captures.
AUDIO_FRAME_SAMPLE_COUNT_TOTAL = AUDIO_FRAME_SAMPLE_COUNT_PER_CHANNEL * channels;
const ALCsizei ringBufSize = AUDIO_FRAME_SAMPLE_COUNT_TOTAL * bytesPerSample * safetyFactor;
const QByteArray qDevName = deviceName.toUtf8(); const QByteArray qDevName = deviceName.toUtf8();
const ALchar* tmpDevName = qDevName.isEmpty() ? nullptr : qDevName.constData(); const ALchar* tmpDevName = qDevName.isEmpty() ? nullptr : qDevName.constData();
alInDev = alcCaptureOpenDevice(tmpDevName, sampleRate, stereoFlag, bufSize); alInDev = alcCaptureOpenDevice(tmpDevName, AUDIO_SAMPLE_RATE, stereoFlag, ringBufSize);
// Restart the capture if necessary // Restart the capture if necessary
if (!alInDev) { if (!alInDev) {
@ -327,7 +317,7 @@ bool OpenAL::initInput(const QString& deviceName, uint32_t channels)
return false; return false;
} }
inputBuffer = new int16_t[AUDIO_FRAME_SAMPLE_COUNT * channels]; inputBuffer = new int16_t[AUDIO_FRAME_SAMPLE_COUNT_TOTAL];
setInputGain(Settings::getInstance().getAudioInGainDecibel()); setInputGain(Settings::getInstance().getAudioInGainDecibel());
setInputThreshold(Settings::getInstance().getAudioThreshold()); setInputThreshold(Settings::getInstance().getAudioThreshold());
@ -542,17 +532,22 @@ void OpenAL::playMono16SoundCleanup()
* *
* @param[in] buf the current audio buffer * @param[in] buf the current audio buffer
* *
* @return volume in percent of max volume * @return normalized volume between 0-1
*/ */
float OpenAL::getVolume() float OpenAL::getVolume()
{ {
quint32 samples = AUDIO_FRAME_SAMPLE_COUNT * channels; const quint32 samples = AUDIO_FRAME_SAMPLE_COUNT_TOTAL;
float sum = 0.0; const float rootTwo = 1.414213562; // sqrt(2), but sqrt is not constexpr
// calculate volume as the root mean squared of amplitudes in the sample
float sumOfSquares = 0;
for (quint32 i = 0; i < samples; i++) { for (quint32 i = 0; i < samples; i++) {
float sample = static_cast<float>(inputBuffer[i]) / std::numeric_limits<int16_t>::max(); float sample = static_cast<float>(inputBuffer[i]) / std::numeric_limits<int16_t>::max();
sum += qAbs(sample); sumOfSquares += std::pow(sample , 2);
} }
return sum / samples; const float rms = std::sqrt(sumOfSquares/samples);
// our calculated normalized volume could possibly be above 1 because our RMS assumes a sinusoidal wave
const float normalizedVolume = std::min(rms * rootTwo, 1.0f);
return normalizedVolume;
} }
/** /**
@ -570,16 +565,20 @@ void OpenAL::doInput()
{ {
ALint curSamples = 0; ALint curSamples = 0;
alcGetIntegerv(alInDev, ALC_CAPTURE_SAMPLES, sizeof(curSamples), &curSamples); alcGetIntegerv(alInDev, ALC_CAPTURE_SAMPLES, sizeof(curSamples), &curSamples);
if (curSamples < static_cast<ALint>(AUDIO_FRAME_SAMPLE_COUNT)) { if (curSamples < static_cast<ALint>(AUDIO_FRAME_SAMPLE_COUNT_PER_CHANNEL)) {
return; return;
} }
captureSamples(alInDev, inputBuffer, AUDIO_FRAME_SAMPLE_COUNT); captureSamples(alInDev, inputBuffer, AUDIO_FRAME_SAMPLE_COUNT_PER_CHANNEL);
applyGain(inputBuffer, AUDIO_FRAME_SAMPLE_COUNT_TOTAL, gainFactor);
float volume = getVolume(); float volume = getVolume();
if (volume >= inputThreshold) { if (volume >= inputThreshold) {
isActive = true; isActive = true;
emit startActive(voiceHold); emit startActive(voiceHold);
} else if (!isActive) {
volume = 0;
} }
emit Audio::volumeAvailable(volume); emit Audio::volumeAvailable(volume);
@ -587,14 +586,7 @@ void OpenAL::doInput()
return; return;
} }
for (quint32 i = 0; i < AUDIO_FRAME_SAMPLE_COUNT * channels; ++i) { emit Audio::frameAvailable(inputBuffer, AUDIO_FRAME_SAMPLE_COUNT_PER_CHANNEL, channels, AUDIO_SAMPLE_RATE);
// gain amplification with clipping to 16-bit boundaries
inputBuffer[i] = qBound<int16_t>(std::numeric_limits<int16_t>::min(),
qRound(inputBuffer[i] * OpenAL::inputGainFactor()),
std::numeric_limits<int16_t>::max());
}
emit Audio::frameAvailable(inputBuffer, AUDIO_FRAME_SAMPLE_COUNT, channels, AUDIO_SAMPLE_RATE);
} }
void OpenAL::doOutput() void OpenAL::doOutput()
@ -757,8 +749,7 @@ void OpenAL::setInputGain(qreal dB)
gainFactor = qPow(10.0, (gain / 20.0)); gainFactor = qPow(10.0, (gain / 20.0));
} }
void OpenAL::setInputThreshold(qreal percent) void OpenAL::setInputThreshold(qreal normalizedThreshold)
{ {
inputThreshold = percent; inputThreshold = normalizedThreshold;
} }

View File

@ -48,6 +48,8 @@ public:
OpenAL(); OpenAL();
virtual ~OpenAL(); virtual ~OpenAL();
qreal maxOutputVolume() const { return 1; }
qreal minOutputVolume() const { return 0; }
qreal outputVolume() const; qreal outputVolume() const;
void setOutputVolume(qreal volume); void setOutputVolume(qreal volume);
@ -61,13 +63,10 @@ public:
void setInputGain(qreal dB); void setInputGain(qreal dB);
qreal minInputThreshold() const; qreal minInputThreshold() const;
void setMinInputThreshold(qreal percent);
qreal maxInputThreshold() const; qreal maxInputThreshold() const;
void setMaxInputThreshold(qreal percent);
qreal getInputThreshold() const; qreal getInputThreshold() const;
void setInputThreshold(qreal percent); void setInputThreshold(qreal normalizedThreshold);
void reinitInput(const QString& inDevDesc); void reinitInput(const QString& inDevDesc);
bool reinitOutput(const QString& outDevDesc); bool reinitOutput(const QString& outDevDesc);
@ -137,13 +136,13 @@ protected:
qreal gainFactor = 1; qreal gainFactor = 1;
qreal minInGain = -30; qreal minInGain = -30;
qreal maxInGain = 30; qreal maxInGain = 30;
qreal inputThreshold; qreal inputThreshold = 0;
qreal voiceHold = 250; qreal voiceHold = 250;
bool isActive = false; bool isActive = false;
QTimer voiceTimer; QTimer voiceTimer;
qreal minInThreshold = 0.0; const qreal minInThreshold = 0.0;
qreal maxInThreshold = 0.4; const qreal maxInThreshold = 0.4;
int16_t* inputBuffer; int16_t* inputBuffer = nullptr;
}; };
#endif // OPENAL_H #endif // OPENAL_H

View File

@ -321,13 +321,13 @@ void OpenAL2::doOutput()
alGetSourcedvSOFT(alProxySource, AL_SEC_OFFSET_LATENCY_SOFT, latency); alGetSourcedvSOFT(alProxySource, AL_SEC_OFFSET_LATENCY_SOFT, latency);
checkAlError(); checkAlError();
ALshort outBuf[AUDIO_FRAME_SAMPLE_COUNT] = {0}; ALshort outBuf[AUDIO_FRAME_SAMPLE_COUNT_PER_CHANNEL] = {0};
alcMakeContextCurrent(alProxyContext); alcMakeContextCurrent(alProxyContext);
alcRenderSamplesSOFT(alProxyDev, outBuf, AUDIO_FRAME_SAMPLE_COUNT); alcRenderSamplesSOFT(alProxyDev, outBuf, AUDIO_FRAME_SAMPLE_COUNT_PER_CHANNEL);
checkAlcError(alProxyDev); checkAlcError(alProxyDev);
alcMakeContextCurrent(alOutContext); alcMakeContextCurrent(alOutContext);
alBufferData(bufids[0], AL_FORMAT_MONO16, outBuf, AUDIO_FRAME_SAMPLE_COUNT * 2, AUDIO_SAMPLE_RATE); alBufferData(bufids[0], AL_FORMAT_MONO16, outBuf, AUDIO_FRAME_SAMPLE_COUNT_PER_CHANNEL * 2, AUDIO_SAMPLE_RATE);
alSourceQueueBuffers(alProxySource, 1, bufids); alSourceQueueBuffers(alProxySource, 1, bufids);
// initialize echo canceler if supported // initialize echo canceler if supported
@ -340,7 +340,7 @@ void OpenAL2::doOutput()
} }
// do echo cancel // do echo cancel
pass_audio_output(filterer, outBuf, AUDIO_FRAME_SAMPLE_COUNT); pass_audio_output(filterer, outBuf, AUDIO_FRAME_SAMPLE_COUNT_PER_CHANNEL);
ALint state; ALint state;
alGetSourcei(alProxySource, AL_SOURCE_STATE, &state); alGetSourcei(alProxySource, AL_SOURCE_STATE, &state);

View File

@ -26,6 +26,8 @@ public:
virtual void setAudioThreshold(qreal percent) = 0; virtual void setAudioThreshold(qreal percent) = 0;
virtual int getOutVolume() const = 0; virtual int getOutVolume() const = 0;
virtual int getOutVolumeMin() const = 0;
virtual int getOutVolumeMax() const = 0;
virtual void setOutVolume(int volume) = 0; virtual void setOutVolume(int volume) = 0;
virtual int getAudioBitrate() const = 0; virtual int getAudioBitrate() const = 0;

View File

@ -353,6 +353,8 @@ public:
void setAudioThreshold(qreal percent) override; void setAudioThreshold(qreal percent) override;
int getOutVolume() const override; int getOutVolume() const override;
int getOutVolumeMin() const override { return 0; }
int getOutVolumeMax() const override { return 100; }
void setOutVolume(int volume) override; void setOutVolume(int volume) override;
int getAudioBitrate() const override; int getAudioBitrate() const override;

View File

@ -70,32 +70,33 @@ AVForm::AVForm(Audio* audio, CoreAV* coreAV, CameraSource& camera,
connect(rescanButton, &QPushButton::clicked, this, &AVForm::rescanDevices); connect(rescanButton, &QPushButton::clicked, this, &AVForm::rescanDevices);
playbackSlider->setTracking(false); playbackSlider->setTracking(false);
playbackSlider->setValue(audioSettings->getOutVolume()); playbackSlider->setMaximum(totalSliderSteps);
playbackSlider->setValue(getStepsFromValue(audioSettings->getOutVolume(),
audioSettings->getOutVolumeMin(), audioSettings->getOutVolumeMax()));
playbackSlider->installEventFilter(this); playbackSlider->installEventFilter(this);
microphoneSlider->setToolTip(tr("Use slider to set the gain of your input device ranging" microphoneSlider->setToolTip(tr("Use slider to set the gain of your input device ranging"
" from %1dB to %2dB.") " from %1dB to %2dB.")
.arg(audio->minInputGain()) .arg(audio->minInputGain())
.arg(audio->maxInputGain())); .arg(audio->maxInputGain()));
microphoneSlider->setMinimum(qRound(audio->minInputGain()) * 10); microphoneSlider->setMaximum(totalSliderSteps);
microphoneSlider->setMaximum(qRound(audio->maxInputGain()) * 10);
microphoneSlider->setTickPosition(QSlider::TicksBothSides); microphoneSlider->setTickPosition(QSlider::TicksBothSides);
microphoneSlider->setTickInterval( static const int numTicks = 4;
(qAbs(microphoneSlider->minimum()) + microphoneSlider->maximum()) / 4); microphoneSlider->setTickInterval(totalSliderSteps / numTicks);
microphoneSlider->setTracking(false); microphoneSlider->setTracking(false);
microphoneSlider->installEventFilter(this); microphoneSlider->installEventFilter(this);
microphoneSlider->setValue(getStepsFromValue(audio->inputGain(), audio->minInputGain(), audio->maxInputGain()));
audioThresholdSlider->setToolTip(tr("Use slider to set the activation volume for your" audioThresholdSlider->setToolTip(tr("Use slider to set the activation volume for your"
" input device.")); " input device."));
audioThresholdSlider->setMinimum(audio->minInputThreshold() * 1000); audioThresholdSlider->setMaximum(totalSliderSteps);
audioThresholdSlider->setMaximum(audio->maxInputThreshold() * 1000); audioThresholdSlider->setValue(getStepsFromValue(audioSettings->getAudioThreshold(),
audioThresholdSlider->setValue(audioSettings->getAudioThreshold() * 1000); audio->minInputThreshold(), audio->maxInputThreshold()));
audioThresholdSlider->setTracking(false); audioThresholdSlider->setTracking(false);
audioThresholdSlider->installEventFilter(this); audioThresholdSlider->installEventFilter(this);
connect(audio, &Audio::volumeAvailable, this, &AVForm::setVolume); connect(audio, &Audio::volumeAvailable, this, &AVForm::setVolume);
volumeDisplay->setMinimum(audio->minInputThreshold() * 1000); volumeDisplay->setMaximum(totalSliderSteps);
volumeDisplay->setMaximum(audio->maxInputThreshold() * 1000);
fillAudioQualityComboBox(); fillAudioQualityComboBox();
@ -166,7 +167,7 @@ void AVForm::rescanDevices()
void AVForm::setVolume(float value) void AVForm::setVolume(float value)
{ {
volumeDisplay->setValue(value * 1000); volumeDisplay->setValue(getStepsFromValue(value, audio->minOutputVolume(), audio->maxOutputVolume()));
} }
void AVForm::on_cbEnableBackend2_stateChanged() void AVForm::on_cbEnableBackend2_stateChanged()
@ -521,41 +522,51 @@ void AVForm::getAudioOutDevices()
void AVForm::on_inDevCombobox_currentIndexChanged(int deviceIndex) void AVForm::on_inDevCombobox_currentIndexChanged(int deviceIndex)
{ {
audioSettings->setAudioInDevEnabled(deviceIndex != 0); const bool inputEnabled = deviceIndex > 0;
audioSettings->setAudioInDevEnabled(inputEnabled);
QString deviceName; QString deviceName;
if (deviceIndex > 0) if (inputEnabled) {
deviceName = inDevCombobox->itemText(deviceIndex); deviceName = inDevCombobox->itemText(deviceIndex);
}
audioSettings->setInDev(deviceName); audioSettings->setInDev(deviceName);
audio->reinitInput(deviceName); audio->reinitInput(deviceName);
microphoneSlider->setEnabled(deviceIndex > 0); microphoneSlider->setEnabled(inputEnabled);
microphoneSlider->setSliderPosition(qRound(audio->inputGain() * 10.0)); if (!inputEnabled) {
volumeDisplay->setValue(volumeDisplay->minimum());
}
} }
void AVForm::on_outDevCombobox_currentIndexChanged(int deviceIndex) void AVForm::on_outDevCombobox_currentIndexChanged(int deviceIndex)
{ {
audioSettings->setAudioOutDevEnabled(deviceIndex != 0); const bool outputEnabled = deviceIndex > 0;
audioSettings->setAudioOutDevEnabled(outputEnabled);
QString deviceName; QString deviceName;
if (deviceIndex > 0) if (outputEnabled) {
deviceName = outDevCombobox->itemText(deviceIndex); deviceName = outDevCombobox->itemText(deviceIndex);
}
audioSettings->setOutDev(deviceName); audioSettings->setOutDev(deviceName);
audio->reinitOutput(deviceName); audio->reinitOutput(deviceName);
playbackSlider->setEnabled(deviceIndex > 0); playbackSlider->setEnabled(outputEnabled);
playbackSlider->setSliderPosition(qRound(audio->outputVolume() * 100.0)); playbackSlider->setSliderPosition(getStepsFromValue(audio->outputVolume(),
audio->minOutputVolume(), audio->maxOutputVolume()));
} }
void AVForm::on_playbackSlider_valueChanged(int value) void AVForm::on_playbackSlider_valueChanged(int sliderSteps)
{ {
audioSettings->setOutVolume(value); const int settingsVolume = getValueFromSteps(sliderSteps,
audioSettings->getOutVolumeMin(),audioSettings->getOutVolumeMax());
audioSettings->setOutVolume(settingsVolume);
if (audio->isOutputReady()) { if (audio->isOutputReady()) {
const qreal percentage = value / 100.0; const qreal volume = getValueFromSteps(sliderSteps, audio->minOutputVolume(), audio->maxOutputVolume());
audio->setOutputVolume(percentage); audio->setOutputVolume(volume);
if (cbEnableTestSound->isChecked()) if (cbEnableTestSound->isChecked())
audio->playMono16Sound(Audio::getSound(Audio::Sound::Test)); audio->playMono16Sound(Audio::getSound(Audio::Sound::Test));
@ -570,22 +581,19 @@ void AVForm::on_cbEnableTestSound_stateChanged()
audio->playMono16Sound(Audio::getSound(Audio::Sound::Test)); audio->playMono16Sound(Audio::getSound(Audio::Sound::Test));
} }
void AVForm::on_microphoneSlider_valueChanged(int value) void AVForm::on_microphoneSlider_valueChanged(int sliderSteps)
{ {
const qreal dB = value / 10.0; const qreal dB = getValueFromSteps(sliderSteps, audio->minInputGain(), audio->maxInputGain());
audioSettings->setAudioInGainDecibel(dB); audioSettings->setAudioInGainDecibel(dB);
audio->setInputGain(dB); audio->setInputGain(dB);
} }
void AVForm::on_audioThresholdSlider_valueChanged(int value) void AVForm::on_audioThresholdSlider_valueChanged(int sliderSteps)
{ {
const qreal percent = value / 1000.0; const qreal normThreshold = getValueFromSteps(sliderSteps, audio->minInputThreshold(), audio->maxInputThreshold());
audioSettings->setAudioThreshold(normThreshold);
audioSettings->setAudioThreshold(percent); Audio::getInstance().setInputThreshold(normThreshold);
Audio::getInstance().setInputThreshold(percent);
} }
void AVForm::createVideoSurface() void AVForm::createVideoSurface()
{ {
if (camVideoSurface) if (camVideoSurface)
@ -616,3 +624,14 @@ void AVForm::retranslateUi()
{ {
Ui::AVForm::retranslateUi(this); Ui::AVForm::retranslateUi(this);
} }
int AVForm::getStepsFromValue(qreal val, qreal valMin, qreal valMax)
{
const float norm = (val - valMin) / (valMax - valMin);
return norm * totalSliderSteps;
}
qreal AVForm::getValueFromSteps(int steps, qreal valMin, qreal valMax)
{
return (static_cast<float>(steps) / totalSliderSteps) * (valMax - valMin) + valMin;
}

View File

@ -68,10 +68,10 @@ private slots:
// audio // audio
void on_inDevCombobox_currentIndexChanged(int deviceIndex); void on_inDevCombobox_currentIndexChanged(int deviceIndex);
void on_outDevCombobox_currentIndexChanged(int deviceIndex); void on_outDevCombobox_currentIndexChanged(int deviceIndex);
void on_playbackSlider_valueChanged(int value); void on_playbackSlider_valueChanged(int sliderSteps);
void on_cbEnableTestSound_stateChanged(); void on_cbEnableTestSound_stateChanged();
void on_microphoneSlider_valueChanged(int value); void on_microphoneSlider_valueChanged(int sliderSteps);
void on_audioThresholdSlider_valueChanged(int value); void on_audioThresholdSlider_valueChanged(int sliderSteps);
void on_audioQualityComboBox_currentIndexChanged(int index); void on_audioQualityComboBox_currentIndexChanged(int index);
// camera // camera
@ -90,6 +90,8 @@ private:
void hideEvent(QHideEvent* event) final override; void hideEvent(QHideEvent* event) final override;
void showEvent(QShowEvent* event) final override; void showEvent(QShowEvent* event) final override;
void open(const QString& devName, const VideoMode& mode); void open(const QString& devName, const VideoMode& mode);
int getStepsFromValue(qreal val, qreal valMin, qreal valMax);
qreal getValueFromSteps(int steps, qreal valMin, qreal valMax);
private: private:
Audio* audio; Audio* audio;
@ -103,6 +105,7 @@ private:
QVector<QPair<QString, QString>> videoDeviceList; QVector<QPair<QString, QString>> videoDeviceList;
QVector<VideoMode> videoModes; QVector<VideoMode> videoModes;
uint alSource; uint alSource;
const uint totalSliderSteps = 100; // arbitrary number of steps to give slider a good "feel"
}; };
#endif #endif