見出し画像

$8 Dual Envelope generator arduino based-DIY Eurorack Modular Synthesizer

Arduino nanoを使用してモジュラーシンセサイザー のDual Envelope generator (EG)を自作したので、その備忘録。


背景

自作モジュラーシンセの46作品目。
私はプリント基板(PCB)の設計をしたことが無かった。PCB製のフロントパネルを設計した事はあるが、電子部品を使用するPCBは設計したことが無い。
私がモジュラーシンセをDIYする目的は、技術の習得のためである。基板設計の学習をするにあたり、PCBを使用したプロジェクトを企画した。

PCBWayの様なPCB製造サービスを作れば、2000円程度(送料込み)で自分の基板を作れる時代だ。しかし、最小ロットの数量が5pcsからなので、PCBを余らせてしまう。
なので、今回は複数のモジュールに流用可能な、Arduino nanoベースの汎用基板を設計することにした。

今回はDual EGを作成する。理由は、プログラミングが簡単だから。今回は基板設計に集中する。回路設計とプログラミングにかける労力は可能な限り小さくしたかった。


制作物のスペック

ユーロラック規格 3U 8HPサイズ
電源:50mA ( at 5V ) / 49mA ( at12V )
5V単電源で動作可能。または12V単電源で動作可能。

Arduino nanoベース。
Attack:アタックタイムの制御
Release:リリースタイムの制御
Level:出力電圧の減衰/増幅
τ(Time Constant):エンベロープカーブの変形

Trigger IN:EGのトリガー(0-5V)
OUT:EG電圧の出力(0-5V)

「τ」とはギリシャ語で「tau」と読む。
電気電子工学では時定数(Time Constant)を示す記号として使われる。
時定数とは、簡単にいうと電圧カーブの形状だ。

τパラメータを変化させることで、EGの電圧カーブを変更することができる。電圧カーブはグラフの16種類から選択する。
分解能はArduinoのフラッシュ領域の都合から2byteとしている。

製作費

総額約850円(PCBではなく、ユニバーサル基板を使う場合)
---------------------------------
Arduino nano 200円
フロントパネル 150円
可変抵抗 28円*8pcs
ジャック 8円*4
他(汎用部品は下記リンク先参照)

PCBを発注する場合、100円/pcs+送料が追加となる。

ハードウェア

回路

可変抵抗の入力が8、ゲート入力が2、CV出力が2のシンプルな回路。
私が過去に作成してきたArduino nanoベースのCVモジュールと同じ構成だ。

CVはPWMをRCローパスフィルターで平滑している。
PWM周波数を高速にすることで、電圧リプルを低減させ、出力抵抗を小さくしている。
出力抵抗が小さいので、オペアンプによるバッファも不要だ。

PCB(プリント基板)

今回作成したArduino nano用の汎用基板を「Genaral board」と呼ぶことにする。先述の通り、Arduino nanoを使用した複数のプロジェクトで使い回す事を想定して設計した。
・可変抵抗によるAD入力*8
・CV入力*3
・CV出力*2(LED点灯回路含む)
・I/O*7
これらの機能を取捨選択してモジュールを設計できる。

今回のDual EGでは
・可変抵抗によるAD入力*8
・CV出力*2(LED点灯回路含む)
・I/O*2
を使用している。
使用していない回路の電子部品は実装していない。

基板設計にはKiCADを使用した。
幅を29mmにすることで、6HPのモジュールに対応している。
高さは99mm。PCBは100mmを超えると値段が大幅に上がるので、100mm以下にするとコストを下げることが出来る。
自動配線はKiCADではなく、Freerouter v1.4.5.1を使用。

基板設計は今回が初めてだが、問題なく動く基板を作ることが出来た。
製造サービスはいつも通りPCBWayを使用。春節明けてすぐの注文だったが、デザインレビューも製造も混乱なくスムーズに進んだ。

PCBのガーバーデータはpatreonメンバーに限定公開している。よろしければ是非。
https://www.patreon.com/posts/64079059

ソフトウェア

特に難しいことはしてない。
高速PWMでCVを作成することについては、過去の私の記事でも説明済みだ。
τ(Time Constant)は事前にエクセルで計算した結果を、Arduinoの配列に格納している。CR Time constantの計算はArduinoの様な非力なMCUだと難しいからだ。

EGカーブの算出式

