名古屋電鉄様の46.MP3サウンドデコーダV5に搭載されている疑似走行音(VVVF音)部分の解説です。
一部のニッチな方から中身を教えて!という話があったので、説明をします。
ぜひ、自分だけのMp3サウンドデコーダを作ってみてください。
(なお、自分で読み返してもかなり分かりづらいので、誰かわかりやすく書き直してくれると嬉しいです)
お約束ですが、スケッチの書き換えは自己責任でお願いいたします。
サンプリング波形の配列の番号の指定(16ビット型)に使用します。小さくすると(小数点以下の誤差が大きくなるので)波形が汚くなり、大きくすると桁あふれのため音がバグります。
現在の音の生成は以下になっています。
(pgm_read_byte_near(&WAV_DATA1 [pwm_state1 >> SHIFT_PWM]) * 3 + pgm_read_byte_near(&WAV_DATA3 [pwm_state3 >> SHIFT_PWM])) >> pwm_shift)
2つの波形から音を生成しており、主周波数の音(WAV_DATA1):副周波数の音(WAV_DATA3)=3:1の波形で出しています。
割り込みなので、計算量が多すぎると、Mp3サウンドデコーダ全体の動きが遅くなり、動作がおかしくなりますので、注意が必要です。
一部のニッチな方から中身を教えて!という話があったので、説明をします。
ぜひ、自分だけのMp3サウンドデコーダを作ってみてください。
(なお、自分で読み返してもかなり分かりづらいので、誰かわかりやすく書き直してくれると嬉しいです)
お約束ですが、スケッチの書き換えは自己責任でお願いいたします。
- VVVF_sound.cpp・・・疑似音生成の本体です。DCCデコーダ部分からスピードをもらって、疑似音を生成します。
- VVVF_sound.h・・・ヘッダファイルです。
- kasoku.h・・・吊りかけ音、VVVF音の速度に対してどの周波数で音を鳴らすかのLUT(look up table)です。これを変更すると、いろいろなVVVF音のバリエーションが作れます。
- test23_loud.h・・・現状の吊りかけ音、VVVF音の元サンプリングファイルを配列にしたものです。この音を変更すると、音色を変えることができます。現在、サンプリングレートは16KHzにしています。このため、若い人(0〜10代)にはサンプリング周波数のモスキート音が聞こえるようです。Mp3サウンドデコーダV5にLPFが入っており1.8kΩ、0.1uFよりカットオフ周波数は884Hzに設定されています(計算はこちら)
- motor_func.h・・・LPF関数(Low Pass Filter:速度の変化を滑らかにする)を使用しています。
- TimerOne.h・・・PWMを生成するためのArudinoのライブラリです。こちらのインラインバージョンを使用しています。
VVVF_sound.hに
#define VVVF_SOUND_PIN 9
として、音波形出力ピンを9としています。
Timer1を使用していますので、10とすれば10ピンに出力できると思います。
#define VVVF_SOUND_PIN 9
として、音波形出力ピンを9としています。
Timer1を使用していますので、10とすれば10ピンに出力できると思います。
ino(スケッチ)からどう呼び出すかを解説します。
2.各種CV値をVVVF_soundにコピーします。
VVVF_SetCV(3, gCV3_AccRatio);
VVVF_SetCV(4, gCV4_DecRatio);
VVVF_SetCV(47, gCV47_SoundSwitch);
VVVF_SetCV(48, gCV48_SoundState);
VVVF_SetCV(49, gCV49_SoundNotch);
VVVF_SetCV(50, gCV50_SoundVolume);
3.VVVF_Init()で、kasoku.hのLUTを本体RAMにコピーします。以前、この処理が遅いためCV値の書き換えがうまくいかない不具合がありました。
gSpeedCmd_vvvfは速度0%〜100%が0〜255になる速度値です。
gFuncBits[3]はVVVF音のOn/Offビットです。
- setup関数内
2.各種CV値をVVVF_soundにコピーします。
VVVF_SetCV(3, gCV3_AccRatio);
VVVF_SetCV(4, gCV4_DecRatio);
VVVF_SetCV(47, gCV47_SoundSwitch);
VVVF_SetCV(48, gCV48_SoundState);
VVVF_SetCV(49, gCV49_SoundNotch);
VVVF_SetCV(50, gCV50_SoundVolume);
3.VVVF_Init()で、kasoku.hのLUTを本体RAMにコピーします。以前、この処理が遅いためCV値の書き換えがうまくいかない不具合がありました。
- loop内
gSpeedCmd_vvvfは速度0%〜100%が0〜255になる速度値です。
gFuncBits[3]はVVVF音のOn/Offビットです。
- #define WAV_DATA1 test23_data
- #define WAV_LENGTH1 test23_length
- #define REF_WAVE_FREQ1 (1000000 / (WAV_LENGTH1 * 62.5))
- #define WAV_DATA* test23_data
- #define WAV_LENGTH* test23_length
- #define REF_WAVE_FREQ* (1000000 / (WAV_LENGTH1 * 62.5))
- #define SHIFT_PWM 5
サンプリング波形の配列の番号の指定(16ビット型)に使用します。小さくすると(小数点以下の誤差が大きくなるので)波形が汚くなり、大きくすると桁あふれのため音がバグります。
- #define COUNT_CONSTANTSPEED 33/* 33d=1sec */
- #define THRESHOLD_RATIO 40
- #define CARRER_FREQ 16000
- int current_period1 =(double)1000000 / CARRER_FREQ;//VVVF周期
- volatile unsigned int pwm_state1 = 0;
- volatile unsigned int pwm_state2 = 10;
- volatile unsigned int pwm_state3 = 20;
- unsigned int pwm_add1 = 0;
- unsigned int pwm_add2 = 10;
- unsigned int pwm_add3 = 20;
- unsigned int old_pwm_add1 = 0;
- unsigned int old_pwm_add2 = 10;
- unsigned int pwm_shift = 0;
- int current_duty_a = 0;
- int gAccRatio = 20;
- int gDecRatio = 20;
- int gNotchSpdCount = 0;
- uint8_t SoundSwitch = 0;
- uint8_t SoundState = 1;
- uint8_t SoundNotch = 0;
- uint8_t SoundVolume = 10;
- long gVVVFLPF_buf = 0;
- float PrevSpeed = 0;
- boolean accel_flag = false;
- extern void VVVF_Setup()
- void VVVF_SetCV(uint8_t iNo, uint8_t inData)
- extern void VVVF_Cont(int inPWMFreq, uint8_t inF2Flag)
- int VVVF_Freq( int inPWMFreq)
- void VVVF_Init()
- void vvvf_int1()
現在の音の生成は以下になっています。
(pgm_read_byte_near(&WAV_DATA1 [pwm_state1 >> SHIFT_PWM]) * 3 + pgm_read_byte_near(&WAV_DATA3 [pwm_state3 >> SHIFT_PWM])) >> pwm_shift)
2つの波形から音を生成しており、主周波数の音(WAV_DATA1):副周波数の音(WAV_DATA3)=3:1の波形で出しています。
割り込みなので、計算量が多すぎると、Mp3サウンドデコーダ全体の動きが遅くなり、動作がおかしくなりますので、注意が必要です。
配列は二つの部分に分かれています。上配列でVVVFの音色の切替ポイントを示しています。下配列がVVVFの音階とモーターの強さの配列です。
注意)このページのソースをスケッチにコピーすると表示のために全角スペースなどを使っているのでエラーになします。
速度は0%〜100%のとき0〜1023です。周波数はHzで入れられますが、合っているかどうか確認していません。
また高い周波数で値を変更していくと、連続的に音が変わらないことがあります。
周波数1、周波数2があるのは、和音を出力するためです。周波数2の音は周波数1の1/3の振幅の波形になります。
標準の配列だと以下のように作っております。(東洋系VVVFの例)
表の例で、領域2は速度(1023で最高速)の171〜330の間に周波数1は246Hz〜415Hzに変わり、周波数2は587Hz〜987Hzに変わるということになります。
注意)このページのソースをスケッチにコピーすると表示のために全角スペースなどを使っているのでエラーになします。
- 上の配列 progmem_ref_kasoku[10]
const PROGMEM int progmem_ref_kasoku[10] = { 0,//0:吊りかけ音 10- 110 5,//1:吊りかけ音 10 - 220 10,//2:吊りかけ音 10- 330 15,//3:吊りかけ音 20 - 110 20,//4:吊りかけ音 20 - 220 25,//5:京急ドレミファ 40,//6:E231系 45,//7:抵抗制御 50,//8:VVVF 東洋系 55,//9:E231 60//終わり+1 };
- 下の配列 progmem_kasoku[55][8]
速度は0%〜100%のとき0〜1023です。周波数はHzで入れられますが、合っているかどうか確認していません。
また高い周波数で値を変更していくと、連続的に音が変わらないことがあります。
周波数1、周波数2があるのは、和音を出力するためです。周波数2の音は周波数1の1/3の振幅の波形になります。
標準の配列だと以下のように作っております。(東洋系VVVFの例)
速度スタート | 速度エンド | 周波数1スタート | 周波数1エンド | 周波数2スタート | 周波数2エンド | ダミー | ダミー | |
領域1 | 0 | 170 | 277 | 369 | 554 | 739 | 512 | 512 |
領域2 | 171 | 330 | 246 | 415 | 587 | 987 | 512 | 512 |
領域3 | 331 | 500 | 130 | 207 | 370 | 587 | 512 | 512 |
領域4 | 501 | 1021 | 207 | 353 | 587 | 1000 | 512 | 512 |
領域5 | 1022 | 1023 | 353 | 353 | 500 | 500 | 512 | 512 |
//速度領域始め、終わり、周波数始め、終わり、周波数2始め、2終わり、-、- const PROGMEM int progmem_kasoku[55][8] = { //省略/// //8:VVVF 東洋系 { 0, 170, 277, 369, 554, 739, 512, 512}, { 171, 330, 246, 415, 587, 987, 512, 512}, { 331, 500, 130, 207, 370, 587, 512, 512}, { 501,1021, 207, 353, 587,1000, 512, 512}, {1022,1023, 353, 353, 500, 500, 512, 512}, //省略// };
VVVF音は音に厚みを出すため、2和音を使用しています。
作り方ですが、まず音の高さを確認するため、WaveToneというソフトで加速音の音声ファイルを読み込みます。
すると、加速するに従っての周波数が分かるようになります。下記のは東洋系のVVVF音についてMp3ファイルを読み込んだものです。

カーソルを合わせると周波数が表示されますので、メモっておきます。

これをKasoku.hに書き込みます。和音は適当です。音を聞きながら自分的に納得するように調整してみてください。私としてはこんな感じになりました。(もともとの吊りかけ音のサンプリング音はすでに倍音を含んだものになります)

イメージグラフが書ける表はこちらです。(一部変かも)
この表は、5段のもののため、ドレミファVVVFみたいのを作るときは、もう少し段数を増やす必要があります。
作り方ですが、まず音の高さを確認するため、WaveToneというソフトで加速音の音声ファイルを読み込みます。
すると、加速するに従っての周波数が分かるようになります。下記のは東洋系のVVVF音についてMp3ファイルを読み込んだものです。

カーソルを合わせると周波数が表示されますので、メモっておきます。

これをKasoku.hに書き込みます。和音は適当です。音を聞きながら自分的に納得するように調整してみてください。私としてはこんな感じになりました。(もともとの吊りかけ音のサンプリング音はすでに倍音を含んだものになります)

イメージグラフが書ける表はこちらです。(一部変かも)
この表は、5段のもののため、ドレミファVVVFみたいのを作るときは、もう少し段数を増やす必要があります。
まずは電車の音を録ってきます。
編集はAudacityで行います。(Audacityの操作方法はネットで探してください。)
(1)音ファイルをAudacityで開きます。
(2)トラック→ステレオからモノラルへ を選んで、モノラルデータにします。
(3)吊りかけ音の特徴はノコギリ波とのことで、低音でそうなってそうな所を探して、切り出します。1周期だけ切り出します。

私は35msぐらいの時間のデータを選びました。
(4)音が小さいときはエフェクト→増幅を選ぶと波形を大きくできます(大きくできないときは「クリッピングを可能にする」にチェックを入れておきます)。振幅が1を超えない程度に大きくすることをお勧めします。
(5)1周期選んだあとZキーを押すと、勝手に波形の0点に時間を合わせてくれます。Shift+Spaceキーを押すと切り出した部分をリピート再生してくれます。よさそうな波形を探してください。
(6)切り出します。ファイル→新規作成でAudacityをもう一個立ち上げ、選択領域をコピー&ペーストします。

(7)画面の左下のプロジェクトのサンプリング周波数(Hz)から、サンプリング周波数を44100Hzに変更します。これは適当に補間された大きな波形データが欲しいためにやっているだけです。(ほかの物を試していないのでわかりませんが、もしかしたらこの設定によって元の音の周波数が変わるかもです)
(8)ファイル→オーディオの書き出しでファイルを書き出します。
ファイルの種類は「その他の非圧縮ファイル」
フォーマットは、ヘッダ:「WAV(Microsoft)」、エンコーディング:「Unsigned8-bitPCM」
でよいと思います。
ファイル名の拡張子は.WAVにしておきます。
私のサンプリングファイルではファイルサイズは1.5KBぐらいでした。
(9)DSWav2C.exeを立ち上げ、Openボタンから先ほどのWAVファイルを読み込ませます。「Sample rate of the Wave file is not 8kHz.」と怒られますが「OK」ボタンを押して無視します。(DSWav2CはYaasan様の作です)
Saveボタンを押して、適当なファイル名.hでセーブします。(test23_loud.hとすると、デコーダのスケッチをいじらないで済むかもです)

なお、私のサンプリングファイルではデータ数が1500程度になっていました。
データ数をもっと大きくしたらもっといい音になるかもですがやっていません。
このファイル名をVVVF_sound.cppで読み込んでいるサンプリング波形ファイル(test23_loud.h)と差し替えて、参照ファイル名も変えてやって、コンパイルして、書き込んで、動けば、オリジナル音源のスケッチの完成です。
編集はAudacityで行います。(Audacityの操作方法はネットで探してください。)
(1)音ファイルをAudacityで開きます。
(2)トラック→ステレオからモノラルへ を選んで、モノラルデータにします。
(3)吊りかけ音の特徴はノコギリ波とのことで、低音でそうなってそうな所を探して、切り出します。1周期だけ切り出します。

私は35msぐらいの時間のデータを選びました。
(4)音が小さいときはエフェクト→増幅を選ぶと波形を大きくできます(大きくできないときは「クリッピングを可能にする」にチェックを入れておきます)。振幅が1を超えない程度に大きくすることをお勧めします。
(5)1周期選んだあとZキーを押すと、勝手に波形の0点に時間を合わせてくれます。Shift+Spaceキーを押すと切り出した部分をリピート再生してくれます。よさそうな波形を探してください。
(6)切り出します。ファイル→新規作成でAudacityをもう一個立ち上げ、選択領域をコピー&ペーストします。

(7)画面の左下のプロジェクトのサンプリング周波数(Hz)から、サンプリング周波数を44100Hzに変更します。これは適当に補間された大きな波形データが欲しいためにやっているだけです。(ほかの物を試していないのでわかりませんが、もしかしたらこの設定によって元の音の周波数が変わるかもです)
(8)ファイル→オーディオの書き出しでファイルを書き出します。
ファイルの種類は「その他の非圧縮ファイル」
フォーマットは、ヘッダ:「WAV(Microsoft)」、エンコーディング:「Unsigned8-bitPCM」
でよいと思います。
ファイル名の拡張子は.WAVにしておきます。
私のサンプリングファイルではファイルサイズは1.5KBぐらいでした。
(9)DSWav2C.exeを立ち上げ、Openボタンから先ほどのWAVファイルを読み込ませます。「Sample rate of the Wave file is not 8kHz.」と怒られますが「OK」ボタンを押して無視します。(DSWav2CはYaasan様の作です)
Saveボタンを押して、適当なファイル名.hでセーブします。(test23_loud.hとすると、デコーダのスケッチをいじらないで済むかもです)

なお、私のサンプリングファイルではデータ数が1500程度になっていました。
データ数をもっと大きくしたらもっといい音になるかもですがやっていません。
このファイル名をVVVF_sound.cppで読み込んでいるサンプリング波形ファイル(test23_loud.h)と差し替えて、参照ファイル名も変えてやって、コンパイルして、書き込んで、動けば、オリジナル音源のスケッチの完成です。
最新コメント