sage/音声合成のメカニズム in Sage
をテンプレートにして作成
[
トップ
] [
新規
|
一覧
|
単語検索
|
最終更新
|
ヘルプ
]
開始行:
[[FrontPage]]
#contents
2013/12/23からのアクセス回数 &counter;
ここで紹介したSageワークシートは、以下のURLからダウンロー...
http://www15191ue.sakura.ne.jp:8000/home/pub/31/
また、Sageのサーバを公開しているサイト(http://www.sagenb...
アップロードし、実行したり、変更していろいろ動きを試すこ...
* 音声合成のメカニズム in Sage [#f254f869]
Interface 2013/11から連載が始まった「実験で入門!音声合成...
この説明は、私のブログの
[[lbed/LM4F120 Launchpadで音声合成]]
と連携しています。
こちらも参考にしてください。
** フーリエ級数 [#kf765bed]
フーリエ級数は、周期的に繰り返される信号をSinとCosで表現...
基本周期\(T_0\)として、周期信号を式で表すと次のようになり...
$$
f(t) = a_0 + \sum_{k=1}^\infty \left( a_k cos \frac{2 \pi...
$$
** フーリエ級数の例 [#j5ea73a9]
Interface 2013/11号では、以下の様な三角波を例題としていま...
Sageで三角波を表現する場合には、区分関数(Piecewse)を使...
三角波では、区間を-0.5から0と0から0.5の2つに分け、それぞ...
sageへの入力:
#pre{{
# [-0.5, 0.5]の区間で以下の関数を定義
n, t = var("n t")
f1 = lambda t: 4*t + 1
f2 = lambda t: -4*t + 1
f = Piecewise([[(-1/2, 0), f1], [(0, 1/2), f2]])
plot(f, figsize=4)
}}
&ref(sage0.png);
*** フーリエ係数を求める [#wb67c612]
基本周期\(T_0\)とするとフーリエ係数は、以下の様に求めるこ...
$$
\left\{
\begin{eqnarray}
a_0 & = & \frac{1}{T_0} \int_{-T_0/2}^{T_0/2} f(t) dt \\
a_k & = & \frac{2}{T_0} \int_{-T_0/2}^{T_0/2} f(t) cos \f...
b_k & = & \frac{2}{T_0} \int_{-T_0/2}^{T_0/2} f(t) sin \f...
\end{eqnarray} \right.
$$
*** Sageでフーリエ級数を求める [#h7e966db]
さっそく、数式処理システムのSageを使って三角波のフーリエ...
残念ながらPiecewiseの関数に直接sin, cosを掛けることができ...
sin, cosを掛けた区間関数を定義して、それを積分することに...
以下がSageでの処理です。最後に$a_0, a_1, a_2, a_3, b_1$を...
この結果は、Interface 2013/11号の式(4)と同じ結果になって...
$$
\left\{
\begin{eqnarray}
a_k & = & \left\{
\begin{eqnarray}
0, & k: 偶数 \\
\frac{8}{(k \pi)^2}, & k: 奇数 \\
\end{eqnarray} \right. \\
b_k & = & 0, k: すべての整数
\end{eqnarray} \right.
$$
sageへの入力:
#pre{{
# Piecewiseの関数にsin, cosを掛けることができないので(た...
# フーリエ級数を求める積分は、sin, cosを掛けた区分関数を...
T0 = 1
k = var('k')
f1s = lambda k: f1(t)*sin((2*pi*k)/T0*t)
f2s = lambda k: f2(t)*sin((2*pi*k)/T0*t)
f1c = lambda k: f1(t)*cos((2*pi*k)/T0*t)
f2c = lambda k: f2(t)*cos((2*pi*k)/T0*t)
b(k) = (2/T0)*Piecewise([[(-1/2, 0), f1s(k)], [(0, 1/2), ...
a(k) = (2/T0)*Piecewise([[(-1/2, 0), f1c(k)], [(0, 1/2), ...
a0 = (2/T0)*Piecewise([[(-1/2, 0), f1c(0)], [(0, 1/2), f2...
# a0 = Piecewise([[(-1/2, 0), f1], [(0, 1/2), f2]]).integ...
# とするとTypeErrorとなります(これもバグ?)
# 値の確認
print a0, a(1), a(2), a(3), b(1)
}}
#pre{{
0 8/pi^2 0 8/9/pi^2 0
}}
*** kの値を変えて波形を計算 [#u66376f5]
求めた\(a_k\)を使ってkの値を1, 5, 19と変えた結果をプロッ...
sageへの入力:
#pre{{
def fk(t, k):
return sum(a(n)*cos((2*pi*n/T0)*t) for n in range(1, ...
show(fk(t, 3))
# n=1,5,19の合成波をプロット
p = plot(fk(t, 2), -1,1, color='blue',legend_label='n=1')
p += plot(fk(t, 5), -1,1, color='red',legend_label='n=5')
p += plot(fk(t, 10), -1,1, color='green',legend_label='n=...
p.show(figsize=5)
}}
&ref(sage1.png);
** 同じ問題をPiecewiseの関数で計算 [#k3bda492]
Piecewiseには、フーリエ級数を計算する機能が備わっています。
先のfkに相当する関数がfourier_series_partial_sumです。
fourier_series_partial_sumの使い方は、以下の様に使います。
#pre{{
g.fourier_series_partial_sum(N, L)
}}
ここで、Nは計算する次数、Lは区間の長さL(区間は、-LからL...
$$
f(x) \sim \frac{a_0}{2} + \sum_{n=1}^N [a_n\cos(\frac{n\p...
$$
*** fourier_series_partial_sumで5次の項まで計算 [#g2509d25]
それでは、同じ問題をfourier_series_partial_sumで計算して...
sageへの入力:
#pre{{
# 同じ問題をPiecewiseのフーリエ級数関数を使って解いてみる
g = Piecewise([[(-1/2, 0), f1], [(0, 1/2), f2]])
plot(g, figsize=4)
}}
&ref(sage2.png);
sageへの入力:
#pre{{
show(g.fourier_series_partial_sum(5, 1/2))
}}
&ref(sage3.png);
*** fourier_series_partial_sumのプロット [#ad2c80fc]
計算結果をプロットしてみます。N=100とするとほとんど三角波...
sageへの入力:
#pre{{
p = plot(g.fourier_series_partial_sum(5, 1/2), -1,1, colo...
p += plot(g.fourier_series_partial_sum(10, 1/2), -1,1, co...
p += plot(g.fourier_series_partial_sum(50, 1/2), -1,1, co...
p += plot(g.fourier_series_partial_sum(100, 1/2), -1,1, c...
p.show(figsize=5)
}}
&ref(sage4.png);
*** 「ア」のオリジナル波形 [#md97ffe3]
最初に「ア」のオリジナル波形をプロットします。
sageへの入力:
#pre{{
snOrg=[
-56, 139, 439, 785, 1041, 1...
-147, -131, -9, 343, 684, ...
501, 481, 695, 961, 1293, 1...
118, 206, 437, 698, 794, 68...
-365, -312, -278, -299, -350, ...
-1289, -1382, -1446, -1511, -16...
-608, -420, -362, -288, -68
]
list_plot(snOrg, plotjoined=True, figsize=4)
}}
&ref(sage5.png);
*** フーリエ係数から波形を合成関数synthesisの定義 [#gc8b4...
フーリエ係数から波形を合成関数synthesisは、ほとんどCのsyn...
sageへの入力:
#pre{{
def synthesis(an, bn, vn, order, nData):
PI2 = 2.0*3.1415926
PI2_T = PI2/nData
for n in range(nData):
vn[n] = an[0]
for k in range(1,order+1):
kPi2T = k*PI2_T
vn[n] += an[k]*cos(kPi2T*n) + bn[k]*sin(kPi2T...
}}
*** 「ア」の合成 [#u5af5395]
Interface 2013/11に出ている「ア」のフーリエ係数を使ってMA...
オリジナルと遜色のないレベルまで再現できているのが分かり...
sageへの入力:
#pre{{
an = [20.61, -376.22, 305.13, 257.95, 45....
-8.32, -19.58, 19.21, -0.73, ...
bn = [0.00, 949.63, 246.53, 181.33, ...
51.38, -34.27, 19.66, 13.44, ...
vn = [0 for i in range(64)]
N_TO = 64
synthesis(an, bn, vn, 15, N_TO)
list_plot(vn, plotjoined=True, figsize=4)
}}
&ref(sage6.png);
*** 次数を変えて波形を合成してみる [#z6c56ced]
Sageのインタラクティブモードを使って次数を変えて「ア」を...
sageへの入力:
#pre{{
@interact
def _(order=selector(range(1,16))):
synthesis(an, bn, vn, order, N_TO)
list_plot(vn, plotjoined=True, figsize=4).show()
}}
&ref(sage7.png);
*** 合成音を再生する [#n93c91e8]
「ア」の波形を上手く合成できているのが、確認できましたの...
ここでは、PySoundFileを使って8KHzの1チャンネルwavファイル...
それをブラウザーの機能を使って再生します。
合成された「ア」は少し短すぎるので、5回繰り返した波形sour...
sageへの入力:
#pre{{
from numpy import abs, max
# 5回繰り返した音を作る
sources = []
sources = flatten([sources + vn for i in range(5)])
sources /= max(abs(vn), axis = 0)
}}
合成波形をwav形式で保存する関数として、recordSoundを定義...
以降、この関数を使って合成波形を再生することにします。
sageへの入力:
#pre{{
def recordSound(sources, name, Hz):
filename = DATA + name
sf.write(sources, filename, samplerate=Hz)
# 結果を確認する方法
html('<a href="%s">録音結果(右クリックでファイルをダ...
}}
録音結果をクリックすると合成した波形が音として再生されま...
自動的に再生できないもののありますので、その時には右クリ...
sageへの入力:
#pre{{
recordSound(sources, "vowel_a.wav", 8000)
}}
- 録音結果(右クリックでファイルをダウンロードして再生し...
** コメント [#s0d28076]
#vote(おもしろかった,そうでもない,わかりずらい)
皆様のご意見、ご希望をお待ちしております。
- PySoundFileを使ったWavファイル出力に変更しました。 -- [...
#comment_kcaptcha
終了行:
[[FrontPage]]
#contents
2013/12/23からのアクセス回数 &counter;
ここで紹介したSageワークシートは、以下のURLからダウンロー...
http://www15191ue.sakura.ne.jp:8000/home/pub/31/
また、Sageのサーバを公開しているサイト(http://www.sagenb...
アップロードし、実行したり、変更していろいろ動きを試すこ...
* 音声合成のメカニズム in Sage [#f254f869]
Interface 2013/11から連載が始まった「実験で入門!音声合成...
この説明は、私のブログの
[[lbed/LM4F120 Launchpadで音声合成]]
と連携しています。
こちらも参考にしてください。
** フーリエ級数 [#kf765bed]
フーリエ級数は、周期的に繰り返される信号をSinとCosで表現...
基本周期\(T_0\)として、周期信号を式で表すと次のようになり...
$$
f(t) = a_0 + \sum_{k=1}^\infty \left( a_k cos \frac{2 \pi...
$$
** フーリエ級数の例 [#j5ea73a9]
Interface 2013/11号では、以下の様な三角波を例題としていま...
Sageで三角波を表現する場合には、区分関数(Piecewse)を使...
三角波では、区間を-0.5から0と0から0.5の2つに分け、それぞ...
sageへの入力:
#pre{{
# [-0.5, 0.5]の区間で以下の関数を定義
n, t = var("n t")
f1 = lambda t: 4*t + 1
f2 = lambda t: -4*t + 1
f = Piecewise([[(-1/2, 0), f1], [(0, 1/2), f2]])
plot(f, figsize=4)
}}
&ref(sage0.png);
*** フーリエ係数を求める [#wb67c612]
基本周期\(T_0\)とするとフーリエ係数は、以下の様に求めるこ...
$$
\left\{
\begin{eqnarray}
a_0 & = & \frac{1}{T_0} \int_{-T_0/2}^{T_0/2} f(t) dt \\
a_k & = & \frac{2}{T_0} \int_{-T_0/2}^{T_0/2} f(t) cos \f...
b_k & = & \frac{2}{T_0} \int_{-T_0/2}^{T_0/2} f(t) sin \f...
\end{eqnarray} \right.
$$
*** Sageでフーリエ級数を求める [#h7e966db]
さっそく、数式処理システムのSageを使って三角波のフーリエ...
残念ながらPiecewiseの関数に直接sin, cosを掛けることができ...
sin, cosを掛けた区間関数を定義して、それを積分することに...
以下がSageでの処理です。最後に$a_0, a_1, a_2, a_3, b_1$を...
この結果は、Interface 2013/11号の式(4)と同じ結果になって...
$$
\left\{
\begin{eqnarray}
a_k & = & \left\{
\begin{eqnarray}
0, & k: 偶数 \\
\frac{8}{(k \pi)^2}, & k: 奇数 \\
\end{eqnarray} \right. \\
b_k & = & 0, k: すべての整数
\end{eqnarray} \right.
$$
sageへの入力:
#pre{{
# Piecewiseの関数にsin, cosを掛けることができないので(た...
# フーリエ級数を求める積分は、sin, cosを掛けた区分関数を...
T0 = 1
k = var('k')
f1s = lambda k: f1(t)*sin((2*pi*k)/T0*t)
f2s = lambda k: f2(t)*sin((2*pi*k)/T0*t)
f1c = lambda k: f1(t)*cos((2*pi*k)/T0*t)
f2c = lambda k: f2(t)*cos((2*pi*k)/T0*t)
b(k) = (2/T0)*Piecewise([[(-1/2, 0), f1s(k)], [(0, 1/2), ...
a(k) = (2/T0)*Piecewise([[(-1/2, 0), f1c(k)], [(0, 1/2), ...
a0 = (2/T0)*Piecewise([[(-1/2, 0), f1c(0)], [(0, 1/2), f2...
# a0 = Piecewise([[(-1/2, 0), f1], [(0, 1/2), f2]]).integ...
# とするとTypeErrorとなります(これもバグ?)
# 値の確認
print a0, a(1), a(2), a(3), b(1)
}}
#pre{{
0 8/pi^2 0 8/9/pi^2 0
}}
*** kの値を変えて波形を計算 [#u66376f5]
求めた\(a_k\)を使ってkの値を1, 5, 19と変えた結果をプロッ...
sageへの入力:
#pre{{
def fk(t, k):
return sum(a(n)*cos((2*pi*n/T0)*t) for n in range(1, ...
show(fk(t, 3))
# n=1,5,19の合成波をプロット
p = plot(fk(t, 2), -1,1, color='blue',legend_label='n=1')
p += plot(fk(t, 5), -1,1, color='red',legend_label='n=5')
p += plot(fk(t, 10), -1,1, color='green',legend_label='n=...
p.show(figsize=5)
}}
&ref(sage1.png);
** 同じ問題をPiecewiseの関数で計算 [#k3bda492]
Piecewiseには、フーリエ級数を計算する機能が備わっています。
先のfkに相当する関数がfourier_series_partial_sumです。
fourier_series_partial_sumの使い方は、以下の様に使います。
#pre{{
g.fourier_series_partial_sum(N, L)
}}
ここで、Nは計算する次数、Lは区間の長さL(区間は、-LからL...
$$
f(x) \sim \frac{a_0}{2} + \sum_{n=1}^N [a_n\cos(\frac{n\p...
$$
*** fourier_series_partial_sumで5次の項まで計算 [#g2509d25]
それでは、同じ問題をfourier_series_partial_sumで計算して...
sageへの入力:
#pre{{
# 同じ問題をPiecewiseのフーリエ級数関数を使って解いてみる
g = Piecewise([[(-1/2, 0), f1], [(0, 1/2), f2]])
plot(g, figsize=4)
}}
&ref(sage2.png);
sageへの入力:
#pre{{
show(g.fourier_series_partial_sum(5, 1/2))
}}
&ref(sage3.png);
*** fourier_series_partial_sumのプロット [#ad2c80fc]
計算結果をプロットしてみます。N=100とするとほとんど三角波...
sageへの入力:
#pre{{
p = plot(g.fourier_series_partial_sum(5, 1/2), -1,1, colo...
p += plot(g.fourier_series_partial_sum(10, 1/2), -1,1, co...
p += plot(g.fourier_series_partial_sum(50, 1/2), -1,1, co...
p += plot(g.fourier_series_partial_sum(100, 1/2), -1,1, c...
p.show(figsize=5)
}}
&ref(sage4.png);
*** 「ア」のオリジナル波形 [#md97ffe3]
最初に「ア」のオリジナル波形をプロットします。
sageへの入力:
#pre{{
snOrg=[
-56, 139, 439, 785, 1041, 1...
-147, -131, -9, 343, 684, ...
501, 481, 695, 961, 1293, 1...
118, 206, 437, 698, 794, 68...
-365, -312, -278, -299, -350, ...
-1289, -1382, -1446, -1511, -16...
-608, -420, -362, -288, -68
]
list_plot(snOrg, plotjoined=True, figsize=4)
}}
&ref(sage5.png);
*** フーリエ係数から波形を合成関数synthesisの定義 [#gc8b4...
フーリエ係数から波形を合成関数synthesisは、ほとんどCのsyn...
sageへの入力:
#pre{{
def synthesis(an, bn, vn, order, nData):
PI2 = 2.0*3.1415926
PI2_T = PI2/nData
for n in range(nData):
vn[n] = an[0]
for k in range(1,order+1):
kPi2T = k*PI2_T
vn[n] += an[k]*cos(kPi2T*n) + bn[k]*sin(kPi2T...
}}
*** 「ア」の合成 [#u5af5395]
Interface 2013/11に出ている「ア」のフーリエ係数を使ってMA...
オリジナルと遜色のないレベルまで再現できているのが分かり...
sageへの入力:
#pre{{
an = [20.61, -376.22, 305.13, 257.95, 45....
-8.32, -19.58, 19.21, -0.73, ...
bn = [0.00, 949.63, 246.53, 181.33, ...
51.38, -34.27, 19.66, 13.44, ...
vn = [0 for i in range(64)]
N_TO = 64
synthesis(an, bn, vn, 15, N_TO)
list_plot(vn, plotjoined=True, figsize=4)
}}
&ref(sage6.png);
*** 次数を変えて波形を合成してみる [#z6c56ced]
Sageのインタラクティブモードを使って次数を変えて「ア」を...
sageへの入力:
#pre{{
@interact
def _(order=selector(range(1,16))):
synthesis(an, bn, vn, order, N_TO)
list_plot(vn, plotjoined=True, figsize=4).show()
}}
&ref(sage7.png);
*** 合成音を再生する [#n93c91e8]
「ア」の波形を上手く合成できているのが、確認できましたの...
ここでは、PySoundFileを使って8KHzの1チャンネルwavファイル...
それをブラウザーの機能を使って再生します。
合成された「ア」は少し短すぎるので、5回繰り返した波形sour...
sageへの入力:
#pre{{
from numpy import abs, max
# 5回繰り返した音を作る
sources = []
sources = flatten([sources + vn for i in range(5)])
sources /= max(abs(vn), axis = 0)
}}
合成波形をwav形式で保存する関数として、recordSoundを定義...
以降、この関数を使って合成波形を再生することにします。
sageへの入力:
#pre{{
def recordSound(sources, name, Hz):
filename = DATA + name
sf.write(sources, filename, samplerate=Hz)
# 結果を確認する方法
html('<a href="%s">録音結果(右クリックでファイルをダ...
}}
録音結果をクリックすると合成した波形が音として再生されま...
自動的に再生できないもののありますので、その時には右クリ...
sageへの入力:
#pre{{
recordSound(sources, "vowel_a.wav", 8000)
}}
- 録音結果(右クリックでファイルをダウンロードして再生し...
** コメント [#s0d28076]
#vote(おもしろかった,そうでもない,わかりずらい)
皆様のご意見、ご希望をお待ちしております。
- PySoundFileを使ったWavファイル出力に変更しました。 -- [...
#comment_kcaptcha
ページ名:
SmartDoc