在Python中捕获输出音频频谱

时间:2015-10-16 14:27:13

标签: python gstreamer audio-recording

挑战

捕获输出音频的频谱。

第一次尝试

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()

它在哪里失败?

由于某些原因,脚本有时只能工作。通常它不会打印任何东西。

在详细模式中找到@otopolsky记录以下行:

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

第二次尝试

正如@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

得到this output

卡住

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

虽然有效

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

(只更改了版本)。

第3次尝试

移至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()

它在哪里失败?

TypeError: unknown type GstValueList

问题

  • 如何修复脚本以适应每次执行?
  • 有没有其他方法可以使用Python捕获输出频谱?

3 个答案:

答案 0 :(得分:1)

似乎gst-python不支持GstValueList

GstValueList获取数据有一种不太优雅的方式。我们可以将消息结构转换为字符串,然后将字符串转换为float数组。

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()

答案 1 :(得分:0)

你正在使用0.10.36 ..很老..你能不能使用更新的gstreamer,比如说1.2?

你正在运行Ubuntu所以它不应该是一个问题.. 0.10.x和1.2可以很容易地在彼此旁边共存..我不知道你的python绑定是否正常..

这可能是有问题的一行(来自您的pastebin,请将该部分添加到您的问题中......)

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

这是来源code .. 它说的是关于舍入误差和未初始化的FFT的事情:

  

/ *如果我们还没有FFT上下文(或由于   参数*更改)获取一个并为所有内容分配内存   * /

     

/ *我们在发布消息之前处理的示例帧数   * interval以ns * /

为单位      

/ *以ns为单位的frames_per_interval舍入错误,   *汇总在cumulative_error * /

您可以再次运行以获取更多详细信息:

export GST_DEBUG=4,spectrum:7

你能在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

更新:

如果你听到它,请尝试使用alsasrc ..(autoaudiosink或alsasink):

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

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

arecord -l获取麦克风等输入设备。

输出设备的

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]

答案 2 :(得分:0)

意识到这个问题很老(但很有帮助!),但是...

我遇到了同样的问题,并且发现这只是使用get_list()绑定而不是get_value()的问题。这会为您提供一个布尔值和一个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)]