Tremolec

02_243_1tremolecp.jpg
東京エフェクター「第6回エフェクタービルダーズ・コンテスト」に向けて製作した、トレモロを周波数帯域別にかけるというエフェクターです。全てデジタル信号処理でやる方が楽だと思いますが、製作時は知識が足りずアナログ回路+マイコン制御の練習として取り組みました。タップテンポ付きで、LFO周期に合わせて左側のLEDが点滅します。名前の由来は、トレモロとイコライザ(Tremolo + EQ)を合わせたものです。

筐体は少し変わった形にしたかったので、タカチのHEN110312Sというケースです。上下側が放熱用の形状なので、DCジャックの穴を開けるのが大変でした。ラベルデザインはKiCadでやってみましたが、フォントを取り込むのは面倒なので標準フォントをそのまま使っています。

▽回路図
02_243_2tremolecs.png
一般的なグラフィックイコライザ回路の可変抵抗部分をフォトカプラLCR0202で置き換えたものとなります。DAコンバータMCP4922から出力される電圧によりフォトカプラのLEDの明るさを制御し、抵抗値を変えるという仕組みです。LFO周期の半分で増幅側のフォトカプラだけを動かし、もう半分で減衰側を動かすという動作となっています。電圧変化が直線的だと音量変化がスムーズでなかったため、独自にデータを取って電圧変化を指数カーブに修正しました。また、フォトカプラの特性はバラつきがあるので、増幅と減衰の幅が同じくらいになるようマッチングしました。

AVRマイコンATmega328Pは内部クロック8MHzで動作させています。ポットやスイッチの読取(ADコンバータ)、LFO(DAコンバータ制御)、タップテンポといった機能を担っています。

▽レイアウトについて(KiCadデータはGitHubへ)
隙間が多いので表面実装でなくてもよかったかもしれません。一応アナログGNDとデジタルGNDを分けるようにしました。デジタルのノイズは測定限界以下で問題ないようです。C7、C9は何も入れておらず、後からコンデンサの値を調節できるように設けた部分になります。

▽Arduinoスケッチ
#include <SPI.h>

// ピン設定 実際は高速処理するため該当レジスタを直接変更
const byte swPin = 2; // タップスイッチ
const byte ledPin = 3; // PD3 周期表示用LED
const byte SS1 = 10; // PB2 MCP4922 Low
const byte SS2 = 9; // PB1 MCP4922 Mid
const byte SS3 = 8; // PB0 MCP4922 Treble
const byte LDAC = 7; // PD7 MCP4922 電圧出力作動ピン

// LFO1周期を500分割 0.002周期経過するごとに電圧値を変更する
volatile int pwmCount = 0; // LFO用カウンタ 0〜499
volatile int waveCount = 0; // 波形用カウンタ 0~125

volatile unsigned long timeCount = 0; // タップ時間取得用カウンタ
unsigned long tapTime = 0; // タップ間隔時間 us
unsigned long timeTemp = 0; // タップ間隔時間一時保存用
unsigned long swCount = 0; // タップスイッチ用カウンタ

byte adcNum = 0; // ADC番号(配列の添字)Bass0 Mid1 Tre2 Wave3 Div4 Rate5
const byte adcPinArray[6] = {16, 17, 18, 19, 14, 15}; // ADCピン設定
unsigned int oldAdcValue[6] = {2000, 2001, 2002, 2003, 2004, 2005}; // 旧ADC値
unsigned int newAdcValue[6] = {1110, 1111, 1112, 1113, 1114, 1115}; // 新ADC値

unsigned int dacArray[626]; // 電圧値配列 626段階 セットアップ時計算
unsigned long dacDepth[3] = {0, 1, 2}; // 電圧値配列添字部分の倍率
volatile unsigned int dacValueA[3] = {4001, 4002, 4003}; // 出力電圧値 増幅側
volatile unsigned int dacValueB[3] = {4011, 4012, 4013}; // 出力電圧値 減衰側
byte waveAmp = 1; // 三角波→矩形波変換 増幅率
const byte SQ = 12; // 上記増幅率設定値
byte tapDiv = 1; // タップ時間分割値
//const float rateAdj = 1.000; // 周期補正 実測して設定→不要

const unsigned int ledOnTime = 40000; // 周期表示LED点灯時間設定値 us
unsigned int ledOffCount = 250; // 上記LEDが消灯するカウンタ値

