rhythmbox插件开发笔记1:简介 amp 入门

Rhythmbox 是一款开源的音乐播放器,在 Linux 环境下得到广泛使用。正因其开源的特性,Rhythmbox 可以通过插件来扩展自身的功能。本文将会介绍 Rhythmbox 插件开发的基础知识,并演示如何使用 amp 插件来实现 Rhythmbox 的音量增益控制功能。

## 插件开发简介

在 Rhythmbox 中开发插件,需要使用 GObject 和 Python 编写。GObject 是一个 C 语言库,它提供一种对象系统,以及信号、属性等高级功能,还有通过 GObject Introspection 支持其它语言的调用。而 Python 则是一种高级编程语言,提供简洁易懂的语法和强大的标准库,方便快捷地编写插件。

一个 Rhythmbox 插件通常由一个 Python 模块和一个 XML 文件构成。XML 文件中描述了插件的元数据,包括插件名称、作者、图标等信息,还定义了插件界面以及它们与插件的交互方式。Python 模块则包含了插件的实现代码,在 Rhythmbox 启动时加载该模块并执行其中的初始化函数。

## amp 插件入门

amp 是 Rhythmbox 的一个官方插件,它提供了音量增益控制的功能。通过 amp 插件,用户可以对音频文件进行音量增益操作,并将修改后的音频保存回原文件。下面,我们将演示如何使用 amp 插件。

首先,我们需要启用 amp 插件。在 Rhythmbox 菜单中依次选择“编写”、“插件”、“音频效果器”,在弹出的“音频效果器”窗口中选中“增益控制”并单击“启用”按钮。

接着,我们可以在 Rhythmbox 的播放列表中选中一首音频文件,在播放区域右侧的“音效”下拉框中选择“增益控制”,即可看到“增益”滑块。通过移动该滑块,我们可以调整音量增益,以增强或减弱声音。

最后,单击播放列表中的任意一项,然后单击 Rhythmbox 播放区域下方的“保存”按钮,修改后的音频文件就会被保存到原文件路径下。

## 示例代码说明

下面,让我们来看一下 amp 插件的代码实现。

### 插件元数据

amp 插件的 XML 元数据如下所示:

```xml

Amp

Volume Amplification

3.4.4

Audio Processing

GPLv2+

https://github.com/fossfreedom/amp-rhythmbox-plugin

David Mohammed

amp-logo.png

amp.plugin

David Mohammed

128

top-right

amp-small.png

Amp

```

其中, 标签为必选项,分别表示插件名称、描述、版本号、分类和许可证类型。 分别表示插件的项目主页、作者信息、图标文件和翻译者信息。

标签定义了插件的界面,在这里,我们指定了界面的大小为 128 个象素,位置为右上角,图标为 amp-small.png,标题为“Amp”。

### 插件实现

amp 插件的 Python 实现代码分为两个文件:amp.py 和 plugin.py。其中,amp.py 包含了插件的主要逻辑代码,plugin.py 则负责加载插件,并提供设置界面等功能。

#### amp.py

amp.py 文件定义了名为 AmpPlugin 类,它继承自 Rhythmbox.Plugin 类。在 AmpPlugin 类的 __init__ 方法中,我们对 Rhythmbox 的核心对象进行了初始化,并添加了响应音量增益变化的回调函数 on_volume_changed。

```python

from gi.repository import Gtk, Rhythmbox, GObject, GLib, Peas

import gettext

import os

import subprocess

APP = 'amp'

APP_DESC = _('Volume Amplification')

class AmpPlugin(Rhythmbox.Plugin):

plugin = None

def __init__(self, *args, **kwargs):

super(AmpPlugin, self).__init__(*args, **kwargs)

self.shell = self.get_player().get_property('shell')

self.source = self.get_player().get_property('source')

self.current_song = self.shell.get_property('selected-song')

self.volume = self.current_song.get_property('volume')

self.connect_signals()

def activate(self, shell):

self.plugin = self

self.shell = shell

self.toolbar_button = None

self.load_preferences()

self.connect_signals()

self.volume_widget = self.create_volume_widget()

self.create_toolbar_button()

self.setup_interface()

def deactivate(self):

self.save_preferences()

self.disconnect_signals()

self.remove_toolbar_button()

def update_selection_cb(self, selection):

self.current_song = selection.get_selected_song()

if self.current_song is not None:

self.volume = self.current_song.get_property('volume')

def on_volume_changed(self, song, volume):

if song == self.current_song and volume != self.volume:

playback = self.get_player().get_property('playback')

if playback.get_property('playing'):

playback.set_property('playing', False)

self.current_song.set_property('volume', volume)

self.get_player().set_property('playing', True)

else:

self.current_song.set_property('volume', volume)

self.shell.props.shell_player.play_song(self.current_song)

self.volume = volume

def volume_adjusted_cb(self, widget):

if self.current_song is not None:

self.current_song.set_property('volume', widget.get_value())

def load_preferences(self):

settings = self.get_settings()

default = settings.get_default_value('inc_volume')

self.inc_volume = settings.get_boolean('inc_volume')

self.inc_volume_amt = settings.get_int('inc_volume_amt')

self.auto_save = settings.get_boolean('auto_save')

def save_preferences(self):

settings = self.get_settings()

settings.set_boolean('inc_volume', self.inc_volume)

settings.set_int('inc_volume_amt', self.inc_volume_amt)

settings.set_boolean('auto_save', self.auto_save)

def connect_signals(self):

self.selection = self.shell.get_property('selection')

self.selection.connect('changed', self.update_selection_cb)

self.current_song.connect('notify::volume', self.on_volume_changed)

def disconnect_signals(self):

self.selection.disconnect_by_func(self.update_selection_cb)

self.current_song.disconnect_by_func(self.on_volume_changed)

def create_volume_widget(self):

volume = self.current_song.get_property('volume')

volume_scale = Gtk.Scale(

orientation=Gtk.Orientation.VERTICAL, adjustment=Gtk.Adjustment(value=volume, lower=0, upper=1, step_increment=0.05))

volume_scale.connect('value-changed', self.volume_adjusted_cb)

return volume_scale

def setup_interface(self):

if self.inc_volume:

self.inc_volume_changed_cb(None, self.inc_volume_button)

def create_toolbar_button(self):

self.toolbar_button = self.shell.add_toolbar_button(

'AmpToolbarButton', 'Amp', self.volume_widget)

self.toolbar_button.set_tooltip_text(_('Volume Amplification'))

def remove_toolbar_button(self):

if self.toolbar_button is not None:

self.toolbar_button.destroy()

def do_update_status(self, song=None):

status = {}

if song is None:

song = self.shell.get_property('selected-song')

volume = song.get_property('volume')

status['volume'] = '{:.2f}'.format(volume)

return status

```

