名古屋電鉄様の46.MP3サウンドデコーダV5に搭載されている疑似走行音(ディーゼル音)部分の解説です。
一部のニッチな方から中身を教えて!という話があったので、説明をします。
やっていることは、スピード指令に合わせて、IAM_ADPCM音のリピート再生です。なぜ普通のWAVじゃないかというと、ATMEGA328PのROMが少ないから圧縮したというだけです。IMA ADPCMは16itですが、再生は8bitで行っています。
ぜひ、自分だけのMp3サウンドデコーダを作ってみてください。
なお、自分で読み返してもかなり分かりづらいので、誰かわかりやすく書き直してくれると嬉しいです。
また、もしかしたら、下記を直さずに0から作り直したほうが良いかもです。
お約束ですが、スケッチの書き換えは自己責任でお願いいたします。
現在、記憶を頼りに書いておりますので、一部間違えているかもです。お気づきの点はご連絡ください。
また、nspeedもリピートスピードに絡んでいます。大きくすると音再生前にリピートします。
現在の音の生成は以下になっています。
gSound_playedの音番号の音を再生します。
音のリピートは、gSound_Lengthですが、リピート間隔は音の終了を待たずに「gSound_Length - nspeed」よりも長くなったらリピートする。としています。nspeedは加速すると値が大きくなりますので、リピート間隔が短くなります。
ここはそのうち作り直したほうが良いかなあと思います・・・。
(私は、IMA ADPCMは音の音の長さが、ヘッダに書いてあるものとどうも違ってしまっていて(どうも読み方が分からない・・・)、正しい長さが分からなくて、リピート部分がヘンテコになっています。DCC館などにヘッダの説明がありますので、だれか確認していただければと思います。)
リピート時にgSound_playnextに音を切り替えます。
電圧は、Timer1.setPwmDuty(VVVF_SOUND_PIN,t);で、t:0〜1023の10ビットで出します。
一部のニッチな方から中身を教えて!という話があったので、説明をします。
やっていることは、スピード指令に合わせて、IAM_ADPCM音のリピート再生です。なぜ普通のWAVじゃないかというと、ATMEGA328PのROMが少ないから圧縮したというだけです。IMA ADPCMは16itですが、再生は8bitで行っています。
ぜひ、自分だけのMp3サウンドデコーダを作ってみてください。
なお、自分で読み返してもかなり分かりづらいので、誰かわかりやすく書き直してくれると嬉しいです。
また、もしかしたら、下記を直さずに0から作り直したほうが良いかもです。
お約束ですが、スケッチの書き換えは自己責任でお願いいたします。
現在、記憶を頼りに書いておりますので、一部間違えているかもです。お気づきの点はご連絡ください。
- VVVF_sound.cpp・・・疑似音生成の本体です。DCCデコーダ部分からスピードをもらって、疑似音を生成します。
- VVVF_sound.h・・・ヘッダファイルです。
- kasoku.h・・・未使用です。
- "D205_16000_WAV6L.h"・・・加速時(1段階目)のIMA ADPCMの音です。フォーマットは16KHz,16bitです。
- "D205_16000_WAV6U.h"・・・加速時(2段階目)のIMA ADPCMの音です。
- "D205_16000_WAV6UU.h"・・・加速時(3段階目)のIMA ADPCMの音です。
- "D205_16000_WAV3.h"・・・アイドル時のIMA ADPCMの音です。
- 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(スケッチ)からどう呼び出すかを解説します。
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);
VVVF_SetCV(52, gCV52_SoundLoopTiming);
2.VVVF_Setup()で、出力ピン(9pin)、Timer1の初期化をします。IMA_ADPCMの各値を初期化します。
gSpeedCmd_vvvfは速度0%〜100%が0〜255になる速度値です。
- setup関数内
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);
VVVF_SetCV(52, gCV52_SoundLoopTiming);
2.VVVF_Setup()で、出力ピン(9pin)、Timer1の初期化をします。IMA_ADPCMの各値を初期化します。
- loop内
gSpeedCmd_vvvfは速度0%〜100%が0〜255になる速度値です。
- #define WAV_DATA1 test23_data
- #define COUNT_CONSTANTSPEED 30
- #define CARRER_FREQ 16000
- int uplimit; //VVVF配列の上限
- int kasoku[15][8];//VVVF配列
- int current_period1 = (double)1000000 / CARRER_FREQ; //Diesel周期
- int current_period2 = (double)1000000 / CARRER_FREQ; //Diesel周期
- volatile unsigned int pwm_state = 0;
- unsigned int pwm_add = 0;
- int pwm_mask = 0xff;
- int pwm_shift = 8;
- 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;
- uint8_t gSoundLoopTiming = 8 ; // Variable set of Sound loop time by MECY 2017/05/14
- int SoundWave_coeff = 1;
- float PrevSpeed = 0;
- boolean vvvf_first_flag = true;//VVVF_Initを一回呼び出すためのFlag
- boolean accel_flag_prev = false;
- boolean accel_flag = false;
- volatile uint8_t gSound_played = 0;
- uint8_t gSound_playnext = 0;
- int gSound_Length = 0;
- int gSound_offset = 0; // aya add RIFF フォーマットをそのまま使っているのでdata chunkまでoffsetを履かせる
- volatile uint16_t sample; // volatile を使う意味があるかな?
- uint16_t ndata; // 11/9 block数をカウント
- byte lastSample; //
- uint16_t nBlockAlign = 252;
- IMADEC imad;
- uint16_t nspeed;
- extern void VVVF_Setup()
- void VVVF_SetCV(uint8_t iNo, uint8_t inData)
- extern void VVVF_Cont(int inPWMFreq, uint8_t inF2Flag)
また、nspeedもリピートスピードに絡んでいます。大きくすると音再生前にリピートします。
- void vvvf_int1()
現在の音の生成は以下になっています。
gSound_playedの音番号の音を再生します。
音のリピートは、gSound_Lengthですが、リピート間隔は音の終了を待たずに「gSound_Length - nspeed」よりも長くなったらリピートする。としています。nspeedは加速すると値が大きくなりますので、リピート間隔が短くなります。
ここはそのうち作り直したほうが良いかなあと思います・・・。
(私は、IMA ADPCMは音の音の長さが、ヘッダに書いてあるものとどうも違ってしまっていて(どうも読み方が分からない・・・)、正しい長さが分からなくて、リピート部分がヘンテコになっています。DCC館などにヘッダの説明がありますので、だれか確認していただければと思います。)
リピート時にgSound_playnextに音を切り替えます。
電圧は、Timer1.setPwmDuty(VVVF_SOUND_PIN,t);で、t:0〜1023の10ビットで出します。
- byte readSoundRom(uint8_t inNo, uint16_t inOffset)
- uint16_t ima_decode( /* Returns the sample value (-32768 to 32767) / Sound extension by MECY 2017/01/14 */ IMADEC* ad, /* Work area for the ADPCM stream */ uint8_t dat, /* ADPCM data, b3:sign (0:+, 1:-), b2-b0:magnify (0..7) */ int8_t hl /* High or low data read */ )
まずはディーゼル音を録ってきます。
編集はAudacityで行います。(Audacityの操作方法はネットで探してください。)
(1)音ファイルをAudacityで開きます。
(2)トラック→ステレオからモノラルへ を選んで、モノラルデータにします。
(3)適当なディーゼル音部分を切り出して、リピート再生させて、変じゃない部分を探します。

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

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

なお、私のサンプリングファイルではデータ数が配列で3500程度になっていました。(画像は別のものです)
このファイル名をVVVF_sound.cppで読み込んでいるサンプリング波形ファイル(D205_16000_WAV3.h)などと差し替えて、参照ファイル名も変えてやって、コンパイルして、書き込んで、動けば、オリジナル音源のスケッチの完成です。
編集はAudacityで行います。(Audacityの操作方法はネットで探してください。)
(1)音ファイルをAudacityで開きます。
(2)トラック→ステレオからモノラルへ を選んで、モノラルデータにします。
(3)適当なディーゼル音部分を切り出して、リピート再生させて、変じゃない部分を探します。

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

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

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