Browse code

Rename SoundView::Refresh to SoundView::Update.

The former is already used by wxDialog but with a different signature.

Naram Qashat authored on 2021/04/10 15:57:44
Showing 1 changed files
... ...
@@ -181,7 +181,13 @@ void SoundView::OnIdle(wxIdleEvent &evt)
181 181
 	evt.RequestMore();
182 182
 }
183 183
 
184
-void SoundView::Refresh()
184
+void SoundView::SyncToConfig()
185
+{
186
+	for (int i = 0; i < 16; ++i)
187
+		this->channelData[i].muteCheckBox->SetValue(this->config->mutes[i]);
188
+}
189
+
190
+void SoundView::Update()
185 191
 {
186 192
 	auto ncsfPlayer = this->player;
187 193
 	std::string buf;
... ...
@@ -270,9 +276,3 @@ void SoundView::Refresh()
270 276
 		chnData.lastState = chn.state;
271 277
 	}
272 278
 }
273
-
274
-void SoundView::SyncToConfig()
275
-{
276
-	for (int i = 0; i < 16; ++i)
277
-		this->channelData[i].muteCheckBox->SetValue(this->config->mutes[i]);
278
-}
Browse code

Replace the Sound View dialog with a wxWidgets-based one.

* Removes the one that was orignally based entirely on the DeSmuME one, while still looking most the same but cleaner.
* To accommodate this, I needed to rework how wxWidgets was initialized so the configuration dialog boxes could also work alongside this.
* Needed to add a custom wxApp to handle the above.
* This also means that the configuration dialog no longer needs the plugin's HINSTANCE passed along.
* Had to not disable wxGauge or wxToogleButton for the Sound View dialog.
* Also remove the now-unneeded enums in the XSFConfig*.cpp files.
* Sound View is still done in a thread so its event loop can run independently from the rest of the plugin.
* XSFConfig_NCSF doesn't need to be the one to start the Sound View dialog now.

