tech.guitarrapc.cóm

C#, PowerShell, Unity, Cloud, Serverless Technical Update and Features

PowerShellでビープ音の「ドレミの歌」を奏でてみよう

ネタです。 次のブログをちらっと見てて、ドレミとかちょっと面白いなーと思いまして。 PowerShell を使用してコマンドラインでドレミ音を鳴らす方法 早速やってみました。

ビープをどうやって鳴らすの?

.NetのSystem.Console.Beep()を利用します。
Console.Beep メソッド (Int32, Int32)
PowerShellでStatic Methodを呼び出すには次のようにします。
[console]::Beep(int32,int32)
それぞれこうですね。
[console]::Beep(frequency,duration)
frequency 型 : System.Int32 ビープ音の周波数。37 Hz から 32767 Hz の範囲で指定できます。 duration 型 : System.Int32 ビープ音の再生時間。ミリ秒単位で指定します。

音価を定義

一々音価を書いていられませんので、先に定義してしまいます。 こうすることで、曲のテンポも簡単に調整できます。
#notes
$whole = 800 #全音符
$half = $whole / 2 #2分音符
$fter = $whole / 4 #4分音符
$qver = $whole / 8 #8分音符

$haft = $half + $fter #付点付2分音符
$ftqv = $fter + $qver #付点付4分音符

休符はどうする

PowerShellならStart-Sleepがありますので。 勿論.Beep()同様に、ミリ秒で指定も出来るので連動可能ですね。
Start-Sleep コマンドレットの使用 -m パラメータを使用してミリ秒で指定することもできます
という訳でScript Blockでこう。
#rest
$fterrest = {sleep -m $fter} #4分休符
$qverrest = {sleep -m $qver} #8分休符
実行するときはこのように"."を頭につけます。
. $fterrest

キーを定義

キーは周波数で定まります。 440Hz (A4)を基準音…とするのは今時のセンスが欠如していると言わざるを得ませんが……ご容赦ください。 最近は440Hzが基準音とは限らないんですけどね…… 今回は、A3からC5までの周波数を求めます。
3..17 | %{ [int]( [Math]::Pow( 2, $_ / 12.0 ) * 220.0 ) } 
int型で算出された周波数をキーに当てはめます。
#keys
$do = 262
$dos = 277
$re = 294
$res = 311
$mi = 330
$fa = 349
$fas = 370
$so = 392
$sos = 415
$la = 440
$sif = 466
$si = 494
$doO = 523
$doOs = 554
$reO = 587
ちなみにこんなサイトもありました。
ドレミファ音階のHz対応表

楽譜はどこだ

耳コピでも、記憶の通りでも(むしろ体が覚えてる)、いいんですが楽譜使いましょうか。 あまりキレイな楽譜じゃないですが…ふむ。
ドレミの歌「DO-RE-MI」(Em)

どうやって音をBeep()に渡す

この記述は無いなぁ。
foreach($v in @(262,294,330,349,392,440,494,523)){[Console]::beep($v,200)}
せめてこうですよね…
(262,294,330,349,392,440,494,523) | % {[Console]::beep($_,200)}
あとは、事前にvariableにセットした、音符と音価を一緒に渡すので2次元配列でこうですね。 ※ドレミの初めの2小節
*1 | % {[console]::Beep($_[0],$_[1])}

Get-BeepでFilter化しておく

毎回 | % {[console]::Beep($_[0],$_[1])}と書くのはあり得ませんので、filter化してしまいます。 ※filterはForeach-Objectが、実際に行っている中身だと思えば分かりやすいかと…。
filter Get-Beep {
	
	param(
	[Parameter(ValueFromPipeline=$true)]
	[int]$keyNote
	)
	
	[console]::Beep($keyNote[0],$keyNote[1])
	
}
これで、Beep()に渡す記述がすっきりします。
(($do,$ftqv),($re,$qver),($mi,$ftqv),($do,$qver),($mi,$fter),($do,$fter),($mi,$half)) | Get-Beep

Doremiの歌もFunction化して実行

ここまでくれば、楽譜通りに入力するだけです。 コード全貌はこの通り!
#notes
$whole = 800 #全音符
$half = $whole / 2 #2分音符
$fter = $whole / 4 #4分音符
$qver = $whole / 8 #8分音符

