Added simple volume meter for reference of input levels.

This commit is contained in:
Danni 2014-05-20 09:26:18 -05:00
parent 1e525c4713
commit bc542a3e75
6 changed files with 114 additions and 25 deletions

View file

@ -713,8 +713,9 @@ uint32_t audio_output_samplerate(audio_t audio)
/* TODO: Optimization of volume multiplication functions */
static inline void mul_vol_u8bit(void *array, float volume, size_t total_num)
static inline int mul_vol_u8bit(void *array, float volume, size_t total_num)
{
int maxVol = 0;
uint8_t *vals = array;
int32_t vol = (int32_t)(volume * 127.0f);
@ -722,18 +723,23 @@ static inline void mul_vol_u8bit(void *array, float volume, size_t total_num)
int32_t val = (int32_t)vals[i] - 128;
int32_t output = val * vol / 127;
vals[i] = (uint8_t)(CLAMP(output, MIN_S8, MAX_S8) + 128);
maxVol = max(maxVol, abs(vals[i]));
}
return maxVol * (10000 / MAX_S8);
}
static inline void mul_vol_16bit(void *array, float volume, size_t total_num)
static inline int mul_vol_16bit(void *array, float volume, size_t total_num)
{
int maxVol = 0;
uint16_t *vals = array;
int64_t vol = (int64_t)(volume * 32767.0f);
for (size_t i = 0; i < total_num; i++) {
int64_t output = (int64_t)vals[i] * vol / 32767;
vals[i] = (int32_t)CLAMP(output, MIN_S16, MAX_S16);
maxVol = max(maxVol, abs(vals[i]));
}
return maxVol * (10000 / MAX_S16);
}
static inline float conv_24bit_to_float(uint8_t *vals)
@ -756,19 +762,23 @@ static inline void conv_float_to_24bit(float fval, uint8_t *vals)
vals[2] = (val >> 16) & 0xFF;
}
static inline void mul_vol_24bit(void *array, float volume, size_t total_num)
static inline int mul_vol_24bit(void *array, float volume, size_t total_num)
{
float maxVol = 0.f;
uint8_t *vals = array;
for (size_t i = 0; i < total_num; i++) {
float val = conv_24bit_to_float(vals) * volume;
conv_float_to_24bit(CLAMP(val, -1.0f, 1.0f), vals);
vals += 3;
maxVol = max(maxVol, (float)fabs(val));
}
return (int) (maxVol * 10000.f);
}
static inline void mul_vol_32bit(void *array, float volume, size_t total_num)
static inline int mul_vol_32bit(void *array, float volume, size_t total_num)
{
int maxVol = 0;
int32_t *vals = array;
double dvol = (double)volume;
@ -776,20 +786,33 @@ static inline void mul_vol_32bit(void *array, float volume, size_t total_num)
double val = (double)vals[i] / 2147483647.0;
double output = val * dvol;
vals[i] = (int32_t)(CLAMP(output, -1.0, 1.0) * 2147483647.0);
maxVol = max(maxVol, abs(vals[i]));
}
return maxVol * (10000 / MAX_S32);
}
static inline void mul_vol_float(void *array, float volume, size_t total_num)
static inline int mul_vol_float(void *array, float volume, size_t total_num)
{
float maxVol = 0;
float *vals = array;
for (size_t i = 0; i < total_num; i++)
for (size_t i = 0; i < total_num; i++) {
vals[i] *= volume;
maxVol = max(maxVol, (float)fabs(vals[i]));
}
return (int)(maxVol * 10000.f);
}
static void audio_line_place_data_pos(struct audio_line *line,
// [Danni] changed to int for volume feedback. Seems like the most logical
// place to calculate this to avoid unnessisary iterations.
// scaled to max of 10000.
static int audio_line_place_data_pos(struct audio_line *line,
const struct audio_data *data, size_t position)
{
int maxVol = 0;
bool planar = line->audio->planes > 1;
size_t total_num = data->frames * (planar ? 1 : line->audio->channels);
size_t total_size = data->frames * line->audio->block_size;
@ -803,19 +826,19 @@ static void audio_line_place_data_pos(struct audio_line *line,
switch (line->audio->info.format) {
case AUDIO_FORMAT_U8BIT:
case AUDIO_FORMAT_U8BIT_PLANAR:
mul_vol_u8bit(array, data->volume, total_num);
maxVol = mul_vol_u8bit(array, data->volume, total_num);
break;
case AUDIO_FORMAT_16BIT:
case AUDIO_FORMAT_16BIT_PLANAR:
mul_vol_16bit(array, data->volume, total_num);
maxVol = mul_vol_16bit(array, data->volume, total_num);
break;
case AUDIO_FORMAT_32BIT:
case AUDIO_FORMAT_32BIT_PLANAR:
mul_vol_32bit(array, data->volume, total_num);
maxVol = mul_vol_32bit(array, data->volume, total_num);
break;
case AUDIO_FORMAT_FLOAT:
case AUDIO_FORMAT_FLOAT_PLANAR:
mul_vol_float(array, data->volume, total_num);
maxVol = mul_vol_float(array, data->volume, total_num);
break;
case AUDIO_FORMAT_UNKNOWN:
blog(LOG_ERROR, "audio_line_place_data_pos: "
@ -826,9 +849,10 @@ static void audio_line_place_data_pos(struct audio_line *line,
circlebuf_place(&line->buffers[i], position,
line->volume_buffers[i].array, total_size);
}
return maxVol;
}
static void audio_line_place_data(struct audio_line *line,
static int audio_line_place_data(struct audio_line *line,
const struct audio_data *data)
{
size_t pos = ts_diff_bytes(line->audio, data->timestamp,
@ -842,25 +866,26 @@ static void audio_line_place_data(struct audio_line *line,
line->buffers[0].size);
#endif
audio_line_place_data_pos(line, data, pos);
return audio_line_place_data_pos(line, data, pos);
}
void audio_line_output(audio_line_t line, const struct audio_data *data)
int audio_line_output(audio_line_t line, const struct audio_data *data)
{
/* TODO: prevent insertation of data too far away from expected
* audio timing */
if (!line || !data) return;
if (!line || !data) return 0;
int maxVol = 0;
pthread_mutex_lock(&line->mutex);
if (!line->buffers[0].size) {
line->base_timestamp = data->timestamp -
line->audio->info.buffer_ms * 1000000;
audio_line_place_data(line, data);
maxVol = audio_line_place_data(line, data);
} else if (line->base_timestamp <= data->timestamp) {
audio_line_place_data(line, data);
maxVol = audio_line_place_data(line, data);
} else {
blog(LOG_DEBUG, "Bad timestamp for audio line '%s', "
@ -872,4 +897,5 @@ void audio_line_output(audio_line_t line, const struct audio_data *data)
}
pthread_mutex_unlock(&line->mutex);
return maxVol;
}

View file

@ -190,7 +190,7 @@ EXPORT const struct audio_output_info *audio_output_getinfo(audio_t audio);
EXPORT audio_line_t audio_output_createline(audio_t audio, const char *name);
EXPORT void audio_line_destroy(audio_line_t line);
EXPORT void audio_line_output(audio_line_t line, const struct audio_data *data);
EXPORT int audio_line_output(audio_line_t line, const struct audio_data *data);
#ifdef __cplusplus

View file

@ -19,6 +19,7 @@
#include "media-io/format-conversion.h"
#include "media-io/video-frame.h"
#include "media-io/audio-io.h"
#include "util/threading.h"
#include "util/platform.h"
#include "callback/calldata.h"
@ -28,6 +29,8 @@
#include "obs.h"
#include "obs-internal.h"
static inline bool source_valid(struct obs_source *source)
{
return source && source->context.data;
@ -79,6 +82,7 @@ static const char *source_signals[] = {
"void show(ptr source)",
"void hide(ptr source)",
"void volume(ptr source, in out float volume)",
"void volumelevel(ptr source, in out float volume)",
NULL
};
@ -568,8 +572,9 @@ static void source_output_audio_line(obs_source_t source,
in.timestamp += source->timing_adjust + source->sync_offset;
in.volume = source->user_volume * source->present_volume *
obs->audio.user_volume * obs->audio.present_volume;
audio_line_output(source->audio_line, &in);
int vol = audio_line_output(source->audio_line, &in);
obs_source_updatevolumelevel(source, vol);
}
enum convert_type {
@ -1597,6 +1602,22 @@ void obs_source_setvolume(obs_source_t source, float volume)
}
}
void obs_source_updatevolumelevel(obs_source_t source, int volume)
{
if (source) {
struct calldata data = { 0 };
calldata_setptr(&data, "source", source);
calldata_setint(&data, "volumelevel", volume);
signal_handler_signal(source->context.signals, "volumelevel", &data);
signal_handler_signal(obs->signals, "source_volumelevel", &data);
volume = (int)calldata_int(&data, "volumelevel");
calldata_free(&data);
}
}
static void set_tree_preset_vol(obs_source_t parent, obs_source_t child,
void *param)
{

View file

@ -554,6 +554,9 @@ EXPORT proc_handler_t obs_source_prochandler(obs_source_t source);
/** Sets the user volume for a source that has audio output */
EXPORT void obs_source_setvolume(obs_source_t source, float volume);
/** Updates live volume for a source */
EXPORT void obs_source_updatevolumelevel(obs_source_t source, int volume);
/** Sets the presentation volume for a source */
EXPORT void obs_source_set_present_volume(obs_source_t source, float volume);

View file

@ -17,6 +17,19 @@ void VolControl::OBSVolumeChanged(void *data, calldata_t calldata)
Q_ARG(int, vol));
}
// [Danni] This may be a bit too resource intensive for such a simple
// application.
void VolControl::OBSVolumeLevel(void *data, calldata_t calldata)
{
VolControl *volControl = static_cast<VolControl*>(data);
int v = calldata_int(calldata, "volumelevel");
QMetaObject::invokeMethod(volControl, "VolumeLevel",
Q_ARG(int, v));
}
void VolControl::VolumeChanged(int vol)
{
signalChanged = false;
@ -24,6 +37,11 @@ void VolControl::VolumeChanged(int vol)
signalChanged = true;
}
void VolControl::VolumeLevel(int vol)
{
volMeter->setValue(vol); /* linear */
}
void VolControl::SliderChanged(int vol)
{
if (signalChanged) {
@ -48,6 +66,7 @@ VolControl::VolControl(OBSSource source_)
nameLabel = new QLabel();
volLabel = new QLabel();
volMeter = new QProgressBar();
slider = new QSlider(Qt::Horizontal);
QFont font = nameLabel->font();
@ -60,8 +79,17 @@ VolControl::VolControl(OBSSource source_)
slider->setMinimum(0);
slider->setMaximum(100);
slider->setValue(vol);
//slider->setMaximumHeight(16);
slider->setMaximumHeight(10);
volMeter->setMaximumHeight(1);
volMeter->setMinimum(0);
volMeter->setMaximum(10000);
volMeter->setTextVisible(false);
// [Danni] Temporary color.
QString testColor = "QProgressBar {border: 0px} QProgressBar::chunk {width: 1px; background-color: #AA0000;}";
volMeter->setStyleSheet(testColor);
textLayout->setContentsMargins(0, 0, 0, 0);
textLayout->addWidget(nameLabel);
textLayout->addWidget(volLabel);
@ -71,6 +99,7 @@ VolControl::VolControl(OBSSource source_)
mainLayout->setContentsMargins(4, 4, 4, 4);
mainLayout->setSpacing(2);
mainLayout->addItem(textLayout);
mainLayout->addWidget(volMeter);
mainLayout->addWidget(slider);
setLayout(mainLayout);
@ -78,6 +107,9 @@ VolControl::VolControl(OBSSource source_)
signal_handler_connect(obs_source_signalhandler(source),
"volume", OBSVolumeChanged, this);
signal_handler_connect(obs_source_signalhandler(source),
"volumelevel", OBSVolumeLevel, this);
QWidget::connect(slider, SIGNAL(valueChanged(int)),
this, SLOT(SliderChanged(int)));
}
@ -86,4 +118,7 @@ VolControl::~VolControl()
{
signal_handler_disconnect(obs_source_signalhandler(source),
"volume", OBSVolumeChanged, this);
signal_handler_disconnect(obs_source_signalhandler(source),
"volumelevel", OBSVolumeLevel, this);
}

View file

@ -2,6 +2,7 @@
#include <obs.hpp>
#include <QWidget>
#include <QProgressBar>
/* TODO: Make a real volume control that isn't terrible */
@ -13,15 +14,18 @@ class VolControl : public QWidget {
private:
OBSSource source;
QLabel *nameLabel;
QLabel *volLabel;
QSlider *slider;
bool signalChanged;
QLabel *nameLabel;
QLabel *volLabel;
QProgressBar *volMeter;
QSlider *slider;
bool signalChanged;
static void OBSVolumeChanged(void *param, calldata_t calldata);
static void OBSVolumeLevel(void *data, calldata_t calldata);
private slots:
void VolumeChanged(int vol);
void VolumeLevel(int vol);
void SliderChanged(int vol);
public: