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:
parent
1fc703c281
commit
a2a32b61c4
6
qtox.pro
6
qtox.pro
|
@ -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 \
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) &&
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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/>
|
||||
|
|
83
src/widget/tool/micfeedbackwidget.cpp
Normal file
83
src/widget/tool/micfeedbackwidget.cpp
Normal 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();
|
||||
}
|
||||
}
|
41
src/widget/tool/micfeedbackwidget.h
Normal file
41
src/widget/tool/micfeedbackwidget.h
Normal 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
|
Loading…
Reference in New Issue
Block a user