「SPRESENSEでデジタルエフェクターを作ろう!」ーモジュレーション系エフェクターの実現ー [SPRESENSE]
今回はエフェクター系統の最後のエフェクター、モジュレーション系エフェクターを実装していきます。

空間系エフェクターは歪み系と空間系エフェクターの中間に接続されるエフェクータです。今回はトレモロ、ビブラート、コーラスを実装したいと思います。モジュレーション系エフェクターは正弦波で変調を加えているのが大きな特徴です。

信号処理の理論は次の本を参考にしました。音声音響信号処理の基本が身につきますのでおすすめです。

■ トレモロの信号処理
トレモロはモジュレーション系エフェクターの中で最も簡単な処理です。正弦波によって音の強弱をかえていきます。うねりのような効果が得られますが、エフェクターとしての効果は控えめな印象です。

dは通常0.3~0.6の値、周波数は数Hzに設定することが多いようです。曲にあわせて調整が必要になります。
■ トレモロの実装
正弦波の処理は時間がかかるのでCoretex M4F の浮動小数点アクセラレータを使うため、ARMが提供している数値ライブラリを用いました。実装では正弦波の周波数を4Hzで、dは0.4を設定しました。
(コードの中では、SAMPLE_SIZE と sample_size が混在していますが同じものです。そのうち整理します)
製品の中には正弦波の他に三角波、矩形波を加える機能をもっているものもあるようです。プログラミングできますので、そのような機能をもたせてみるのも楽しいかもしれません。
■ ビブラートの信号処理
ビブラートはディレイと同じように音を遅延させる処理になります。ただし、その遅延量は、正弦波で与えます。トレモロと異なりエフェクトの効果は抜群でギターの音がシンセのような音に変わります。ただ、演奏するには慣れが必要そうです。

dは遅延量を設定するもので、0~2d の間で変化します。ここはサンプルで指定しますが、時間に換算するには、サンプリング周波数の逆数をサンプル数でかけた数になります。正弦波の周波数は小数点以下から数Hzに設定することが多いようです。
■ ビブラートの実装
ビブラートの変数 d には 96サンプル、2ミリ秒の遅延を与えます。音の遅延は0~4ミリ秒で変化します。また、周波数はトレモロと同じく4Hzに設定しました。
■ コーラスの信号処理
コーラスの信号処理は、ビブラートの変形になります。エコーと同じく遅延した音をもとの音に重ね合わせます。コーラスの効果は、ビブラートのような機械的な音ではなく、自然な音が出せるのでいろいろな場面で使えそうです。
コーラスはその名の通り、声の重ね合わせを表現するので、遅延料 d は数十ミリ秒と比較的大きな値を与え、周波数は小数点以下の値を与えることが多いようです。

■ コーラスの実装
コーラスの遅延量 d には480サンプル、100ミリ秒を与えます。また周波数は 0.1Hz に設定しました。かなり自然な音に仕上がっていると思います。
■ 処理の確認
実際の効果を確認してみました。ビブラートの音はかなりエグいですね。SFやホラーの曲で使うと効果がありそうです。プロの演奏を見るとすごく効果的に使っているので関心します。ギターど素人の私には到底ムリなレベル。ペダルでオンオフ、効果の変化を与えられると効果的に使えそうですね。ギター練習しようかな…
今後、簡単に使えるように Arduino のライブラリにまとめていきたいと思います!
「SPRESENSEでデジタルエフェクターを作ろう!」ープリアンプの製作編
「SPRESENSEでデジタルエフェクターを作ろう!」ー低遅延入出力の実現ー
「SPRESENSEでデジタルエフェクターを作ろう!」ーコンプレッサーとディストーションの実現ー
「SPRESENSEでデジタルエフェクターを作ろう!」ー空間系エフェクターの実現ー
「SPRESENSEでデジタルエフェクターを作ろう!」ーモジュレーション系エフェクターの実現ー




空間系エフェクターは歪み系と空間系エフェクターの中間に接続されるエフェクータです。今回はトレモロ、ビブラート、コーラスを実装したいと思います。モジュレーション系エフェクターは正弦波で変調を加えているのが大きな特徴です。

信号処理の理論は次の本を参考にしました。音声音響信号処理の基本が身につきますのでおすすめです。

音声音響信号処理の基礎と実践 - フィルタ,ノイズ除去,音響エフェクトの原理 - (次世代信号情報処理シリーズ 2)
- 出版社/メーカー: コロナ社
- 発売日: 2021/04/08
- メディア: 単行本
■ トレモロの信号処理
トレモロはモジュレーション系エフェクターの中で最も簡単な処理です。正弦波によって音の強弱をかえていきます。うねりのような効果が得られますが、エフェクターとしての効果は控えめな印象です。

