lbed/LM4F120 Launchpadで音声合成
をテンプレートにして作成
[
トップ
] [
新規
|
一覧
|
単語検索
|
最終更新
|
ヘルプ
]
開始行:
[[lbed]]
#contents
2013/12/14からのアクセス回数 &counter;
Interface 2013/11から連載が始まった「実験で入門!音声合成...
ここでは、LM4F120 LaunchPadを使って実際に音声合成をし、理...
[[sage/音声合成のメカニズム in Sage]]
で説明していきます。こちらも参考にしてください。
** DACモジュールの作成 [#uef269c2]
LM4F120 Lauchpadには、DAC(デジタルからアナログへの変換)...
SPIインタフェースを持つ、12-bit DAC(デジタル・アナログ変...
[[MCP4922>http://akizukidenshi.com/catalog/goods/search.a...
を使用します。
MCP4922の使い方は、[[arduino/DACを試す]]を参照してくださ...
*** MCP4922クラスを作成 [#n9038886]
MCP4922にアクセスするために、SPIクラスのサブクラスとしてM...
#pre{{
#include "MCP4922.h"
#include "lbed.h"
#define HIGHT (1)
#define LOW (0)
MCP4922::MCP4922(PinName mosi, PinName miso, PinName sclk...
: SPI(mosi, miso, sclk), _ldac(ldac), _cs(cs)
{
}
void MCP4922::write(int value) {
_ldac = HIGHT;
_cs = LOW;
SPI::write((value >> 8) | 0x30);
SPI::write(value & 0xFF);
_cs = HIGHT;
_ldac = LOW;
}
void MCP4922::write(int valueA, int valueB) {
_ldac = HIGHT;
_cs = LOW;
SPI::write((valueA >> 8) | 0x70);
SPI::write(valueA & 0xFF);
_cs = HIGHT;
_ldac = LOW;
wait_us(1);
_ldac = HIGHT;
_cs = LOW;
SPI::write((valueB >> 8) | 0xF0);
SPI::write(valueB & 0xFF);
_cs = HIGHT;
_ldac = LOW;
}
void MCP4922::frequency(int hz) {
SPI::frequency(hz);
}
}}
*** テストプログラムで動作を確認 [#dfc39520]
SPIの通信には、SSI1を使用することにして、MOSI(PD3), MIS...
CS(PE1), LDAC(PE2)としてJ3列のレジスタで揃えました。
&ref(LaunchPad-DAC-setting.png);
TestMCP4922.cppは、以下の通りです。
#pre{{
#include "lbed.h"
#include "MCP4922.h"
int main(void) {
// PD_2は使用していないので、未接続で実行
MCP4922 mcp4922(PD_3, PD_2, PD_0, PE_1, PE_2); ...
// 16MHzにセット
mcp4922.frequency(16000000);
while(1) {
for (int i=0; i < 4096; i+=4) {
mcp4922.write(i);
}
}
}
}}
こんなに簡単にノコギリ波の生成プログラムが出来上がります。
オシロスコープで生成された波形を見ると以下の様になります。
&ref(saw-wave.png);
LM4F120 LaunchPadは、FPUが付いているので、sine波を計算す...
#pre{{
#include "lbed.h"
#include "MCP4922.h"
#include "math.h"
#define PI 3.1415926
#define SAMPLE 4096
#define sin(x) sinf(x)
int main(void) {
// PD_2は使用していないので、未接続で実行
MCP4922 mcp4922(PD_3, PD_2, PD_0, PE_1, PE_2); ...
// 16MHzにセット
mcp4922.frequency(16000000);
while(1) {
for (int i=0; i < 4096; i+=4) {
int sineValue = (int)(0xFFF*(1 + sin(2*PI*...
mcp4922.write(sineValue);
}
}
}
}}
sine波の出力でも、39.39Hzで1024ポイント(1ポイント: 1/39....
これなら音声合成で使用する8KHzサンプリング(1ポイント: 1/...
&ref(sine-wave.png);
** 第1回の課題 [#a24222f4]
Interface 2013/11号の第1回目の課題をLauchpadで実験してみ...
*** 「あ」を合成するマイコン・プログラム [#ef52b3f6]
Synthesisという関数を作成して、フーリエ係数から「あ」を合...
((例題では、サンプリングの不連続をちょっと補正するために...
母音の「あ」の合成には、以下のようなフーリエ関数を使って...
$$
f\left( \frac{n}{8000} \right) = a_0 + \sum_{k=1}^K \left...
$$
*** synthesis関数 [#v299b541]
上記の式に合わせて、合成関数synthesisを作ってみます。
ほとんどInterfaceの記事と同じですが、vnの計算が少し違いま...
((オリジナルは、きっと学生さんが作ったプログラムなのでし...
#pre{{
// データ: 元の音声とそのフーリエ係数
// 母音 /ア/,サンプリング周波数: 8 KHz
const int N_DATA = 65;
const short snOrg[N_DATA] = {
-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
};
// フーリエ係数
const int HARMO_MAX = 15;
const float an[HARMO_MAX + 1] = {
20.61, -376.22, 305.13, 257.95, ...
-8.32, -19.58, 19.21, -0.73, ...
};
const float bn[HARMO_MAX + 1] = {
0.00, 949.63, 246.53, 181.33, ...
51.38, -34.27, 19.66, 13.44, ...
};
void synthesis(const float an[], const float bn[], short ...
const float PI2 = 2.0*3.1415926;
const float PI2_T = PI2/(float)nData;
for (int n = 0; n < nData; n++) {
vn[n] = (short)an[0];
for (int k = 1; k <= order; k++) {
float kPi2T = k*PI2_T;
vn[n] += (short)(an[k]*cos(kPi2T*n) + bn[k...
}
}
}
}}
** 実際に「ア」を合成してみる [#gc900771]
準備ができたので、実際に「ア」を合成してみます。
メインのプログラムは次のようになります。
((オリジナルよりもすっきりしています。))
#pre{{
// 8KHzのタイミングでデータをDACに送るためにok変数とTicke...
volatile bool ok = false;
void getTiming() {
ok = true;
}
#define N_TO (N_DATA - 1)
#define FS (8000)
#define COUNT (5)
#define DC (2048) // 12bit分は、409...
int main(void) {
Serial pc(PA_1, PA_0);
pc.baud(19200);
Ticker timer;
timer.attach(&getTiming, 1.0/FS);
// PD_2は使用していないので、未接続で実行
MCP4922 mcp4922(PD_3, PD_2, PD_0, PE_1, PE_2); ...
// 10MHzにセット
mcp4922.frequency(16000000);
short sn[N_TO];
short vn[N_TO];
int order = 15;
sn[0] = (snOrg[0] + snOrg[N_TO])/2; // サンプリ...
// サンプリングデータをsnにセット
for (int n = 1; n < N_TO; n++)
sn[n] = snOrg[n];
// フーリエ係数から「ア」を音声合成
synthesis(an, bn, vn, order, N_TO);
pc.println("Input Order:[1-9]");
while(1) {
if (pc.available()) {
// フーリエ係数の次数を変更する
char c = pc.read();
order = c - '0';
synthesis(an, bn, vn, order, N_TO);
}
for (int count = 0; count < COUNT; count++) { ...
for (int n = 0; n < N_TO; n++) {
// 出力タイミングまで待つ
while(!ok) continue;
mcp4922.write(sn[n] + DC, vn[n] + DC);
ok = false;
}
}
}
}
}}
*** 計算結果 [#ic74a005]
オシロスコープで、次数5と次数9の波形を出力してみました。
意外だったのが、次数7から結構いい感じの出力波形が出ていた...
次数5の場合の出力波形(上がオリジナル、下が合成波形)で...
&ref(out_5order.png);
次に次数9の波形です。
&ref(out_9order.png);
** 秋月電子のLCDオシロスコープキット [#g143facb]
子供たちでも波形を確認できるように
[[「秋月電子のLCDオシロスコープキット」>http://akizukiden...
(4,700円)を組み立てました。
この値段で音声合成の波形がきちんと表示できています。
&ref(aki-LCD-scope.png);
** 連載に合わせて更新していきます! [#uc423ec3]
** コメント [#d9d80076]
#vote(おもしろかった,そうでもない,わかりずらい)
皆様のご意見、ご希望をお待ちしております。
#comment_kcaptcha
終了行:
[[lbed]]
#contents
2013/12/14からのアクセス回数 &counter;
Interface 2013/11から連載が始まった「実験で入門!音声合成...
ここでは、LM4F120 LaunchPadを使って実際に音声合成をし、理...
[[sage/音声合成のメカニズム in Sage]]
で説明していきます。こちらも参考にしてください。
** DACモジュールの作成 [#uef269c2]
LM4F120 Lauchpadには、DAC(デジタルからアナログへの変換)...
SPIインタフェースを持つ、12-bit DAC(デジタル・アナログ変...
[[MCP4922>http://akizukidenshi.com/catalog/goods/search.a...
を使用します。
MCP4922の使い方は、[[arduino/DACを試す]]を参照してくださ...
*** MCP4922クラスを作成 [#n9038886]
MCP4922にアクセスするために、SPIクラスのサブクラスとしてM...
#pre{{
#include "MCP4922.h"
#include "lbed.h"
#define HIGHT (1)
#define LOW (0)
MCP4922::MCP4922(PinName mosi, PinName miso, PinName sclk...
: SPI(mosi, miso, sclk), _ldac(ldac), _cs(cs)
{
}
void MCP4922::write(int value) {
_ldac = HIGHT;
_cs = LOW;
SPI::write((value >> 8) | 0x30);
SPI::write(value & 0xFF);
_cs = HIGHT;
_ldac = LOW;
}
void MCP4922::write(int valueA, int valueB) {
_ldac = HIGHT;
_cs = LOW;
SPI::write((valueA >> 8) | 0x70);
SPI::write(valueA & 0xFF);
_cs = HIGHT;
_ldac = LOW;
wait_us(1);
_ldac = HIGHT;
_cs = LOW;
SPI::write((valueB >> 8) | 0xF0);
SPI::write(valueB & 0xFF);
_cs = HIGHT;
_ldac = LOW;
}
void MCP4922::frequency(int hz) {
SPI::frequency(hz);
}
}}
*** テストプログラムで動作を確認 [#dfc39520]
SPIの通信には、SSI1を使用することにして、MOSI(PD3), MIS...
CS(PE1), LDAC(PE2)としてJ3列のレジスタで揃えました。
&ref(LaunchPad-DAC-setting.png);
TestMCP4922.cppは、以下の通りです。
#pre{{
#include "lbed.h"
#include "MCP4922.h"
int main(void) {
// PD_2は使用していないので、未接続で実行
MCP4922 mcp4922(PD_3, PD_2, PD_0, PE_1, PE_2); ...
// 16MHzにセット
mcp4922.frequency(16000000);
while(1) {
for (int i=0; i < 4096; i+=4) {
mcp4922.write(i);
}
}
}
}}
こんなに簡単にノコギリ波の生成プログラムが出来上がります。
オシロスコープで生成された波形を見ると以下の様になります。
&ref(saw-wave.png);
LM4F120 LaunchPadは、FPUが付いているので、sine波を計算す...
#pre{{
#include "lbed.h"
#include "MCP4922.h"
#include "math.h"
#define PI 3.1415926
#define SAMPLE 4096
#define sin(x) sinf(x)
int main(void) {
// PD_2は使用していないので、未接続で実行
MCP4922 mcp4922(PD_3, PD_2, PD_0, PE_1, PE_2); ...
// 16MHzにセット
mcp4922.frequency(16000000);
while(1) {
for (int i=0; i < 4096; i+=4) {
int sineValue = (int)(0xFFF*(1 + sin(2*PI*...
mcp4922.write(sineValue);
}
}
}
}}
sine波の出力でも、39.39Hzで1024ポイント(1ポイント: 1/39....
これなら音声合成で使用する8KHzサンプリング(1ポイント: 1/...
&ref(sine-wave.png);
** 第1回の課題 [#a24222f4]
Interface 2013/11号の第1回目の課題をLauchpadで実験してみ...
*** 「あ」を合成するマイコン・プログラム [#ef52b3f6]
Synthesisという関数を作成して、フーリエ係数から「あ」を合...
((例題では、サンプリングの不連続をちょっと補正するために...
母音の「あ」の合成には、以下のようなフーリエ関数を使って...
$$
f\left( \frac{n}{8000} \right) = a_0 + \sum_{k=1}^K \left...
$$
*** synthesis関数 [#v299b541]
上記の式に合わせて、合成関数synthesisを作ってみます。
ほとんどInterfaceの記事と同じですが、vnの計算が少し違いま...
((オリジナルは、きっと学生さんが作ったプログラムなのでし...
#pre{{
// データ: 元の音声とそのフーリエ係数
// 母音 /ア/,サンプリング周波数: 8 KHz
const int N_DATA = 65;
const short snOrg[N_DATA] = {
-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
};
// フーリエ係数
const int HARMO_MAX = 15;
const float an[HARMO_MAX + 1] = {
20.61, -376.22, 305.13, 257.95, ...
-8.32, -19.58, 19.21, -0.73, ...
};
const float bn[HARMO_MAX + 1] = {
0.00, 949.63, 246.53, 181.33, ...
51.38, -34.27, 19.66, 13.44, ...
};
void synthesis(const float an[], const float bn[], short ...
const float PI2 = 2.0*3.1415926;
const float PI2_T = PI2/(float)nData;
for (int n = 0; n < nData; n++) {
vn[n] = (short)an[0];
for (int k = 1; k <= order; k++) {
float kPi2T = k*PI2_T;
vn[n] += (short)(an[k]*cos(kPi2T*n) + bn[k...
}
}
}
}}
** 実際に「ア」を合成してみる [#gc900771]
準備ができたので、実際に「ア」を合成してみます。
メインのプログラムは次のようになります。
((オリジナルよりもすっきりしています。))
#pre{{
// 8KHzのタイミングでデータをDACに送るためにok変数とTicke...
volatile bool ok = false;
void getTiming() {
ok = true;
}
#define N_TO (N_DATA - 1)
#define FS (8000)
#define COUNT (5)
#define DC (2048) // 12bit分は、409...
int main(void) {
Serial pc(PA_1, PA_0);
pc.baud(19200);
Ticker timer;
timer.attach(&getTiming, 1.0/FS);
// PD_2は使用していないので、未接続で実行
MCP4922 mcp4922(PD_3, PD_2, PD_0, PE_1, PE_2); ...
// 10MHzにセット
mcp4922.frequency(16000000);
short sn[N_TO];
short vn[N_TO];
int order = 15;
sn[0] = (snOrg[0] + snOrg[N_TO])/2; // サンプリ...
// サンプリングデータをsnにセット
for (int n = 1; n < N_TO; n++)
sn[n] = snOrg[n];
// フーリエ係数から「ア」を音声合成
synthesis(an, bn, vn, order, N_TO);
pc.println("Input Order:[1-9]");
while(1) {
if (pc.available()) {
// フーリエ係数の次数を変更する
char c = pc.read();
order = c - '0';
synthesis(an, bn, vn, order, N_TO);
}
for (int count = 0; count < COUNT; count++) { ...
for (int n = 0; n < N_TO; n++) {
// 出力タイミングまで待つ
while(!ok) continue;
mcp4922.write(sn[n] + DC, vn[n] + DC);
ok = false;
}
}
}
}
}}
*** 計算結果 [#ic74a005]
オシロスコープで、次数5と次数9の波形を出力してみました。
意外だったのが、次数7から結構いい感じの出力波形が出ていた...
次数5の場合の出力波形(上がオリジナル、下が合成波形)で...
&ref(out_5order.png);
次に次数9の波形です。
&ref(out_9order.png);
** 秋月電子のLCDオシロスコープキット [#g143facb]
子供たちでも波形を確認できるように
[[「秋月電子のLCDオシロスコープキット」>http://akizukiden...
(4,700円)を組み立てました。
この値段で音声合成の波形がきちんと表示できています。
&ref(aki-LCD-scope.png);
** 連載に合わせて更新していきます! [#uc423ec3]
** コメント [#d9d80076]
#vote(おもしろかった,そうでもない,わかりずらい)
皆様のご意見、ご希望をお待ちしております。
#comment_kcaptcha
ページ名:
SmartDoc