void setup() {
TIMSK0 = 0; // Timer0割り込み停止 安定動作のため割り込みはTimer1のみ

// 電圧値の配列を計算 指数カーブ
for (int i = 0; i <= 625; i++) {
dacArray[i] = 4141 - 46 * exp(0.0072 * i);
}

pinMode(swPin, INPUT_PULLUP);
pinMode(ledPin, OUTPUT);
pinMode(SS1, OUTPUT);
pinMode(SS2, OUTPUT);
pinMode(SS3, OUTPUT);
pinMode(LDAC, OUTPUT);

SPI.begin();
SPI.beginTransaction(SPISettings(8000000, MSBFIRST, SPI_MODE0)); // SPI 8MHz

// Timer1 電圧値変更間隔時間管理・タップ時間計測
TCCR1A = 0b00000000; // Timer1 CTCモード
TCCR1B = 0b00001010; // Timer1 CTCモード クロック8分周
OCR1A = 100; // Timer1 比較Aの値 = 割り込み間隔 us
TIMSK1 |= (1 << OCIE1A); // Timer1 比較A割り込み許可
}

// LFO(Timer1 比較A割り込み)-----------------------------------------------------
ISR(TIMER1_COMPA_vect) {
timeCount++; // タップ時間取得用カウンタ
PORTD &= ~_BV(7); // LDAC LOW (最初に電圧出力)
PORTD |= _BV(7); // LDAC HIGH
if (pwmCount == 500) pwmCount = 0; // 0〜499 ループ
if (pwmCount <= 125) { // 三角波 増幅側上昇
waveCount = waveAmp * pwmCount; // 三角波を増幅後、
waveCount = min(waveCount, 125); // クリップし矩形波とする
dacA(waveCount);
} else if (pwmCount <= 250) { // 三角波 増幅側下降
waveCount = waveAmp * (250 - pwmCount);
waveCount = min(waveCount, 125);
dacA(waveCount);
} else if (pwmCount <= 375) { // 三角波 減衰側上昇
waveCount = waveAmp * (pwmCount - 250);
waveCount = min(waveCount, 125);
dacB(waveCount);
} else { // 三角波 減衰側下降
waveCount = waveAmp * (500 - pwmCount);
waveCount = min(waveCount, 125);
dacB(waveCount);
}
if (pwmCount == 125) PORTD |= _BV(3); // 周期表示LED点灯
if (pwmCount == ledOffCount) PORTD &= ~_BV(3); // 消灯
pwmCount++;
}

void loop() {
// タップテンポ -----------------------------------------------------------------
if (digitalRead(swPin) == LOW) {
swCount++;
if (swCount == 50) { // チャタリング対策 数msスイッチ押下で検出
// 前回スイッチ検出から経過した時間を記録
tapTime = timeTemp + timeCount * OCR1A + TCNT1;
TCNT1 = 0; // 経過時間をリセット
timeTemp = 0;
timeCount = 0;
pwmCount = 124; // 増幅最大の点にリセット
if ( 200000 < tapTime && tapTime < 2100000) { // 周期制限 0.2秒~2.1秒
// タップ間隔を電圧値変更間隔時間へ換算(Divスイッチ加味)
OCR1A = tapTime * 0.002 / tapDiv;
// どの周期でも周期表示LEDの点灯時間が同程度になるよう計算
ledOffCount = 125 + ledOnTime / OCR1A;
}
}
}
else swCount = 0;

// ADC --------------------------------------------------------------------------
adcNum++;
if (adcNum == 6) adcNum = 0; // 0〜5 ループ
newAdcValue[adcNum] = analogRead(adcPinArray[adcNum]); // 読取値が4以上変化で変更
if (abs(newAdcValue[adcNum] - oldAdcValue[adcNum]) >= 4) {
if (adcNum <= 2) { // Depth 0〜640 160までは急な変化
if (newAdcValue[adcNum] < 100) dacDepth[adcNum] = 1.6 * newAdcValue[adcNum];
else dacDepth[adcNum] = 0.5201 * newAdcValue[adcNum] + 108;
} else if (adcNum == 3) { // Wave 1 or SQ 矩形波変換増幅率
if (newAdcValue[adcNum] < 500) waveAmp = 1;
else waveAmp = SQ;
} else if (adcNum == 4) { // Div 1〜3 タップ時間分割値
tapDiv = 0.0029 * newAdcValue[adcNum] + 1;
} else if (adcNum == 5) { // Rate 4004〜133 電圧値変更間隔時間
// Rate変更前から経過した時間を記録
timeTemp = timeTemp + timeCount * OCR1A + TCNT1;
TCNT1 = 0; // 経過時間をリセット
timeCount = 0;
// Rate計算 指数カーブ
OCR1A = 73 * exp(0.0039 * (1023 - newAdcValue[adcNum])) + 60;
// どの周期でも周期表示LEDの点灯時間が同程度になるよう計算
ledOffCount = 125 + ledOnTime / OCR1A;
}
oldAdcValue[adcNum] = newAdcValue[adcNum];
}
}