dは通常0.3~0.6の値、周波数は数Hzに設定することが多いようです。曲にあわせて調整が必要になります。
■ トレモロの実装
正弦波の処理は時間がかかるのでCoretex M4F の浮動小数点アクセラレータを使うため、ARMが提供している数値ライブラリを用いました。実装では正弦波の周波数を4Hzで、dは0.4を設定しました。
(コードの中では、SAMPLE_SIZE と sample_size が混在していますが同じものです。そのうち整理します)
#define ARM_MATH_CM4 #define __FPU_PRESENT 1U #include <cmsis/arm_math.h> void signal_process(int16_t* mono_input, int16_t* stereo_output, const uint32_t sample_size) { /* clean up the output buffer */ memset(stereo_output, 0, sizeof(int16_t)*sample_size*2); /* memory pool for 1.5sec (= 720*100*(1/48000)) */ static const int lines = 100; static int16_t src_buf[sample_size*lines]; /* 2*720*100=144kBytes */ /* shift the buffer data in src_buf and add the latest data to top of the bufer */ memcpy(&src_buf[0], &src_buf[sample_size], SAMPLE_SIZE*sizeof(int16_t)*(lines-1)); memcpy(&src_buf[(lines-1)*sample_size], &mono_input[0], SAMPLE_SIZE*sizeof(int16_t)); static int theta = 0; const int mod_freq = 4; /* Hz */ const float omega = 2.*PI*mod_freq/AS_SAMPLINGRATE_48000; const int sin_total_samples = AS_SAMPLINGRATE_48000/mod_freq; const float d = 0.4; /* amplitude of moduration */ const int src_buf_end_point = lines*SAMPLE_SIZE-1; for (int n = SAMPLE_SIZE-1; n >= 0; --n) { float modulation = 1.-d*arm_sin_f32(omega*theta); mono_input[(SAMPLE_SIZE-1)-n] = (int16_t)(modulation*src_buf[src_buf_end_point-n]); if (++theta >= sin_total_samples) theta = 0; } /* copy the signal to output buffer */ for (int n = SAMPLE_SIZE-1; n >= 0; --n) { stereo_output[n*2] = stereo_output[n*2+1] = mono_input[n]; } return; }
製品の中には正弦波の他に三角波、矩形波を加える機能をもっているものもあるようです。プログラミングできますので、そのような機能をもたせてみるのも楽しいかもしれません。
■ ビブラートの信号処理
ビブラートはディレイと同じように音を遅延させる処理になります。ただし、その遅延量は、正弦波で与えます。トレモロと異なりエフェクトの効果は抜群でギターの音がシンセのような音に変わります。ただ、演奏するには慣れが必要そうです。

dは遅延量を設定するもので、0~2d の間で変化します。ここはサンプルで指定しますが、時間に換算するには、サンプリング周波数の逆数をサンプル数でかけた数になります。正弦波の周波数は小数点以下から数Hzに設定することが多いようです。
■ ビブラートの実装
ビブラートの変数 d には 96サンプル、2ミリ秒の遅延を与えます。音の遅延は0~4ミリ秒で変化します。また、周波数はトレモロと同じく4Hzに設定しました。
#define ARM_MATH_CM4 #define __FPU_PRESENT 1U #include <cmsis/arm_math.h> void signal_process(int16_t* mono_input, int16_t* stereo_output, const uint32_t sample_size) { /* clean up the output buffer */ memset(stereo_output, 0, sizeof(int16_t)*sample_size*2); /* memory pool for 1.5sec (= 720*100*(1/48000)) */ static const int lines = 100; static int16_t src_buf[SAMPLE_SIZE*lines]; /* 2*720*100=144kBytes */ /* shift the buffer data in src_buf and add the latest data to top of the bufer */ memcpy(&src_buf[0], &src_buf[SAMPLE_SIZE], SAMPLE_SIZE*sizeof(int16_t)*(lines-1)); memcpy(&src_buf[(lines-1)*SAMPLE_SIZE], &mono_input[0], SAMPLE_SIZE*sizeof(int16_t)); const float mod_freq = 4; /* Hz */ const float omega = 2.*PI*mod_freq/AS_SAMPLINGRATE_48000; const int sin_total_samples = AS_SAMPLINGRATE_48000/mod_freq; const int d = 96; /* delay samples = delay time / Sampling Rate */ static int theta = 0; const int src_buf_end_point = lines*SAMPLE_SIZE-1; for (int n = SAMPLE_SIZE-1; n >= 0; --n) { float modulation = 1. + arm_sin_f32(omega*theta); int offset = (int)(modulation*d); mono_input[(SAMPLE_SIZE-1)-n] = src_buf[src_buf_end_point-n-offset]; if (++theta == sin_total_samples) theta = 0; } /* copy the signal to output buffer */ for (int n = SAMPLE_SIZE-1; n >= 0; --n) { stereo_output[n*2] = stereo_output[n*2+1] = mono_input[n]; } return; }
■ コーラスの信号処理
コーラスの信号処理は、ビブラートの変形になります。エコーと同じく遅延した音をもとの音に重ね合わせます。コーラスの効果は、ビブラートのような機械的な音ではなく、自然な音が出せるのでいろいろな場面で使えそうです。
コーラスはその名の通り、声の重ね合わせを表現するので、遅延料 d は数十ミリ秒と比較的大きな値を与え、周波数は小数点以下の値を与えることが多いようです。

