Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
尘离序散
obs-studio
提交
9f3ab85d
O
obs-studio
项目概览
尘离序散
/
obs-studio
与 Fork 源项目一致
从无法访问的项目Fork
通知
30
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
O
obs-studio
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
9f3ab85d
编写于
12月 21, 2014
作者:
J
Jim
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #311 from fryshorts/audio-analyzer-move
libobs: Move audio level calculations
上级
c456e421
43552478
变更
5
隐藏空白更改
内联
并排
Showing
5 changed file
with
239 addition
and
103 deletion
+239
-103
libobs/obs-audio-controls.c
libobs/obs-audio-controls.c
+185
-19
libobs/obs-audio-controls.h
libobs/obs-audio-controls.h
+43
-0
libobs/obs-source.c
libobs/obs-source.c
+10
-69
obs/volume-control.cpp
obs/volume-control.cpp
+1
-14
obs/volume-control.hpp
obs/volume-control.hpp
+0
-1
未找到文件。
libobs/obs-audio-controls.c
浏览文件 @
9f3ab85d
...
...
@@ -54,6 +54,21 @@ struct obs_volmeter {
obs_source_t
*
source
;
enum
obs_fader_type
type
;
float
cur_db
;
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
;
};
static
const
char
*
fader_signals
[]
=
{
...
...
@@ -260,35 +275,137 @@ 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
)
static
void
volmeter_source_
destroyed
(
void
*
vptr
,
calldata_t
*
calldata
)
{
UNUSED_PARAMETER
(
calldata
);
struct
obs_volmeter
*
volmeter
=
(
struct
obs_volmeter
*
)
vptr
;
pthread_mutex_lock
(
&
volmeter
->
mutex
);
obs_volmeter_detach_source
(
volmeter
);
}
float
mul
=
db_to_mul
(
volmeter
->
cur_db
);
static
void
volmeter_sum_and_max
(
float
*
data
,
size_t
frames
,
float
*
sum
,
float
*
max
)
{
float
s
=
*
sum
;
float
m
=
*
max
;
float
level
=
(
float
)
calldata_float
(
calldata
,
"level"
);
float
magnitude
=
(
float
)
calldata_float
(
calldata
,
"magnitude"
);
float
peak
=
(
float
)
calldata_float
(
calldata
,
"peak"
);
for
(
float
*
c
=
data
;
c
<
data
+
frames
;
++
c
)
{
const
float
pow
=
*
c
*
*
c
;
s
+=
pow
;
m
=
(
m
>
pow
)
?
m
:
pow
;
}
*
sum
=
s
;
*
max
=
m
;
}
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
));
/**
* @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
float
alpha
=
0
.
15
f
;
const
float
frames
=
(
float
)
volmeter
->
ival_frames
;
const
float
samples
=
frames
*
(
float
)
volmeter
->
channels
;
const
float
ival_max
=
sqrtf
(
volmeter
->
ival_max
);
const
float
ival_rms
=
sqrtf
(
volmeter
->
ival_sum
/
samples
);
if
(
ival_max
>
volmeter
->
vol_max
)
{
volmeter
->
vol_max
=
ival_max
;
}
else
{
volmeter
->
vol_max
=
alpha
*
volmeter
->
vol_max
+
(
1
.
0
f
-
alpha
)
*
ival_max
;
}
signal_handler_t
*
sh
=
volmeter
->
signals
;
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
+=
frames
;
}
pthread_mutex_unlock
(
&
volmeter
->
mutex
);
volmeter
->
vol_mag
=
alpha
*
ival_rms
+
volmeter
->
vol_mag
*
(
1
.
0
f
-
alpha
);
signal_levels_updated
(
sh
,
volmeter
,
level
,
magnitude
,
peak
);
/* reset interval data */
volmeter
->
ival_frames
=
0
;
volmeter
->
ival_sum
=
0
.
0
f
;
volmeter
->
ival_max
=
0
.
0
f
;
}
static
void
volmeter_source_destroyed
(
void
*
vptr
,
calldata_t
*
calldata
)
static
bool
volmeter_process_audio_data
(
obs_volmeter_t
*
volmeter
,
struct
audio_data
*
data
)
{
bool
updated
=
false
;
size_t
frames
=
0
;
size_t
samples
=
0
;
size_t
left
=
data
->
frames
;
float
*
adata
=
(
float
*
)
data
->
data
[
0
];
while
(
left
)
{
frames
=
(
volmeter
->
ival_frames
+
left
>
volmeter
->
update_frames
)
?
volmeter
->
update_frames
-
volmeter
->
ival_frames
:
left
;
samples
=
frames
*
volmeter
->
channels
;
volmeter_sum_and_max
(
adata
,
samples
,
&
volmeter
->
ival_sum
,
&
volmeter
->
ival_max
);
volmeter
->
ival_frames
+=
frames
;
left
-=
frames
;
adata
+=
samples
;
/* break if we did not reach the end of the interval */
if
(
volmeter
->
ival_frames
!=
volmeter
->
update_frames
)
break
;
volmeter_calc_ival_levels
(
volmeter
);
updated
=
true
;
}
return
updated
;
}
static
void
volmeter_source_data_received
(
void
*
vptr
,
calldata_t
*
calldata
)
{
UNUSED_PARAMETER
(
calldata
);
struct
obs_volmeter
*
volmeter
=
(
struct
obs_volmeter
*
)
vptr
;
bool
updated
=
false
;
float
mul
,
level
,
mag
,
peak
;
signal_handler_t
*
sh
;
obs_volmeter_detach_source
(
volmeter
);
pthread_mutex_lock
(
&
volmeter
->
mutex
);
struct
audio_data
*
data
=
calldata_ptr
(
calldata
,
"data"
);
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
));
sh
=
volmeter
->
signals
;
}
pthread_mutex_unlock
(
&
volmeter
->
mutex
);
if
(
updated
)
signal_levels_updated
(
sh
,
volmeter
,
level
,
mag
,
peak
);
}
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
);
volmeter
->
channels
=
audio_output_get_channels
(
audio
);
volmeter
->
update_frames
=
volmeter
->
update_ms
*
sr
/
1000
;
volmeter
->
peakhold_frames
=
volmeter
->
peakhold_ms
*
sr
/
1000
;
}
obs_fader_t
*
obs_fader_create
(
enum
obs_fader_type
type
)
...
...
@@ -521,6 +638,9 @@ obs_volmeter_t *obs_volmeter_create(enum obs_fader_type type)
}
volmeter
->
type
=
type
;
obs_volmeter_set_update_interval
(
volmeter
,
50
);
obs_volmeter_set_peak_hold
(
volmeter
,
1500
);
return
volmeter
;
fail:
obs_volmeter_destroy
(
volmeter
);
...
...
@@ -553,8 +673,8 @@ bool obs_volmeter_attach_source(obs_volmeter_t *volmeter, obs_source_t *source)
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
,
"
audio_data
"
,
volmeter_source_
data_received
,
volmeter
);
signal_handler_connect
(
sh
,
"destroy"
,
volmeter_source_destroyed
,
volmeter
);
...
...
@@ -581,8 +701,8 @@ void obs_volmeter_detach_source(obs_volmeter_t *volmeter)
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
,
"
audio_data
"
,
volmeter_source_
data_received
,
volmeter
);
signal_handler_disconnect
(
sh
,
"destroy"
,
volmeter_source_destroyed
,
volmeter
);
...
...
@@ -597,3 +717,49 @@ signal_handler_t *obs_volmeter_get_signal_handler(obs_volmeter_t *volmeter)
return
(
volmeter
)
?
volmeter
->
signals
:
NULL
;
}
void
obs_volmeter_set_update_interval
(
obs_volmeter_t
*
volmeter
,
const
unsigned
int
ms
)
{
if
(
!
volmeter
||
!
ms
)
return
;
pthread_mutex_lock
(
&
volmeter
->
mutex
);
volmeter
->
update_ms
=
ms
;
volmeter_update_audio_settings
(
volmeter
);
pthread_mutex_unlock
(
&
volmeter
->
mutex
);
}
unsigned
int
obs_volmeter_get_update_interval
(
obs_volmeter_t
*
volmeter
)
{
if
(
!
volmeter
)
return
0
;
pthread_mutex_lock
(
&
volmeter
->
mutex
);
const
unsigned
int
interval
=
volmeter
->
update_ms
;
pthread_mutex_unlock
(
&
volmeter
->
mutex
);
return
interval
;
}
void
obs_volmeter_set_peak_hold
(
obs_volmeter_t
*
volmeter
,
const
unsigned
int
ms
)
{
if
(
!
volmeter
)
return
;
pthread_mutex_lock
(
&
volmeter
->
mutex
);
volmeter
->
peakhold_ms
=
ms
;
volmeter_update_audio_settings
(
volmeter
);
pthread_mutex_unlock
(
&
volmeter
->
mutex
);
}
unsigned
int
obs_volmeter_get_peak_hold
(
obs_volmeter_t
*
volmeter
)
{
if
(
!
volmeter
)
return
0
;
pthread_mutex_lock
(
&
volmeter
->
mutex
);
const
unsigned
int
peakhold
=
volmeter
->
peakhold_ms
;
pthread_mutex_unlock
(
&
volmeter
->
mutex
);
return
peakhold
;
}
libobs/obs-audio-controls.h
浏览文件 @
9f3ab85d
...
...
@@ -208,6 +208,49 @@ EXPORT void obs_volmeter_detach_source(obs_volmeter_t *volmeter);
EXPORT
signal_handler_t
*
obs_volmeter_get_signal_handler
(
obs_volmeter_t
*
volmeter
);
/**
* @brief Set the update interval for the volume meter
* @param volmeter pointer to the volume meter object
* @param ms update interval in ms
*
* This sets the update interval in milliseconds that should be processed before
* the resulting values are emitted by the levels_updated signal. The resulting
* number of audio samples is rounded to an integer.
*
* Please note that due to way obs does receive audio data from the sources
* this is no hard guarantee for the timing of the signal itself. When the
* volume meter receives a chunk of data that is multiple the size of the sample
* interval, all data will be sampled and the values updated accordingly, but
* only the signal for the last segment is actually emitted.
* On the other hand data might be received in a way that will cause the signal
* to be emitted in shorter intervals than specified here under some
* circumstances.
*/
EXPORT
void
obs_volmeter_set_update_interval
(
obs_volmeter_t
*
volmeter
,
const
unsigned
int
ms
);
/**
* @brief Get the update interval currently used for the volume meter
* @param volmeter pointer to the volume meter object
* @return update interval in ms
*/
EXPORT
unsigned
int
obs_volmeter_get_update_interval
(
obs_volmeter_t
*
volmeter
);
/**
* @brief Set the peak hold time for the volume meter
* @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
);
#ifdef __cplusplus
}
#endif
libobs/obs-source.c
浏览文件 @
9f3ab85d
...
...
@@ -80,10 +80,9 @@ static const char *source_signals[] = {
"void hide(ptr source)"
,
"void rename(ptr source, string new_name, string prev_name)"
,
"void volume(ptr source, in out float volume)"
,
"void volume_level(ptr source, float level, float magnitude, "
"float peak)"
,
"void update_properties(ptr source)"
,
"void update_flags(ptr source, int flags)"
,
"void audio_data(ptr source, ptr data)"
,
NULL
};
...
...
@@ -261,7 +260,7 @@ void obs_source_destroy(struct obs_source *source)
pthread_mutex_destroy
(
&
source
->
audio_mutex
);
pthread_mutex_destroy
(
&
source
->
video_mutex
);
obs_context_data_free
(
&
source
->
context
);
if
(
source
->
owns_info_id
)
bfree
((
void
*
)
source
->
info
.
id
);
...
...
@@ -627,77 +626,19 @@ static inline void handle_ts_jump(obs_source_t *source, uint64_t expected,
reset_audio_timing
(
source
,
ts
,
os_time
);
}
static
void
calc_volume_levels
(
struct
obs_source
*
source
,
float
*
array
,
size_t
frames
,
float
volume
)
{
float
sum_val
=
0
.
0
f
;
float
max_val
=
0
.
0
f
;
float
rms_val
=
0
.
0
f
;
audio_t
*
audio
=
obs_get_audio
();
const
uint32_t
sample_rate
=
audio_output_get_sample_rate
(
audio
);
const
size_t
channels
=
audio_output_get_channels
(
audio
);
const
size_t
count
=
frames
*
channels
;
const
size_t
vol_peak_delay
=
sample_rate
*
3
;
const
float
alpha
=
0
.
15
f
;
for
(
size_t
i
=
0
;
i
<
count
;
i
++
)
{
float
val
=
array
[
i
];
float
val_pow2
=
val
*
val
;
sum_val
+=
val_pow2
;
max_val
=
(
max_val
>
val_pow2
)
?
max_val
:
val_pow2
;
}
/*
We want the volume meters scale linearly in respect to current
volume, so, no need to apply volume here.
*/
UNUSED_PARAMETER
(
volume
);
rms_val
=
sqrtf
(
sum_val
/
(
float
)
count
);
max_val
=
sqrtf
(
max_val
);
if
(
max_val
>
source
->
vol_max
)
source
->
vol_max
=
max_val
;
else
source
->
vol_max
=
alpha
*
source
->
vol_max
+
(
1
.
0
f
-
alpha
)
*
max_val
;
if
(
source
->
vol_max
>
source
->
vol_peak
||
source
->
vol_update_count
>
vol_peak_delay
)
{
source
->
vol_peak
=
source
->
vol_max
;
source
->
vol_update_count
=
0
;
}
else
{
source
->
vol_update_count
+=
count
;
}
source
->
vol_mag
=
alpha
*
rms_val
+
source
->
vol_mag
*
(
1
.
0
f
-
alpha
);
}
/* TODO update peak/etc later */
static
void
obs_source_update_volume_level
(
obs_source_t
*
source
,
static
void
source_signal_audio_data
(
obs_source_t
*
source
,
struct
audio_data
*
in
)
{
if
(
source
&&
in
)
{
struct
calldata
data
=
{
0
};
struct
calldata
data
;
calc_volume_levels
(
source
,
(
float
*
)
in
->
data
[
0
],
in
->
frames
,
in
->
volume
);
calldata_init
(
&
data
);
calldata_set_ptr
(
&
data
,
"source"
,
source
);
calldata_set_float
(
&
data
,
"level"
,
source
->
vol_max
);
calldata_set_float
(
&
data
,
"magnitude"
,
source
->
vol_mag
);
calldata_set_float
(
&
data
,
"peak"
,
source
->
vol_peak
);
calldata_set_ptr
(
&
data
,
"source"
,
source
);
calldata_set_ptr
(
&
data
,
"data"
,
in
);
signal_handler_signal
(
source
->
context
.
signals
,
"volume_level"
,
&
data
);
signal_handler_signal
(
obs
->
signals
,
"source_volume_level"
,
&
data
);
signal_handler_signal
(
source
->
context
.
signals
,
"audio_data"
,
&
data
);
calldata_free
(
&
data
);
}
calldata_free
(
&
data
);
}
static
inline
uint64_t
uint64_diff
(
uint64_t
ts1
,
uint64_t
ts2
)
...
...
@@ -740,7 +681,7 @@ static void source_output_audio_line(obs_source_t *source,
obs
->
audio
.
user_volume
*
obs
->
audio
.
present_volume
;
audio_line_output
(
source
->
audio_line
,
&
in
);
obs_source_update_volume_level
(
source
,
&
in
);
source_signal_audio_data
(
source
,
&
in
);
}
enum
convert_type
{
...
...
obs/volume-control.cpp
浏览文件 @
9f3ab85d
...
...
@@ -12,8 +12,6 @@
using
namespace
std
;
#define UPDATE_INTERVAL_MS 50
void
VolControl
::
OBSVolumeChanged
(
void
*
data
,
calldata_t
*
calldata
)
{
Q_UNUSED
(
calldata
);
...
...
@@ -42,17 +40,7 @@ void VolControl::VolumeChanged()
void
VolControl
::
VolumeLevel
(
float
mag
,
float
peak
,
float
peakHold
)
{
uint64_t
curMeterTime
=
os_gettime_ns
()
/
1000000
;
/*
Add again peak averaging?
*/
/* only update after a certain amount of time */
if
((
curMeterTime
-
lastMeterTime
)
>
UPDATE_INTERVAL_MS
)
{
lastMeterTime
=
curMeterTime
;
volMeter
->
setLevels
(
mag
,
peak
,
peakHold
);
}
volMeter
->
setLevels
(
mag
,
peak
,
peakHold
);
}
void
VolControl
::
SliderChanged
(
int
vol
)
...
...
@@ -74,7 +62,6 @@ void VolControl::SetName(const QString &newName)
VolControl
::
VolControl
(
OBSSource
source_
)
:
source
(
source_
),
lastMeterTime
(
0
),
levelTotal
(
0.0
f
),
levelCount
(
0.0
f
),
obs_fader
(
obs_fader_create
(
OBS_FADER_CUBIC
)),
...
...
obs/volume-control.hpp
浏览文件 @
9f3ab85d
...
...
@@ -32,7 +32,6 @@ private:
QLabel
*
volLabel
;
VolumeMeter
*
volMeter
;
QSlider
*
slider
;
uint64_t
lastMeterTime
;
float
levelTotal
;
float
levelCount
;
obs_fader_t
*
obs_fader
;
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录