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

Audio: persistent volume sliders, mic feedback and volume

This commit is contained in:
Nils Fenner 2015-10-18 10:15:02 +02:00
parent 1fc703c281
commit a2a32b61c4
No known key found for this signature in database
GPG Key ID: 9591A163FF9BE04C
10 changed files with 236 additions and 26 deletions

View File

@ -494,12 +494,13 @@ SOURCES += \
src/widget/friendlistlayout.cpp \
src/widget/genericchatitemlayout.cpp \
src/widget/categorywidget.cpp \
src/widget/tool/removefrienddialog.cpp \
src/widget/contentlayout.cpp \
src/widget/contentdialog.cpp \
src/video/genericnetcamview.cpp \
src/widget/tool/activatedialog.cpp \
src/widget/tool/movablewidget.cpp \
src/video/genericnetcamview.cpp \
src/widget/tool/micfeedbackwidget.cpp \
src/widget/tool/removefrienddialog.cpp \
src/video/groupnetcamview.cpp
HEADERS += \
@ -547,6 +548,7 @@ HEADERS += \
src/widget/contentlayout.h \
src/widget/contentdialog.h \
src/widget/tool/activatedialog.h \
src/widget/tool/micfeedbackwidget.h \
src/widget/tool/removefrienddialog.h \
src/widget/tool/movablewidget.h \
src/video/genericnetcamview.h \

View File

@ -45,6 +45,7 @@ ALCdevice* Audio::alOutDev{nullptr};
ALCcontext* Audio::alContext{nullptr};
ALuint Audio::alMainSource{0};
float Audio::outputVolume{1.0};
float Audio::inputVolume{1.0};
Audio& Audio::getInstance()
{
@ -99,6 +100,11 @@ void Audio::setOutputVolume(float volume)
}
}
void Audio::setInputVolume(float volume)
{
inputVolume = volume;
}
void Audio::suscribeInput()
{
if (!alInDev)
@ -366,6 +372,23 @@ bool Audio::tryCaptureSamples(uint8_t* buf, int framesize)
memset(buf, 0, framesize * 2 * av_DefaultSettings.audio_channels); // Avoid uninitialized values (Valgrind)
alcCaptureSamples(Audio::alInDev, buf, framesize);
if (inputVolume != 1)
{
int16_t* bufReal = reinterpret_cast<int16_t*>(buf);
for (int i = 0; i < framesize; ++i)
{
int sample = bufReal[i] * pow(inputVolume, 2);
if (sample < std::numeric_limits<int16_t>::min())
sample = std::numeric_limits<int16_t>::min();
else if (sample > std::numeric_limits<int16_t>::max())
sample = std::numeric_limits<int16_t>::max();
bufReal[i] = sample;
}
}
return true;
}

View File

@ -50,6 +50,7 @@ public:
static float getOutputVolume(); ///< Returns the current output volume, between 0 and 1
static void setOutputVolume(float volume); ///< The volume must be between 0 and 1
static void setInputVolume(float volume); ///< The volume must be between 0 and 2
static void suscribeInput(); ///< Call when you need to capture sound from the open input device.
static void unsuscribeInput(); ///< Call once you don't need to capture on the open input device anymore.
@ -95,6 +96,7 @@ private:
static ALCdevice* alOutDev, *alInDev;
static QMutex* audioInLock, *audioOutLock;
static float outputVolume;
static float inputVolume;
static ALuint alMainSource;
static QThread* audioThread;
static ALCcontext* alContext;

View File