宣伝:オープンソースプロジェクトの支援をお願いします

DIYモジュラーシンセのオープンソースプロジェクトを継続するために、patreonというサービスでパトロンを募集しています。
コーヒー一杯の支援をいただけると嬉しいです。
また、パトロン限定のコンテンツも配信しています。

ソースコード

粗末だが公開する。悪い点があれば指摘を貰えると嬉しい。

#include <avr/io.h>//for fast PWM

int atk1, atk2, rel1, rel2, lev1, lev2, con1, con2, out1, out2, count1, count2;
//count -- 0 is not triggerd , 1 is attack duration , 2 is release duration.
bool in1, in2, old_in1, old_in2;
int i = 0;//CH1 count
int j = 0;//CH2 count
int last_out1 = 0; //If retriggered at the release time, the CV voltage will be restarted from the middle of the line, not from zero.
int last_out2 = 0;
long timer1 = 0;
long timer2 = 0;

const static byte curve[16][128] PROGMEM = {
  {0, 4, 7, 10, 14, 17, 21, 24, 27, 31, 34, 37, 40, 43, 46, 49, 52, 55, 58, 61, 64, 67, 70, 73, 76, 78, 81, 84, 87, 89, 92, 95, 97, 100, 102, 105, 107, 110, 112, 115, 117, 119, 122, 124, 126, 128, 131, 133, 135, 137, 140, 142, 144, 146, 148, 150, 152, 154, 156, 158, 160, 162, 164, 166, 168, 169, 171, 173, 175, 177, 178, 180, 182, 184, 185, 187, 189, 190, 192, 194, 195, 197, 198, 200, 202, 203, 205, 206, 208, 209, 210, 212, 213, 215, 216, 217, 219, 220, 221, 223, 224, 225, 227, 228, 229, 230, 232, 233, 234, 235, 237, 238, 239, 240, 241, 242, 243, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255},
  {0, 4, 8, 12, 16, 20, 24, 27, 31, 35, 38, 42, 46, 49, 53, 56, 59, 63, 66, 69, 72, 75, 78, 82, 85, 88, 90, 93, 96, 99, 102, 105, 107, 110, 113, 115, 118, 120, 123, 125, 128, 130, 133, 135, 137, 140, 142, 144, 146, 149, 151, 153, 155, 157, 159, 161, 163, 165, 167, 169, 171, 173, 175, 176, 178, 180, 182, 183, 185, 187, 189, 190, 192, 193, 195, 197, 198, 200, 201, 203, 204, 205, 207, 208, 210, 211, 212, 214, 215, 216, 218, 219, 220, 221, 223, 224, 225, 226, 227, 228, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 247, 248, 249, 250, 251, 252, 253, 253, 254, 255},
  {0, 5, 9, 14, 18, 23, 27, 31, 35, 39, 43, 47, 51, 55, 59, 63, 66, 70, 73, 77, 80, 84, 87, 90, 94, 97, 100, 103, 106, 109, 112, 115, 118, 120, 123, 126, 128, 131, 134, 136, 139, 141, 144, 146, 148, 151, 153, 155, 157, 159, 162, 164, 166, 168, 170, 172, 174, 176, 177, 179, 181, 183, 185, 186, 188, 190, 191, 193, 195, 196, 198, 199, 201, 202, 204, 205, 206, 208, 209, 211, 212, 213, 214, 216, 217, 218, 219, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 240, 241, 242, 243, 244, 245, 245, 246, 247, 248, 248, 249, 250, 250, 251, 252, 252, 253, 254, 254, 255},
  {0, 5, 10, 16, 20, 25, 30, 35, 39, 44, 48, 53, 57, 61, 65, 69, 73, 77, 81, 85, 89, 92, 96, 99, 103, 106, 109, 112, 116, 119, 122, 125, 128, 130, 133, 136, 139, 141, 144, 147, 149, 152, 154, 156, 159, 161, 163, 165, 168, 170, 172, 174, 176, 178, 180, 182, 183, 185, 187, 189, 191, 192, 194, 195, 197, 199, 200, 202, 203, 205, 206, 207, 209, 210, 211, 213, 214, 215, 216, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 237, 238, 239, 240, 241, 241, 242, 243, 243, 244, 245, 245, 246, 247, 247, 248, 249, 249, 250, 250, 251, 251, 252, 253, 253, 254, 254, 255, 255},
  {0, 6, 12, 17, 23, 28, 34, 39, 44, 49, 54, 58, 63, 68, 72, 76, 81, 85, 89, 93, 97, 100, 104, 108, 111, 115, 118, 122, 125, 128, 131, 134, 137, 140, 143, 146, 149, 151, 154, 156, 159, 161, 164, 166, 168, 171, 173, 175, 177, 179, 181, 183, 185, 187, 189, 191, 192, 194, 196, 197, 199, 201, 202, 204, 205, 207, 208, 209, 211, 212, 213, 215, 216, 217, 218, 219, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 232, 233, 234, 235, 236, 237, 237, 238, 239, 239, 240, 241, 242, 242, 243, 243, 244, 245, 245, 246, 246, 247, 247, 248, 249, 249, 249, 250, 250, 251, 251, 252, 252, 253, 253, 253, 254, 254, 255, 255},
  {0, 7, 13, 19, 25, 31, 37, 43, 48, 54, 59, 64, 69, 74, 79, 83, 88, 92, 96, 101, 105, 109, 113, 116, 120, 124, 127, 131, 134, 137, 140, 144, 147, 149, 152, 155, 158, 161, 163, 166, 168, 171, 173, 175, 178, 180, 182, 184, 186, 188, 190, 192, 194, 195, 197, 199, 200, 202, 204, 205, 207, 208, 210, 211, 212, 214, 215, 216, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 234, 235, 236, 237, 237, 238, 239, 239, 240, 241, 241, 242, 243, 243, 244, 244, 245, 245, 246, 246, 247, 247, 248, 248, 249, 249, 250, 250, 250, 251, 251, 251, 252, 252, 253, 253, 253, 254, 254, 254, 254, 255, 255},
  {0, 7, 14, 21, 28, 34, 41, 47, 53, 58, 64, 70, 75, 80, 85, 90, 95, 99, 104, 108, 113, 117, 121, 125, 128, 132, 136, 139, 143, 146, 149, 152, 155, 158, 161, 164, 167, 169, 172, 174, 177, 179, 182, 184, 186, 188, 190, 192, 194, 196, 198, 200, 201, 203, 205, 206, 208, 209, 211, 212, 214, 215, 216, 218, 219, 220, 221, 222, 223, 224, 226, 227, 228, 228, 229, 230, 231, 232, 233, 234, 235, 235, 236, 237, 238, 238, 239, 240, 240, 241, 241, 242, 243, 243, 244, 244, 245, 245, 246, 246, 247, 247, 247, 248, 248, 249, 249, 249, 250, 250, 250, 251, 251, 251, 252, 252, 252, 253, 253, 253, 253, 254, 254, 254, 254, 255, 255, 255},
  {0, 8, 16, 23, 30, 37, 44, 51, 57, 63, 69, 75, 81, 86, 92, 97, 102, 107, 111, 116, 120, 124, 129, 133, 136, 140, 144, 147, 151, 154, 157, 161, 164, 167, 169, 172, 175, 177, 180, 182, 185, 187, 189, 191, 194, 196, 198, 199, 201, 203, 205, 207, 208, 210, 211, 213, 214, 216, 217, 218, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 235, 236, 237, 238, 238, 239, 240, 240, 241, 241, 242, 243, 243, 244, 244, 245, 245, 246, 246, 246, 247, 247, 248, 248, 248, 249, 249, 249, 250, 250, 250, 251, 251, 251, 251, 252, 252, 252, 252, 253, 253, 253, 253, 254, 254, 254, 254, 254, 255, 255, 255, 255},
  {0, 9, 17, 25, 33, 40, 48, 55, 62, 68, 74, 81, 87, 92, 98, 103, 108, 113, 118, 123, 128, 132, 136, 140, 144, 148, 152, 155, 159, 162, 165, 168, 171, 174, 177, 180, 182, 185, 187, 190, 192, 194, 196, 199, 201, 202, 204, 206, 208, 210, 211, 213, 214, 216, 217, 219, 220, 221, 222, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 235, 236, 237, 238, 238, 239, 240, 240, 241, 241, 242, 243, 243, 244, 244, 245, 245, 245, 246, 246, 247, 247, 248, 248, 248, 249, 249, 249, 250, 250, 250, 250, 251, 251, 251, 251, 252, 252, 252, 252, 253, 253, 253, 253, 253, 253, 254, 254, 254, 254, 254, 254, 254, 255, 255, 255, 255},
  {0, 10, 20, 29, 38, 47, 55, 63, 70, 78, 85, 91, 98, 104, 110, 116, 121, 127, 132, 137, 141, 146, 150, 154, 158, 162, 166, 169, 173, 176, 179, 182, 185, 188, 191, 193, 196, 198, 200, 203, 205, 207, 209, 211, 212, 214, 216, 217, 219, 220, 222, 223, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 238, 239, 240, 240, 241, 242, 242, 243, 243, 244, 244, 245, 245, 246, 246, 247, 247, 247, 248, 248, 248, 249, 249, 249, 250, 250, 250, 250, 251, 251, 251, 251, 252, 252, 252, 252, 252, 252, 253, 253, 253, 253, 253, 253, 253, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255},
  {0, 11, 22, 32, 42, 52, 61, 69, 77, 85, 93, 100, 107, 113, 120, 126, 131, 137, 142, 147, 152, 156, 161, 165, 169, 173, 176, 180, 183, 186, 190, 192, 195, 198, 200, 203, 205, 207, 210, 212, 214, 215, 217, 219, 221, 222, 224, 225, 226, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 239, 240, 241, 241, 242, 243, 243, 244, 244, 245, 245, 246, 246, 247, 247, 247, 248, 248, 249, 249, 249, 249, 250, 250, 250, 251, 251, 251, 251, 251, 252, 252, 252, 252, 252, 252, 253, 253, 253, 253, 253, 253, 253, 253, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
  {0, 12, 24, 36, 46, 57, 66, 75, 84, 93, 101, 108, 115, 122, 129, 135, 141, 146, 152, 157, 161, 166, 170, 175, 179, 182, 186, 189, 192, 196, 198, 201, 204, 206, 209, 211, 213, 215, 217, 219, 221, 223, 224, 226, 227, 229, 230, 231, 232, 233, 234, 236, 236, 237, 238, 239, 240, 241, 241, 242, 243, 243, 244, 244, 245, 246, 246, 246, 247, 247, 248, 248, 248, 249, 249, 249, 250, 250, 250, 251, 251, 251, 251, 251, 252, 252, 252, 252, 252, 252, 253, 253, 253, 253, 253, 253, 253, 253, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
  {0, 14, 27, 39, 50, 61, 72, 82, 91, 100, 108, 116, 123, 130, 137, 143, 149, 155, 160, 165, 170, 175, 179, 183, 187, 191, 194, 197, 201, 203, 206, 209, 211, 214, 216, 218, 220, 222, 224, 225, 227, 228, 230, 231, 233, 234, 235, 236, 237, 238, 239, 240, 241, 241, 242, 243, 244, 244, 245, 245, 246, 246, 247, 247, 248, 248, 248, 249, 249, 249, 250, 250, 250, 251, 251, 251, 251, 252, 252, 252, 252, 252, 252, 253, 253, 253, 253, 253, 253, 253, 253, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
  {0, 15, 29, 42, 54, 66, 77, 87, 97, 106, 115, 123, 131, 138, 145, 151, 157, 163, 168, 174, 178, 183, 187, 191, 195, 198, 202, 205, 208, 210, 213, 215, 218, 220, 222, 224, 226, 227, 229, 231, 232, 233, 235, 236, 237, 238, 239, 240, 241, 242, 242, 243, 244, 245, 245, 246, 246, 247, 247, 248, 248, 249, 249, 249, 250, 250, 250, 251, 251, 251, 251, 252, 252, 252, 252, 252, 252, 253, 253, 253, 253, 253, 253, 253, 253, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
  {0, 16, 31, 45, 58, 71, 82, 93, 103, 113, 122, 130, 138, 146, 152, 159, 165, 171, 176, 181, 186, 190, 194, 198, 201, 205, 208, 211, 214, 216, 219, 221, 223, 225, 227, 229, 230, 232, 233, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 245, 246, 246, 247, 247, 248, 248, 249, 249, 250, 250, 250, 251, 251, 251, 251, 252, 252, 252, 252, 252, 253, 253, 253, 253, 253, 253, 253, 253, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
  {0, 17, 33, 48, 62, 75, 87, 99, 109, 119, 128, 137, 145, 152, 159, 166, 172, 177, 183, 188, 192, 196, 200, 204, 208, 211, 214, 217, 219, 222, 224, 226, 228, 230, 231, 233, 235, 236, 237, 238, 240, 241, 242, 242, 243, 244, 245, 246, 246, 247, 247, 248, 248, 249, 249, 250, 250, 250, 251, 251, 251, 251, 252, 252, 252, 252, 253, 253, 253, 253, 253, 253, 253, 253, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}
};

void setup()
{
  pinMode(3, INPUT) ;//Z button
  pinMode(11, INPUT) ;//C button
  pinMode(10, OUTPUT) ;//accelx
  pinMode(9, OUTPUT) ;//accely
  timer1 = micros();
  timer2 = micros();
  TCCR1B &= B11111000;//fast pwm setting
  TCCR1B |= B00000001;//fast pwm setting
  //  Serial.begin(9600);
  delay(50);
}

void loop()
{
  old_in1 = in1;
  old_in2 = in2;
  in1 = digitalRead(11);// trig input
  in2 = digitalRead(3);// trig input

  if (old_in1 == 0 && in1 == 1) {// if detect trigger
    if (count1 == 2) {
      last_out1 = out1;
    }
    else if (count1 != 2) {
      last_out1 = 0;
    }
    i = 0;//wave table count reset
    count1 = 1;//start attack duration
    atk1 = analogRead(1) * 12;
    rel1 = analogRead(2) * 16;
    lev1 = analogRead(4) / 4;
    con1 = analogRead(7) / 64;
  }

  else if (count1 == 1 && i > 127) {//attack duration end
    count1 = 2;//start release duration
  }
  else if (count1 == 2 && i > 255) {//release duration end
    count1 = 0;
  }

  if (old_in2 == 0 && in2 == 1) {// if detect trigger
    if (count2 == 2) {
      last_out2 = out2;
    }
    else if (count2 != 2) {
      last_out2 = 0;
    }
    j = 0;//wave table count reset
    count2 = 1;//start attack duration
    atk2 = analogRead(0) * 12;
    rel2 = analogRead(3) * 16;
    lev2 = analogRead(5) / 4;
    con2 = analogRead(6) / 64;
  }

  else if (count2 == 1 && j > 127) {//attack duration end
    count2 = 2;//start release duration
  }
  else if (count2 == 2 && j > 255) {//release duration end
    count2 = 0;
  }

  //----------------------CV output buffer CH1-------------------------
  if (count1 == 1) {//attack
    if (atk1 <= 32) {//Minimize atk time
      i = 128;
      count1 = 2;
    }
    out1 = (pgm_read_byte(&(curve[con1][i])));//store output voltage value
    if (timer1 + atk1 <= micros()) {
      i++;
      timer1 = micros();
    }
  }

  else if (count1 == 2) {//release
    out1 = 255 - (pgm_read_byte(&(curve[con1][i - 128])));//store output voltage value
    if (timer1 + rel1 <= micros()) {
      i++;
      timer1 = micros();
    }
  }

  //----------------------CV output buffer CH2-------------------------
  if (count2 == 1) {//attack
    if (atk2 <= 32) {//Minimize atk time
      j = 128;
      count2 = 2;
    }
    out2 = (pgm_read_byte(&(curve[con2][j])));//store output voltage value
    if (timer2 + atk2 <= micros()) {
      j++;
      timer2 = micros();
    }
  }

  else if (count2 == 2) {//release
    out2 = 255 - (pgm_read_byte(&(curve[con1][j - 128])));//store output voltage value
    if (timer2 + rel2 <= micros()) {
      j++;
      timer2 = micros();
    }
  }
  //----------------------CV output-------------------------
  PWM_OUT();//CV out
}
void PWM_OUT() {//PWM duty setting
  if (count1 == 1) {
    out1 = map(out1, 0, 255, last_out1, lev1);
  }
  else if (count1 == 2) {
    out1 = map(out1, 0, 255, 0, lev1);
  }
  if (count2 == 1) {
    out2 = map(out2, 0, 255, last_out2, lev2);
  }
  else if (count2 == 2) {
    out2 = map(out2, 0, 255, 0, lev2);
  }
  analogWrite(10, out1);//PWM output
  analogWrite(9, out2);//PWM output

}

この記事が気に入ったらサポートをしてみませんか?