tech.guitarrapc.cóm

Technical updates

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

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

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

.NET のSystem.Console.Beep()を利用します。

Console.Beep メソッド (Int32, Int32)

PowerShellでStatic Methodを呼び出すには次のようにします。

[console]::Beep(int32 frequency, int32 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 で渡すのはメンテしにくくなります。

foreach($v in @(262,294,330,349,392,440,494,523)){[Console]::beep($v,200)}

ForEach-Object で渡すと少しは扱いやすくなります。

(262,294,330,349,392,440,494,523) | % {[Console]::beep($_,200)}

変数にセットした、音符と音価を一緒に渡すので2次元配列で書けます。 ※ドレミの初めの2小節

(($do,$ftqv),($re,$qver),($mi,$ftqv),($do,$qver),($mi,$fter),($do,$fter),($mi,$half)) | % {[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 | %{
			(($do,$ftqv),($re,$qver),($mi,$ftqv),($do,$qver),($mi,$fter),($do,$fter),($mi,$half)) | Get-Beep
			(($re,$ftqv),($mi,$qver),($fa,$qver),($fa,$qver),($mi,$qver),($re,$qver),($fa,$whole)) | Get-Beep
			. $fterrest
			(($mi,$ftqv),($fa,$qver),($so,$ftqv),($mi,$qver),($so,$fter),($mi,$fter),($so,$half)) | Get-Beep
			(($fa,$ftqv),($so,$qver),($la,$qver),($la,$qver),($so,$qver),($fa,$qver),($la,$whole)) | Get-Beep
			. $fterrest
			(($so,$ftqv),($do,$qver),($re,$qver),($mi,$qver),($fa,$qver),($so,$qver),($la,$whole)) | Get-Beep
			. $fterrest
			(($la,$ftqv),($re,$qver),($mi,$qver),($fas,$qver),($so,$qver),($la,$qver),($si,$whole)) | Get-Beep
			. $fterrest
			(($si,$ftqv),($mi,$qver),($fas,$qver),($sos,$qver),($la,$qver),($si,$qver),($doO,$whole)) | Get-Beep
			(($si,$qver),($sif,$qver),($la,$fter),($fa,$fter),($si,$fter),($so,$fter),($doO,$haft)) | Get-Beep
			. $fterrest
		}

		. $fterrest
		(($do,$fter),($re,$fter),($mi,$fter)) | Get-Beep
		(($fa,$fter),($so,$fter),($la,$fter),($si,$fter),($doO,$fter),($doO,$fter),($si,$fter),($la,$fter)) | Get-Beep
		(($so,$fter),($fa,$fter),($mi,$fter),($re,$fter),($do,$fter),($mi,$fter),($mi,$half)) | Get-Beep
		(($mi,$fter),($so,$fter),($so,$half),($re,$fter),($fa,$fter),($fa,$half)) | Get-Beep
		(($la,$fter),($si,$fter),($si,$half),($do,$qver),($mi,$qver),($mi,$fter)) | Get-Beep
		. $qverrest
		(($mi,$qver),($so,$qver),($so,$fter)) | Get-Beep
		. $qverrest
		(($re,$qver),($fa,$qver),($fa,$fter)) | Get-Beep
		. $qverrest
		(($la,$qver),($si,$qver),($si,$fter)) | Get-Beep
		. $qverrest
		(($so,$half),($do,$half)) | Get-Beep
		(($la,$half),($fa,$half),($mi,$half),($do,$half),($re,$whole)) | Get-Beep
		(($so,$half),($do,$half),($la,$half),($si,$half),($doO,$half),($reO,$half),($doO,$whole)) | Get-Beep
    }

    end{
    }
}

doremi-song

まとめ

いい利用例ですね。

次回は、PowerShellでMMLにてドレミの歌を演奏してみます。