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