Board logo

标题: 用机器生成的音乐监控 Linux 计算机(2) [打印本页]

作者: look_w    时间: 2018-5-19 15:55     标题: 用机器生成的音乐监控 Linux 计算机(2)

chordStats.pl 程序一般策略节拍、音色、和音以及通知速率的选择综合了艺术与科学两个方面,而这种综合的方式已经远远超出本文讨论范围。为了简化开发及信息分发,此程序的主要特性包括 1-Hz 刷新率和基于八度音阶的通知标准。vmstat 程序为基本系统数据提供了一个简单接口,而且创建了一个 1-Hz “心跳” 并以它为节拍。
清单 2. 主程序参数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/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. 主程序开始
1
2
3
4
5
6
7
8
9
10
11
12
13
# 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. 主程序通知处理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
    # 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 子例程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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 子例程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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 之间的通知速率,并作为电子钢琴通知播放。




欢迎光临 电子技术论坛_中国专业的电子工程师学习交流社区-中电网技术论坛 (http://bbs.eccn.com/) Powered by Discuz! 7.0.0