HAGIWO 2OSC VCO と SYNC LFO を作る
概要
次のHAGIWO作品を作ることにした。2OSC VCO は前に作った Triple VCO の並びで揃えるため、SYNC LFO はシンセ用ソフト作りの勉強のためだ。
2OSC VCO はMozzi を使っている。自分では単音なら鳴らせても、VCO はとても手が出ない。したがって、フルコピーだ。
SYNC LFO はハード構成がマイコンと入出力のみというシンプルな構成なので、ソフトに注目できることも作りたくなった理由である。
- No.18 2OSC VCO:Mozziを使ったノコギリ波、方形波、三角波、サイン波、ノイズ 2オシレータ。
- No.12 Clock SYNC LFO:Fast PWMを使って疑似的にDA変換によってLFO波形を作る。
マイコンには素のAtmega328Pを使う。Nano に比べてアナログポートが2つ少なく6ポートだが、上記2作例では、それぞれ5ポートと4ポート使いなので問題ない。素のAtmega328P に16MHz のクリスタル発振器を外付けすれば、Arduino Uno と同等になる。
本文
モジュラーシンセを自作するにあたって、どんな機能が必要で、その仕様をどうすべきかということが全く分からない。まして、音楽面の知識も経験もないので、電気信号と音の関係は皆無である。
そういったことから、ハードもソフトもHAGIWOサイト情報の丸写しなので、ここで特記することはない。基板に組む前にブレッドボードに組んでソフトを走らせて、波形を見たり音を聴いたりするくらいのことしかやっていない。場合によっては、そのときプラスαを盛り込むこともあるが、今回はそういったこともない。
パネルサイズを4HPで作ったことしかオリジナルなものはない。
いつも通りFusion360でパネルや部品/基板レイアウト設計を行った。
2OSC VCO
スケッチから読み取れる2OSC VCOの内容
このコードは、Mozziライブラリを使用して、さまざまな波形を生成するArduinoプログラムです。複数のオシレーターを使用し、外部入力とアナログ読み取りに基づいて音声出力を生成します。以下に、このコードのインターフェースと動作を説明します。
インターフェース
ピン定義
- デジタルピン:
- 2, 3: OCTスイッチ入力用ピン
- アナログピン:
- A0: OSC1の基本周波数設定
- A1: OSC2の基本周波数設定
- A3: 波形選択用ノブ
- A4: 出力ゲイン設定用ノブ
- A5: V/OCT入力
オシレーター
- 鋸波(SAW)、矩形波(SQUARE)、三角波(TRIANGLE)、正弦波(SIN)、ホワイトノイズ(NOISE)の各オシレーターを定義
変数
freq1
,freq2
: OSC1およびOSC2の基本周波数voct
: 外部V/OCT入力値freqv1
,freqv2
: V/OCT適用後のOSC1およびOSC2の周波数octsw
: オクターブスイッチの状態(-1オクターブ、0オクターブ、+1オクターブ)wave_knob
: 波形選択用ノブのアナログ値wave
: 波形モード(0: SAW, 1: SQUARE, 2: TRIANGLE, 3: SIN, 4: NOISE)gain
: 出力ゲインvoctpow
: V/OCTの指数テーブルgain_table
: ゲインテーブル動作
セットアップ
- ピンモードを設定し、Mozziの初期化を行う
コントロール更新 (
updateControl
)
- 波形選択ノブの値に基づいて波形モードを設定
- 出力ゲイン設定ノブの値に基づいてゲインを設定
- OCTスイッチの状態に基づいてオクターブスイッチを設定
- OSC1およびOSC2の基本周波数を設定
- V/OCT入力を読み取り、適用
- 選択された波形モードに基づいてOSC1およびOSC2の周波数を設定
オーディオ更新 (
updateAudio
)
- 現在の波形モードに基づいて、OSC1およびOSC2の音声出力を合成し、ゲインテーブルを適用して出力
メインループ (
loop
)
- Mozziのオーディオフックを呼び出してオーディオを更新
各関数の説明
setup()
- Arduinoの初期設定を行い、Mozziのオーディオ出力を開始する
updateControl()
- 波形選択、ゲイン設定、オクターブスイッチの状態、OSCの周波数設定、V/OCTの適用を行う
updateAudio()
- 選択された波形モードに基づいてOSC1およびOSC2の音声出力を合成し、ゲインテーブルを適用して出力する
loop()
- Mozziのオーディオフックを呼び出してオーディオを更新する
このコードは、Mozziライブラリを使用して、OSC1およびOSC2の周波数と波形を制御し、指定された設定に基づいてオーディオ出力を生成します。ユーザーはアナログ入力を使用して、波形モード、ゲイン、オクターブスイッチ、および周波数を調整できます。
ハード構成
- マイコン :Atmega328p + 16MHz セラロック
- オペアンプ:LMC6482(CMOS レール ツー レール フルスイング , 16V)Aliexpress品
SYNC LFO
![]()
このコードは、FlexiTimer2ライブラリを使用してPWM信号を生成し、外部クロック入力を監視しながら様々な波形を出力します。
インターフェース
ピン定義
PWMPin
(10): PWM出力ピンCheckPin
(13,PIN_CHECK
が1の場合): デバッグ用の出力ピン- アナログ入力ピン
- A0: 振幅設定用
- A1: 内部クロック/フェーズ設定用
- A3: 波形モード設定用
- A5: モジュレーション設定用
変数
duty
: PWMのデューティ比(0.0~1.0)count
: 波形テーブルのカウントwave
: 波形モード選択set_freq
: 周波数設定freq_max
: 最大周波数amp
: 振幅amp_rate
: 振幅比率phase
: 位相mod
: モジュレーションモードext_injudge
: 外部クロック使用判定ext_pulse
: 外部クロック入力old_ext_pulse
: 前回の外部クロック入力ext_count
,ext_count_result
,old_ext_count_result
: 外部クロックカウントext_period
: 外部クロック周期reset_count
: リセットカウント動作
セットアップ
- PWM出力ピンと入力ピンのモードを設定
- タイマー2を50µsごとに割り込みをかけるように設定
- PWMの10ビット高速モードを設定
メインループ
- 外部クロック入力を監視し、前回の状態と比較
- 各種設定関数を呼び出して波形、フェーズ、モジュレーション、振幅、外部入力の判定、クロック設定を行う
- PWMの設定を更新
割り込み処理
- 50µsごとに呼び出される
- 外部クロックカウントをインクリメント
- 周波数設定カウントをインクリメント
- チェックピンのトグル(
PIN_CHECK
が1の場合)- 周波数設定カウントが最大周波数を超えた場合、カウントをリセットし、波形テーブルからデューティ比を取得してPWMを更新
各関数の説明
selectWaveMode()
- A3ピンのアナログ値に基づいて波形モードを選択
setPhaseAndClock()
- 内部クロック使用時と外部クロック使用時でフェーズと最大周波数を設定
selectModulation()
- A5ピンのアナログ値に基づいてモジュレーションモードを選択し、対応する波形テーブルを使用してフェーズを更新
setAmplitude()
- A0ピンのアナログ値に基づいて振幅を設定
judgeExternalInput()
- 外部クロック信号が8秒間無い場合は内部クロックを使用するように設定
setClock()
- 外部クロック信号が変化した場合、クロックカウントをリセットし、周期を計算して最大周波数を設定
timer_count()
- 50µsごとに呼び出され、外部クロックカウントと周波数設定カウントをインクリメント
- 周波数設定カウントが最大周波数を超えた場合、カウントをリセットし、波形テーブルからデューティ比を取得してPWMを更新
PWMが8bitで出力しているようなので、10bit出力に変更してみた。
// PWM設定
OCR1A = 1023; // 10-bit max value
OCR1B = (unsigned int)(1023 * duty * amp_rate);
ハード構成
- マイコン :Atmega328p + 16MHz セラロック
実験波形
サイン波形とRamdam波形を出してみた事例。
まとめ
Mozziについては、プログラミングの手順は理解したが、自分で波形を作るまでは習得できていない。
以前、Fast PWMを使ったことがあるが、DA変換をすることを今回経験した。