// 電圧値設定 A:増幅側 B:減衰側--------------------------------------------------
void dacA(int w) { // w:waveCount 波形用カウンタ
// w(0〜125)にDepth(0〜640)をかけ128で割ったものが電圧値配列の添字(0〜625)
dacValueA[0] = dacArray[(dacDepth[0] * w) >> 7];
dacValueA[1] = dacArray[(dacDepth[1] * w) >> 7];
dacValueA[2] = dacArray[(dacDepth[2] * w) >> 7];
PORTB &= ~_BV(2); // SS1(PB2) LOW
SPI.transfer((dacValueA[0] >> 8) | 0x30); // 0x30=0b00110000 A出力 バッファなし
SPI.transfer(dacValueA[0] & 0xff); // ゲイン1倍 シャットダウンなし
PORTB |= _BV(2); // SS1(PB2) HIGH
PORTB &= ~_BV(1); // SS2(PB1)
SPI.transfer((dacValueA[1] >> 8) | 0x30);
SPI.transfer(dacValueA[1] & 0xff);
PORTB |= _BV(1);
PORTB &= ~_BV(0); // SS3(PB0)
SPI.transfer((dacValueA[2] >> 8) | 0x30);
SPI.transfer(dacValueA[2] & 0xff);
PORTB |= _BV(0);
}

void dacB(int w) {
dacValueB[0] = dacArray[(dacDepth[0] * w) >> 7];
dacValueB[1] = dacArray[(dacDepth[1] * w) >> 7];
dacValueB[2] = dacArray[(dacDepth[2] * w) >> 7];
PORTB &= ~_BV(2);
SPI.transfer((dacValueB[0] >> 8) | 0xb0); // 0xb0=0b10110000 B出力
SPI.transfer(dacValueB[0] & 0xff);
PORTB |= _BV(2);
PORTB &= ~_BV(1);
SPI.transfer((dacValueB[1] >> 8) | 0xb0);
SPI.transfer(dacValueB[1] & 0xff);
PORTB |= _BV(1);
PORTB &= ~_BV(0);
SPI.transfer((dacValueB[2] >> 8) | 0xb0);
SPI.transfer(dacValueB[2] & 0xff);
PORTB |= _BV(0);
}
過去記事(→ATtiny85 タップテンポ付LFO その2)と同じようなスケッチで、割り込み時の処理がDAコンバータ制御に変わっています。MCP4922の使い方は下記ページを参考にしました。高速処理するため、今回はレジスタを直接変更しています。
きむ茶工房ガレージハウス - DAコンバータ MCP4922(SPI)を利用しD/A変換を行う

音については今までにない効果だと思うので、どう評価されるかわかりません。TREBLEのみ揺らす、MIDのみ揺らさない等、いろんなパターンを試せるので、誰でもきっと「お気に入りのトレモロ」が見つけられるんじゃないかと思います。



以下、採用にならなかった案をメモしておきます。

<他のイコライザ回路>
下記ページのような3バンドイコライザ回路があります。DJミキサーに使われているらしいです。
Equalisers, The Various Types And How They Work - 9 - Frequency 'Isolators'
シミュレーションしてみたのですが、減衰時の特性がいまいち気に入りませんでした。

<デジタルポテンショメータ(以下DPOT)>
フォトカプラの部分にDPOTを使うことを最初検討していました。しかし普通のDPOTは分解能が8ビットなので、1/256ずつ飛び飛びに値を動かすことになり、ノイズが発生してしまうことになります。常にDPOTを動かし続ける今回の用途には向いていないと判断しました。

<フォトカプラのPWM制御>
フォトカプラのLED側をPWMで制御しようと思い、PWM出力が6つ使えるマイコンATmega1284Pを準備しました。しかしPWMが一部8ビットなので、256段階でしか抵抗値を調節できず、スムーズに増幅・減衰の変化をさせることができませんでした。後から考えると、高性能な32ビットマイコンを使えばよかったかもしれません。

