提交 50ce2284 编写于 作者: T Tjienta Vara

UI: Rework volume-meters, adding more information

The following features have been added to the audio-meters:
 * Stereo PPM-level meter, with 40 dB/1.7s decay rate.
 * Stereo VU-level meter, with 300 ms integration time.
 * Stereo Peak-hold meter, with 20 second sustain.
 * Input peak level color-squares in front of every meter.
 * Minor-ticks for each dB.
 * Major-ticks for every 5 dB.
 * Meter is divided in sections at -20 dB and -9 dB.

The ballistic parameters chosen here where taken from:
 * https://en.wikipedia.org/wiki/Peak_programme_meter (SMPTE RP.0155)
 * https://en.wikipedia.org/wiki/VU_meter

In the rework I have removed any ballistic calculations from
libobs/obs-audio-controls.c making the calculations here a lot more
simple doing only MAX and RMS calculations for only the samples in
the current update. The actual ballistics are now done by just
the UI/volume-control.cpp because ballistics need to be updated
based on the repaint-rate of the user-interface.

The dB to pixel conversion has been moved from
libobs/obs-audio-controls.c to UI/volume-control.cpp as well to reduce
coupling between these two objects, especially when implementing the
major- and minor-ticks and the sections.

All colors and ballistic parameters are adjustable via QT style sheets.
There are slight differences in colors for each of the themes.
上级 2f577c1b
......@@ -464,10 +464,16 @@ QSlider::handle:disabled {
/* Volume Control */
VolumeMeter {
qproperty-bkColor: rgb(31,30,31); /* veryDark */
qproperty-magColor:;
qproperty-peakColor:;
qproperty-peakHoldColor: rgb(225,224,225); /* veryLight */
qproperty-backgroundNominalColor: rgb(38, 127, 38);
qproperty-backgroundWarningColor: rgb(127, 127, 38);
qproperty-backgroundErrorColor: rgb(127, 38, 38);
qproperty-foregroundNominalColor: rgb(76, 255, 76);
qproperty-foregroundWarningColor: rgb(255, 255, 76);
qproperty-foregroundErrorColor: rgb(255, 76, 76);
qproperty-magnitudeColor: rgb(0, 0, 0);
qproperty-majorTickColor: rgb(225,224,225); /* veryLight */
qproperty-minorTickColor: rgb(122,121,122); /* light */
qproperty-peakDecayRate: 23.4; /* Override of the standard PPM Type I rate. */
}
......
......@@ -55,10 +55,16 @@ OBSHotkeyLabel[hotkeyPairHover=true] {
/* Volume Control */
VolumeMeter {
qproperty-bkColor: rgb(221, 221, 221);
qproperty-magColor: rgb(32, 125, 23);
qproperty-peakColor: rgb(62, 241, 43);
qproperty-peakHoldColor: rgb(0, 0, 0);
qproperty-backgroundNominalColor: rgb(15, 100, 15);
qproperty-backgroundWarningColor: rgb(100, 100, 15);
qproperty-backgroundErrorColor: rgb(100, 15, 15);
qproperty-foregroundNominalColor: rgb(50, 200, 50);
qproperty-foregroundWarningColor: rgb(255, 200, 50);
qproperty-foregroundErrorColor: rgb(200, 50, 50);
qproperty-magnitudeColor: rgb(0, 0, 0);
qproperty-majorTickColor: rgb(0, 0, 0);
qproperty-minorTickColor: rgb(50, 50, 50);
qproperty-peakDecayRate: 23.4; /* Override of the standard PPM Type I rate. */
}
......
......@@ -670,12 +670,16 @@ QProgressBar::chunk {
/**************************/
VolumeMeter {
qproperty-bkColor: rgb(35, 38, 41); /* Dark Gray */
qproperty-magColor: rgb(153, 204, 0);
qproperty-peakColor: rgb(96, 128, 0);
qproperty-peakHoldColor: rgb(210, 255, 77);
qproperty-clipColor1: rgb(230, 40, 50);
qproperty-clipColor2: rgb(140, 0, 40);
qproperty-backgroundNominalColor: rgb(0, 128, 79);
qproperty-backgroundWarningColor: rgb(128, 57, 0);
qproperty-backgroundErrorColor: rgb(128, 9, 0);
qproperty-foregroundNominalColor: rgb(119, 255, 143);
qproperty-foregroundWarningColor: rgb(255, 157, 76);
qproperty-foregroundErrorColor: rgb(255, 89, 76);
qproperty-magnitudeColor: rgb(49, 54, 59); /* Blue-gray */
qproperty-majorTickColor: rgb(239, 240, 241); /* White */
qproperty-minorTickColor: rgb(118, 121, 124); /* Light Gray */
qproperty-peakDecayRate: 23.4; /* Override of the standard PPM Type I rate. */
}
/*******************/
......
此差异已折叠。
......@@ -13,45 +13,178 @@ class VolumeMeterTimer;
class VolumeMeter : public QWidget
{
Q_OBJECT
Q_PROPERTY(QColor bkColor READ getBkColor WRITE setBkColor DESIGNABLE true)
Q_PROPERTY(QColor magColor READ getMagColor WRITE setMagColor DESIGNABLE true)
Q_PROPERTY(QColor peakColor READ getPeakColor WRITE setPeakColor DESIGNABLE true)
Q_PROPERTY(QColor peakHoldColor READ getPeakHoldColor WRITE setPeakHoldColor DESIGNABLE true)
Q_PROPERTY(QColor clipColor1 READ getClipColor1 WRITE setClipColor1 DESIGNABLE true)
Q_PROPERTY(QColor clipColor2 READ getClipColor2 WRITE setClipColor2 DESIGNABLE true)
Q_PROPERTY(QColor backgroundNominalColor
READ getBackgroundNominalColor
WRITE setBackgroundNominalColor DESIGNABLE true)
Q_PROPERTY(QColor backgroundWarningColor
READ getBackgroundWarningColor
WRITE setBackgroundWarningColor DESIGNABLE true)
Q_PROPERTY(QColor backgroundErrorColor
READ getBackgroundErrorColor
WRITE setBackgroundErrorColor DESIGNABLE true)
Q_PROPERTY(QColor foregroundNominalColor
READ getForegroundNominalColor
WRITE setForegroundNominalColor DESIGNABLE true)
Q_PROPERTY(QColor foregroundWarningColor
READ getForegroundWarningColor
WRITE setForegroundWarningColor DESIGNABLE true)
Q_PROPERTY(QColor foregroundErrorColor
READ getForegroundErrorColor
WRITE setForegroundErrorColor DESIGNABLE true)
Q_PROPERTY(QColor clipColor
READ getClipColor
WRITE setClipColor DESIGNABLE true)
Q_PROPERTY(QColor magnitudeColor
READ getMagnitudeColor
WRITE setMagnitudeColor DESIGNABLE true)
Q_PROPERTY(QColor majorTickColor
READ getMajorTickColor
WRITE setMajorTickColor DESIGNABLE true)
Q_PROPERTY(QColor minorTickColor
READ getMinorTickColor
WRITE setMinorTickColor DESIGNABLE true)
// Levels are denoted in dBFS.
Q_PROPERTY(qreal minimumLevel
READ getMinimumLevel
WRITE setMinimumLevel DESIGNABLE true)
Q_PROPERTY(qreal warningLevel
READ getWarningLevel
WRITE setWarningLevel DESIGNABLE true)
Q_PROPERTY(qreal errorLevel
READ getErrorLevel
WRITE setErrorLevel DESIGNABLE true)
Q_PROPERTY(qreal clipLevel
READ getClipLevel
WRITE setClipLevel DESIGNABLE true)
Q_PROPERTY(qreal minimumInputLevel
READ getMinimumInputLevel
WRITE setMinimumInputLevel DESIGNABLE true)
// Rates are denoted in dB/second.
Q_PROPERTY(qreal peakDecayRate
READ getPeakDecayRate
WRITE setPeakDecayRate DESIGNABLE true)
// Time in seconds for the VU meter to integrate over.
Q_PROPERTY(qreal magnitudeIntegrationTime
READ getMagnitudeIntegrationTime
WRITE setMagnitudeIntegrationTime DESIGNABLE true)
// Duration is denoted in seconds.
Q_PROPERTY(qreal peakHoldDuration
READ getPeakHoldDuration
WRITE setPeakHoldDuration DESIGNABLE true)
Q_PROPERTY(qreal inputPeakHoldDuration
READ getInputPeakHoldDuration
WRITE setInputPeakHoldDuration DESIGNABLE true)
private:
obs_volmeter_t *obs_volmeter;
static QWeakPointer<VolumeMeterTimer> updateTimer;
QSharedPointer<VolumeMeterTimer> updateTimerRef;
float curMag = 0.0f, curPeak = 0.0f, curPeakHold = 0.0f;
inline void calcLevels();
inline void resetLevels();
inline void handleChannelCofigurationChange();
inline bool detectIdle(uint64_t ts);
inline void calculateBallistics(uint64_t ts,
qreal timeSinceLastRedraw=0.0);
inline void calculateBallisticsForChannel(int channelNr,
uint64_t ts, qreal timeSinceLastRedraw);
void paintInputMeter(QPainter &painter, int x, int y,
int width, int height, float peakHold);
void paintMeter(QPainter &painter, int x, int y,
int width, int height,
float magnitude, float peak, float peakHold);
void paintTicks(QPainter &painter, int x, int y, int width, int height);
QMutex dataMutex;
float mag = 0.0f, peak = 0.0f, peakHold = 0.0f;
float multiple = 0.0f;
uint64_t lastUpdateTime = 0;
QColor bkColor, magColor, peakColor, peakHoldColor;
QColor clipColor1, clipColor2;
uint64_t currentLastUpdateTime = 0;
float currentMagnitude[MAX_AUDIO_CHANNELS];
float currentPeak[MAX_AUDIO_CHANNELS];
float currentInputPeak[MAX_AUDIO_CHANNELS];
QPixmap *tickPaintCache = NULL;
int displayNrAudioChannels = 0;
float displayMagnitude[MAX_AUDIO_CHANNELS];
float displayPeak[MAX_AUDIO_CHANNELS];
float displayPeakHold[MAX_AUDIO_CHANNELS];
uint64_t displayPeakHoldLastUpdateTime[MAX_AUDIO_CHANNELS];
float displayInputPeakHold[MAX_AUDIO_CHANNELS];
uint64_t displayInputPeakHoldLastUpdateTime[MAX_AUDIO_CHANNELS];
QColor backgroundNominalColor;
QColor backgroundWarningColor;
QColor backgroundErrorColor;
QColor foregroundNominalColor;
QColor foregroundWarningColor;
QColor foregroundErrorColor;
QColor clipColor;
QColor magnitudeColor;
QColor majorTickColor;
QColor minorTickColor;
qreal minimumLevel;
qreal warningLevel;
qreal errorLevel;
qreal clipLevel;
qreal minimumInputLevel;
qreal peakDecayRate;
qreal magnitudeIntegrationTime;
qreal peakHoldDuration;
qreal inputPeakHoldDuration;
uint64_t lastRedrawTime = 0;
public:
explicit VolumeMeter(QWidget *parent = 0);
explicit VolumeMeter(QWidget *parent = 0,
obs_volmeter_t *obs_volmeter = 0);
~VolumeMeter();
void setLevels(float nmag, float npeak, float npeakHold);
QColor getBkColor() const;
void setBkColor(QColor c);
QColor getMagColor() const;
void setMagColor(QColor c);
QColor getPeakColor() const;
void setPeakColor(QColor c);
QColor getPeakHoldColor() const;
void setPeakHoldColor(QColor c);
QColor getClipColor1() const;
void setClipColor1(QColor c);
QColor getClipColor2() const;
void setClipColor2(QColor c);
void setLevels(
const float magnitude[MAX_AUDIO_CHANNELS],
const float peak[MAX_AUDIO_CHANNELS],
const float inputPeak[MAX_AUDIO_CHANNELS]);
QColor getBackgroundNominalColor() const;
void setBackgroundNominalColor(QColor c);
QColor getBackgroundWarningColor() const;
void setBackgroundWarningColor(QColor c);
QColor getBackgroundErrorColor() const;
void setBackgroundErrorColor(QColor c);
QColor getForegroundNominalColor() const;
void setForegroundNominalColor(QColor c);
QColor getForegroundWarningColor() const;
void setForegroundWarningColor(QColor c);
QColor getForegroundErrorColor() const;
void setForegroundErrorColor(QColor c);
QColor getClipColor() const;
void setClipColor(QColor c);
QColor getMagnitudeColor() const;
void setMagnitudeColor(QColor c);
QColor getMajorTickColor() const;
void setMajorTickColor(QColor c);
QColor getMinorTickColor() const;
void setMinorTickColor(QColor c);
qreal getMinimumLevel() const;
void setMinimumLevel(qreal v);
qreal getWarningLevel() const;
void setWarningLevel(qreal v);
qreal getErrorLevel() const;
void setErrorLevel(qreal v);
qreal getClipLevel() const;
void setClipLevel(qreal v);
qreal getMinimumInputLevel() const;
void setMinimumInputLevel(qreal v);
qreal getPeakDecayRate() const;
void setPeakDecayRate(qreal v);
qreal getMagnitudeIntegrationTime() const;
void setMagnitudeIntegrationTime(qreal v);
qreal getPeakHoldDuration() const;
void setPeakHoldDuration(qreal v);
qreal getInputPeakHoldDuration() const;
void setInputPeakHoldDuration(qreal v);
protected:
void paintEvent(QPaintEvent *event);
......@@ -92,8 +225,10 @@ private:
obs_volmeter_t *obs_volmeter;
static void OBSVolumeChanged(void *param, float db);
static void OBSVolumeLevel(void *data, float level, float mag,
float peak, float muted);
static void OBSVolumeLevel(void *data,
const float magnitude[MAX_AUDIO_CHANNELS],
const float peak[MAX_AUDIO_CHANNELS],
const float inputPeak[MAX_AUDIO_CHANNELS]);
static void OBSVolumeMuted(void *data, calldata_t *calldata);
void EmitConfigClicked();
......
......@@ -32,6 +32,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#pragma warning(disable : 4756)
#endif
#define CLAMP(x, min, max) ((x) < min ? min : ((x) > max ? max : (x)))
typedef float (*obs_fader_conversion_t)(const float val);
struct fader_cb {
......@@ -61,8 +63,6 @@ struct meter_cb {
struct obs_volmeter {
pthread_mutex_t mutex;
obs_fader_conversion_t pos_to_db;
obs_fader_conversion_t db_to_pos;
obs_source_t *source;
enum obs_fader_type type;
float cur_db;
......@@ -70,20 +70,10 @@ struct obs_volmeter {
pthread_mutex_t callback_mutex;
DARRAY(struct meter_cb)callbacks;
unsigned int channels;
unsigned int update_ms;
unsigned int update_frames;
unsigned int peakhold_ms;
unsigned int peakhold_frames;
unsigned int peakhold_count;
unsigned int ival_frames;
float ival_sum;
float ival_max;
float vol_peak;
float vol_mag;
float vol_max;
float vol_magnitude[MAX_AUDIO_CHANNELS];
float vol_peak[MAX_AUDIO_CHANNELS];
};
static float cubic_def_to_db(const float def)
......@@ -205,13 +195,14 @@ static void signal_volume_changed(struct obs_fader *fader, const float db)
}
static void signal_levels_updated(struct obs_volmeter *volmeter,
const float level, const float magnitude, const float peak,
bool muted)
const float magnitude[MAX_AUDIO_CHANNELS],
const float peak[MAX_AUDIO_CHANNELS],
const float input_peak[MAX_AUDIO_CHANNELS])
{
pthread_mutex_lock(&volmeter->callback_mutex);
for (size_t i = volmeter->callbacks.num; i > 0; i--) {
struct meter_cb cb = volmeter->callbacks.array[i - 1];
cb.callback(cb.param, level, magnitude, peak, muted);
cb.callback(cb.param, magnitude, peak, input_peak);
}
pthread_mutex_unlock(&volmeter->callback_mutex);
}
......@@ -265,145 +256,84 @@ static void volmeter_source_destroyed(void *vptr, calldata_t *calldata)
obs_volmeter_detach_source(volmeter);
}
/* TODO: Separate for individual channels */
static void volmeter_sum_and_max(float *data[MAX_AV_PLANES], size_t frames,
float *sum, float *max)
{
float s = *sum;
float m = *max;
for (size_t plane = 0; plane < MAX_AV_PLANES; plane++) {
if (!data[plane])
break;
for (float *c = data[plane]; c < data[plane] + frames; ++c) {
const float pow = *c * *c;
s += pow;
m = (m > pow) ? m : pow;
}
}
*sum = s;
*max = m;
}
/**
* @todo The IIR low pass filter has a different behavior depending on the
* update interval and sample rate, it should be replaced with something
* that is independent from both.
*/
static void volmeter_calc_ival_levels(obs_volmeter_t *volmeter)
{
const unsigned int samples = volmeter->ival_frames * volmeter->channels;
const float alpha = 0.15f;
const float ival_max = sqrtf(volmeter->ival_max);
const float ival_rms = sqrtf(volmeter->ival_sum / (float)samples);
if (ival_max > volmeter->vol_max) {
volmeter->vol_max = ival_max;
} else {
volmeter->vol_max = alpha * volmeter->vol_max +
(1.0f - alpha) * ival_max;
}
if (volmeter->vol_max > volmeter->vol_peak ||
volmeter->peakhold_count > volmeter->peakhold_frames) {
volmeter->vol_peak = volmeter->vol_max;
volmeter->peakhold_count = 0;
} else {
volmeter->peakhold_count += volmeter->ival_frames;
}
volmeter->vol_mag = alpha * ival_rms +
volmeter->vol_mag * (1.0f - alpha);
/* reset interval data */
volmeter->ival_frames = 0;
volmeter->ival_sum = 0.0f;
volmeter->ival_max = 0.0f;
}
static bool volmeter_process_audio_data(obs_volmeter_t *volmeter,
static void volmeter_process_audio_data(obs_volmeter_t *volmeter,
const struct audio_data *data)
{
bool updated = false;
size_t frames = 0;
size_t left = data->frames;
float *adata[MAX_AV_PLANES];
int nr_samples = data->frames;
int channel_nr = 0;
for (size_t i = 0; i < MAX_AV_PLANES; i++)
adata[i] = (float*)data->data[i];
while (left) {
frames = (volmeter->ival_frames + left >
volmeter->update_frames)
? volmeter->update_frames - volmeter->ival_frames
: left;
volmeter_sum_and_max(adata, frames, &volmeter->ival_sum,
&volmeter->ival_max);
volmeter->ival_frames += (unsigned int)frames;
left -= frames;
for (size_t i = 0; i < MAX_AV_PLANES; i++) {
if (!adata[i])
break;
adata[i] += frames;
for (size_t plane_nr = 0; plane_nr < MAX_AV_PLANES; plane_nr++) {
float *samples = (float *)data->data[plane_nr];
if (!samples) {
// This plane does not contain data.
continue;
}
/* break if we did not reach the end of the interval */
if (volmeter->ival_frames != volmeter->update_frames)
break;
// For each plane calculate:
// * peak = the maximum-absolute of the sample values.
// * magnitude = root-mean-square of the sample values.
// A VU meter needs to integrate over 300ms, but this will
// be handled by the ballistics of the meter itself,
// reality. Which makes this calculation independent of
// sample rate or update rate.
float peak = 0.0;
float sum_of_squares = 0.0;
for (int sample_nr = 0; sample_nr < nr_samples; sample_nr++) {
float sample = samples[sample_nr];
peak = fmaxf(peak, fabsf(sample));
sum_of_squares += (sample * sample);
}
volmeter_calc_ival_levels(volmeter);
updated = true;
volmeter->vol_magnitude[channel_nr] = sqrtf(sum_of_squares /
nr_samples);
volmeter->vol_peak[channel_nr] = peak;
channel_nr++;
}
return updated;
// Clear audio channels that are not in use.
for (; channel_nr < MAX_AUDIO_CHANNELS; channel_nr++) {
volmeter->vol_magnitude[channel_nr] = 0.0;
volmeter->vol_peak[channel_nr] = 0.0;
}
}
static void volmeter_source_data_received(void *vptr, obs_source_t *source,
const struct audio_data *data, bool muted)
{
struct obs_volmeter *volmeter = (struct obs_volmeter *) vptr;
bool updated = false;
float mul, level, mag, peak;
float mul;
float magnitude[MAX_AUDIO_CHANNELS];
float peak[MAX_AUDIO_CHANNELS];
float input_peak[MAX_AUDIO_CHANNELS];
pthread_mutex_lock(&volmeter->mutex);
updated = volmeter_process_audio_data(volmeter, data);
if (updated) {
mul = db_to_mul(volmeter->cur_db);
level = volmeter->db_to_pos(mul_to_db(volmeter->vol_max * mul));
mag = volmeter->db_to_pos(mul_to_db(volmeter->vol_mag * mul));
peak = volmeter->db_to_pos(
mul_to_db(volmeter->vol_peak * mul));
volmeter_process_audio_data(volmeter, data);
// Adjust magnitude/peak based on the volume level set by the user.
// And convert to dB.
mul = muted ? 0.0 : db_to_mul(volmeter->cur_db);
for (int channel_nr = 0; channel_nr < MAX_AUDIO_CHANNELS;
channel_nr++) {
magnitude[channel_nr] = mul_to_db(
volmeter->vol_magnitude[channel_nr] * mul);
peak[channel_nr] = mul_to_db(
volmeter->vol_peak[channel_nr] * mul);
input_peak[channel_nr] = mul_to_db(
volmeter->vol_peak[channel_nr]);
}
// The input-peak is NOT adjusted with volume, so that the user
// can check the input-gain.
pthread_mutex_unlock(&volmeter->mutex);
if (updated)
signal_levels_updated(volmeter, level, mag, peak, muted);
signal_levels_updated(volmeter, magnitude, peak, input_peak);
UNUSED_PARAMETER(source);
}
static void volmeter_update_audio_settings(obs_volmeter_t *volmeter)
{
audio_t *audio = obs_get_audio();
const unsigned int sr = audio_output_get_sample_rate(audio);
uint32_t channels = (uint32_t)audio_output_get_channels(audio);
pthread_mutex_lock(&volmeter->mutex);
volmeter->channels = channels;
volmeter->update_frames = volmeter->update_ms * sr / 1000;
volmeter->peakhold_frames = volmeter->peakhold_ms * sr / 1000;
pthread_mutex_unlock(&volmeter->mutex);
}
obs_fader_t *obs_fader_create(enum obs_fader_type type)
{
struct obs_fader *fader = bzalloc(sizeof(struct obs_fader));
......@@ -634,28 +564,9 @@ obs_volmeter_t *obs_volmeter_create(enum obs_fader_type type)
if (pthread_mutex_init(&volmeter->callback_mutex, NULL) != 0)
goto fail;
/* set conversion functions */
switch(type) {
case OBS_FADER_CUBIC:
volmeter->pos_to_db = cubic_def_to_db;
volmeter->db_to_pos = cubic_db_to_def;
break;
case OBS_FADER_IEC:
volmeter->pos_to_db = iec_def_to_db;
volmeter->db_to_pos = iec_db_to_def;
break;
case OBS_FADER_LOG:
volmeter->pos_to_db = log_def_to_db;
volmeter->db_to_pos = log_db_to_def;
break;
default:
goto fail;
break;
}
volmeter->type = type;
obs_volmeter_set_update_interval(volmeter, 50);
obs_volmeter_set_peak_hold(volmeter, 1500);
return volmeter;
fail:
......@@ -739,8 +650,6 @@ void obs_volmeter_set_update_interval(obs_volmeter_t *volmeter,
pthread_mutex_lock(&volmeter->mutex);
volmeter->update_ms = ms;
pthread_mutex_unlock(&volmeter->mutex);
volmeter_update_audio_settings(volmeter);
}
unsigned int obs_volmeter_get_update_interval(obs_volmeter_t *volmeter)
......@@ -755,28 +664,26 @@ unsigned int obs_volmeter_get_update_interval(obs_volmeter_t *volmeter)
return interval;
}
void obs_volmeter_set_peak_hold(obs_volmeter_t *volmeter, const unsigned int ms)
int obs_volmeter_get_nr_channels(obs_volmeter_t *volmeter)
{
if (!volmeter)
return;
int source_nr_audio_channels;
int obs_nr_audio_channels;
pthread_mutex_lock(&volmeter->mutex);
volmeter->peakhold_ms = ms;
pthread_mutex_unlock(&volmeter->mutex);
volmeter_update_audio_settings(volmeter);
}
unsigned int obs_volmeter_get_peak_hold(obs_volmeter_t *volmeter)
{
if (!volmeter)
return 0;
if (volmeter->source) {
source_nr_audio_channels = get_audio_channels(
volmeter->source->sample_info.speakers);
} else {
source_nr_audio_channels = 1;
}
pthread_mutex_lock(&volmeter->mutex);
const unsigned int peakhold = volmeter->peakhold_ms;
pthread_mutex_unlock(&volmeter->mutex);
struct obs_audio_info audio_info;
if (obs_get_audio_info(&audio_info)) {
obs_nr_audio_channels = get_audio_channels(audio_info.speakers);
} else {
obs_nr_audio_channels = 2;
}
return peakhold;
return CLAMP(source_nr_audio_channels, 1, obs_nr_audio_channels);
}
void obs_volmeter_add_callback(obs_volmeter_t *volmeter,
......@@ -805,26 +712,3 @@ void obs_volmeter_remove_callback(obs_volmeter_t *volmeter,
pthread_mutex_unlock(&volmeter->callback_mutex);
}
float obs_volmeter_get_cur_db(enum obs_fader_type type, const float def)
{
float db;
switch(type) {
case OBS_FADER_CUBIC:
db = cubic_def_to_db(def);
break;
case OBS_FADER_IEC:
db = iec_def_to_db(def);
break;
case OBS_FADER_LOG:
db = log_def_to_db(def);
break;
default:
goto fail;
break;
}
return db;
fail:
return -INFINITY;
}
......@@ -229,30 +229,21 @@ EXPORT void obs_volmeter_set_update_interval(obs_volmeter_t *volmeter,
EXPORT unsigned int obs_volmeter_get_update_interval(obs_volmeter_t *volmeter);
/**
* @brief Set the peak hold time for the volume meter
* @brief Get the number of channels which are configured for this source.
* @param volmeter pointer to the volume meter object
* @param ms peak hold time in ms
*/
EXPORT void obs_volmeter_set_peak_hold(obs_volmeter_t *volmeter,
const unsigned int ms);
/**
* @brief Get the peak hold time for the volume meter
* @param volmeter pointer to the volume meter object
* @return the peak hold time in ms
*/
EXPORT unsigned int obs_volmeter_get_peak_hold(obs_volmeter_t *volmeter);
EXPORT int obs_volmeter_get_nr_channels(obs_volmeter_t *volmeter);
typedef void (*obs_volmeter_updated_t)(void *param, float level,
float magnitude, float peak, float muted);
typedef void (*obs_volmeter_updated_t)(void *param,
const float magnitude[MAX_AUDIO_CHANNELS],
const float peak[MAX_AUDIO_CHANNELS],
const float input_peak[MAX_AUDIO_CHANNELS]);
EXPORT void obs_volmeter_add_callback(obs_volmeter_t *volmeter,
obs_volmeter_updated_t callback, void *param);
EXPORT void obs_volmeter_remove_callback(obs_volmeter_t *volmeter,
obs_volmeter_updated_t callback, void *param);
EXPORT float obs_volmeter_get_cur_db(enum obs_fader_type type, const float def);
#ifdef __cplusplus
}
#endif
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册