|
|
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.