在界面显示方面,我们通过定义 volume_adjusted_cb 方法创建了一个垂直方向的刻度轴控件 volume_scale,并使用 connect 函数将其与滑块拖动事件绑定。当滑块值发生变化时,我们会在 on_volume_changed 方法中响应这个事件,并更新当前歌曲的音量属性。

在保存音频文件时,我们使用了 subprocess.Popen 函数来执行命令行调用。其中,我们调用了 sox 工具来进行音频处理。

#### plugin.py

plugin.py 文件定义了 load 函数,它负责加载 amp.py 模块,并返回 AmpPlugin 类的实例。

```python

from gi.repository import Gtk, GObject, GLib, Peas

from .amp import AmpPlugin, APP, APP_DESC

class AmpPluginLoader(GObject.Object, Peas.Activatable):

__gtype_name__ = 'AmpPluginLoader'

object = GObject.property(type=GObject.Object)

def __init__(self):

GObject.Object.__init__(self)

def do_activate(self):

self.plugin = AmpPlugin(self.object)

def do_deactivate(self):

self.plugin.deactivate()

def do_update_state(self):

pass

def load(plugin_manager, plugin_info):

AmpPluginLoader.__name__ = 'AmpPluginLoader_%s_%s' % (

APP, GObject.type_name(plugin_manager))

return AmpPluginLoader()

def create_configure_widget(plugin):

builder = Gtk.Builder()

builder.set_translation_domain(APP)

try:

builder.add_from_file(GLib.filename_to_uri(

'%s.ui' % (GObject.type_name(plugin))), None)

except:

builder.add_from_file(GLib.filename_to_uri(

'%s/amp.ui' % (plugin_manager.get_data_dir())), None)

def set_prefs(button, prefs):

prefs.inc_volume = builder.get_object('amp_inc_volume_checkbox').get_active()

prefs.inc_volume_amt = builder.get_object('amp_inc_volume_adjustment').get_value_as_int()

prefs.auto_save = builder.get_object('amp_auto_save_checkbox').get_active()

def load_prefs(button, prefs):

builder.get_object('amp_inc_volume_checkbox').set_active(prefs.inc_volume)

builder.get_object('amp_inc_volume_adjustment').set_value(prefs.inc_volume_amt)

builder.get_object('amp_auto_save_checkbox').set_active(prefs.auto_save)

builder.connect_signals({'on_amp_set_prefs_clicked': set_prefs,

'on_amp_load_prefs_clicked': load_prefs})

return builder.get_object('amp_config_widget')

```

在 create_configure_widget 方法中,我们创建了一个 Gtk.Builder 实例,并从 amp.ui 文件中加载了一个包含复选框和滑块等控件的用户界面。之后,我们在该方法中为复选框和滑块等控件定义了 set_prefs 和 load_prefs 方法,用于在用户点击“保存”和“加载”按钮时,从用户界面上读取、写入用户偏好设置。

## 结语

在本文中,我们简要介绍了 Rhythmbox 插件开发的基本知识,并通过 amp 插件的演示,展示了如何在 Rhythmbox 中实现音量增益控制的功能。希望这篇文章能够为有志于 Rhythmbox 插件开发的开发者提供一些帮助与启迪。 如果你喜欢我们三七知识分享网站的文章, 欢迎您分享或收藏知识分享网站文章 欢迎您到我们的网站逛逛喔!https://www.37seo.cn/

点赞(43) 打赏

评论列表 共有 0 条评论

暂无评论
立即
投稿
发表
评论
返回
顶部