Excel VBAのBeep音で簡単なメロディを鳴らす
Excel VBAのBeep音とドレミファソラシドと言う記事を書きました。それならば、簡単なメロディーもならせるなと思ったので、作りました。
ピアノなら左端の一番低い「ラ」を「A0」として、「ラ,ラ#,シ,ド,ド#,レ…」を「A0,A#0,B0,C1,C#1,D1,…」と呼ぶようなので、それを使って音程を指定します。
音の長さは、8分音符の長さを1として、4分音符なら2、2分音符なら4と指定します。さらにその1の長さが何ミリ秒なのかも指定します。
そういうデータを作ってプロシジャー(BeepSound)に渡すと、どうにかこうにかビープ音でメロディが鳴らせます。単音です。和音はできません。コードの説明は省きます。すいません。
以下のtestTraumerei()を実行すると、「トロイメライ」の最初の4小節がビープ音で鳴ります。
ご興味のある方、お時間のある方はお試しください。なお、最初はパソコンの音量を小さくしてください。
Public Declare Function Beep Lib "kernel32.dll" (ByVal dwFreq As Long, ByVal dwDuration As Long) As Long
Public Sub testTraumerei()
'音階データ
'低いドは「C1」,そこそこのソ#は「G#4」。 または、ド1,ソ#4などと音階を指定。
'シャープは、「#」,「#」 フラットは「♭」,「b」
Const scl = "C4,F4,E4,F4,A4,C5,F5,F5,E5,D5,C5,F5,G4,A4,Bb4,D5,F4,G4,A4,C5,G4"
'音長データ
'音階に対応させて、音の長さを指定。
'8分音符を1として、長さを指定。2分音符なら4。
Const dur = " 2, 3, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5"
'8分音符を1とした時のミリ秒数
Const rate = 300
BeepSound scl, dur, rate
End Sub
Public Sub BeepSound(scl As String, dur As String, rate As Double)
Dim s As Variant
Dim d As Variant
s = Split(scl, ",")
d = Split(dur, ",")
Dim i As Long
Dim f As Double
For i = 0 To UBound(s)
f = CalcFreq(CStr(s(i)))
Debug.Print s(i), f
Beep f, CDbl(d(i)) * rate
DoEvents
Next
End Sub
Private Function CalcFreq(ScaleName As String) As Double
Const BaseF = 32.70319564 '基準音階C1の周波数
Dim ABC As String
Dim SF As String
Dim OCT As String
Dim scl As String
scl = ScaleName
If Len(scl) >= 2 And Len(scl) <= 3 Then
ABC = Ra2A(Left(scl, 1))
OCT = StrConv(Right(scl, 1), vbNarrow)
If Len(scl) = 3 Then
SF = Mid(scl, 2, 1)
End If
'ドレミファの乗数
Dim kABC As Long
kABC = InStr(1, "C.D.EF.G.A.B", ABC) - 1
'シャープ、フラットの乗数
Dim kSF As Long
If SF = "#" Or SF = "#" Then
kSF = 1
ElseIf SF = "b" Or SF = "♭" Then
kSF = -1
Else
kSF = 0
End If
'オクターブの乗数
Dim kOCT As Long
kOCT = 12 * (CDbl(OCT) - 1)
Dim k As Long '基準音階C1からの総合乗数
k = kABC + kSF + kOCT
Dim freq As Double '音階の周波数
freq = BaseF * (2 ^ (1 / 12)) ^ k
CalcFreq = freq
Else
CalcFreq = 0
End If
End Function
'カナ音階をアルファベットに変換
Private Function Ra2A(s As String) As String
Const DoReMiFa = "ド,レ,ミ,ファ,ソ,ラ,シ"
Const ABCD = "C,D,E,F,G,A,B"
Dim ret As String
ret = ""
If InStr(1, ABCD, s) > 0 Then
ret = s
ElseIf InStr(1, DoReMiFa, s) > 0 Then
Dim d As Variant
Dim A As Variant
d = Split(DoReMiFa, ",")
A = Split(ABCD, ",")
Dim i As Long
For i = 0 To UBound(d)
If d(i) = s Then
ret = A(i)
Exit For
End If
Next
End If
Ra2A = ret
End Function
参考:音階の周波数、https://tomari.org/main/java/oto.html、2022.4.11閲覧
#Excel , #VBA , #Beep音 , #トロイメライ
応援してやろうということで、お気持ちをいただければ嬉しいです。もっと勉強したり、調べたりする糧にしたいと思います。