简体   繁体   English

在 Python 中捕获输出音频频谱

[英]Capture output audio spectrum in Python

The challenge挑战

To capture the spectrum of the output audio.捕获输出音频的频谱。

1st attempt第一次尝试

import gtk, gst

def playerbin_message(bus, message):
    if message.type == gst.MESSAGE_ELEMENT:
        struct = message.structure
        if struct.get_name() == 'spectrum':
            print struct['magnitude']
pipeline = gst.parse_launch(
    'pulsesrc device="alsa_output.pci-0000_00_1b.0.analog-stereo.monitor" ! spectrum ! fakesink')
bus = pipeline.get_bus()
bus.add_signal_watch()
bus.connect('message', playerbin_message)
pipeline.set_state(gst.STATE_PLAYING)
gtk.main()

Where does it fail?它在哪里失败?

From some reason, the script work only sometimes.由于某种原因,脚本仅在某些时候起作用。 Usually it won't print anything.通常它不会打印任何东西。

@otopolsky found in verbose mode log the following line: @otopolsky 在详细模式下发现记录以下行:

INFO spectrum gstspectrum.c:1051:gst_spectrum_transform_ip:<spectrum0> interval 0:00:00.100000000, fpi 4410, error 0:00:00.000000000

2nd attempt第二次尝试

As @otopolsky adviced, I tried running:正如@otopolsky 所建议的,我尝试运行:

GST_DEBUG=4,spectrum:7 gst-launch-0.10 pulsesrc device="alsa_output.pci-0000_00_1b.0.analog-stereo.monitor" ! spectrum ! fakesink > out.log

And got this output .并得到了这个输出

This get stuck :卡住了

gst-launch-0.10 -v -m pulsesrc device="alsa_output.pci-0000_00_1b.0.analog-stereo.monitor" ! spectrum ! fakesink

While this works :虽然这有效

gst-launch-1.0 -v -m pulsesrc device="alsa_output.pci-0000_00_1b.0.analog-stereo.monitor" ! spectrum ! fakesink

(only the version was changed). (仅更改了版本)。

3rd attempt第三次尝试

Moved to python gi:移至 python gi:

import gi
gi.require_version('Gst', '1.0')
from gi.repository import GObject, Gst

GObject.threads_init()
Gst.init(None)

def handler(bus, msg):
    if msg.type == Gst.MessageType.ELEMENT:
        struct = msg.get_structure()
        print struct.get_value('magnitude')

p = Gst.parse_launch(
    'pulsesrc device="alsa_output.pci-0000_00_1b.0.analog-stereo.monitor" ! spectrum ! fakesink')

bus = p.get_bus()
bus.add_signal_watch()
bus.connect('message', handler)
p.set_state(Gst.State.PLAYING)

ctx = GObject.main_context_default()
while ctx:
    ctx.iteration()

Where does it fail?它在哪里失败?

TypeError: unknown type GstValueList

The questions问题

  • How can the scripts be fixed to work on every execution?如何修复脚本以在每次执行时工作?
  • Is there another way to capture output spectrum using Python?是否有另一种使用 Python 捕获输出频谱的方法?

You are using 0.10.36 .. quite old.. can you not use newer gstreamer, say 1.2?您正在使用 0.10.36 .. 很旧.. 您不能使用较新的 gstreamer,例如 1.2?

you are running Ubuntu so it should not be a problem.. the 0.10.x and 1.2 can easily coexist beside each other.. I dont know if its ok with your python bindings..你正在运行 Ubuntu 所以它应该不是问题.. 0.10.x 和 1.2 可以很容易地彼此共存.. 我不知道你的 python 绑定是否可以..

This may be the problematic line (from your pastebin, please add that part into your question..)这可能是有问题的行(来自您的粘贴箱,请将该部分添加到您的问题中..)

INFO spectrum gstspectrum.c:1051:gst_spectrum_transform_ip:<spectrum0> interval 0:00:00.100000000, fpi 4410, error 0:00:00.000000000

This is the source code .. It says something about rounding error and uninitialized FFT:这是源代码..它说明了舍入误差和未初始化的 FFT:

/* If we don't have a FFT context yet (or it was reset due to parameter * changes) get one and allocate memory for everything /* 如果我们还没有 FFT 上下文(或者由于参数 * 更改而重置)获取一个并为所有内容分配内存
*/ */

/* number of sample frames we process before posting a message * interval is in ns */ /* 我们在发布消息之前处理的样本帧数 * 间隔以 ns 为单位 */

/* rounding error for frames_per_interval in ns, * aggregated it in accumulated_error */ /* ns中frames_per_interval的舍入误差,*在accumulated_error中聚合*/

you can run again to get more details with:您可以再次运行以获取更多详细信息:

export GST_DEBUG=4,spectrum:7

Can you run the pipe in gst-launch?您可以在 gst-launch 中运行管道吗?

GST_DEBUG=4,spectrum:7 gst-launch-0.10 pulsesrc device="alsa_output.pci-0000_00_1b.0.analog-stereo.monitor" ! spectrum ! fakesink

UPDATE:更新:

Try with alsasrc if you hear it.. (autoaudiosink or alsasink):如果您听到它,请尝试使用 alsasrc..(autoaudiosink 或 alsasink):

gst-launch-1.0 alsasrc device=hw:0,2 ! spectrum ! autoaudiosink

hw:X,Y format explanation: X = card number, Y = device name hw:X,Y格式说明: X = card number, Y = device name

Getting it from arecord -l for input devices like microphone etc..arecord -l获取它用于麦克风等输入设备。

and aplay -l for output devices..aplay -l用于输出设备..

> arecord -l | grep card
card 0: PCH [HDA Intel PCH], device 0: ALC887-VD Analog [ALC887-VD Analog]
card 0: PCH [HDA Intel PCH], device 2: ALC887-VD Alt Analog [ALC887-VD Alt Analog]

It seems that GstValueList is not supported by gst-python. gst-python 似乎不支持GstValueList

There is an inelegant way to get data from the GstValueList .GstValueList获取数据有一种不雅的方式。 We can convert the message structure into a string, then convert the string to a float array.我们可以将消息结构转换为字符串,然后将字符串转换为浮点数组。

import gi
gi.require_version('Gst', '1.0')
from gi.repository import GObject, Gst
import re

GObject.threads_init()
Gst.init(None)


def on_message(bus, msg):
    struct = msg.get_structure()
    if struct.get_name() == 'spectrum':
        struct_str = struct.to_string()
        magnitude_str = re.match(r'.*magnitude=\(float\){(.*)}.*', struct_str)
        if magnitude_str:
            magnitude = map(float, magnitude_str.group(1).split(','))
            print magnitude

pipeline = Gst.parse_launch(
    'audiotestsrc ! spectrum interval=1000000000 bands=16 post-messages=true message-magnitude=1 ! directsoundsink'
)

bus = pipeline.get_bus()
bus.add_signal_watch()
bus.connect('message::element', on_message)

pipeline.set_state(Gst.State.PLAYING)

loop = GObject.MainLoop()
loop.run()

Realising this question is very old (but helpful!), but...意识到这个问题已经很老了(但很有帮助!),但是......

I had the same problem and figured out it was just a matter of using the get_list() binding not get_value() .我遇到了同样的问题,并发现这只是使用get_list()绑定而不是get_value() This gives you a boolean and and a GObject.ValueArray which seems usable:这为您提供了一个布尔值和一个似乎可用的GObject.ValueArray

struct = msg.get_structure()
success, values = struct.get_list("magnitude")
if struct.get_name() == "spectrum":
    mags = [values.get_nth(i) for i in range(values.n_values)]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM