復元・復旧サービス充実|(有)フロンティア・オンライン

復元・復旧サービス充実|(有)フロンティア・オンライン

【深淵オーディオ】(13)Core'4 Timeline Dynamics Processor:ProAudio仕様PopoDAC(USB DAC) 自作(DIY)

‹ 2026/01/09 ›

こんにちは。激寒いです・・・。


皆さん、お待たせしました!

大待望Core’4 TDP相(Timeline Dynamics Processor、旧称I2S相)の回がやってきましたよ♪^^

本丸中の本丸、頂上の回です。


ここまで理解を深めてきたあなた、なんだか分からないままついて来てしまったあなた、たまたま立ち寄ってしまったあなた、この回ではPopoDACの驚愕する実力を知ることになります。

(えぇ、えぇ、棒〇MEクラス程に達してます)


TDP相

では早速、TDP相の概要説明。

旧称の通り、TDPはI2S出力そのものを担う相になります。


そして、TDP相は単なるバケツリレー出力は行いません。

出力方式はASRC(Adaptive SampleRate Conversion)を伴う粒子スラスター、粒度はフレーム量子精度となります。


「ちょっと何言っちゃってんの?」

・・・という方のほうが圧倒的に多いかも知れません。汗


概念図を用意しました。^^



図の通り、TDPの役割はUAC~I2Sへ至る伝送行程のうち、CCC管理下でMASTER RINGからI2Sへ転送する機能部の実現となります。


で、そこには'D.J. Popo'がいます。汗


そうなんです、極論で申し上げますと、PopoDAC TDPの仕事人は「量子を扱うD.J. Popo」と言えます。

これによってDDCは、単純なパケット転送者から音のひと粒(量子)を繊細に転送、再配置する’音の操者’へと昇格します。


「具体的にどういうこと?」

--- デジタル音源をPopoDAC MTL(時間軸)内で量子サンプル毎に扱うとどうなるのか?


時流の中で進むサンプル量子単位の再配置は、その音の量子の長さ、速さ、解像度に影響を及ぼしながら時を歩みます。

そして、TDR相(UAC相)から送られてきたパケット(量子を含むバケツ)には、音の量子だけでなく、音の反射音の量子、背景音の量子、可聴領域外の量子も含まれています。


これらひと粒ひと粒を丁寧に適切に操るということは、時間軸への正しい再配置という機能だけでなく、楽曲の定位の再構築、音像の再構築、空間の再構築や見えない領域のエネルギの最適化さえできうることを意味しています。


(これにはDolby Atmosがその名で示すようなことさえも含まれます・・・)


「どうでしょう?」

DIYでESP32-S3でできること、PopoDACがやろうとしていることにようやく光が射してきましたね。^^


モジュール構成

TDP相は3モジュールで構成されます。


Module 6: Velocity Vector Stabilizer(速度ベクトル安定化)

Module 7: Timeline Interpolation(時間軸補間)

Module 8: Timeline Thruster(時間軸スラスター出力)


扱うのはどこまでも時間との関係性、目の前に現れたPCMデータそのものを単純に直視しないことが重要になります。


Module 6: VVS(Velocity Vector Stabilizer)

VVSは、GNC相TLAで得られた実効fSと速度ベクトルから、量子をそれぞれどういう配置構成でスラスター出力に伝達すればよいのか、その最適値を算出します。

PopoDACの音質、立体空間像の決め手となるのが、GNC相TLAの対となるVVSとなります。


Module 7: TLI(Timeline Interpolation)

TLIは、バケツで受け取ったデータを実際の探査機噴射同様にスラスター化する機能を提供します。

つまりVVSで決定された配置に量子を実際に再配置することが主な役割になります。


そして、名前のとおりTLIにはもう一つ大きな仕事も同時に進めてもらわなくてはいけません。

それは「補間」です。


GNC相の調整によって、UAC相(バケツ軸、SOF軸)とMTL軸に大きなズレのある瞬間があれば、補間も大きく作用します。

もちろん双方の時間軸にズレが少ない場合、TLIの補間は少なくて済みます。


VVSによって理想的な再配置場所が決定された結果、量子と量子の間には僅かな隙間ができることもあります。

或いはUAC由来の抑えきれないジッタもそうです。


この隙間空間にも適切な量子を埋め込みませんと、空間(時)に穴があき、より大粒の量子ノイズが発生します。


量子ノイズとは?

量子ノイズは時に穴があいたようなノイズ(或いは量子レベルの誤差ノイズ)には間違いありませんが、ジッタでできるクリックノイズとは聴感性特徴がまったく異なります。


例えば、クリックノイズ音は、バリッとかブツッとか時間そのものが途切れた音がします。

そして時に穴があくほどですので、その穴をどれだけ小さくしても聴感性に強い悪影響を及ぼし続けます。


対して量子ノイズは実際には時間軸の中のひと粒の誤差ですので、実は時間そのものには穴があきません。

楽曲の中で実際にはこう聞こえます。


「チリ、チリーと、決して時を遮らず、非常に小さく時空間を舞う微塵音」


楽曲の時の中、とあるときに時の流れに乗った埃のようなものが舞うことがあります。

とても小さな埃なので、楽曲或いは時の空間に乗って漂うように聞こえます。


従って、時に割って入るクリックノイズとは異なり、聴感に対しての悪影響は極小さいか、微細であれば感じる必要性もないようなものとなります。

(※量子ノイズはASRC補間の自然な副産物であり、正しく制御されていれば“音場の空気感”として知覚されるレベルに収まります。)

Module 8: TLT(Timeline Thruster)

TLTの仕事は至ってシンプルです。

TLIで出来上がった'スラスター化燃料'を実際の射出部I2S DMAにセットするだけになります。


「おお、いよいよ噴射ですね!」

はい、そうです。

シンプルな仕事ですが、TLTには実はPopoDACで最も重要かつ最終の役割もあります。


以前より「PopoDAC DDCでは一切ロックをしない」と断言し続けてきました。

しかしそれは、半分当たりで半分ウソです。


TLTの最後のひと仕事・・・、それは「PopoDAC DDC唯一のロックをTLTで必ず行う」です。


「ひぇ~、ロックすんのかい!」

はい、汗


PopoDAC CCC自転車図をもう一度見てみます。

GNCが作り出す真の時間軸’MTL’は、既にUACホストからDDCまでの同調に成功しています。

この同調をI2Sを通しリスナーまで同調するために、たった一つのギアが必要になります。


そのギア(ロック)を担うのがI2S DMAとなります。

つまりTLTでは、スラスター化燃料投入の際、このI2S DMAの歯車にガッチリ嵌め込む必要があります。

ここがPopoDAC唯一のロック、そしてこれは全身同調に繋がります。


実装例

では、実際の実装に入りましょう。


発動部

TDP相はFreeOSタスクで発動しますので、メインループでシンプルに発動を促します。


void app_main(void)

{

...

    // I2S Write タスク開始

    ret_val = xTaskCreatePinnedToCore(i2s_write_task, "ForI2sWrite", TASK_I2S_WRITE_STACKSIZE, NULL, TASK_I2S_WRITE_PRIORITY, NULL, TASK_I2S_WRITE_CORE);

    ESP_LOGI(TAG, "%s to create %s", ret_val == pdPASS?"Succeeded":"Failed", "i2s_write_task");

...

}


なんどか紹介されてきましたし、なんてことはありません。


重要な点は、TDR相、GNC相、TDP相はリアルタイム性においてそれぞれ均衡的に重要ですので、変に突出したプライオリティでなければ問題ありません。

同時に3層特にTDR相とは対極位置、かつ双方に相当の処理負担がありますので、コア分けを整理するくらいでしょう。


実働部

ここはGNC同様、モジュール順に整然と並べれば良いだけです。


void IRAM_ATTR i2s_write_task(void *param)

