Annotation of nono/vm/sound.h, revision 1.1.1.2

1.1       root        1: //
                      2: // nono
                      3: // Copyright (C) 2025 nono project
                      4: // Licensed under nono-license.txt
                      5: //
                      6: 
                      7: //
                      8: // サウンドレンダラ
                      9: //
                     10: 
                     11: #pragma once
                     12: 
                     13: #include "thread.h"
                     14: #include "fixedqueue.h"
                     15: #include <array>
                     16: #include <condition_variable>
                     17: #include <mutex>
                     18: 
1.1.1.2 ! root       19: class BitmapRGBX;
1.1       root       20: class Syncer;
                     21: class HostSoundDevice;
                     22: 
                     23: // 定数。
                     24: class Sound
                     25: {
                     26:  public:
                     27:        // (1フレームの)チャンネル数 (デバイスと SoundRenderer の間はステレオ固定)。
                     28:        static constexpr int NCHAN = 2;
                     29: 
                     30:        // 1フレームのバイト数。
                     31:        static constexpr size_t FRAME_BYTES = NCHAN * sizeof(int16);
                     32: 
                     33:        // 1ブロックの時間。
                     34:        // ADPCM の制約からこれ以上小さくは出来ない(し大きくする必要もない)。
1.1.1.2 ! root       35:        static constexpr uint64 BLK_TSEC = 40_msec;
1.1       root       36: 
                     37:        // サウンドソースのブロック数。
                     38:        // ダブルバッファ方式なので 2。
                     39:        static constexpr uint NSRCBLKS = 2;
                     40: 
                     41:        // 合成バッファのブロック数。
                     42:        // 1ブロック境界ごとに逐次処理するので 1。
                     43:        static constexpr uint NMIXBLKS = 1;
                     44: 
                     45:        // 出力バッファのブロック数。
                     46:        // 最低 3 ブロック必要だが、2 のべき乗だとお得。
                     47:        static constexpr uint NOUTBLKS = 4;
                     48: };
                     49: 
                     50: enum SoundStat {
                     51:        Stopped,        // デバイスは再生をしていない
                     52:        Drained,
                     53:        Running,        // デバイスは再生中
                     54:        Draining,       // デバイスはこのブロック処理後に再生を停止
                     55: };
                     56: 
                     57: // サウンドの 1 トラック (ソースデバイス) 分。
                     58: class SoundTrack : private Sound
                     59: {
                     60:  public:
                     61:        SoundTrack(Device *dev_, size_t frames_per_blk_);
                     62: 
                     63:        int16 *GetBlockBySeq(uint64 vseq);
                     64:        int16 *GetBlockByIdx(uint32 idx);
                     65:        int16 *AllocSeq(uint64 vseq);
                     66:        void ClearSeq(uint64 vseq);
                     67: 
                     68:        // ソースデバイスを返す。
                     69:        Device *GetDevice() const noexcept { return dev; }
                     70: 
                     71:        // ソースデバイス名を返す。
                     72:        const std::string& GetName() const { return dev->GetName(); }
                     73: 
                     74:        // 再生状態
                     75:        SoundStat status {};
                     76: 
                     77:        // レベル(L,R)。
                     78:        std::array<double, NCHAN> dbfs {};
                     79: 
                     80:  private:
                     81:        Device *dev {};
                     82: 
                     83:        // NBLKS 分のバッファ。
                     84:        std::unique_ptr<int16[]> buf {};
                     85: 
                     86:        // buf の各ブロックが有効ならそのシーケンス。-1 なら未使用。
                     87:        std::array<uint64, NSRCBLKS> blkseq {};
                     88: 
                     89:        // 1ブロックのサンプル数。
                     90:        size_t samples_per_blk {};
                     91: };
                     92: 
                     93: // サウンドレンダラ
                     94: class SoundRenderer : public ThreadDevice, private Sound
                     95: {
                     96:        using inherited = ThreadDevice;
                     97: 
                     98:  private:
                     99:        // ソースデバイスの最大数。2 のべき乗であること。
                    100:        static constexpr uint32 MAX_SOUND_SOURCES       = 4;
                    101: 
                    102:        static constexpr uint32 REQ_TERMINATE   = 0x80000000;
                    103:        static constexpr uint32 REQ_RECONFIG    = 0x00000001;
                    104: 
1.1.1.2 ! root      105:        static constexpr int METER_LEN = 20;    // メータ部分の文字数
        !           106:        static constexpr int METER_DIV = 3;             // 1文字あたりの dbFS
        !           107: 
1.1       root      108:  public:
                    109:        SoundRenderer();
                    110:        ~SoundRenderer() override;
                    111: 
                    112:        bool Create() override;
                    113:        void SetLogLevel(int loglevel_) override;
                    114:        bool Init() override;
                    115:        void ResetHard(bool poweron) override;
                    116: 
                    117:        SoundTrack *RegistTrack(Device *);
                    118:        void StartPlay(SoundTrack *);
                    119:        void StopPlay(SoundTrack *);
                    120: 
                    121:        uint GetMixerFreq() const noexcept { return mixerfreq; }
                    122:        uint GetOutFrequency() const noexcept { return outfreq; }
                    123:        uint GetOutBytesPerBlk() const noexcept;
                    124: 
                    125:        static void ClearDBFS(std::array<double, NCHAN>& dbFS);
                    126: 
                    127:  protected:
                    128:        void ThreadRun() override;
                    129:        void Terminate() override;
                    130:        bool Reconfig(bool startup);
                    131: 
                    132:        void Callback(Event *);
                    133: 
                    134:        void Mix(uint64 vseq);
                    135:        void AddPCM(int16 *dst, const int16 *src);
                    136:        void CalcDBFS(std::array<double, NCHAN>& dbFS, const int16 *src);
                    137: 
1.1.1.2 ! root      138:        DECLARE_MONITOR_SCREEN(MonitorScreen);
        !           139:        DECLARE_MONITOR_BITMAP(MonitorBitmap);
        !           140:        void MonitorScreenLevelMeter(TextScreen&, int x, int y,
1.1       root      141:                const std::array<double, NCHAN> dbfs);
                    142: 
                    143:        // VM スレッドからの通知用。
                    144:        uint32 request {};
                    145:        std::mutex mtx {};
                    146:        std::condition_variable cv {};
                    147: 
                    148:        // VM スレッドからの処理依頼キュー。
                    149:        // キューにする必要ある?
                    150:        FixedQueue<uint64, NSRCBLKS> request_q {};
                    151: 
                    152:        // サウンドトラック(ソース)。
                    153:        std::vector<SoundTrack> tracks {};
                    154: 
                    155:        // サウンドミキサーのサンプリングレート [Hz]。
                    156:        // サウンドトラック(ソース)もこの周波数。機種によって異なる。
                    157:        uint mixerfreq {};
                    158: 
                    159:        // ミキサーバッファ 1ブロックのサンプル数。
                    160:        size_t mixer_samples_per_blk {};
                    161: 
                    162:        // 合成用バッファ。
                    163:        std::unique_ptr<int16[]> mixbuf {};
                    164: 
                    165:        // マスターレベル。
                    166:        std::array<double, NCHAN> master_dbfs {};
                    167: 
                    168:        // 出力サンプリングレート [Hz]
                    169:        uint outfreq {};
                    170: 
                    171:        // 出力バッファ 1ブロックのサンプル数。
                    172:        size_t out_samples_per_blk {};
                    173: 
                    174:        // 出力バッファ。
                    175:        std::unique_ptr<int16[]> outbuf {};
                    176: 
                    177:        // 現在の出力ブロック位置。
                    178:        uint outpos {};
                    179: 
                    180:        // 出力キュー。バッファの先頭だけで扱う。
                    181:        FixedQueue<const uint16 *, NOUTBLKS> output_q {};
                    182: 
                    183:        // 出力サンプリングレート変更指示。
                    184:        uint request_outfreq {};
                    185: 
                    186:        std::unique_ptr<HostSoundDevice> hostsnd /*{}*/;
                    187: 
                    188:        Event *play_event {};
                    189: 
                    190:        Monitor *monitor {};
                    191: 
                    192:        Syncer *syncer {};
                    193: };
                    194: 
1.1.1.2 ! root      195: inline SoundRenderer *GetSoundRenderer() {
1.1       root      196:        return Object::GetObject<SoundRenderer>(OBJ_SOUND_RENDERER);
                    197: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.