|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.