@ -226,6 +226,8 @@ void Settings::loadGlobal()
s.beginGroup("Audio");
inDev = s.value("inDev", "").toString();
outDev = s.value("outDev", "").toString();
inVolume = s.value("inVolume", 100).toInt();
outVolume = s.value("outVolume", 100).toInt();
filterAudio = s.value("filterAudio", false).toBool();
s.endGroup();
@ -426,6 +428,8 @@ void Settings::saveGlobal()
s.beginGroup("Audio");
s.setValue("inDev", inDev);
s.setValue("outDev", outDev);
s.setValue("inVolume", inVolume);
s.setValue("outVolume", outVolume);
s.setValue("filterAudio", filterAudio);
s.endGroup();
@ -1174,6 +1178,18 @@ void Settings::setInDev(const QString& deviceSpecifier)
inDev = deviceSpecifier;
}
int Settings::getInVolume() const
{
QMutexLocker locker{&bigLock};
return inVolume;
}
void Settings::setInVolume(int volume)
{
QMutexLocker locker{&bigLock};
inVolume = volume;
}
QString Settings::getVideoDev() const
{
QMutexLocker locker{&bigLock};
@ -1198,6 +1214,18 @@ void Settings::setOutDev(const QString& deviceSpecifier)
outDev = deviceSpecifier;
}
int Settings::getOutVolume() const
{
QMutexLocker locker{&bigLock};
return outVolume;
}
void Settings::setOutVolume(int volume)
{
QMutexLocker locker{&bigLock};
outVolume = volume;
}
bool Settings::getFilterAudio() const
{
QMutexLocker locker{&bigLock};

View File

@ -154,6 +154,12 @@ public:
QString getOutDev() const;
void setOutDev(const QString& deviceSpecifier);
int getInVolume() const;
void setInVolume(int volume);
int getOutVolume() const;
void setOutVolume(int volume);
bool getFilterAudio() const;
void setFilterAudio(bool newValue);
@ -374,6 +380,8 @@ private:
// Audio
QString inDev;
QString outDev;
int inVolume;
int outVolume;
bool filterAudio;
// Video

View File

@ -62,8 +62,10 @@ AVForm::AVForm() :
connect(bodyUI->filterAudio, &QCheckBox::toggled, this, &AVForm::onFilterAudioToggled);
connect(bodyUI->rescanButton, &QPushButton::clicked, this, [=](){getAudioInDevices(); getAudioOutDevices();});
bodyUI->playbackSlider->setValue(100);
bodyUI->microphoneSlider->setValue(100);
connect(bodyUI->playbackSlider, &QSlider::sliderReleased, this, &AVForm::onPlaybackSliderReleased);
connect(bodyUI->microphoneSlider, &QSlider::sliderReleased, this, &AVForm::onMicrophoneSliderReleased);
bodyUI->playbackSlider->setValue(Settings::getInstance().getOutVolume());
bodyUI->microphoneSlider->setValue(Settings::getInstance().getInVolume());
for (QComboBox* cb : findChildren<QComboBox*>())
{
@ -332,10 +334,20 @@ void AVForm::on_playbackSlider_valueChanged(int value)
void AVForm::on_microphoneSlider_valueChanged(int value)
{
Audio::setOutputVolume(value / 100.0);
Audio::setInputVolume(value / 100.0);
bodyUI->microphoneMax->setText(QString::number(value));
}
void AVForm::onPlaybackSliderReleased()
{
Settings::getInstance().setOutVolume(bodyUI->playbackSlider->value());
}
void AVForm::onMicrophoneSliderReleased()
{
Settings::getInstance().setInVolume(bodyUI->microphoneSlider->value());
}
bool AVForm::eventFilter(QObject *o, QEvent *e)
{
if ((e->type() == QEvent::Wheel) &&

View File

@ -59,6 +59,8 @@ private slots:
void onFilterAudioToggled(bool filterAudio);
void on_playbackSlider_valueChanged(int value);
void on_microphoneSlider_valueChanged(int value);
void onPlaybackSliderReleased();
void onMicrophoneSliderReleased();
// camera
void onVideoDevChanged(int index);

View File

@ -48,7 +48,7 @@
</property>
</widget>
</item>
<item row="5" column="0">
<item row="7" column="0">
<widget class="QCheckBox" name="filterAudio">
<property name="toolTip">
<string>Filter sound from your microphone, so that people hearing you would get better sound.</string>
@ -74,15 +74,15 @@
</property>
</widget>
</item>
<item row="4" column="0">
<item row="5" column="0">
<widget class="QLabel" name="microphoneLabel">
<property name="text">
<string>Microphone</string>
</property>
</widget>
</item>
<item row="2" column="3">
<widget class="QLabel" name="playbackMax">
<item row="5" column="3">
<widget class="QLabel" name="microphoneMax">
<property name="text">
<string>100</string>
</property>
@ -95,27 +95,13 @@
</property>
</widget>
</item>
<item row="4" column="3">
<widget class="QLabel" name="microphoneMax">
<item row="2" column="3">
<widget class="QLabel" name="playbackMax">
<property name="text">
<string>100</string>
</property>
</widget>
</item>
<item row="4" column="2">
<widget class="QSlider" name="microphoneSlider">
<property name="toolTip">
<string>Use slider to set volume of your microphone.
WARNING: slider is not supposed to work yet.</string>
</property>
<property name="maximum">
<number>100</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="inDevLabel">
<property name="text">
@ -123,13 +109,27 @@ WARNING: slider is not supposed to work yet.</string>
</property>
</widget>
</item>
<item row="4" column="1">
<item row="5" column="1">
<widget class="QLabel" name="microphoneMin">
<property name="text">
<string>0</string>
</property>
</widget>
</item>
<item row="5" column="2">
<widget class="QSlider" name="microphoneSlider">
<property name="toolTip">
<string>Use slider to set volume of your microphone.
WARNING: slider is not supposed to work yet.</string>
</property>
<property name="maximum">
<number>200</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="playbackLabel">
<property name="text">
@ -147,6 +147,9 @@ WARNING: slider is not supposed to work yet.</string>
</property>
</widget>
</item>
<item row="6" column="2">
<widget class="MicFeedbackWidget" name="microphoneFeedback" native="true"/>
</item>
</layout>
</widget>
</item>
@ -234,6 +237,12 @@ which may lead to problems with video calls.</string>
<header>src/widget/form/settings/verticalonlyscroller.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>MicFeedbackWidget</class>
<extends>QWidget</extends>
<header>src/widget/tool/micfeedbackwidget.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>

View File

@ -0,0 +1,83 @@
/*
Copyright © 2015 by The qTox Project
This file is part of qTox, a Qt-based graphical interface for Tox.
qTox is libre software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
qTox is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with qTox. If not, see <http://www.gnu.org/licenses/>.
*/
#include "micfeedbackwidget.h"
#include "src/audio/audio.h"
#include <QPainter>
#include <QLinearGradient>
MicFeedbackWidget::MicFeedbackWidget(QWidget *parent) : QWidget(parent)
{
setFixedHeight(20);
startTimer(60);
Audio::suscribeInput();
Audio::setOutputVolume(1.0f);
}
void MicFeedbackWidget::paintEvent(QPaintEvent*)
{
QPainter painter(this);
painter.setPen(QPen(Qt::black));
painter.drawRect(QRect(0, 0, width() - 1, height() - 1));
int gradientWidth = round(width() * rms) - 4;
if (gradientWidth < 0)
gradientWidth = 0;
QRect gradientRect(2, 2, gradientWidth, height() - 4);
QLinearGradient gradient(0, 0, width(), 0);
gradient.setColorAt(0, Qt::red);
gradient.setColorAt(0.5, Qt::yellow);
gradient.setColorAt(1, Qt::green);
painter.fillRect(gradientRect, gradient);
float slice = width() / 5;
int padding = slice / 2;
for (int i = 0; i < 5; ++i)
{
float pos = slice * i + padding;
painter.drawLine(pos, 2, pos, height() - 4);
}
}
void MicFeedbackWidget::timerEvent(QTimerEvent*)
{
const int framesize = (20 * 48000) / 1000;
const int bufsize = framesize * 2;
uint8_t buff[bufsize];
memset(buff, 0, bufsize);
if (Audio::tryCaptureSamples(buff, framesize))
{
double max = 0;
int16_t* buffReal = (int16_t*)(&buff[0]);
for (int i = 0; i < bufsize / 2; ++i)
max = std::max(max, fabs(buffReal[i] / 32767.0));
if (max > rms)
rms = max;
else
rms -= 0.05;
update();
}
}

View File

@ -0,0 +1,41 @@
/*
Copyright © 2015 by The qTox Project
This file is part of qTox, a Qt-based graphical interface for Tox.
qTox is libre software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
qTox is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with qTox. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MICFEEDBACKWIDGET_H
#define MICFEEDBACKWIDGET_H
#include <QWidget>
class MicFeedbackWidget : public QWidget
{
Q_OBJECT
public:
explicit MicFeedbackWidget(QWidget *parent = 0);
protected:
void paintEvent(QPaintEvent* event) override;
void timerEvent(QTimerEvent* event) override;
private:
double rms;
static const int previousNum = 4;
double previous[previousNum];
};
#endif // MICFEEDBACKWIDGET_H