■ コーラスの実装
コーラスの遅延量 d には480サンプル、100ミリ秒を与えます。また周波数は 0.1Hz に設定しました。かなり自然な音に仕上がっていると思います。
#define ARM_MATH_CM4 #define __FPU_PRESENT 1U #include <cmsis/arm_math.h> void signal_process(int16_t* mono_input, int16_t* stereo_output, const uint32_t sample_size) { /* clean up the output buffer */ memset(stereo_output, 0, sizeof(int16_t)*sample_size*2); /* memory pool for 1.5sec (= 720*100*(1/48000)) */ static const int lines = 100; static int16_t src_buf[SAMPLE_SIZE*lines]; /* 2*720*100=144kBytes */ /* shift the buffer data in src_buf and add the latest data to top of the bufer */ memcpy(&src_buf[0], &src_buf[SAMPLE_SIZE], SAMPLE_SIZE*sizeof(int16_t)*(lines-1)); memcpy(&src_buf[(lines-1)*SAMPLE_SIZE], &mono_input[0], SAMPLE_SIZE*sizeof(int16_t)); const float mod_freq = 0.1; /* Hz */ const float omega = 2.*PI*mod_freq/AS_SAMPLINGRATE_48000; const int sin_total_samples = AS_SAMPLINGRATE_48000/mod_freq; const int d = 720*2; /* delay samples = 720(samples/frame) * delay time (msec) / 15 (msec/frame) */ const int p = 480; /* p must be less than d */ static int theta = 0; const int src_buf_end_point = lines*SAMPLE_SIZE-1; for (int n = SAMPLE_SIZE-1; n >= 0; --n) { int offset = (int)(d + p*arm_sin_f32(omega*theta)); mono_input[(SAMPLE_SIZE-1)-n] = (src_buf[src_buf_end_point-n] + src_buf[src_buf_end_point-n-offset])/2; if (++theta == sin_total_samples) theta = 0; } /* copy the signal to output buffer */ for (int n = SAMPLE_SIZE-1; n >= 0; --n) { stereo_output[n*2] = stereo_output[n*2+1] = mono_input[n]; } return; }
■ 処理の確認
実際の効果を確認してみました。ビブラートの音はかなりエグいですね。SFやホラーの曲で使うと効果がありそうです。プロの演奏を見るとすごく効果的に使っているので関心します。ギターど素人の私には到底ムリなレベル。ペダルでオンオフ、効果の変化を与えられると効果的に使えそうですね。ギター練習しようかな…
今後、簡単に使えるように Arduino のライブラリにまとめていきたいと思います!
モジューレーション系エフェクターをSPRESENSEで試してみました。あとは簡単に使えるように全てのエフェクトをArduinoライブラリにまとめたいと思います。SPRESENSE一台で全てのエフェクトがかけられるといいな
— よしのたろう 純国産ボード”スプレッセンス”応援団長(仮) (@Taro_Yoshino) June 11, 2022pic.twitter.com/iV4Lo6hd3I
「SPRESENSEでデジタルエフェクターを作ろう!」ープリアンプの製作編
「SPRESENSEでデジタルエフェクターを作ろう!」ー低遅延入出力の実現ー
「SPRESENSEでデジタルエフェクターを作ろう!」ーコンプレッサーとディストーションの実現ー
「SPRESENSEでデジタルエフェクターを作ろう!」ー空間系エフェクターの実現ー
「SPRESENSEでデジタルエフェクターを作ろう!」ーモジュレーション系エフェクターの実現ー

音声音響信号処理の基礎と実践 - フィルタ,ノイズ除去,音響エフェクトの原理 - (次世代信号情報処理シリーズ 2)
- 出版社/メーカー: コロナ社
- 発売日: 2021/04/08
- メディア: 単行本

SPRESENSEではじめるローパワーエッジAI (Make: PROJECTS)
- 出版社/メーカー: オライリージャパン
- 発売日: 2022/02/28
- メディア: 単行本(ソフトカバー)

SONY SPRESENSE メインボード CXD5602PWBMAIN1
- 出版社/メーカー: スプレッセンス(Spresense)
- メディア: Tools & Hardware

SONY SPRESENSE 拡張ボード CXD5602PWBEXT1
- 出版社/メーカー: スプレッセンス(Spresense)
- メディア: Tools & Hardware
コメント 0