gpt4 book ai didi

audio - ALSA Hooks——在播放时修改音频

转载 作者:行者123 更新时间:2023-12-02 22:37:58 25 4
gpt4 key购买 nike

我对此不知所措——我有几个个人项目基本上需要我“点击”音频流:读取音频数据,进行一些处理并在最终发送之前修改音频数据到音频设备。

这些个人项目的一个例子是基于软件的主动交叉。如果我有一个有 6 个 channel 的音频设备(即 3 个左 + 3 个右),那么我可以读取数据,应用一个 LP 滤波器(×2 - 左 + 右),一个 BP 滤波器和一个 HP 滤波器并输出通过六个 channel 中的每一个流。

请注意,我知道如何编写执行此操作的播放器应用程序 — 相反,我想这样做,以便来自任何来源(音频播放器、视频播放器、youtube 或任何其他音频来源)的任何音频正在播放Web 浏览器等)受此处理。

我看过一些示例(例如,来自 alsa-project 网站的 pcm_min.c,Jeff Tranter 在 2004 年 9 月发表的 Linux Journal 文章中播放和记录示例),但我似乎还不够信息来做我上面描述的事情。

如有任何帮助或指点,我们将不胜感激。

最佳答案

您可以将项目实现为 LADSPA 插件,使用 audacity 或任何其他支持 LADSPA 插件的程序对其进行测试,并在需要时将其插入 alsa/pulseaudio/jack 播放链。

“LADSPA”是一个single header file定义一个简单的接口(interface)来编写音频处理插件。每个插件都有其输入/输出/控制端口和 run() 函数。 run() 函数针对每个样本 block 执行实际的音频处理——将“控制”参数应用于“输入”缓冲区并将结果写入“输出”缓冲区。

示例 LADSPA 立体声放大器插件(单个控制参数:“放大系数”,两个输入端口,两个输出端口):

///gcc -shared -o /full/path/to/plugindir/amp_example.so amp_example.c
#include <stdlib.h>
#include "ladspa.h"

enum PORTS {
PORT_CAMP,
PORT_INPUT1,
PORT_INPUT2,
PORT_OUTPUT1,
PORT_OUTPUT2
};

typedef struct {
LADSPA_Data *c_amp;
LADSPA_Data *i_audio1;
LADSPA_Data *i_audio2;
LADSPA_Data *o_audio1;
LADSPA_Data *o_audio2;
} MyAmpData;

static LADSPA_Handle myamp_instantiate(const LADSPA_Descriptor *Descriptor, unsigned long SampleRate)
{
MyAmpData *data = (MyAmpData*)malloc(sizeof(MyAmpData));
data->c_amp = NULL;
data->i_audio1 = NULL;
data->i_audio2 = NULL;
data->o_audio1 = NULL;
data->o_audio2 = NULL;
return data;
}

static void myamp_connect_port(LADSPA_Handle Instance, unsigned long Port, LADSPA_Data *DataLocation)
{
MyAmpData *data = (MyAmpData*)Instance;
switch (Port)
{
case PORT_CAMP: data->c_amp = DataLocation; break;
case PORT_INPUT1: data->i_audio1 = DataLocation; break;
case PORT_INPUT2: data->i_audio2 = DataLocation; break;
case PORT_OUTPUT1: data->o_audio1 = DataLocation; break;
case PORT_OUTPUT2: data->o_audio2 = DataLocation; break;
}
}

static void myamp_run(LADSPA_Handle Instance, unsigned long SampleCount)
{
MyAmpData *data = (MyAmpData*)Instance;
double amp = *data->c_amp;
size_t i;
for (i = 0; i < SampleCount; i++)
{
data->o_audio1[i] = data->i_audio1[i]*amp;
data->o_audio2[i] = data->i_audio2[i]*amp;
}
}

static void myamp_cleanup(LADSPA_Handle Instance)
{
MyAmpData *data = (MyAmpData*)Instance;
free(data);
}

static LADSPA_Descriptor myampDescriptor = {
.UniqueID = 123, // for public release see http://ladspa.org/ladspa_sdk/unique_ids.html
.Label = "amp_example",
.Name = "My Amplify Plugin",
.Maker = "alsauser",
.Copyright = "WTFPL",
.PortCount = 5,
.PortDescriptors = (LADSPA_PortDescriptor[]){
LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO,
LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO,
LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO,
LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO
},
.PortNames = (const char * const[]){
"Amplification factor",
"Input left",
"Input right",
"Output left",
"Output right"
},
.PortRangeHints = (LADSPA_PortRangeHint[]){
{ /* PORT_CAMP */
LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_DEFAULT_1,
0, /* LowerBound*/
10 /* UpperBound */
},
{0, 0, 0}, /* PORT_INPUT1 */
{0, 0, 0}, /* PORT_INPUT2 */
{0, 0, 0}, /* PORT_OUTPUT1 */
{0, 0, 0} /* PORT_OUTPUT2 */
},
.instantiate = myamp_instantiate,
//.activate = myamp_activate,
.connect_port = myamp_connect_port,
.run = myamp_run,
//.deactivate = myamp_deactivate,
.cleanup = myamp_cleanup
};

// NULL-terminated list of plugins in this library
const LADSPA_Descriptor *ladspa_descriptor(unsigned long Index)
{
if (Index == 0)
return &myampDescriptor;
else
return NULL;
}

(如果您更喜欢“简短”的 40 行版本,请参阅 https://pastebin.com/unCnjYfD)

根据需要添加任意数量的输入/输出 channel ,在 myamp_run() 函数中实现您的代码。构建插件并将 LADSPA_PATH 环境变量设置为您构建它的目录,以便其他应用程序可以找到它:

export LADSPA_PATH=/usr/lib/ladspa:/full/path/to/plugindir

audacity 或任何其他支持 LADSPA 插件的程序中对其进行测试。要在终端中测试它,您可以使用“ladspa-sdk”包中的 applyplugin 工具:

applyplugin input.wav output.wav /full/path/to/plugindir/amp_example.so amp_example 2

如果您喜欢结果,请将其插入您的默认播放链。对于普通的 alsa,您可以使用类似的配置(不适用于脉冲/插孔):

# ~/.asoundrc
pcm.myamp {
type plug
slave.pcm {
type ladspa
path "/usr/lib/ladspa" # required but ignored as `filename` is set
slave.pcm "sysdefault"
playback_plugins [{
filename "/full/path/to/plugindir/amp_example.so"
label "amp_example"
input.controls [ 2.0 ] # Amplification=2
}]
}
}
# to test it: aplay -Dmyamp input.wav

# to point "default" pcm to it uncomment next line:
#pcm.!default "myamp"

另见:

关于audio - ALSA Hooks——在播放时修改音频,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42866579/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com