- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我正在使用 PulseAudio API“实时”获取当前麦克风输入。缓冲区数据作为 16 位小端字节数组传送。我想做的是找出缓冲区中的最大峰值电平并将其转换为分贝值。为此,我必须将每两个字节数组值转换为一个整数值。在同一个循环过程中,我也在寻找最大值。之后,我将最大值转换为分贝值。这是 C 代码:
static ssize_t loop_write(int fd, const uint8_t *data, size_t size)
{
int newsize = size / 2;
uint16_t max_value = 0;
int i = 0;
for (i = 0; i < size; i += 2)
{
// put two bytes into one integer
uint16_t val = data[i] + ((uint32_t)data[i+1] << 8);
// find max value
if(val > max_value)
max_value = val;
}
// convert to decibel
float decibel = max_value / pow(2, 15);
if(decibel != 0)
decibel = 20 * log(decibel);
// print result
printf("%f, ", decibel);
return size;
}
据我所知,PA_SAMPLE_S16LE 的振幅值应介于 0 和 32768 之间。但在分贝转换之前,我得到的值介于 0 和 65536 之间。我的转换有什么问题吗?
为了完整起见,我还发布了我的 pulseaudio 设置:
int main(int argc, char*argv[])
{
char *device = "alsa_input.usb-041e_30d3_121023000184-00-U0x41e0x30d3.analog-mono";
// The sample type to use
static const pa_sample_spec ss = {
.format = PA_SAMPLE_S16LE,
.rate = 44100,
.channels = 1
};
pa_simple *s = NULL;
int ret = 1;
int error;
// Create the recording stream
if (!(s = pa_simple_new(NULL, argv[0], PA_STREAM_RECORD, device, "record", &ss, NULL, NULL, &error))) {
fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error));
goto finish;
}
for (;;) {
uint8_t buf[BUFSIZE];
// Record some data ...
if (pa_simple_read(s, buf, sizeof(buf), &error) < 0) {
fprintf(stderr, __FILE__": pa_simple_read() failed: %s\n", pa_strerror(error));
goto finish;
}
// And write it to STDOUT
if (loop_write(STDOUT_FILENO, buf, sizeof(buf)) != sizeof(buf)) {
fprintf(stderr, __FILE__": write() failed: %s\n", strerror(errno));
goto finish;
}
}
ret = 0;
finish:
if (s)
pa_simple_free(s);
return 0;
}
最佳答案
What I'd like to do is to find out the maximum peak level in the buffer and transform it into a decibel value.
从物理角度来看,这种方法没有意义。虽然可以指定与整个动态范围相关的单个样本值,但您可能对声级更感兴趣,即信号的功率。单个峰值,即使它是满刻度,也只携带很少的能量;由于谐波失真和有限的带宽,它可能会导致非常响亮的爆音,但从技术上讲,它的功率密度分布在整个频带有限的频谱上。
您真正应该做的是确定 RMS 值(均方根)。即
RMS = sqrt( sum( square(samples) )/n_samples )
编辑: 请注意,以上仅适用于没有直流部分的信号。大多数模拟声音接口(interface)都是交流耦合的,所以这不是问题。但如果还有 DC 部分,则必须先从样本中减去 mean 值,即
RMS_DC_reject = sqrt( sum( square(samples - mean_sample) )/n_samples )
我将把它作为练习留给读者将其添加到下面的代码中。
这为您提供了处理样本的能力,这正是您真正想要的。你问的是分贝。现在我要问你 dB(什么)?您需要引用值,因为 Bels(或分贝)是一种相对(即比较)度量。对于数字信号,满刻度为 0 dB(FS),零线为 -20 log10( 2^B )
,其中 B = 采样位深度
。对于大约 -96 dB(FS) 的 16 位信号。
如果我们谈论线路上的信号,一个常见的引用是功率 1 mW,在这种情况下,标度是 dB(m)。对于音频线路电平,已定义满刻度等于 1 mW 的信号功率,这是 1 V RMS 在 1 kOhm 电阻上耗散的功率(你又得到了 RMS)。
现在,由于我们的满刻度立即由输入电路确定,输入电路以 dB(m) 定义,您稍后可以将 dB(FS) 显示为 dB(m)(或 dBm)就好了。
说到实际音量,嗯,这取决于你的输入放大器增益,以及所用麦克风的转换效率。
To my knowledge the amplitude value should be between 0 and 32768 for PA_SAMPLE_S16LE. But I am getting values between 0 and 65536 before the decibel conversion. Is there anything wrong with my conversion?
您问的是有符号整数格式。但是您正在将值转换为无符号整数。并且由于 dB_FS 是相对于满量程的,所以不要将它除以位数。对于 16 位的零信号,结果应该约为 -96 dB。该除法无论如何都没有意义,因为它只是将您的 RMS 缩放到范围 [0; 1],但 log(0) 发散到 -infinity。因此你的 if
语句。但请记住,这是物理,物理是连续的,这里不应该有 if 语句。
你应该这样写
// even for signed values this should be 2^N
// we're going to deal with signed later
double const MAX_SIGNAL = 1 << SAMPLE_BITS;
// using double here, because float offers only 25 bits of
// distortion free dynamic range.
double accum = 0;
int const n_samples = size/2;
for (i = 0; i < size; i += 2)
{
// put two bytes into one __signed__ integer
int16_t val = data[i] + ((int16_t)data[i+1] << 8);
accum += val*val;
}
accum /= n_samples;
// Since we're using signed values we need to
// double the accumulation; of course this could be
// contracted into the statement above
accum *= 2.;
float const dB_FS = -20 * log10( MAX_SIGNAL - sqrt(accum) );
关于c - 16Bit Little Endian字节数组转整数数组转分贝值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15134740/
this post完美地描述了我的原始问题:我想遵循TDD: 写一个小测试 观看失败 写足够的代码使它成功 观看成功 重复 我正在IntelliJ中从事Grails项目。如果我只想编写普通的JUnit
据我所知,little-oh 应该有一个接近无穷大的 n 的极限(函数/little-oh,omega 函数)= 0,对于 little omega,极限应该等于无穷大。但是,是否有可能存在多个 li
您好,我目前正在使用 Little Man Computer对于一个学校项目,我知道 LMC 有一个 ADD 和一个 SUB 功能。但是我知道 LMC 中没有乘法或除法函数,我想知道为什么会这样。 最
little-oh 和 little Omega 符号的用途/目的是什么? 尽管我完全理解符号本身及其代表的含义。我还没有看到任何一本书或算法在任何计算中使用它们,所以我不禁想知道如果不使用它们,为什
我正在阅读“小计划者”,以更好地理解编程的某些核心元素(即递归),并获得更多关于如何像程序员一样思考的想法。 这本书被推荐作为入门级书籍,并且在引言中指出,我所需要知道的只是英文,数字和计数(我会这样
考虑以下 s 表达式: ((lambda (car) (car (quote (a b c)))) cdr) 在我尝试过的大多数方案实现中,计算结果为 (b c)因为cdr传递给 lambda,将其命
我的目标是拥有一个在后台运行的服务,并以指定的时间间隔(例如每 10 分钟)将我的设备位置发送到远程服务器。我正在尝试使用 Little Fluffy Location Library 来优化电池生命
我刚刚学习了 Python (3.x),但我一直在将十六进制字符串转换为 float 。我有这个十六进制字符串值:'0x22354942F31AFA42CE6A494311518A43082CAF43
所以,我可以理解为 0x1234 的一个字,当存储为 little-endian 时,在内存中变为 0x3412。我还看到字节 0x12 作为位域 a:4,b:4 将存储为 0x21。但是,如果我有更
我有一个 C 程序,它通过套接字在 UDP 数据包中从大型机接收数据。 C 程序的主机正在从 Unix(大端)更改为 Linux(小端),程序不再运行。我目前没有更改大型机客户端程序的选项。 程序执行
我正在使用 PulseAudio API“实时”获取当前麦克风输入。缓冲区数据作为 16 位小端字节数组传送。我想做的是找出缓冲区中的最大峰值电平并将其转换为分贝值。为此,我必须将每两个字节数组值转换
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 这个问题似乎与 help center 中定义的范围内的编程无关。 . 关闭 8 年前。 Improve
这个问题在这里已经有了答案: Difference between Big-O and Little-O Notation (5 个答案) 关闭 8 年前。 直观上,nb = o(an)(o 是小哦
我正在使用 file.readAsBytes()。但它只提供List来接收数据。我正在尝试 Uint8List 但没有用。 最佳答案 readAsBytes将为您提供字节列表。它可能是一个 Uint8
我想快速了解 F# 并且想知道“The Little ML'er”这本书是否会有所帮助,因为 F# 基于 OCaml,它是 ML 的衍生物。或者,ML 与 F# 的差别太大而没有任何帮助吗? 谢谢。
将小端系统中的数据转换为网络字节顺序所需的底层转换是什么?对于2字节和4字节数据,有众所周知的函数(如htons,ntohl等)来封装变化,1字节数据的字符串(如果有的话)会发生什么? 此外,维基百科
我很难理解 The Little Schemer 的 evens-only*&co 发生了什么事情第 145 页的示例。 这是代码: (define evens-only*&co (lambda (
在从SICP学习了一些Scheme之后,我开始阅读The Little Schemer(我觉得很有趣),并且完成了大约四分之一。我注意到,无需使用lambda即可编写许多(大多数?全部?)解决方案,而
我正在尝试了解计算机的实际工作原理,我找到了一些模拟器软件,但它们似乎非常复杂(我还是个初学者)。我看到了Little Man Computer (LMC)这是很旧的。恐怕软件的工作方式与现在完全不同
我正在尝试了解计算机的实际工作原理,我找到了一些模拟器软件,但它们似乎非常复杂(我还是个初学者)。我看到了Little Man Computer (LMC)这是很旧的。恐怕软件的工作方式与现在完全不同
我是一名优秀的程序员,十分优秀!