Electro-smith Daisy seedでライブラリのクラスを改造する
Daisyはデフォルトで提供されているクラスが充実していてそれだけで遊んでいても楽しいですが、以下の記事で書いたように、触っていると「もうちょっとパラメータを外から触れるようにしてほしい」と思うことがあります。
さいわい、DaisySPのコードはMITライセンスで公開されているものなので、コピーして好きなようにいじることができます(改造したものを公開するときはattributionをつけるようにしましょう)。
プロジェクトをつくる
まずは新規のプロジェクトを作ります。最近は、DaisyExamplesレポジトリにhelper.py
というスクリプトが用意されているのでこれを使いましょう。このスクリプトはあくまでDaisyExamplesレポジトリ内に新しいプロジェクトをつくるためのものなので、他の場所につくる場合は多少作業が必要ですが、そこは後述します。
python3 ./helper.py create path/to/<プロジェクト名> --board seed
スクリプトを実行すると、以下のような構造で空のプロジェクトができあがっています。
❯ tree -a .
.
├── .vscode
│ ├── .cortex-debug.peripherals.state.json
│ ├── .cortex-debug.registers.state.json
│ ├── STM32H750x.svd
│ ├── c_cpp_properties.json
│ ├── launch.json
│ └── tasks.json
├── Makefile
├── README.md
├── <プロジェクト名>.cpp
├── <プロジェクト名>.sln
└── vs
├── <プロジェクト名>-Debug.vgdbsettings
├── <プロジェクト名>-Release.vgdbsettings
├── <プロジェクト名>.vcxproj
├── <プロジェクト名>.vcxproj.filters
├── stm32.props
└── stm32.xml
さっそくmake
でビルドしてみると...、エラーになります。
❯ make
Makefile:13: ../../libdaisy/core/Makefile: No such file or directory
make: *** No rule to make target '../../libdaisy/core/Makefile'. Stop.
これは先程書いたように、デフォルトではDaisyExamplesの中で実行されるのが前提になっているためです。具体的には、Makefile
のこの部分を書き換える必要があります。
# Library Locations
LIBDAISY_DIR = ../../libdaisy
DAISYSP_DIR = ../../DaisySP
すでにあるDaisyExamplesにパスを通すか、git submoduleとしてlibDaisyとDaisySPを追加してそのパスを指定するかしましょう。後者でやるなら、以下のようにしてからlib/libDaisy
、lib/DaisySP
をMakefile
に指定します。
mkdir lib
git submodule add git@github.com:electro-smith/libDaisy.git lib/libDaisy
git submodule add git@github.com:electro-smith/DaisySP.git lib/DaisySP
# ライブラリをビルド
(cd lib/libDaisy/ && make)
(cd lib/DaisySP/ && make)
ライブラリから必要なファイルをコピーしてきて編集
例として、クロックとして使えるユーティリティであるMetro
を改造する場合を考えてみましょう。Metro
はスピードを周波数で指定しますが、BPMで指定するようにしてみます。
元のコードはそれぞれ以下にあります。
-
metro.cpp
: https://github.com/electro-smith/DaisySP/blob/master/Source/Utility/metro.cpp -
metro.h
: https://github.com/electro-smith/DaisySP/blob/master/Source/Utility/metro.h
これをコピーしてきて編集します。
cp lib/DaisySP/Source/Utility/metro.cpp metro.cpp
cp lib/DaisySP/Source/Utility/metro.h metro.h
やることはfreq
をbpm
と書き換えて60で割るだけですが、metro.cpp
の方だけ貼っておきます。変数が1つdsp.h
に定義されていたのでそこだけコピーしてますが、dsp.h
ごとコピーしてきてもいいかもです。
--- lib/DaisySP/Source/Utility/metro.cpp 2021-05-05 20:17:37.750956917 +0900
+++ metro.cpp 2021-05-05 20:49:21.337804387 +0900
@@ -1,15 +1,17 @@
#include <math.h>
#include "metro.h"
-#include "dsp.h"
+// dsp.h から必要な定義だけ持ってくる
+#define PI_F 3.1415927410125732421875f
+#define TWOPI_F (2.0f * PI_F)
-using namespace daisysp;
+using namespace my_metro;
-void Metro::Init(float freq, float sample_rate)
+void Metro::Init(float bpm, float sample_rate)
{
- freq_ = freq;
+ bpm_ = bpm;
phs_ = 0.0f;
sample_rate_ = sample_rate;
- phs_inc_ = (TWOPI_F * freq_) / sample_rate_;
+ phs_inc_ = (TWOPI_F * bpm_ / 60.0f) / sample_rate_;
}
uint8_t Metro::Process()
@@ -23,8 +25,8 @@ uint8_t Metro::Process()
return 0;
}
-void Metro::SetFreq(float freq)
+void Metro::SetBpm(float bpm)
{
- freq_ = freq;
- phs_inc_ = (TWOPI_F * freq_) / sample_rate_;
+ bpm_ = bpm;
+ phs_inc_ = (TWOPI_F * bpm_ / 60.0f) / sample_rate_;
}
Makefileに追加
細かい点ですが、.cpp
ファイルはMakefile
のこの行に追加する必要があります。
# Sources
CPP_SOURCES = <プロジェクト名>.cpp metro.cpp
これで、以下のように自作のMetro
を呼び出せるようになっているはずです。
#include "daisy_seed.h"
#include "daisysp.h"
#include "metro.h"
// ...
my_metro::Metro clock;
void AudioCallback(float **in, float **out, size_t size)
{
// (余談1)
for (size_t i = 0; i < size; i++) {
if (clock.Process()) {
// 何らかの処理
}
// ...
}
}
int main(void)
{
// ...
// BPM120
clock.Init(120.0f, hw.AudioSampleRate());
while (1)
{
// (余談2)
}
}
ビルドしてDaisyに送り込みましょう。
make && program-dfu
ちなみに余談ですが、Metro.Process()
はAudioCallback()
のforループの中で動かす必要があります。上のコードで(余談1)や(余談2)の位置でLEDをチカチカさせるのに使おうとしたんですが、うまく動いてくれませんでした。内部の処理はサンプルレートの数だけ呼び出されるのはそのforループの中だけで、他の場所で使うなら自分で秒数を数える必要があるみたいです(DaisySeed.system.GetNow()
とかを使うのかな?)。
最後に
C++も組み込みもDSPも初心者なので、なにか変なこと書いていればツッコミをいただけるとありがたいです...
Discussion