タグ : 自作エフェクター 回路図 レイアウト マイコン トレモロ 

Srempy

03s_242_1srempy.jpg
デジタルエフェクターというとディスプレイをつけたくなるもので、ポットなしでスイッチのみを使って操作するというエフェクターを製作しました。精度よく角穴加工するのはかなり大変なので、Tabby's工房さんにお願いしました。

▽ディスプレイ・スイッチ基板レイアウト
03s_242_2srempyL.png
いつものようにチャタリング防止を行っています。OLEDディスプレイ基板用押ボタンスイッチは秋月電子で購入しました。

DSP基板はOwm Pedalと同じものを使用しています。下写真のように合体させます。
03s_242_3srempyi.jpg

ディスプレイの詳細は前回記事をご覧ください。スイッチ操作は割り込みではなくメインループで処理しています(GitHubはこちら)。エフェクトオフ時にはスイッチの反応が速くなりますが、実用上問題ないので特に対処していません。▲▼スイッチ長押しでフラッシュメモリにパラメータ保存できます。下記ページの内容を使わせていただきました。
sora lab - STM + HAL Flashの書き込み・読み込み

エフェクトプログラムはもちろん変え放題ですが、今回私が考えたものを紹介したいと思います。※信号処理は旧処理方法(TxRxCpltCallback関数利用なし、16ビット)のままです。



アナログ回路でのフィルタ設計は複雑になる場合が多く、コンデンサの容量値も限られています。また、リアルタイムに動かすとなると可変抵抗やフォトカプラを使うぐらいしか選択肢がありません。デジタル信号処理でのフィルタについては計算方法が確立しているため、専門知識がなくとも設計可能で、任意の定数を動かすこともできます。計算式は下記ページのものを利用させていただきました。
C++でVST作り - 簡単なデジタルフィルタの実装

フェイザーはノッチフィルタがかかったような周波数特性で、谷となる周波数が動いています(参考ページ→MXR Phase 90 Analysis)。今回はこの特性をピーキングフィルタを使って再現、発展させたエフェクトを考えました。フェイザーとワウを合わせたような効果で、5つのモード(STD、SOFT、INV、HIGH、LOW)があります。名前の由来は3つ(Three)のピーキングフィルタ(Peaking Filter)です。

<STD・SOFTモード>
03s_242_4srempyF1.png
SOFTモードでは、単純に谷となるフィルタを2つかけています。谷と谷の間は減衰し、スッキリとした感じとなります。STD(スタンダード)モードは、Phase 90の特性に近づけています。うねり感を得るためには、2つの谷の間に山が必要なようです。ちなみに2つの谷の間隔が広いとユニヴァイブのコーラスモードっぽい音になります。谷となる周波数の揺れ幅や高低は、出音への影響は少なかったです。

<INV・HIGH・LOWモード>
03s_242_5srempyF2.png
フィルタを谷ではなく山にした場合、山が1つだとオートワウのようになります。山を2つにすると、クセは強いもののフェイザーっぽいシュワシュワ感が現れます。INV(インバース)モードでは、2つの山の間にさらに谷を追加しています。HIGH/LOWモードは谷と山を混ぜており、通常のフェイザーの高音域/低音域が強調された感じとなります。

<計算高速化>
BiQuadフィルタの係数は三角関数の計算が入っていて、そのままでは処理に時間がかかり過ぎると思われます。そのため表計算ソフトで近似式を算出するなどして対応しています。それでも実際のCPU使用率は70%程度となってしまいましたので、計算高速化についてはもう少し検討していく予定です。

タグ : 自作エフェクター 周波数特性 マイコン フェイザー 

STM32 I2C接続OLEDディスプレイを使う

03s_241_1oled.jpg
秋月電子等で取り扱いがある、128×64ドットのI2C制御有機ELディスプレイモジュールを使ってみます。使われているSSD1306は定番の制御ICらしいです。接続は上写真の通り、GND、VCC(3.3V)、SCL、SDAをつなぎます。SCL、SDAのプルアップ抵抗はモジュールに搭載されているようです。



<STM32CubeMX(5.1.0) Pinout & Configurationタブ>
左側列のConnectivity→I2C1を開く

・中央列上側 Mode
 I2C : I2C