$haft = $half + $fter #付点付2分音符
$ftqv = $fter + $qver #付点付4分音符

#rest
$fterrest = {sleep -m $fter} #4分休符
$qverrest = {sleep -m $qver} #8分休符

#keys
$do = 262
$dos = 277
$re = 294
$res = 311
$mi = 330
$fa = 349
$fas = 370
$so = 392
$sos = 415
$la = 440
$sif = 466
$si = 494
$doO = 523
$doOs = 554
$reO = 587

filter Get-Beep {
	
	param(
	[Parameter(ValueFromPipeline=$true)]
	[int]$keyNote
	)
	
	[console]::Beep($keyNote[0],$keyNote[1])
	
}


function doremi-song {

    param(
    )

    begin{
    }
	
    process{
		
		1..2 | %{
			*2 | Get-Beep
			*3 | Get-Beep
			. $fterrest
			*4 | Get-Beep
			*5 | Get-Beep
			. $fterrest
			*6 | Get-Beep
			. $fterrest
			*7 | Get-Beep
			. $fterrest
			*8 | Get-Beep
			*9 | Get-Beep
			. $fterrest
		}

		. $fterrest
		*10 | Get-Beep
		*11 | Get-Beep
		*12 | Get-Beep
		*13 | Get-Beep
		*14 | Get-Beep
		. $qverrest
		*15 | Get-Beep
		. $qverrest
		*16 | Get-Beep
		. $qverrest
		*17 | Get-Beep
		. $qverrest
		*18 | Get-Beep
		*19 | Get-Beep
		*20 | Get-Beep
    }

    end{
    }
}

doremi-song

まとめ

Twitterで見せたところ、いいことまとめがwww 次回は、PowerShellでMMLにてドレミの歌を演奏してみます。

*1:$do,$ftqv),($re,$qver),($mi,$ftqv),($do,$qver),($mi,$fter),($do,$fter),($mi,$half

*2:$do,$ftqv),($re,$qver),($mi,$ftqv),($do,$qver),($mi,$fter),($do,$fter),($mi,$half

*3:$re,$ftqv),($mi,$qver),($fa,$qver),($fa,$qver),($mi,$qver),($re,$qver),($fa,$whole

*4:$mi,$ftqv),($fa,$qver),($so,$ftqv),($mi,$qver),($so,$fter),($mi,$fter),($so,$half

*5:$fa,$ftqv),($so,$qver),($la,$qver),($la,$qver),($so,$qver),($fa,$qver),($la,$whole

*6:$so,$ftqv),($do,$qver),($re,$qver),($mi,$qver),($fa,$qver),($so,$qver),($la,$whole

*7:$la,$ftqv),($re,$qver),($mi,$qver),($fas,$qver),($so,$qver),($la,$qver),($si,$whole

*8:$si,$ftqv),($mi,$qver),($fas,$qver),($sos,$qver),($la,$qver),($si,$qver),($doO,$whole

*9:$si,$qver),($sif,$qver),($la,$fter),($fa,$fter),($si,$fter),($so,$fter),($doO,$haft

*10:$do,$fter),($re,$fter),($mi,$fter

*11:$fa,$fter),($so,$fter),($la,$fter),($si,$fter),($doO,$fter),($doO,$fter),($si,$fter),($la,$fter

*12:$so,$fter),($fa,$fter),($mi,$fter),($re,$fter),($do,$fter),($mi,$fter),($mi,$half

*13:$mi,$fter),($so,$fter),($so,$half),($re,$fter),($fa,$fter),($fa,$half

*14:$la,$fter),($si,$fter),($si,$half),($do,$qver),($mi,$qver),($mi,$fter

*15:$mi,$qver),($so,$qver),($so,$fter

*16:$re,$qver),($fa,$qver),($fa,$fter

*17:$la,$qver),($si,$qver),($si,$fter

*18:$so,$half),($do,$half

*19:$la,$half),($fa,$half),($mi,$half),($do,$half),($re,$whole

*20:$so,$half),($do,$half),($la,$half),($si,$half),($doO,$half),($reO,$half),($doO,$whole