用机器生成的音乐监控 Linux 计算机
使用开源 FluidSynth 和 Perl 创建用于表示 Linux 计算机中各种参数状态的简单音调组合
有很多种可视化信息监控程序可用于评估计算机环境的运行状况。可以使用从简单文本显示,到实时图表和 3D 彩色图表的一切手段来协助您诊断个人计算设备、服务器计算设备或网络计算设备的问题。chordStats 将新的接口通道添加到系统监视设置中 —— 通过音调、音色以及和声传递信息。
大约在 1998 年,这种功能破土而出!Network Auralizer 被开发用于提供一种 “环境式” 音效环境,以辅助管理员来判断网络的基准和紊乱状态。使用根据特定事件回放的声音效果,管理员可以专注于网络的正常音效(例如,水浪声表示一般负载,鸟叫声表示网络事件),并在出问题时通过环境音效的变化立即得知情况。
chordStats 用添加音调的方法生成类似的声音环境,配备声音特征,并且根据系统负载创建和声。在本文中,您将创建一个简单的 Perl 脚本将通知事件发送给 FluidSynth,强制将各种系统事件解释为悦耳的声音,文中还探讨了增强音乐监控环境的未来选择。
要求
硬件
本文是部分基于 Intel® Pentium® 4 及 256 MB RAM 开发的。由于 FluidSynth MIDI 软件合成非常耗费资源,因此请不要尝试在低于 Pentium III 及 256 MB RAM 配置的机器上执行。还需要使用声卡。为实现本文的目的,我们假定用户的声卡中没有硬件 MIDI 波表合成器,并因此而使用了软件合成器。如果声卡中硬件合成器或需要将 chordStats 与外部硬件结合使用,请参阅 参考资料 获得帮助入门的链接。
软件
建议使用最新版本(2.4 或更高版本)的 Linux®,以及 Perl 和 FluidSynth。有关 FluidSynth 应用程序,请参阅 参考资料。另外建议您选用 SoundFonts。下载 部分附带了专用于打击乐器(管钟、钢琴、木琴)的内置 SoundFont。Internet 上有很多免费的 SoundFonts 资源(请参阅 参考资料)。
我们使用 vmstat 程序进行简单的系统状态监视。vmstat 是很多 Linux 发行版的标准配置,它提供了三种形式的 CPU 负载,一般磁盘块出入以及监视很多其他系统功能的能力。
设置和配置示例
FluidSynth 设置和检验
安装 FluidSynth 并下载示例 SoundFont 后,用命令 fluidsynth Hammered_Instruments.sf2
启动 FluidSynth 程序。您将看到类似以下内容的输出:
清单 1. FluidSynth 输出
lash_open_socket: could not look up host 'localhost': \ Servname not supported for ai_socktype lash_open_socket: could not connect to host 'localhost', service '14541' lash_comm_connect_to_server: could not create server connection lash_init: could not connect to server 'localhost' - disabling LASH lash_init: LASH_START_SERVER unset, not attempting to start server automatically fluidsynth: warning: Failed to pin the sample data to RAM; swapping is possible. ALSA lib timer_hw.c:269:(snd_timer_hw_open) \ extended read is not supported (SNDRV_TIMER_IOCTL_TREAD) fluidsynth: warning: Requested a period size of 64, got 940 instead fluidsynth: ALSA driver: Using format s16, rw, interleaved FluidSynth version 1.0.7 Copyright (C) 2000-2006 Peter Hanappe and others. Distributed under the LGPL license. SoundFont(R) is a registered trademark of E-mu Systems, Inc. Type 'help' for information on commands and 'help help' for help topics. >
不必担心这些警告消息。如果看到 >
符号,则 FluidSynth 已经准备好开始生成声音。尝试使用 noteon 5 77 100
在通道 5 中创建一个速率为 77、音量级别为 100 的通知。如果可以听到电子钢琴声,那么您就已经准备好继续执行下一步。键入 quit
或使用 Ctrl+C 组合键退出 FluidSynth。如果声音不可用或者收到错误消息,则请确保声音服务器已经启动并且混音器的设置都正确。
向 FluidSynth 发送多个通知事件时,您可能会注意到一些声音波动 —— 就像音乐 CD 跳帧一样。采用命令 fluidsynth Hammered_Instruments.sf2 -c10000 -z10000
增加音频缓冲区的数目和每个缓冲区的大小,以便缓解此问题。这将启动有 10,000 个音频缓冲区且每个缓冲区大小为 10,000 的 FluidSynth —— 这个空间很大,足以减少波动。
chordStats.pl 程序
一般策略
节拍、音色、和音以及通知速率的选择综合了艺术与科学两个方面,而这种综合的方式已经远远超出本文讨论范围。为了简化开发及信息分发,此程序的主要特性包括 1-Hz 刷新率和基于八度音阶的通知标准。vmstat 程序为基本系统数据提供了一个简单接口,而且创建了一个 1-Hz “心跳” 并以它为节拍。
清单 2. 主程序参数
#!/usr/bin/perl -w # chordStats.pl - create music based on system status use strict; my $vmStatCmd = "vmstat 1"; # run vmstat every second my $totalPackets = 0; # total of packets received and transmitted my $lineCount = 0; # count number of vmstat output lines my %fields = (); my $count = 0; # the field headers in the vmstat output, useful for referring to them by name for( split " ", "r b swpd free buff cache si so bi bo in cs us sy id wa" ){ $fields{$_} = $count; $count++; } # buffering output must be turned off because fluidsynth does not appear to # accept buffered input from stdin $|=1;
在脚本的开头,我们选择 vmstat 1
作为要被执行的命令并且每秒读取一次。为各次读取之间记录的信息包总数设置一个变量并记录从 vmstat 程序中读取到的行数,接下来定义标题。每秒都会从 vmstat 程序中读取字段标题 bi
(磁盘块入)、bo
(磁盘块出)和 us
(用户 CPU 使用量)。字段散列允许稍后在程序中按名称引用这些数据字段。请注意 $|=1
行。如果删除此行,您将会遇到一些难以诊断的行为;还需要为缓冲而头疼!
清单 3. 主程序开始
# open the vmstat program to read from open( INPIPE, "$vmStatCmd |" ) || die "can't read from vmstat"; # wait while the fluidsynth program opens sleep(3); while(my $statLine = <INPIPE> ){ # ignore the header display, and the fieldname display lines if( $statLine !~ /\-\-\-\-/ && $statLine !~ /swpd/ ){ # the first line of vmstat data is a recent average, ignore if( $lineCount > 2 ){
代码的下一部分将通过 vmstat 命令创建一个管道,程序将在其中每秒读取一次数据。等待几秒待 FluidSynth 程序激活后,即可开始处理 vmstat 输出。输出的前三行将被忽略,因为它们分别包含分隔符、标题信息和最新的平均值。
清单 4. 主程序通知处理
# reset wavetable synthesis if( $totalTime % 10 == 0 ){ print "reset\n" } $totalTime ++; my $note = ""; my @currLine = split " ", $statLine; # user cpu usage $note = $currLine[ $fields{us} ]; sendNote( $note, 14, 12, 96 ); # conglomerate disk i/o fields to one stat $note = $currLine[ $fields{bi} ] + $currLine[ $fields{bo} ]; if( $note > 1000 ){ $note = 1000; } $note = $note/10; sendNote( $note, 8, 12, 96 ); # network throughput on eth0 $note = getNetworkStats(); sendNote( $note, 5, 12, 84 ); }#if not first 3 lines to ignore }#if not a header line $lineCount++; }#while reading the pipe close(INPIPE);
如果经过了 10 秒钟时间,请将一个重置事件发送给 FluidSynth。这将清除仍在处理的所有剩余通知,即使它们已经减弱为听不见的音量级别。变量初始化后,与 us
(用户 CPU 使用量)对应的通知将被 sendNote
命令激活。由于 us
字段的值总是在 0 到 100 之间,因此无需进行其他处理。只要使用 sendNote
子例程在通道 14 中发送通知速率,其中最低速率为 12,最高速率为 96。
在最初通知事件后,vmstat 中的 bi
(磁盘块入)和 bo
(磁盘块出)数据字段将被聚结为范围在 0 到 1,000 的一个字段。请注意,这些值十分适于测试计算机的标准 IDE 磁盘设置。如果在整个磁盘子系统中有一个高磁盘配置或低磁盘配置,则可能需要修改最大值,以便更准确地表示可用带宽。一旦总磁盘使用量的范围落在 0 到 1,000 的范围内,就会被除以 10 以获得 0 到 100 之间的值。然后将在通道 8 中使用通常的最小值和最大值把此值作为通知速率发送。
getNetworkStats
部分略微更复杂,但正如您所见,返回的数据库值范围在 0 到 100 之间,并作为另一个 noteon
事件发送出去。注意此最后一个通知事件的最大值是 84。这是由于 SoundFont 仅在通道 5 中创建音频通知,音频速率范围从 0 到 84。这可以证明足以检测在最大负荷状态下和声中的变化的那些音频通知是表示有问题的。
在圈选循环括号和计时代码后,它就成为了子例程。
清单 5. sendNote 子例程
sub sendNote { my( $noteVal, $noteChan, $min, $max ) = @_; if( $noteVal < $min ){ $noteVal = $min; }else{ # divide it into twelve parts $noteVal = sprintf( "%0.0f", $noteVal/12); # reduce the note to 12 at the very least; $noteVal = ($noteVal * 12); if( $noteVal > $max ) { $noteVal = $max } }#if note is > minimum print "noteon $noteChan $noteVal 100\n"; }#sendNote
sendNote
子例程将获得值在 0 到 100 之间的通知速率,并将把该通知速率转换为基本通知中最接近 12 的通知步骤。在这种情况下,基本通知是 12,并且所有通知都将使用该值作为其 0
状态。这就为系统处于低负载状态时提供了频率相当低的 “跳动”(如果为令人满意的固定状态赋予人性的话)。为简单起见,所有通知都是以音量级别 100 输出的。根据其他系统元素修改音量级别会是添加信息的直观方法,而无需添加通知或和声变化。
清单 6. getNetworkStats 子例程
sub getNetworkStats { my $networkCmd = "/sbin/ifconfig eth0 | grep 'RX bytes'"; $networkCmd = `$networkCmd`; my $rxBytes = 0; my $txBytes = 0; chomp($networkCmd); for( $networkCmd ){ $rxBytes = substr($_, 19); $rxBytes = substr($rxBytes,0,index($rxBytes," ")); $txBytes = substr($_, 52); $txBytes = substr($txBytes,0,index($txBytes," ")); my $bothBytes = $rxBytes + $txBytes; if( $totalPackets == 0 ){ $totalPackets = $bothBytes; }else{ # find the difference between measurements, set maximum difference to # 1Mbit, which works well for `saturated' on a 100Mbit/sec network # reduce the value by a factor of 10000, which spreads the usage # nicely over 1-100 my $diffRX = $bothBytes - $totalPackets; if( $diffRX > 1000000 ){ $diffRX = 1000000 } $diffRX = ($diffRX / 10000); $totalPackets = $bothBytes; return( $diffRX ); }# if not first packet check }# packet count check }#getNetworkStats
如果 obtuse 方法接近网卡的负载,则这段代码是简单的。/sbin/ifconfig/eth0
命令的输出将列出收到和传输的所有信息包总数。在网络连接速度为 100Mbit/sec 的测试计算机上,超过 1000,000 个传输或接收信息包的所有情况都被视为完全饱和。该值的范围随后会被调整为 0 到 100 之间的通知速率,并作为电子钢琴通知播放。
运行 chordStats
chordStats 程序将读取标准的 vmstat 程序,并在不缓冲的情况下把通知事件写入 FluidSynth 的 stdin
。用命令 perl chordStats.pl |fluidsynth Hammered_Instruments.sf2 -c10000 -z10000 >/dev/null
启动 chordStats 程序。请记住,-c
和 -z
参数适用于扩大声音缓冲选项,而且可能需要进一步调整才能用于特殊的系统。
现在 chordStats 程序已经运行,尝试启动 Mozilla。首先要注意的是用管钟和钢片琴表示的 CPU 使用量的增加和磁盘 I/O 活动。如果用 wget
在 Mozilla 中装入一个较大的页面或下载文件,您将听到电子钢琴在网络链接饱和时发出更加刺耳的音调。
修改 chordStats
除了基本的系统负载之外,可以轻松地修改 chordStats 来表示计算环境的各个方面。回想 vmstat 1
将在每秒钟生成一张值列表。这可用于提供通知值,以及创建基本的节拍命令。修改 chordStats 的一种简单方法是将 vmstat
命令替换为刷新速度更快的事件生成器。例如,代码发行版归档附带的 fastUpdate.pl 程序将每五分之一秒扫描一次可用内存、当前进程和以太网中断。要使用最新更新的版本,请修改 chordStats.pl 程序以包含以下更改。
把命令从:
my $vmStatCmd = "vmstat 1";
更改为:
my $vmStatCmd = "./fastUpdate.pl 0.2 "
并把标题描述区域从:
for( split " ", "r b swpd free buff cache si so bi bo in cs us sy id wa" ){
更改为:
for( split " ", "memFree ethInt proc" ){
在主程序循环中,代码无需忽略标题行和输入的前两行。您可以根据需要移除这些条件。fastUpdate.pl 脚本的输出已被调整为范围在 0 到 100 之间,因此把 sendNote
事件从:
# user cpu usage $note = $currLine[ $fields{us} ]; sendNote( $note, 14, 12, 96 ); # conglomerate disk i/o fields to one stat $note = $currLine[ $fields{bi} ] + $currLine[ $fields{bo} ]; if( $note > 1000 ){ $note = 1000; } $note = $note/10; sendNote( $note, 8, 12, 96 ); # network throughput on eth0 $note = getNetworkStats(); sendNote( $note, 5, 12, 84 );
更改为:
$note = $currLine[ $fields{memFree} ]; sendNote( $note, 14, 48, 96 ); $note = $currLine[ $fields{ethInt} ]; sendNote( $note, 8, 48, 96 ); $note = $currLine[ $fields{proc} ]; sendNote( $note, 5, 48, 96 );
请注意,此修正版中将最小值增加到了 48。这是对选定的 SoundFont (Electronic_Sounds.sf2) 的特性的补偿。用命令 perl chordStats.pl |fluidsynth Electronic_Sounds.sf2 -c10000 -z10000 >/dev/null
来运行此更新版本的 chordStats,并且您将听到扬声器发射出的优美的 1960s sci-fi/B-movie 声道。
结束语
通过本示例,可以修改 chordStats 来根据所选的任何参数来播放音乐。修改 fastUpdate
以读取 strace
或 gprof
输出,比较构建过程日志文件并监视错误,或将多台计算机和网络设备的性能统计信息组合为通知流。
如果还有兴趣,请尝试根据附加数据修改音量参数。例如,如果信息包的数目保持不变,但中断次数不断增加,则需要增加网络通知的音量以强调对这方面的注意力。尝试移入三度音阶而不是整个八度音阶,或在检测到值发生较大变化时插入一个休止符以强调随后的阶段。
下载资源
- 源代码 (os-linuxmusic_chordStats-0.1.zip | 10MB)
相关主题
- 您可以参阅本文在 developerWorks 全球站点上的 英文原文 。
- 获得 chordStats 打击乐器示例。
- 查阅 sci-fi/B-movie 电子示例。
- 在 SourceForge 上了解关于 Peep! The Network Auralizer 的信息。
- 下载 FluidSynth。
- 在 Linux 上选择和使用 MIDI 硬件和软件的优秀资源 MIDI 的高级 PC 声卡。
- 在 HammerSound.net 查阅 SoundFonts 和说明。
- 可在 AndreLouis.com 获得含有大量 免费 SoundFonts 的优秀目录。
- 访问 developerWorks Linux 专区 以获得适用于 Linux 开发人员的更多资源。
- 访问 developerWorks 开放源码专区 以获得大量的 how-to 信息、工具和项目更新信息,可以帮助您利用开放源码技术进行开发,并与 IBM 的产品结合使用。
- 使用 IBM 试用软件 改进您的下一个开放源码开发项目,这些软件可以通过下载或从 DVD 中获得。
- 访问 Safari 在线书店 浏览关于各种开源技术主题的书籍。
- developerWorks podcasts 中包括了很多适合于软件开发人员的有趣的访谈和讨论。