Teensy 4.1にPCM1802で音声入力→PCM5102A差動出力
前回は、PCM5102Aを用いた音声の出力方法を紹介しましたが、今回はその応用として、PCM1802で音声を入力し、2つのPCM5102Aを組み合わせてステレオの差動(バランス)出力をする方法を解説します。
PCM1802で音声入力
PCM1802は最大24bit/96kHzでステレオのオーディオデータを取り込めるADCです。
TeensyではオーディオライブラリにあるAudioInputI2S
を使って音声を取り込むことができます。
PCM1802のデータシート より
※PCM1802をI2Sモードで使用するにはFMT1をLOW、FMT0をHIGHにする必要があります。
使用したボードと注意点
ADCの動作確認をするためにAliExpressでPCM1802を搭載したボードを購入しました。
以下のページで解説されていますが、FMT0のパッドと3.3Vを配線して接続する必要があります。
PCM1802を配線
PCM1802とTeensy 4.1を接続します。
Teensy 4.1のピン配置図を参考に各ピンを接続してください。
PCM1802 | Teensy 4.1 | Teensy側ピン番号 |
---|---|---|
SCK | MCLK1 | 23 |
POW | 3.3V | 3V |
LRCK | LRCLK1 | 20 |
FSY | 3.3V | 3V |
BCK | BCLK1 | 21 |
DOUT | IN1 | 8 |
GND | GND | G |
3.3V | 3.3V | 3V |
+5V | 5V | 5V |
PCM5102Aを2つ使って差動出力
PCM5102Aはシングルエンド出力、このまま音声端子に接続する場合アンバランス接続となるため、ノイズなどの影響を受けやすくなります。
1つのPCM5102Aを左チャンネル用、もう1つを右チャンネル用として、それぞれで通常の信号と位相を反転させた信号を送ることでノイズを除去することが可能です。
※参考:PCM5102を調べてみよう!の巻き。
今回はソフトウェア側で非反転のデータと反転させたデータを用意してDACに送信します。
使用したボードと注意点
Youmile PCM5102 DAC GY-PCM5102
AmazonにあるPCM5102Aボードを使用しました。
このボードを使用する際、以下のようにパッドがはんだ付けされていない場合は、同じようにはんだ付けしてください。
PCM5102Aを配線
差動構成のため、今回はAudioOutputI2SQuad
を使用します。
2つのPCM5102AとPCM1802は共通のBCLK、LRCKピンを使います。
以下のようにTeensy 4.1と接続します。
Lチャンネル用
Teensy 4.1 | Teensy側ピン番号 | PCM5102A |
---|---|---|
GND | G | SCK |
BCLK | 21 | BCK |
TX (ch 1+2) | 7 | DIN |
LRCLK | 20 | LCK |
GND | G | GND |
3.3V | 3V | VIN |
Rチャンネル用
Teensy 4.1 | Teensy側ピン番号 | PCM5102A |
---|---|---|
GND | G | SCK |
BCLK | 21 | BCK |
TX (ch 3+4) | 32 | DIN |
LRCLK | 20 | LCK |
GND | G | GND |
3.3V | 3V | VIN |
コード
PCM1802→Teensy4.1→PCM5102A差動 となるようにコードを書いていきます。
プログラムを図で表すと以下のようになります。
Input→RecordQueue→反転処理→PlayQueue→Output
プログラム全体
#include <Arduino.h>
#include <Audio.h>
// --------------
// Audio Object
// --------------
// I2S 入力 -> RecordQueue(Left, Right)
AudioInputI2S i2s; // BCLK=21, MCLK=23, LRCLK=20, RX=8
AudioRecordQueue rec_L; // L
AudioRecordQueue rec_R; // R
// I2SQuad 出力 (4ch: L+, L-, R+, R-)
AudioOutputI2SQuad i2s_quad;
AudioPlayQueue queue_L; // L+
AudioPlayQueue queue_LM; // L- (L の符号反転)
AudioPlayQueue queue_R; // R+
AudioPlayQueue queue_RM; // R- (R の符号反転)
// --------------
// Audio Connection
// --------------
// I2S 入力 -> RecordQueue(Left, Right)
AudioConnection patchCord1(i2s, 0, rec_L, 0);
AudioConnection patchCord2(i2s, 1, rec_R, 0);
// PlayQueue -> I2SQuad 出力 (チャネル順: 0=L+, 1=L-, 2=R+, 3=R-)
AudioConnection patchCord3(queue_L, 0, i2s_quad, 0);
AudioConnection patchCord4(queue_LM, 0, i2s_quad, 1);
AudioConnection patchCord5(queue_R, 0, i2s_quad, 2);
AudioConnection patchCord6(queue_RM, 0, i2s_quad, 3);
// --------------
// Audio Buffer
// --------------
// 1ブロック(=128サンプル)単位で作業するための配列
static const int BLOCK_SIZE = AUDIO_BLOCK_SAMPLES; // 通常128
int16_t samples_L [BLOCK_SIZE];
int16_t samples_LM[BLOCK_SIZE];
int16_t samples_R [BLOCK_SIZE];
int16_t samples_RM[BLOCK_SIZE];
inline int16_t negation(int16_t value) {
return (value == INT16_MIN) ? INT16_MAX : -value;
}
void setup() {
// Audio処理用メモリの割り当て (必要な量を確保 100は適当)
AudioMemory(100);
// RecordQueue を開始 (オーディオ入力の取り込みスタート)
rec_L.begin();
rec_R.begin();
}
void loop() {
// L, R それぞれのキューにオーディオデータが溜まっているか確認
if ((rec_L.available() > 0) && (rec_R.available() > 0)) {
// それぞれ1ブロック(128サンプル)を取り出す
int16_t *blockL = rec_L.readBuffer();
int16_t *blockR = rec_R.readBuffer();
if (blockL != nullptr && blockR != nullptr) {
// blockL, blockR に各128サンプルの音声データがある
// 符号反転 (L-, R-) や必要な処理を行い、別バッファへコピー
for (int i = 0; i < BLOCK_SIZE; i++) {
samples_L [i] = blockL[i]; // L+
samples_LM[i] = negation(blockL[i]); // L- (反転)
samples_R [i] = blockR[i]; // R+
samples_RM[i] = negation(blockR[i]); // R- (反転)
}
// PlayQueue へ書き込み → Quad 出力へ
queue_L.play(samples_L, BLOCK_SIZE);
queue_LM.play(samples_LM, BLOCK_SIZE);
queue_R.play(samples_R, BLOCK_SIZE);
queue_RM.play(samples_RM, BLOCK_SIZE);
}
// 使い終わったらバッファを解放 (重要)
rec_L.freeBuffer();
rec_R.freeBuffer();
}
}
実行してみる
シンプルな三角波を入力してみました。
KORGのオシロスコープで確認すると、正しくバランス出力ができていることが確認できます。
右チャンネルの出力 非反転の位相と反転の位相になっている
音楽をPCM1802に入力してPCM5102Aから出力したものを録音してみました。
16bit/44.1kHzですが、割と良い音に聞こえます。
Discussion