提交 46686ec5 编写于 作者: F fryshorts

libobs: Add volume meter object

This adds a volume meter object to libobs that can be used by the GUI
or plugins to convert the raw audio level data from sources to values
that can easily be used to display the audio data.
The volume meter object will use the same mapping functions as the
fader object to map dB levels to a scale.
上级 e43962ac
......@@ -46,11 +46,27 @@ struct obs_fader {
bool ignore_next_signal;
};
struct obs_volmeter {
pthread_mutex_t mutex;
signal_handler_t *signals;
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;
};
static const char *fader_signals[] = {
"void volume_changed(ptr fader, float db)",
NULL
};
static const char *volmeter_signals[] = {
"void levels_updated(ptr volmeter, float level, "
"float magnitude, float peak)",
NULL
};
static inline float mul_to_db(const float mul)
{
return (mul == 0.0f) ? -INFINITY : 20.0f * log10f(mul);
......@@ -96,6 +112,24 @@ static void signal_volume_changed(signal_handler_t *sh,
calldata_free(&data);
}
static void signal_levels_updated(signal_handler_t *sh,
struct obs_volmeter *volmeter,
const float level, const float magnitude, const float peak)
{
struct calldata data;
calldata_init(&data);
calldata_set_ptr (&data, "volmeter", volmeter);
calldata_set_float(&data, "level", level);
calldata_set_float(&data, "magnitude", magnitude);
calldata_set_float(&data, "peak", peak);
signal_handler_signal(sh, "levels_updated", &data);
calldata_free(&data);
}
static void fader_source_volume_changed(void *vptr, calldata_t *calldata)
{
struct obs_fader *fader = (struct obs_fader *) vptr;
......@@ -118,6 +152,18 @@ static void fader_source_volume_changed(void *vptr, calldata_t *calldata)
signal_volume_changed(sh, fader, db);
}
static void volmeter_source_volume_changed(void *vptr, calldata_t *calldata)
{
struct obs_volmeter *volmeter = (struct obs_volmeter *) vptr;
pthread_mutex_lock(&volmeter->mutex);
float mul = (float) calldata_float(calldata, "volume");
volmeter->cur_db = mul_to_db(mul);
pthread_mutex_unlock(&volmeter->mutex);
}
static void fader_source_destroyed(void *vptr, calldata_t *calldata)
{
UNUSED_PARAMETER(calldata);
......@@ -126,6 +172,37 @@ static void fader_source_destroyed(void *vptr, calldata_t *calldata)
obs_fader_detach_source(fader);
}
static void volmeter_source_volume_levels(void *vptr, calldata_t *calldata)
{
struct obs_volmeter *volmeter = (struct obs_volmeter *) vptr;
pthread_mutex_lock(&volmeter->mutex);
float mul = db_to_mul(volmeter->cur_db);
float level = (float) calldata_float(calldata, "level");
float magnitude = (float) calldata_float(calldata, "magnitude");
float peak = (float) calldata_float(calldata, "peak");
level = volmeter->db_to_pos(mul_to_db(level * mul));
magnitude = volmeter->db_to_pos(mul_to_db(magnitude * mul));
peak = volmeter->db_to_pos(mul_to_db(peak * mul));
signal_handler_t *sh = volmeter->signals;
pthread_mutex_unlock(&volmeter->mutex);
signal_levels_updated(sh, volmeter, level, magnitude, peak);
}
static void volmeter_source_destroyed(void *vptr, calldata_t *calldata)
{
UNUSED_PARAMETER(calldata);
struct obs_volmeter *volmeter = (struct obs_volmeter *) vptr;
obs_volmeter_detach_source(volmeter);
}
obs_fader_t *obs_fader_create(enum obs_fader_type type)
{
struct obs_fader *fader = bzalloc(sizeof(struct obs_fader));
......@@ -309,3 +386,106 @@ signal_handler_t *obs_fader_get_signal_handler(obs_fader_t *fader)
return (fader) ? fader->signals : NULL;
}
obs_volmeter_t *obs_volmeter_create(enum obs_fader_type type)
{
struct obs_volmeter *volmeter = bzalloc(sizeof(struct obs_volmeter));
if (!volmeter)
return NULL;
pthread_mutex_init_value(&volmeter->mutex);
if (pthread_mutex_init(&volmeter->mutex, NULL) != 0)
goto fail;
volmeter->signals = signal_handler_create();
if (!volmeter->signals)
goto fail;
if (!signal_handler_add_array(volmeter->signals, volmeter_signals))
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;
default:
goto fail;
break;
}
volmeter->type = type;
return volmeter;
fail:
obs_volmeter_destroy(volmeter);
return NULL;
}
void obs_volmeter_destroy(obs_volmeter_t *volmeter)
{
if (!volmeter)
return;
obs_volmeter_detach_source(volmeter);
signal_handler_destroy(volmeter->signals);
pthread_mutex_destroy(&volmeter->mutex);
bfree(volmeter);
}
bool obs_volmeter_attach_source(obs_volmeter_t *volmeter, obs_source_t *source)
{
signal_handler_t *sh;
if (!volmeter || !source)
return false;
obs_volmeter_detach_source(volmeter);
pthread_mutex_lock(&volmeter->mutex);
sh = obs_source_get_signal_handler(source);
signal_handler_connect(sh, "volume",
volmeter_source_volume_changed, volmeter);
signal_handler_connect(sh, "volume_level",
volmeter_source_volume_levels, volmeter);
signal_handler_connect(sh, "destroy",
volmeter_source_destroyed, volmeter);
volmeter->source = source;
volmeter->cur_db = mul_to_db(obs_source_get_volume(source));
pthread_mutex_unlock(&volmeter->mutex);
return true;
}
void obs_volmeter_detach_source(obs_volmeter_t *volmeter)
{
signal_handler_t *sh;
if (!volmeter)
return;
pthread_mutex_lock(&volmeter->mutex);
if (!volmeter->source)
goto exit;
sh = obs_source_get_signal_handler(volmeter->source);
signal_handler_disconnect(sh, "volume",
volmeter_source_volume_changed, volmeter);
signal_handler_disconnect(sh, "volume_level",
volmeter_source_volume_levels, volmeter);
signal_handler_disconnect(sh, "destroy",
volmeter_source_destroyed, volmeter);
volmeter->source = NULL;
exit:
pthread_mutex_unlock(&volmeter->mutex);
}
signal_handler_t *obs_volmeter_get_signal_handler(obs_volmeter_t *volmeter)
{
return (volmeter) ? volmeter->signals : NULL;
}
......@@ -137,6 +137,53 @@ EXPORT void obs_fader_detach_source(obs_fader_t *fader);
*/
EXPORT signal_handler_t *obs_fader_get_signal_handler(obs_fader_t *fader);
/**
* @brief Create a volume meter
* @param type the mapping type to use for the volume meter
* @return pointer to the volume meter object
*
* A volume meter object is used to prepare the sound levels reported by audio
* sources for display in a GUI.
* It will automatically take source volume into account and map the levels
* to a range [0.0f, 1.0f].
*/
EXPORT obs_volmeter_t *obs_volmeter_create(enum obs_fader_type type);
/**
* @brief Destroy a volume meter
* @param volmeter pointer to the volmeter object
*
* Destroy the volume meter and free all related data
*/
EXPORT void obs_volmeter_destroy(obs_volmeter_t *volmeter);
/**
* @brief Attach the volume meter to a source
* @param volmeter pointer to the volume meter object
* @param source pointer to the source object
* @return true on success
*
* When the volume meter is attached to a source it will start to listen to
* volume updates on the source and after preparing the data emit its own
* signal.
*/
EXPORT bool obs_volmeter_attach_source(obs_volmeter_t *volmeter,
obs_source_t *source);
/**
* @brief Detach the volume meter from the currently attached source
* @param volmeter pointer to the volume meter object
*/
EXPORT void obs_volmeter_detach_source(obs_volmeter_t *volmeter);
/**
* @brief Get signal handler for the volume meter object
* @param volmeter pointer to the volume meter object
* @return signal handler
*/
EXPORT signal_handler_t *obs_volmeter_get_signal_handler(
obs_volmeter_t *volmeter);
#ifdef __cplusplus
}
#endif
......@@ -48,6 +48,7 @@ struct obs_encoder;
struct obs_service;
struct obs_module;
struct obs_fader;
struct obs_volmeter;
typedef struct obs_display obs_display_t;
typedef struct obs_view obs_view_t;
......@@ -59,6 +60,7 @@ typedef struct obs_encoder obs_encoder_t;
typedef struct obs_service obs_service_t;
typedef struct obs_module obs_module_t;
typedef struct obs_fader obs_fader_t;
typedef struct obs_volmeter obs_volmeter_t;
#include "obs-source.h"
#include "obs-encoder.h"
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册