Naram Qashat authored on 2021/04/10 15:19:43
Showing 1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,278 @@
1
+/*
2
+ * xSF - Sound View Dialog
3
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
4
+ *
5
+ * Partially based on the vio*sf framework
6
+ *
7
+ * Based on the Sound View dialog box from DeSmuME
8
+ * http://desmume.org/
9
+ */
10
+
11
+#include <string>
12
+#ifdef __GNUC__
13
+# pragma GCC diagnostic push
14
+# pragma GCC diagnostic ignored "-Wold-style-cast"
15
+#elif defined(__clang__)
16
+# pragma clang diagnostic push
17
+# pragma clang diagnostic ignored "-Wold-style-cast"
18
+#endif
19
+#include <wx/button.h>
20
+#include <wx/checkbox.h>
21
+#include <wx/dialog.h>
22
+#include <wx/event.h>
23
+#include <wx/gauge.h>
24
+#include <wx/gbsizer.h>
25
+#include <wx/sizer.h>
26
+#include <wx/stattext.h>
27
+#include <wx/tglbtn.h>
28
+#ifdef __GNUC__
29
+# pragma GCC diagnostic pop
30
+#elif defined(__clang__)
31
+# pragma clang diagnostic pop
32
+#endif
33
+#include "convert.h"
34
+#include "SoundView.h"
35
+#include "SSEQPlayer/common.h"
36
+#include "SSEQPlayer/consts.h"
37
+#include "XSFCommon.h"
38
+#include "XSFConfig_NCSF.h"
39
+#include "XSFPlayer_NCSF.h"
40
+
41
+class wxWindow;
42
+
43
+enum
44
+{
45
+	idVolumeMode = 1,
46
+	idUnmuteAll,
47
+	idChannel00Mute
48
+};
49
+
50
+// Idea comes from https://derekwill.com/2014/06/24/combating-the-lag-of-the-winforms-progressbar/
51
+void SoundView::GaugeSetValueImmediate(wxGauge *gauge, int value)
52
+{
53
+	// This whole thing is to get around the progressive animation of progress bars since Windows Vista
54
+	if (value == gauge->GetRange())
55
+	{
56
+		// When the value equals the maximum, we have to temporarily increase the maximum before setting the value
57
+		gauge->SetRange(value + 1);
58
+		gauge->SetValue(value);
59
+		gauge->SetRange(value);
60
+	}
61
+	else
62
+		gauge->SetValue(value + 1);
63
+	gauge->SetValue(value);
64
+}
65
+
66
+SoundView::SoundView(wxWindow *parent, XSFConfig_NCSF *ncsfConfig, XSFPlayer_NCSF *ncsfPlayer) : wxDialog(parent, wxID_ANY, "Sound View"), config(ncsfConfig), player(ncsfPlayer), channelData(), volumeModeAlternative(false)
67
+{
68
+	auto outerSizer = new wxBoxSizer(wxVERTICAL);
69
+
70
+	auto mainSizer = new wxGridBagSizer;
71
+
72
+	auto volumeModeButton = new wxToggleButton(this, idVolumeMode, "Vol. Mode");
73
+	mainSizer->Add(volumeModeButton, { 0 ,0 }, { 1, 2 }, wxALIGN_LEFT | wxBOTTOM | wxLEFT, 5);
74
+	this->Bind(wxEVT_TOGGLEBUTTON, [&](wxCommandEvent &)
75
+	{
76
+		this->volumeModeAlternative = !this->volumeModeAlternative;
77
+	}, idVolumeMode);
78
+
79
+	auto unmuteAllButton = new wxButton(this, idUnmuteAll, "Unmute All");
80
+	mainSizer->Add(unmuteAllButton, { 0, 5 }, { 1, 1 }, wxALIGN_RIGHT | wxBOTTOM | wxRIGHT, 5);
81
+	this->Bind(wxEVT_BUTTON, [&](wxCommandEvent &)
82
+	{
83
+		for (int i = 0; i < 16; ++i)
84
+			this->channelData[i].muteCheckBox->SetValue(false);
85
+		this->config->mutes.reset();
86
+		this->config->SaveConfig();
87
+		this->player->SetMutes(this->config->mutes);
88
+	}, idUnmuteAll);
89
+
90
+	outerSizer->Add(mainSizer, 1, wxALL | wxEXPAND, 10);
91
+
92
+	for (int i = 0; i < 2; ++i)
93
+	{
94
+		auto volumeLabel = new wxStaticText(this, wxID_ANY, "Volume", wxDefaultPosition, { 150, -1 }, wxALIGN_CENTER_HORIZONTAL | wxBORDER_STATIC);
95
+		mainSizer->Add(volumeLabel, { 1, 7 * i + 1 }, { 1, 2 }, wxALL, 1);
96
+
97
+		auto repeatModeLabel = new wxStaticText(this, wxID_ANY, "Repeat Mode", wxDefaultPosition, { 108, -1 }, wxALIGN_CENTER_HORIZONTAL | wxBORDER_STATIC);
98
+		mainSizer->Add(repeatModeLabel, { 1, 7 * i + 3 }, { 1, 1 }, wxALL, 1);
99
+
100
+		auto stateLabel = new wxStaticText(this, wxID_ANY, "State", wxDefaultPosition, { 90, -1 }, wxALIGN_CENTER_HORIZONTAL | wxBORDER_STATIC);
101
+		mainSizer->Add(stateLabel, { 1, 7 * i + 4 }, { 1, 1 }, wxALL, 1);
102
+
103
+		auto timerValueLabel = new wxStaticText(this, wxID_ANY, "Timer Value", wxDefaultPosition, { 132, -1 }, wxALIGN_CENTER_HORIZONTAL | wxBORDER_STATIC);
104
+		mainSizer->Add(timerValueLabel, { 1, 7 * i + 5 }, { 1, 1 }, wxALL, 1);
105
+
106
+		auto panLabel = new wxStaticText(this, wxID_ANY, "Pan", wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER_HORIZONTAL | wxBORDER_STATIC);
107
+		mainSizer->Add(panLabel, { 2, 7 * i + 1 }, { 1, 2 }, wxALL | wxEXPAND, 1);
108
+
109
+		auto formatLabel = new wxStaticText(this, wxID_ANY, "Format", wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER_HORIZONTAL | wxBORDER_STATIC);
110
+		mainSizer->Add(formatLabel, { 2, 7 * i + 3 }, { 1, 1 }, wxALL | wxEXPAND, 1);
111
+
112
+		auto loopStartLabel = new wxStaticText(this, wxID_ANY, "Loop Start", wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER_HORIZONTAL | wxBORDER_STATIC);
113
+		mainSizer->Add(loopStartLabel, { 2, 7 * i + 4 }, { 1, 1 }, wxALL | wxEXPAND, 1);
114
+
115
+		auto soundPosLenLabel = new wxStaticText(this, wxID_ANY, "Sound Pos / Len", wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER_HORIZONTAL | wxBORDER_STATIC);
116
+		mainSizer->Add(soundPosLenLabel, { 2, 7 * i + 5 }, { 1, 1 }, wxALL | wxEXPAND, 1);
117
+	}
118
+
119
+	for (int i = 0; i < 8; ++i)
120
+		for (int j = 0; j < 2; ++j)
121
+		{
122
+			int channelNum = 8 * j + i;
123
+			auto channelLabel = new wxStaticText(this, wxID_ANY, std::string("#") + (channelNum < 10 ? "0" : "") + std::to_string(channelNum));
124
+			mainSizer->Add(channelLabel, { 2 * i + 3, 7 * j }, { 1, 1 }, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT | wxALL, 1);
125
+
126
+			auto &currentChannelData = this->channelData[channelNum];
127
+
128
+			currentChannelData.volumeGauge = new wxGauge(this, wxID_ANY, 128, wxDefaultPosition, { 102, 18 }, wxGA_SMOOTH);
129
+			mainSizer->Add(currentChannelData.volumeGauge, { 2 * i + 3, 7 * j + 1 }, { 1, 1 }, wxALIGN_CENTER_VERTICAL | wxALL, 1);
130
+
131
+			currentChannelData.volumeLabel = new wxStaticText(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER_HORIZONTAL | wxBORDER_STATIC | wxST_NO_AUTORESIZE);
132
+			mainSizer->Add(currentChannelData.volumeLabel, { 2 * i + 3, 7 * j + 2 }, { 1, 1 }, wxALL | wxEXPAND, 1);
133
+
134
+			currentChannelData.repeatModeLabel = new wxStaticText(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER_HORIZONTAL | wxBORDER_STATIC | wxST_NO_AUTORESIZE);
135
+			mainSizer->Add(currentChannelData.repeatModeLabel, { 2 * i + 3, 7 * j + 3 }, { 1, 1 }, wxALL | wxEXPAND, 1);
136
+
137
+			currentChannelData.stateLabel = new wxStaticText(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER_HORIZONTAL | wxBORDER_STATIC | wxST_NO_AUTORESIZE);
138
+			mainSizer->Add(currentChannelData.stateLabel, { 2 * i + 3, 7 * j + 4 }, { 1, 1 }, wxALL | wxEXPAND, 1);
139
+
140
+			currentChannelData.timerValueLabel = new wxStaticText(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER_HORIZONTAL | wxBORDER_STATIC | wxST_NO_AUTORESIZE);
141
+			mainSizer->Add(currentChannelData.timerValueLabel, { 2 * i + 3, 7 * j + 5 }, { 1, 1 }, wxALL | wxEXPAND, 1);
142
+
143
+			currentChannelData.muteCheckBox = new wxCheckBox(this, idChannel00Mute + channelNum, wxEmptyString);
144
+			mainSizer->Add(currentChannelData.muteCheckBox, { 2 * i + 4, 7 * j }, { 1, 1 }, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT | wxALL, 1);
145
+			this->Bind(wxEVT_CHECKBOX, [this, currentChannelData, channelNum](wxCommandEvent &)
146
+			{
147
+				this->config->mutes[channelNum] = currentChannelData.muteCheckBox->GetValue();
148
+				this->config->SaveConfig();
149
+				this->player->SetMutes(this->config->mutes);
150
+			}, idChannel00Mute + channelNum);
151
+
152
+			currentChannelData.panGauge = new wxGauge(this, wxID_ANY, 128, wxDefaultPosition, { 102, 18 }, wxGA_SMOOTH);
153
+			mainSizer->Add(currentChannelData.panGauge, { 2 * i + 4, 7 * j + 1 }, { 1, 1 }, wxALIGN_CENTER_VERTICAL | wxALL, 1);
154
+
155
+			currentChannelData.panLabel = new wxStaticText(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER_HORIZONTAL | wxBORDER_STATIC | wxST_NO_AUTORESIZE);
156
+			mainSizer->Add(currentChannelData.panLabel, { 2 * i + 4, 7 * j + 2 }, { 1, 1 }, wxALL | wxEXPAND, 1);
157
+
158
+			currentChannelData.formatLabel = new wxStaticText(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER_HORIZONTAL | wxBORDER_STATIC | wxST_NO_AUTORESIZE);
159
+			mainSizer->Add(currentChannelData.formatLabel, { 2 * i + 4, 7 * j + 3 }, { 1, 1 }, wxALL | wxEXPAND, 1);
160
+
161
+			currentChannelData.loopStartLabel = new wxStaticText(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER_HORIZONTAL | wxBORDER_STATIC | wxST_NO_AUTORESIZE);
162
+			mainSizer->Add(currentChannelData.loopStartLabel, { 2 * i + 4, 7 * j + 4 }, { 1, 1 }, wxALL | wxEXPAND, 1);
163
+
164
+			currentChannelData.soundPosLenLabel = new wxStaticText(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER_HORIZONTAL | wxBORDER_STATIC | wxST_NO_AUTORESIZE);
165
+			mainSizer->Add(currentChannelData.soundPosLenLabel, { 2 * i + 4, 7 * j + 5 }, { 1, 1 }, wxALL | wxEXPAND, 1);
166
+		}
167
+
168
+	this->SetSizer(outerSizer);
169
+	this->Layout();
170
+	outerSizer->Fit(this);
171
+
172
+	this->Center();
173
+
174
+	this->SyncToConfig();
175
+	this->Bind(wxEVT_IDLE, &SoundView::OnIdle, this);
176
+}
177
+
178
+void SoundView::OnIdle(wxIdleEvent &evt)
179
+{
180
+	this->Refresh();
181
+	evt.RequestMore();
182
+}
183
+
184
+void SoundView::Refresh()
185
+{
186
+	auto ncsfPlayer = this->player;
187
+	std::string buf;
188
+	for (std::size_t chanId = 0; chanId < 16; ++chanId)
189
+	{
190
+		const auto &chn = ncsfPlayer->GetChannel(chanId);
191
+		auto &chnData = this->channelData[chanId];
192
+
193
+		if (chn.state > ChannelState::Start)
194
+		{
195
+			this->GaugeSetValueImmediate(chnData.panGauge, muldiv7(128, chn.reg.panning));
196
+			std::uint8_t datashift = chn.reg.volumeDiv;
197
+			if (datashift == 3)
198
+				datashift = 4;
199
+			std::int32_t vol = muldiv7(128, chn.reg.volumeMul) >> datashift;
200
+			this->GaugeSetValueImmediate(chnData.volumeGauge, vol);
201
+
202
+			if (this->volumeModeAlternative)
203
+				buf = std::to_string(chn.reg.volumeMul) + "/" + std::to_string(1 << datashift);
204
+			else
205
+				buf = std::to_string(vol);
206
+			chnData.volumeLabel->SetLabel(buf);
207
+
208
+			if (!chn.reg.panning)
209
+				buf = "L";
210
+			else if (chn.reg.panning == 64)
211
+				buf = "C";
212
+			else if (chn.reg.panning == 127)
213
+				buf = "R";
214
+			else if (chn.reg.panning < 64)
215
+				buf = "L" + std::to_string(64 - chn.reg.panning);
216
+			else //if (chn.reg.panning > 64)
217
+				buf = "R" + std::to_string(chn.reg.panning - 64);
218
+			chnData.panLabel->SetLabel(buf);
219
+
220
+			static const std::string modes[] = { "Manual", "Loop Infinite", "One-Shot", "Prohibited" };
221
+			chnData.repeatModeLabel->SetLabel(std::to_string(chn.reg.repeatMode) + " (" + modes[chn.reg.repeatMode] + ")");
222
+
223
+			if (chn.reg.format != 3)
224
+			{
225
+				static const std::string formats[] = { "PCM8", "PCM16", "IMA-ADPCM" };
226
+				chnData.formatLabel->SetLabel(std::to_string(chn.reg.format) + " (" + formats[chn.reg.format] + ")");
227
+			}
228
+			else
229
+			{
230
+				buf = "3 (";
231
+				if (chanId < 8)
232
+					buf += "PSG/Noise?";
233
+				else if (chanId < 14)
234
+					buf += ConvertFuncs::TrimDoubleString(std::to_string(chn.reg.waveDuty == 7 ? 0 : 12.5 * (chn.reg.waveDuty + 1))) + "% Square";
235
+				else
236
+					buf += "Noise";
237
+				buf += ")";
238
+				chnData.formatLabel->SetLabel(buf);
239
+			}
240
+
241
+			static const std::string states[] = { "NONE", "START", "ATTACK", "DECAY", "SUSTAIN", "RELEASE" };
242
+			chnData.stateLabel->SetLabel(states[ConvertFuncs::ToIntegral(chn.state)]);
243
+
244
+			chnData.loopStartLabel->SetLabel("samp #" + std::to_string(chn.reg.loopStart));
245
+
246
+			std::string tmpBuf = NumToHexString(chn.reg.timer).substr(2);
247
+			buf = "$" + tmpBuf + " (";
248
+			tmpBuf = ConvertFuncs::TrimDoubleString(std::to_string((ARM7_CLOCK / 2) / static_cast<double>(0x10000 - chn.reg.timer) / 8));
249
+			if (tmpBuf.find('.') != std::string::npos)
250
+				tmpBuf = tmpBuf.substr(0, tmpBuf.find('.') + 2);
251
+			buf += tmpBuf + " Hz)";
252
+			chnData.timerValueLabel->SetLabel(buf);
253
+
254
+			chnData.soundPosLenLabel->SetLabel("samp #" + std::to_string(static_cast<std::uint32_t>(chn.reg.samplePosition)) + " / " + std::to_string(chn.reg.totalLength));
255
+		}
256
+		else if (chnData.lastState != ChannelState::None)
257
+		{
258
+			chnData.panGauge->SetValue(0);
259
+			chnData.volumeGauge->SetValue(0);
260
+			chnData.volumeLabel->SetLabel("---");
261
+			chnData.panLabel->SetLabel("---");
262
+			chnData.repeatModeLabel->SetLabel("---");
263
+			chnData.formatLabel->SetLabel("---");
264
+			chnData.stateLabel->SetLabel("NONE");
265
+			chnData.loopStartLabel->SetLabel("---");
266
+			chnData.timerValueLabel->SetLabel("---");
267
+			chnData.soundPosLenLabel->SetLabel("---");
268
+		}
269
+
270
+		chnData.lastState = chn.state;
271
+	}
272
+}
273
+
274
+void SoundView::SyncToConfig()
275
+{
276
+	for (int i = 0; i < 16; ++i)
277
+		this->channelData[i].muteCheckBox->SetValue(this->config->mutes[i]);
278
+}