・中央列下側 Configuration→Parameter Settingsタブ
 Rise Time (ns) : 1000
 Fall Time (ns) : 300

・右側列 IC画像
 ピン位置を変更
  (61)-PB8 : I2C1_SCL
  (62)-PB9 : I2C1_SDA



<TrueSTUDIO(9.3.0)>
下記ページのライブラリを利用します。必要最小限となっているので使いやすいと思います。
 github.com/4ilo/ssd1306-stm32HAL(右側の[Clone or download]ボタンから全ファイルをダウンロードできます。)

以下の4ファイルを自分のプロジェクトへコピーします。
 Incフォルダ→fonts.h ssd1306.h
 Srcフォルダ→fonts.c ssd1306.c

私のNucleoボードはSTM32F3シリーズなので、fonts.hとssd1306.h最上部に記載されている"stm32f4xx_hal.h"を"stm32f3xx_hal.h"へ変更します。STM32F4シリーズを使う場合は、そのままでOKです。

ライブラリのmain.cから以下の2箇所のコードを自分のmain.cへコピーします。
 /* USER CODE BEGIN Includes */〜/* USER CODE END Includes */
 /* USER CODE BEGIN 2 */〜/* USER CODE END 2 */

実行しディスプレイに文字が表示されれば成功です。以下は各関数の簡単な説明です。円などの図形を描く関数はないので、必要なものはssd1306_DrawPixel関数を使って描画することになります。
 ssd1306_Init…初期化
 ssd1306_Fill…画面全体塗りつぶし
 ssd1306_DrawPixel…1ピクセル描画
 ssd1306_SetCursor…文字描画位置を設定
 ssd1306_WriteString…文字列を描画
 ssd1306_UpdateScreen…描画を反映して画面を更新



<画面端の文字を強制描画>
ディスプレイ端のピクセル数が足りない場合、文字描画しないようになっていますが、文字が切れてでも描画するようにします。ssd1306_DrawPixel関数で画面外は描画しないよう制限されているので、たぶん問題ないでしょう。

ssd1306.c内、ssd1306_WriteChar関数の以下の記述を削除
// Check remaining space on current line
if (SSD1306_WIDTH <= (SSD1306.CurrentX + Font.FontWidth) ||
SSD1306_HEIGHT <= (SSD1306.CurrentY + Font.FontHeight))
{
// Not enough space on current line
return 0;
}



<フォント自作>
font.cにフォントのデータが入っており、自分で文字データを作成することができます。例として7x10ピクセルの「2」を0と1で描きます。横は左側7列だけ使いますが、後々のために16列準備します。
0011100000000000
0100010000000000
0100010000000000
0000010000000000
0000100000000000
0001000000000000
0010000000000000
0111110000000000
0000000000000000
0000000000000000
1行ずつを16桁の2進数とみなし、16進数へ変換します。
→0x3800, 0x4400, 0x4400, 0x0400, 0x0800, 0x1000, 0x2000, 0x7C00, 0x0000, 0x0000
これを「2」のフォントデータとすればOKです。自動計算できる表計算ファイル(LibreOfficeやOpenOfficeで開けるodsファイル)をGitHubに置いています。

タグ : マイコン 

STM32 I2S DMA利用時の32ビット対応

たいていのオーディオコーデックICでは、24ビットや32ビットのデータを取り扱うことができます。Owm Pedalは16ビットに設定していましたが、32ビットに対応できるよう変更します。



リファレンスマニュアルによると、I2Sで32ビットデータを取り扱うには16ビットずつデータ転送する必要があります。DMAは16ビット(Half Word)設定のままでうまく処理するようです。しかしここで問題があり、上位16ビットと下位16ビットが入れ替わって送受信されてしまいます。STM32のコミュニティで質問されていましたが、修正するには自分でビットを入れ替えるコードを書くしかないようです。

単純に元の数を左シフトしたものと右シフトしたものを合わせればいいのですが、負の数を右シフトすると左側が1で埋まるので、0で置き換えるようにします。
int32_t swap16(int32_t x)
{
return (0x0000FFFF & x >> 16) | x << 16;
}

符号なし整数へ型変換してから右シフトする方法もあります。処理速度は上記と変わりませんでした。
int32_t swap16(int32_t x)
{
return (int32_t)((uint32_t) x >> 16) | x << 16;
}



その他の変更部分については下記の通りです。