{

    static TU_ATTR_ALIGNED(32) DRAM_ATTR uint8_t local_buf[TRANSFER_BUFFER_SIZE * (TRANSFER_BUFFER_COUNT/2) ] = {0};

    TickType_t xLastWakeTime = xTaskGetTickCount();

    static size_t written = 0;

    static size_t got = 0;

    static int16_t i2s_size;


    i2s_size = g_ddc.uac_quality.frame_size>>I2S_BUFFER_STROKESIZE;


    while (1) {


        if (!g_ddc.uac_alt1_active) {

            vTaskDelayUntil(&xLastWakeTime, 1);

            continue;

        }


        // ---- I2S preroll ----

        if (g_ddc.i2s_starting) {

            if (!i2s_preroll_done(i2s_size)) {

                continue;

            }

            g_ddc.i2s_starting    = false;

            g_ddc.i2s_src_inited  = true;

            continue;

        }


        // ---- 渇水評価----

        got = rb_available(&g_audio_ring);

        if (got < i2s_size) {

            g_ddc.ddc_ring_looses = g_ddc.ddc_ring_looses>=99?0:g_ddc.ddc_ring_looses+ 1;

        }


#if DDC_LOG == 1

        usb_packet_log_lastjoint(got);

#endif


        // ---- VVS ----

        g_ddc.i2s_src_phase_ratio = g_data_functions.pSRC_update_ratio(&g_ddc, g_cnt_ideal.delta_fb_q, g_cnt_ideal.source_clock_ratio);


        // ---- TLI ----

        g_data_functions.pASRC_interpolate_ring(&g_audio_ring, local_buf, i2s_size, &g_ddc);


        // ---- 音量 ----

        if (g_ddc.uac_alt1_volume < 0) {

            g_data_functions.padjustVolume(

                local_buf, i2s_size,

                VOLUME_SCALE(g_ddc.uac_alt1_volume, vol_range.min)

            );

        }


        // ---- TLT ----

        i2s_channel_write(tx_handle, g_ddc.uac_alt1_muted ? g_silence : local_buf, i2s_size, &written, portMAX_DELAY);        

        g_ddc.ddc_tx_size = got;

    }

}


並びは説明のないものも踏まえ、実際には'(preroll) -> (渇水監視) -> VVS -> TLI -> (音量) -> TLT'となっています。


そして、上流バッファはMASTER RING上にありますので、単純な’Bytes to Bytes’にはなっていないのが分かります。


バイトバッファとして唯一存在する'local_buf'は、量子スラスター化した燃料を格納するバケツとなります。

I2S DMAへはスラスター化燃料をバケツで引き渡す必要があるからです。

(preroll) 

プレロールは、ALT1開時のアイドル無音助走を担当します。

'ordinary USBDAC'ですと、これはI2S有効化前のaudio sof内で行う事例を見たこともあるでしょう。


しかし、PopoDAC DCCのMTL唯一の同期先はI2S DMAになりますので、アイドリングもここで実施します。


(渇水監視)

監視はなくても良いものです。

目的は、デバッグ、操作パネルの視覚性向上のために尽きます。


(音量)

音量操作は、存外USBDACの利便性に寄与します。

ホストのボリューム操作に追従させたい場合、ここで行います。


TLT:i2s_channel_write

ここが唯一のロック場所となります。

’portMAX_DELAY’のみが正解の一手となります。


また、PopoDACではミュートへの対応もここで行っています。

(ホストのミュート操作で、UAC伝送パケットの中身を無音にしてくることはありません、あくまで対応はデバイス側に委ねられています)


結論

PopoDAC TDP相で行っていること。


VVS:量子の配置(速度ベクトル)を決める

TLI:量子を再配置し、必要に応じて補間する

TLT:I2S DMA に噴射(唯一のロック)


さあ、ここでPopoDAC CCCが管理の下で行う全ミッションの説明を終えました。


「いかがでしたでしょうか?」


次回は、完成されたPopoDACはどんな仕様・性能で現れるのか!?

実写・実例を踏まえて紹介いたします。


お楽しみに♪