・STM32CubeMX設定
 Multimedia→I2S2→Configuration→Parameter Settings
 →Data and Frame Format [32 Bits Data on 32 Bits Frame]

・送受信バッファを32ビット整数へ
 volatile int32_t RX_BUFFER[BLOCK_SIZE*2] = {}; // 受信バッファ
 volatile int32_t TX_BUFFER[BLOCK_SIZE*2] = {}; // 送信バッファ

・float変換時の乗除算に使う数を変更(32ビット符号付き整数の範囲は-2147483648~+2147483647)
 32768.0f→2147483648.0f



Owm Pedalに正弦波を入力し、実際のデータで確認しました。DMAで受信したデータはバラバラの値ですが、上下16ビットを入れ替えると正しいデータになることがわかります。
03s_240_1o32.png

GitHubのmain.cファイルも変更しています。オーディオコーデックV4220Mでは上位24ビット分のみ有効なので、下位8ビット分は0として取り扱われますが特に支障はないでしょう。

タグ : マイコン 

HAL_I2SEx_TransmitReceive_DMA使用時の割り込み修正

Owm Pedal ソフトウェア編で書いていた通り、「HAL_I2SEx_TransmitReceive_DMA」使用時に「HAL_I2SEx_TxRxCpltCallback」が起こらないというバグがあります。STM32のコミュニティで質問されていましたがその後のバージョンでも修正されていないので、自力で修正することにします。



プロジェクトフォルダ内のファイルDrivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2s_ex.cを編集します。「I2SEx_TxRxDMACplt」関数がDMA転送完了時に呼び出されるようになっています。この関数を見ると、「if (hdma->Init.Mode == DMA_NORMAL)」以下のカッコ内に「/* Call user TxRx complete callback */」以下の記述が入っているため、DMAサーキュラーモードでは何も起きないことがわかります。なのでこの記述をカッコ外に移動すれば解決するはずです。(同フォルダ内にあるstm32f4xx_hal_i2s.cの「I2S_DMATxCplt」関数を見ると正しいコードがわかります。)

細かい修正をすると間違えそうなので、私は単純にHAL_I2SEx_TxRxCpltCallback関数を追加記載することにしました。
static void I2SEx_TxRxDMACplt(DMA_HandleTypeDef *hdma)
{
I2S_HandleTypeDef *hi2s = (I2S_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;

HAL_I2SEx_TxRxCpltCallback(hi2s); // ←追加!CubeMXでコード出力すると元に戻るので注意

/* if DMA is configured in DMA_NORMAL mode */
if (hdma->Init.Mode == DMA_NORMAL)
{
if (hi2s->hdmarx == hdma)
{
/* 中略 */
}

if (hi2s->hdmatx == hdma)
{
/* 中略 */
}
}
}

<データ処理方法変更>
1つのブロックにつき「HAL_I2SEx_TxRxHalfCpltCallback」と「HAL_I2SEx_TxRxCpltCallback」の2回割り込みが使えるようになったので、Owm Pedalの信号処理を下図のように変更しました。GitHubのmain.cファイルも変更しています。
03s_239_1owmI2S.png
最初の割り込みでグループA前半の信号処理と送信バッファへの代入を開始し、次の割り込みでグループA後半を処理開始します。処理後のグループA(A')を送信するときには送信バッファへの代入が余裕をもって終わっていると考えられるので、安定した動作が見込めます。ただし、実質的にブロックサイズ半分で処理しているという点には注意が必要です。

タグ : マイコン 

管理人

管理人

自己紹介のページ
記事一覧
Twitter
GitHub

ブログ内検索
カテゴリー
タグ

自作エフェクター   レイアウト   回路図   歪み   PureData   周波数特性   波形・倍音   マイコン   RaspberryPi   エレキギター   アンプ   エフェクター自作方法   歪率   エレキベース   真空管   コーラス   ピックアップ   静音ギター   ヘッドフォンアンプ   擬似ギター出力   市販エフェクター   アコースティックギター   ブースター   コンデンサ   ソロギター   ポールピース   イコライザー   コンプレッサー   ビブラート   フェイザー   トレモロ   TAB譜   ディレイ   DIY_Layout_Creator   ワウ   オートワウ   バッファー   

最近の記事
最新コメント
Twitter
RSS
メールフォーム
当ブログに関するお問い合わせはこちらからお願いします。 ※FAQ(よくある質問)もお読みください。

お名前
メールアドレス
件名
本文

アクセスカウンター