Browse code

[NCSF] Fix volume issues with a little help from the Nintendo DS SDK.

Also added a clone of DeSmuME's Sound View that is only build during a
debug build, which helped to identify the above issues.

Naram Qashat authored on 2014/10/05 20:00:09
Showing 16 changed files
... ...
@@ -45,14 +45,20 @@ v1.8.1 - 2014-06-17 - Reverted Sinc interpolation back to the Lanczos window.
45 45
   v1.9 - 2014-09-28 - Removed the Cosine, B-Spline, and Osculating
46 46
                       interpolations, added 4-point and 6-point Legrange
47 47
                       interpolations in their place.
48
-                    - Updated zlib to v1.28.
48
+                    - Updated zlib to v1.2.8.
49
+v1.9.1 - 2014-10-05 - Fixed volume issues that stemmed from how FeOS Sound
50
+                      System was handling volume. Utilized some code from the
51
+                      Nintendo DS SDK to help fix this.
52
+                    - Added a clone of DeSmuME's Sound View that only shows up
53
+                      in debug builds, was used to help me identify the above
54
+                      issue to fix it.
49 55
 
50 56
 This is a Winamp plugin to play NCSF files. NCSF is a PSF-style music format that
51 57
 uses SDAT files from Nintendo DS ROMs as it's "program".
52 58
 
53 59
 Contains:
54
-*    in_ncsf.dll - The NCSF Winamp plugin
55
-* zlib DLL v1.28 - Required by the plugin
60
+*     in_ncsf.dll - The NCSF Winamp plugin
61
+* zlib DLL v1.2.8 - Required by the plugin
56 62
 
57 63
 To allow Winamp to use the plugin, place in_ncsf.dll into your Winamp plugins
58 64
 directory and zlib1.dll into your Winamp directory (NOTE: NOT the plugins
... ...
@@ -1,7 +1,7 @@
1 1
 /*
2 2
  * SSEQ Player - Channel structures
3 3
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
4
- * Last modification on 2014-06-17
4
+ * Last modification on 2014-10-05
5 5
  *
6 6
  * Adapted from source code of FeOS Sound System
7 7
  * By fincs
... ...
@@ -71,10 +71,8 @@ Channel::Channel() : chnId(-1), tempReg(), state(CS_NONE), trackId(-1), prio(0),
71 71
 void Channel::UpdateVol(const Track &trk)
72 72
 {
73 73
 	int finalVol = trk.ply->masterVol;
74
-	finalVol += Cnv_Sust(trk.vol);
75
-	finalVol += Cnv_Sust(trk.expr);
76
-	if (finalVol < -AMPL_K)
77
-		finalVol = -AMPL_K;
74
+	finalVol += Cnv_Scale(trk.vol);
75
+	finalVol += Cnv_Scale(trk.expr);
78 76
 	this->extAmpl = finalVol;
79 77
 }
80 78
 
... ...
@@ -390,7 +388,7 @@ static inline uint16_t Timer_Adjust(uint16_t basetmr, int pitch)
390 388
 		tmr <<= shift;
391 389
 	}
392 390
 	else
393
-		return 0x10;
391
+		return 0xFFFF;
394 392
 
395 393
 	if (tmr < 0x10)
396 394
 		return 0x10;
... ...
@@ -539,18 +537,19 @@ void Channel::Update()
539 537
 			totalVol += this->velocity;
540 538
 			if (bModulation && this->modType == 1)
541 539
 				totalVol += modParam;
542
-			totalVol += AMPL_K;
543
-			if (totalVol < 0)
540
+			if (totalVol < -AMPL_K)
541
+				totalVol = -AMPL_K;
542
+			else if (totalVol > 0)
544 543
 				totalVol = 0;
545 544
 
546 545
 			cr &= ~(SOUND_VOL(0x7F) | SOUND_VOLDIV(3));
547
-			cr |= SOUND_VOL(static_cast<int>(getvoltbl[totalVol]));
546
+			cr |= SOUND_VOL(static_cast<int>(getvoltbl[totalVol + AMPL_K]));
548 547
 
549
-			if (totalVol < AMPL_K - 240)
548
+			if (totalVol < -240)
550 549
 				cr |= SOUND_VOLDIV(3);
551
-			else if (totalVol < AMPL_K - 120)
550
+			else if (totalVol < -120)
552 551
 				cr |= SOUND_VOLDIV(2);
553
-			else if (totalVol < AMPL_K - 60)
552
+			else if (totalVol < -60)
554 553
 				cr |= SOUND_VOLDIV(1);
555 554
 
556 555
 			this->vol = ((cr & SOUND_VOL(0x7F)) << 4) >> calcVolDivShift((cr & SOUND_VOLDIV(3)) >> 8);
... ...
@@ -1,7 +1,7 @@
1 1
 /*
2 2
  * SSEQ Player - Track structure
3 3
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
4
- * Last modification on 2013-04-01
4
+ * Last modification on 2014-10-05
5 5
  *
6 6
  * Adapted from source code of FeOS Sound System
7 7
  * By fincs
... ...
@@ -187,7 +187,7 @@ int Track::NoteOn(int key, int vel, int len)
187 187
 	chn->prio = this->prio;
188 188
 	chn->key = key;
189 189
 	chn->orgKey = bIsPCM ? noteDef->noteNumber : 69;
190
-	chn->velocity = Cnv_Sust(vel);
190
+	chn->velocity = Cnv_Scale(vel);
191 191
 	chn->pan = static_cast<int>(noteDef->pan) - 64;
192 192
 	chn->modDelayCnt = 0;
193 193
 	chn->modCounter = 0;
... ...
@@ -229,7 +229,7 @@ int Track::NoteOnTie(int key, int vel)
229 229
 	chn->flags.reset();
230 230
 	chn->prio = this->prio;
231 231
 	chn->key = key;
232
-	chn->velocity = Cnv_Sust(vel);
232
+	chn->velocity = Cnv_Scale(vel);
233 233
 	chn->modDelayCnt = 0;
234 234
 	chn->modCounter = 0;
235 235
 
... ...
@@ -1,7 +1,7 @@
1 1
 /*
2 2
  * SSEQ Player - Common functions
3 3
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
4
- * Last modification on 2014-09-08
4
+ * Last modification on 2014-10-05
5 5
  *
6 6
  * Some code from FeOS Sound System
7 7
  * By fincs
... ...
@@ -161,6 +161,33 @@ inline int Cnv_Fall(int fall)
161 161
 		return (0x1E00 / (0x7E - fall)) & 0xFFFF;
162 162
 }
163 163
 
164
+// This function actually doesn't come from FSS, I got the lookup table from the Nintendo DS SDK.
165
+inline int Cnv_Scale(int scale)
166
+{
167
+	static const int16_t lut[] =
168
+	{
169
+		-32768, -421, -361, -325, -300, -281, -265, -252,
170
+		-240, -230, -221, -212, -205, -198, -192, -186,
171
+		-180, -175, -170, -165, -161, -156, -152, -148,
172
+		-145, -141, -138, -134, -131, -128, -125, -122,
173
+		-120, -117, -114, -112, -110, -107, -105, -103,
174
+		-100, -98, -96, -94, -92, -90, -88, -86,
175
+		-85, -83, -81, -79, -78, -76, -74, -73,
176
+		-71, -70, -68, -67, -65, -64, -62, -61,
177
+		-60, -58, -57, -56, -54, -53, -52, -51,
178
+		-49, -48, -47, -46, -45, -43, -42, -41,
179
+		-40, -39, -38, -37, -36, -35, -34, -33,
180
+		-32, -31, -30, -29, -28, -27, -26, -25,
181
+		-24, -23, -23, -22, -21, -20, -19, -18,
182
+		-17, -17, -16, -15, -14, -13, -12, -12,
183
+		-11, -10, -9, -9, -8, -7, -6, -6,
184
+		-5, -4, -3, -3, -2, -1, -1, 0
185
+	};
186
+	if (scale & 0x80)
187
+		scale = 0x7F;
188
+	return lut[scale];
189
+}
190
+
164 191
 inline int Cnv_Sust(int sust)
165 192
 {
166 193
 	static const int16_t lut[] =
... ...
@@ -184,7 +211,7 @@ inline int Cnv_Sust(int sust)
184 211
 	};
185 212
 
186 213
 	if (sust & 0x80) // Supposedly invalid value...
187
-		sust = 0; // Use apparently correct default
214
+		sust = 0x7F; // Use apparently correct default
188 215
 	return lut[sust];
189 216
 }
190 217
 
... ...
@@ -1,15 +1,17 @@
1 1
 /*
2 2
  * xSF - NCSF configuration
3 3
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
4
- * Last modification on 2014-09-28
4
+ * Last modification on 2014-10-05
5 5
  *
6 6
  * Partially based on the vio*sf framework
7 7
  */
8 8
 
9
-#include <bitset>
10
-#include "XSFPlayer_NCSF.h"
11
-#include "XSFConfig.h"
9
+#include "XSFConfig_NCSF.h"
12 10
 #include "convert.h"
11
+#ifdef _DEBUG
12
+# include "resource.h"
13
+# include <CommCtrl.h>
14
+#endif
13 15
 
14 16
 enum
15 17
 {
... ...
@@ -17,31 +19,9 @@ enum
17 19
 	idMutes
18 20
 };
19 21
 
20
-class XSFConfig_NCSF : public XSFConfig
21
-{
22
-protected:
23
-	static unsigned initInterpolation;
24
-	static std::string initMutes;
25
-
26
-	friend class XSFConfig;
27
-	unsigned interpolation;
28
-	std::bitset<16> mutes;
29
-
30
-	XSFConfig_NCSF();
31
-	void LoadSpecificConfig();
32
-	void SaveSpecificConfig();
33
-	void GenerateSpecificDialogs();
34
-	INT_PTR CALLBACK ConfigDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
35
-	void ResetSpecificConfigDefaults(HWND hwndDlg);
36
-	void SaveSpecificConfigDialog(HWND hwndDlg);
37
-	void CopySpecificConfigToMemory(XSFPlayer *xSFPlayer, bool preLoad);
38
-public:
39
-	void About(HWND parent);
40
-};
41
-
42 22
 unsigned XSFConfig::initSampleRate = 44100;
43 23
 std::string XSFConfig::commonName = "NCSF Decoder";
44
-std::string XSFConfig::versionNumber = "1.9";
24
+std::string XSFConfig::versionNumber = "1.9.1";
45 25
 unsigned XSFConfig_NCSF::initInterpolation = 4;
46 26
 std::string XSFConfig_NCSF::initMutes = "0000000000000000";
47 27
 
... ...
@@ -51,6 +31,9 @@ XSFConfig *XSFConfig::Create()
51 31
 }
52 32
 
53 33
 XSFConfig_NCSF::XSFConfig_NCSF() : XSFConfig(), interpolation(0), mutes()
34
+#ifdef _DEBUG
35
+	, soundViewData()
36
+#endif
54 37
 {
55 38
 	this->supportedSampleRates.push_back(8000);
56 39
 	this->supportedSampleRates.push_back(11025);
... ...
@@ -131,7 +114,7 @@ void XSFConfig_NCSF::SaveSpecificConfigDialog(HWND hwndDlg)
131 114
 
132 115
 void XSFConfig_NCSF::CopySpecificConfigToMemory(XSFPlayer *xSFPlayer, bool)
133 116
 {
134
-	XSFPlayer_NCSF *NCSFPlayer = static_cast<XSFPlayer_NCSF *>(xSFPlayer);
117
+	auto NCSFPlayer = static_cast<XSFPlayer_NCSF *>(xSFPlayer);
135 118
 	NCSFPlayer->SetInterpolation(this->interpolation);
136 119
 	NCSFPlayer->SetMutes(this->mutes);
137 120
 }
... ...
@@ -141,3 +124,223 @@ void XSFConfig_NCSF::About(HWND parent)
141 124
 	MessageBoxW(parent, ConvertFuncs::StringToWString(XSFConfig::commonName + " v" + XSFConfig::versionNumber + ", using xSF Winamp plugin framework (based on the vio*sf plugins) by Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]\n\n"
142 125
 		"Utilizes code adapted from the FeOS Sound System library by fincs, git revision 5204c55 on GitHub, for audio playback.").c_str(), ConvertFuncs::StringToWString(XSFConfig::commonName + " v" + XSFConfig::versionNumber).c_str(), MB_OK);
143 126
 }
127
+
128
+#ifdef _DEBUG
129
+INT_PTR CALLBACK XSFConfig_NCSF::SoundViewDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
130
+{
131
+	auto data = reinterpret_cast<SoundViewData *>(GetWindowLongW(hwndDlg, DWLP_USER));
132
+	if (!data && uMsg != WM_INITDIALOG)
133
+		return false;
134
+
135
+	switch (uMsg)
136
+	{
137
+		case WM_INITDIALOG:
138
+			if (!data)
139
+			{
140
+				data = reinterpret_cast<SoundViewData *>(lParam);
141
+				SetWindowLongW(hwndDlg, DWLP_USER, reinterpret_cast<LONG>(data));
142
+			}
143
+			data->hDlg = hwndDlg;
144
+			for (int chanId = 0; chanId < 16; ++chanId)
145
+			{
146
+				SendDlgItemMessageW(hwndDlg, IDC_SOUND0VOLBAR + chanId, PBM_SETRANGE, 0, MAKELPARAM(0, 128));
147
+				SendDlgItemMessageW(hwndDlg, IDC_SOUND0PANBAR + chanId, PBM_SETRANGE, 0, MAKELPARAM(0, 128));
148
+				SendDlgItemMessageW(hwndDlg, IDC_SOUND0MUTE + chanId, BM_SETCHECK, data->config->mutes[chanId], 0);
149
+			}
150
+			break;
151
+		case WM_CLOSE:
152
+		case WM_DESTROY:
153
+			data->config->CloseSoundView();
154
+			break;
155
+		case WM_COMMAND:
156
+			{
157
+				auto id = GET_WM_COMMAND_ID(wParam, lParam);
158
+				switch (id)
159
+				{
160
+					case IDC_BUTTON_VOLMODE:
161
+						data->volModeAlternative = !!IsDlgButtonChecked(hwndDlg, IDC_BUTTON_VOLMODE);
162
+						break;
163
+					case IDC_SOUND0MUTE:
164
+					case IDC_SOUND1MUTE:
165
+					case IDC_SOUND2MUTE:
166
+					case IDC_SOUND3MUTE:
167
+					case IDC_SOUND4MUTE:
168
+					case IDC_SOUND5MUTE:
169
+					case IDC_SOUND6MUTE:
170
+					case IDC_SOUND7MUTE:
171
+					case IDC_SOUND8MUTE:
172
+					case IDC_SOUND9MUTE:
173
+					case IDC_SOUND10MUTE:
174
+					case IDC_SOUND11MUTE:
175
+					case IDC_SOUND12MUTE:
176
+					case IDC_SOUND13MUTE:
177
+					case IDC_SOUND14MUTE:
178
+					case IDC_SOUND15MUTE:
179
+						data->config->mutes[id - IDC_SOUND0MUTE] = !!IsDlgButtonChecked(hwndDlg, id);
180
+						data->config->SaveConfig();
181
+						data->player->SetMutes(data->config->mutes);
182
+						break;
183
+					case IDC_SOUND_UNMUTE_ALL:
184
+						for (int chanId = 0; chanId < 16; ++chanId)
185
+							SendDlgItemMessageW(hwndDlg, IDC_SOUND0MUTE + chanId, BM_SETCHECK, false, 0);
186
+						data->config->mutes.reset();
187
+						data->config->SaveConfig();
188
+						data->player->SetMutes(data->config->mutes);
189
+						break;
190
+					default:
191
+						return false;
192
+				}
193
+			}
194
+			break;
195
+		default:
196
+			return false;
197
+	}
198
+
199
+	return true;
200
+}
201
+
202
+void XSFConfig_NCSF::CallSoundView(XSFPlayer *xSFPlayer, HINSTANCE hInstance, HWND hwndParent)
203
+{
204
+	this->soundViewData.reset(new SoundViewData);
205
+	this->soundViewData->config = this;
206
+	this->soundViewData->player = static_cast<XSFPlayer_NCSF *>(xSFPlayer);
207
+
208
+	auto hDlg = CreateDialogParamW(hInstance, MAKEINTRESOURCEW(IDD_SOUND_VIEW), hwndParent, XSFConfig_NCSF::SoundViewDialogProc, reinterpret_cast<LPARAM>(this->soundViewData.get()));
209
+	if (!hDlg)
210
+	{
211
+		this->soundViewData.reset();
212
+		return;
213
+	}
214
+
215
+	ShowWindow(hDlg, SW_SHOW);
216
+	UpdateWindow(hDlg);
217
+}
218
+
219
+static inline void ProgressSetPosImmediate(HWND hDlg, int nIDDlgItem, int nPos)
220
+{
221
+	int nMin = SendDlgItemMessageW(hDlg, nIDDlgItem, PBM_GETRANGE, true, reinterpret_cast<LPARAM>(nullptr));
222
+	int nMax = SendDlgItemMessageW(hDlg, nIDDlgItem, PBM_GETRANGE, false, reinterpret_cast<LPARAM>(nullptr));
223
+
224
+	// get rid of fancy progress animation since Windows Vista
225
+	// http://stackoverflow.com/questions/1061715/how-do-i-make-tprogressbar-stop-lagging
226
+	if (nPos < nMax)
227
+	{
228
+		SendDlgItemMessageW(hDlg, nIDDlgItem, PBM_SETPOS, nPos + 1, 0);
229
+		SendDlgItemMessageW(hDlg, nIDDlgItem, PBM_SETPOS, nPos, 0); // This will set Progress backwards and give an instant update
230
+	}
231
+	else
232
+	{
233
+		SendDlgItemMessageW(hDlg, nIDDlgItem, PBM_SETRANGE32, nMin, nPos + 1);
234
+		SendDlgItemMessageW(hDlg, nIDDlgItem, PBM_SETPOS, nPos + 1, 0);
235
+		SendDlgItemMessageW(hDlg, nIDDlgItem, PBM_SETRANGE32, nMin, nPos); // This will also set Progress backwards also so instant update
236
+	}
237
+}
238
+
239
+static inline int32_t muldiv7(int32_t val, uint8_t mul)
240
+{
241
+	return mul == 127 ? val : ((val * mul) >> 7);
242
+}
243
+
244
+void XSFConfig_NCSF::RefreshSoundView()
245
+{
246
+	auto player = this->soundViewData->player;
247
+	auto hDlg = this->soundViewData->hDlg;
248
+	std::wstring buf;
249
+	for (size_t chanId = 0; chanId < 16; ++chanId)
250
+	{
251
+		auto &chn = player->GetChannel(chanId);
252
+
253
+		if (chn.state > CS_START)
254
+		{
255
+			ProgressSetPosImmediate(hDlg, IDC_SOUND0PANBAR + chanId, muldiv7(128, chn.reg.panning));
256
+			uint8_t datashift = chn.reg.volumeDiv;
257
+			if (datashift == 3)
258
+				datashift = 4;
259
+			int32_t vol = muldiv7(128, chn.reg.volumeMul) >> datashift;
260
+			ProgressSetPosImmediate(hDlg, IDC_SOUND0VOLBAR + chanId, vol);
261
+
262
+			if (this->soundViewData->volModeAlternative)
263
+				buf = wstringify(chn.reg.volumeMul) + L"/" + wstringify(1 << datashift);
264
+			else
265
+				buf = wstringify(vol);
266
+			SetDlgItemTextW(hDlg, IDC_SOUND0VOL + chanId, buf.c_str());
267
+
268
+			if (!chn.reg.panning)
269
+				buf = L"L";
270
+			else if (chn.reg.panning == 64)
271
+				buf = L"C";
272
+			else if (chn.reg.panning == 127)
273
+				buf = L"R";
274
+			else if (chn.reg.panning < 64)
275
+				buf = L"L" + wstringify(64 - chn.reg.panning);
276
+			else //if (chn.reg.panning > 64)
277
+				buf = L"R" + wstringify(chn.reg.panning - 64);
278
+			SetDlgItemTextW(hDlg, IDC_SOUND0PAN + chanId, buf.c_str());
279
+
280
+			SetDlgItemTextW(hDlg, IDC_SOUND0HOLD + chanId, L"---");
281
+			SetDlgItemTextW(hDlg, IDC_SOUND0BUSY + chanId, L"---");
282
+
283
+			static const std::wstring modes[] = { L"Manual", L"Loop Infinite", L"One-Shot", L"Prohibited" };
284
+			SetDlgItemTextW(hDlg, IDC_SOUND0REPEATMODE + chanId, (wstringify(chn.reg.repeatMode) + L" (" + modes[chn.reg.repeatMode] + L")").c_str());
285
+
286
+			if (chn.reg.format != 3)
287
+			{
288
+				static const std::wstring formats[] = { L"PCM8", L"PCM16", L"IMA-ADPCM" };
289
+				SetDlgItemTextW(hDlg, IDC_SOUND0FORMAT + chanId, (wstringify(chn.reg.format) + L" (" + formats[chn.reg.format] + L")").c_str());
290
+			}
291
+			else
292
+			{
293
+				buf = L"3 (";
294
+				if (chanId < 8)
295
+					buf += L"PSG/Noise?";
296
+				else if (chanId < 14)
297
+					buf += wstringify(chn.reg.waveDuty == 7 ? 0 : 12.5 * (chn.reg.waveDuty + 1)) + L"% Square";
298
+				else
299
+					buf += L"Noise";
300
+				buf += L")";
301
+				SetDlgItemTextW(hDlg, IDC_SOUND0FORMAT + chanId, buf.c_str());
302
+			}
303
+
304
+			SetDlgItemTextW(hDlg, IDC_SOUND0SAD + chanId, L"---");
305
+
306
+			SetDlgItemTextW(hDlg, IDC_SOUND0PNT + chanId, (L"samp #" + wstringify(chn.reg.loopStart)).c_str());
307
+
308
+			std::wstring tmpBuf = ConvertFuncs::StringToWString(NumToHexString(chn.reg.timer)).substr(2);
309
+			buf = L"$" + tmpBuf + L" (";
310
+			tmpBuf = wstringify((ARM7_CLOCK / 2) / static_cast<double>(0x10000 - chn.reg.timer));
311
+			if (tmpBuf.find('.') != std::wstring::npos)
312
+				tmpBuf = tmpBuf.substr(0, tmpBuf.find('.') + 2);
313
+			buf += tmpBuf + L" Hz)";
314
+			SetDlgItemTextW(hDlg, IDC_SOUND0TMR + chanId, buf.c_str());
315
+
316
+			SetDlgItemTextW(hDlg, IDC_SOUND0POSLEN + chanId, (L"samp #" + wstringify(static_cast<uint32_t>(chn.reg.samplePosition)) + L" / " + wstringify(chn.reg.totalLength)).c_str());
317
+		}
318
+		else if (this->soundViewData->channelLastStates[chanId] != CS_NONE)
319
+		{
320
+			ProgressSetPosImmediate(hDlg, IDC_SOUND0PANBAR + chanId, 0);
321
+			ProgressSetPosImmediate(hDlg, IDC_SOUND0VOLBAR + chanId, 0);
322
+			SetDlgItemTextW(hDlg, IDC_SOUND0VOL + chanId, L"---");
323
+			SetDlgItemTextW(hDlg, IDC_SOUND0PAN + chanId, L"---");
324
+			SetDlgItemTextW(hDlg, IDC_SOUND0HOLD + chanId, L"---");
325
+			SetDlgItemTextW(hDlg, IDC_SOUND0BUSY + chanId, L"---");
326
+			SetDlgItemTextW(hDlg, IDC_SOUND0REPEATMODE + chanId, L"---");
327
+			SetDlgItemTextW(hDlg, IDC_SOUND0FORMAT + chanId, L"---");
328
+			SetDlgItemTextW(hDlg, IDC_SOUND0SAD + chanId, L"---");
329
+			SetDlgItemTextW(hDlg, IDC_SOUND0PNT + chanId, L"---");
330
+			SetDlgItemTextW(hDlg, IDC_SOUND0TMR + chanId, L"---");
331
+			SetDlgItemTextW(hDlg, IDC_SOUND0POSLEN + chanId, L"---");
332
+		}
333
+
334
+		this->soundViewData->channelLastStates[chanId] = chn.state;
335
+	}
336
+}
337
+
338
+void XSFConfig_NCSF::CloseSoundView()
339
+{
340
+	if (this->soundViewData)
341
+	{
342
+		DestroyWindow(this->soundViewData->hDlg);
343
+		this->soundViewData.reset();
344
+	}
345
+}
346
+#endif
144 347
new file mode 100644
... ...
@@ -0,0 +1,69 @@
1
+/*
2
+ * xSF - NCSF configuration
3
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
4
+ * Last modification on 2014-10-05
5
+ *
6
+ * Partially based on the vio*sf framework
7
+ */
8
+
9
+#pragma once
10
+
11
+#include <bitset>
12
+#include <memory>
13
+#include "XSFConfig.h"
14
+#include "XSFPlayer_NCSF.h"
15
+#include "windowsh_wrapper.h"
16
+
17
+class XSFConfig_NCSF;
18
+
19
+#ifdef _DEBUG
20
+struct SoundViewData
21
+{
22
+	XSFConfig_NCSF *config;
23
+	XSFPlayer_NCSF *player;
24
+	uint8_t channelLastStates[16];
25
+	HWND hDlg;
26
+
27
+	bool volModeAlternative;
28
+
29
+	SoundViewData() : config(nullptr), player(nullptr), hDlg(nullptr), volModeAlternative(false)
30
+	{
31
+		std::fill_n(&this->channelLastStates[0], sizeof(this->channelLastStates), CS_START);
32
+	}
33
+};
34
+#endif
35
+
36
+class XSFConfig_NCSF : public XSFConfig
37
+{
38
+protected:
39
+	static unsigned initInterpolation;
40
+	static std::string initMutes;
41
+
42
+	friend class XSFConfig;
43
+	friend struct SoundViewData;
44
+	unsigned interpolation;
45
+	std::bitset<16> mutes;
46
+
47
+	XSFConfig_NCSF();
48
+	void LoadSpecificConfig();
49
+	void SaveSpecificConfig();
50
+	void GenerateSpecificDialogs();
51
+	INT_PTR CALLBACK ConfigDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
52
+	void ResetSpecificConfigDefaults(HWND hwndDlg);
53
+	void SaveSpecificConfigDialog(HWND hwndDlg);
54
+	void CopySpecificConfigToMemory(XSFPlayer *xSFPlayer, bool preLoad);
55
+
56
+#ifdef _DEBUG
57
+	std::unique_ptr<SoundViewData> soundViewData;
58
+
59
+	static INT_PTR CALLBACK SoundViewDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
60
+#endif
61
+public:
62
+	void About(HWND parent);
63
+
64
+#ifdef _DEBUG
65
+	void CallSoundView(XSFPlayer *xSFPlayer, HINSTANCE hInstance, HWND hwndParent);
66
+	void RefreshSoundView();
67
+	void CloseSoundView();
68
+#endif
69
+};
... ...
@@ -1,7 +1,7 @@
1 1
 /*
2 2
  * xSF - NCSF Player
3 3
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
4
- * Last modification on 2014-09-24
4
+ * Last modification on 2014-10-05
5 5
  *
6 6
  * Partially based on the vio*sf framework
7 7
  *
... ...
@@ -13,6 +13,7 @@
13 13
 #include <zlib.h>
14 14
 #include "convert.h"
15 15
 #include "XSFPlayer_NCSF.h"
16
+#include "XSFConfig_NCSF.h"
16 17
 #include "XSFCommon.h"
17 18
 #include "SSEQPlayer/SDAT.h"
18 19
 #include "SSEQPlayer/Player.h"
... ...
@@ -20,6 +21,8 @@
20 21
 const char *XSFPlayer::WinampDescription = "NCSF Decoder";
21 22
 const char *XSFPlayer::WinampExts = "ncsf;minincsf\0DS Nitro Composer Sound Format files (*.ncsf;*.minincsf)\0";
22 23
 
24
+extern XSFConfig *xSFConfig;
25
+
23 26
 XSFPlayer *XSFPlayer::Create(const std::string &fn)
24 27
 {
25 28
 	return new XSFPlayer_NCSF(fn);
... ...
@@ -115,11 +118,53 @@ XSFPlayer_NCSF::XSFPlayer_NCSF(const std::wstring &filename) : XSFPlayer()
115 118
 }
116 119
 #endif
117 120
 
121
+#ifdef _DEBUG
122
+static HANDLE soundViewThreadHandle = INVALID_HANDLE_VALUE;
123
+static bool killSoundViewThread;
124
+
125
+static DWORD WINAPI soundViewThread(void *b)
126
+{
127
+	auto xSFConfig_NCSF = static_cast<XSFConfig_NCSF *>(xSFConfig);
128
+	xSFConfig_NCSF->CallSoundView(static_cast<XSFPlayer_NCSF *>(b), xSFConfig->GetHInstance(), nullptr);
129
+	MSG msg;
130
+	while (!killSoundViewThread)
131
+	{
132
+		xSFConfig_NCSF->RefreshSoundView();
133
+		if (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE))
134
+		{
135
+			TranslateMessage(&msg);
136
+			DispatchMessageW(&msg);
137
+		}
138
+	}
139
+	xSFConfig_NCSF->CloseSoundView();
140
+	return 0;
141
+}
142
+#endif
143
+
144
+XSFPlayer_NCSF::~XSFPlayer_NCSF()
145
+{
146
+#ifdef _DEBUG
147
+	killSoundViewThread = true;
148
+	if (WaitForSingleObject(soundViewThreadHandle, 2000) == WAIT_TIMEOUT)
149
+	{
150
+		TerminateThread(soundViewThreadHandle, 0);
151
+		static_cast<XSFConfig_NCSF *>(xSFConfig)->CloseSoundView();
152
+	}
153
+	CloseHandle(soundViewThreadHandle);
154
+	soundViewThreadHandle = INVALID_HANDLE_VALUE;
155
+#endif
156
+}
157
+
118 158
 bool XSFPlayer_NCSF::Load()
119 159
 {
120 160
 	if (!this->LoadNCSF())
121 161
 		return false;
122 162
 
163
+#ifdef _DEBUG
164
+	killSoundViewThread = false;
165
+	soundViewThreadHandle = CreateThread(nullptr, 0, soundViewThread, this, 0, nullptr);
166
+#endif
167
+
123 168
 	PseudoFile file;
124 169
 	file.data = &this->sdatData;
125 170
 	this->sdat.reset(new SDAT(file, this->sseq));
... ...
@@ -211,3 +256,10 @@ void XSFPlayer_NCSF::SetMutes(const std::bitset<16> &newMutes)
211 256
 {
212 257
 	this->mutes = newMutes;
213 258
 }
259
+
260
+#ifdef _DEBUG
261
+const Channel &XSFPlayer_NCSF::GetChannel(size_t chanNum) const
262
+{
263
+	return this->player.channels[chanNum];
264
+}
265
+#endif
... ...
@@ -1,7 +1,7 @@
1 1
 /*
2 2
  * xSF - NCSF Player
3 3
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
4
- * Last modification on 2014-09-24
4
+ * Last modification on 2014-10-05
5 5
  *
6 6
  * Partially based on the vio*sf framework
7 7
  *
... ...
@@ -36,10 +36,14 @@ public:
36 36
 #ifdef _WIN32
37 37
 	XSFPlayer_NCSF(const std::wstring &filename);
38 38
 #endif
39
+	~XSFPlayer_NCSF();
39 40
 	bool Load();
40 41
 	void GenerateSamples(std::vector<uint8_t> &buf, unsigned offset, unsigned samples);
41 42
 	void Terminate();
42 43
 
43 44
 	void SetInterpolation(unsigned interpolation);
44 45
 	void SetMutes(const std::bitset<16> &newMutes);
46
+#ifdef _DEBUG
47
+	const Channel &GetChannel(size_t chanNum) const;
48
+#endif
45 49
 };
46 50
new file mode 100644
47 51
Binary files /dev/null and b/src/in_ncsf/in_ncsf.rc differ
... ...
@@ -97,6 +97,7 @@
97 97
     <ClCompile Include="XSFPlayer_NCSF.cpp" />
98 98
   </ItemGroup>
99 99
   <ItemGroup>
100
+    <ClInclude Include="resource.h" />
100 101
     <ClInclude Include="SSEQPlayer\Channel.h" />
101 102
     <ClInclude Include="SSEQPlayer\common.h" />
102 103
     <ClInclude Include="SSEQPlayer\consts.h" />
... ...
@@ -112,6 +113,7 @@
112 113
     <ClInclude Include="SSEQPlayer\SWAV.h" />
113 114
     <ClInclude Include="SSEQPlayer\SYMBSection.h" />
114 115
     <ClInclude Include="SSEQPlayer\Track.h" />
116
+    <ClInclude Include="XSFConfig_NCSF.h" />
115 117
     <ClInclude Include="XSFPlayer_NCSF.h" />
116 118
   </ItemGroup>
117 119
   <ItemGroup>
... ...
@@ -119,6 +121,11 @@
119 121
       <Project>{9d6d2540-b3dc-462b-bbc0-5b7c32a4d581}</Project>
120 122
     </ProjectReference>
121 123
   </ItemGroup>
124
+  <ItemGroup>
125
+    <ResourceCompile Include="in_ncsf.rc">
126
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
127
+    </ResourceCompile>
128
+  </ItemGroup>
122 129
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
123 130
   <ImportGroup Label="ExtensionTargets">
124 131
   </ImportGroup>
... ...
@@ -113,8 +113,19 @@
113 113
     <ClInclude Include="SSEQPlayer\Track.h">
114 114
       <Filter>Header Files\SSEQPlayer</Filter>
115 115
     </ClInclude>
116
+    <ClInclude Include="resource.h">
117
+      <Filter>Header Files</Filter>
118
+    </ClInclude>
119
+    <ClInclude Include="XSFConfig_NCSF.h">
120
+      <Filter>Header Files</Filter>
121
+    </ClInclude>
116 122
     <ClInclude Include="XSFPlayer_NCSF.h">
117 123
       <Filter>Header Files</Filter>
118 124
     </ClInclude>
119 125
   </ItemGroup>
126
+  <ItemGroup>
127
+    <ResourceCompile Include="in_ncsf.rc">
128
+      <Filter>Resource Files</Filter>
129
+    </ResourceCompile>
130
+  </ItemGroup>
120 131
 </Project>
121 132
\ No newline at end of file
122 133
new file mode 100644
123 134
Binary files /dev/null and b/src/in_ncsf/resource.h differ
... ...
@@ -1,7 +1,7 @@
1 1
 /*
2 2
  * xSF - Core configuration handler
3 3
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
4
- * Last modification on 2014-09-24
4
+ * Last modification on 2014-10-05
5 5
  *
6 6
  * Partially based on the vio*sf framework
7 7
  */
... ...
@@ -321,12 +321,12 @@ INT_PTR CALLBACK XSFConfig::InfoDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wPara
321 321
 
322 322
 void XSFConfig::CallConfigDialog(HINSTANCE hInstance, HWND hwndParent)
323 323
 {
324
-	DialogBoxIndirectParam(hInstance, this->configDialog.GenerateTemplate(), hwndParent, XSFConfig::ConfigDialogProcStatic, reinterpret_cast<LPARAM>(this));
324
+	DialogBoxIndirectParamW(hInstance, this->configDialog.GenerateTemplate(), hwndParent, XSFConfig::ConfigDialogProcStatic, reinterpret_cast<LPARAM>(this));
325 325
 }
326 326
 
327 327
 void XSFConfig::CallInfoDialog(HINSTANCE hInstance, HWND hwndParent)
328 328
 {
329
-	DialogBoxIndirectParam(hInstance, this->infoDialog.GenerateTemplate(), hwndParent, XSFConfig::InfoDialogProcStatic, reinterpret_cast<LPARAM>(this));
329
+	DialogBoxIndirectParamW(hInstance, this->infoDialog.GenerateTemplate(), hwndParent, XSFConfig::InfoDialogProcStatic, reinterpret_cast<LPARAM>(this));
330 330
 }
331 331
 
332 332
 void XSFConfig::ResetConfigDefaults(HWND hwndDlg)
... ...
@@ -370,6 +370,16 @@ void XSFConfig::CopyConfigToMemory(XSFPlayer *xSFPlayer, bool preLoad)
370 370
 	this->CopySpecificConfigToMemory(xSFPlayer, preLoad);
371 371
 }
372 372
 
373
+void XSFConfig::SetHInstance(HINSTANCE hInstance)
374
+{
375
+	this->configIO->SetHInstance(hInstance);
376
+}
377
+
378
+HINSTANCE XSFConfig::GetHInstance() const
379
+{
380
+	return this->configIO->GetHInstance();
381
+}
382
+
373 383
 bool XSFConfig::GetPlayInfinitely() const
374 384
 {
375 385
 	return this->playInfinitely;
... ...
@@ -1,7 +1,7 @@
1 1
 /*
2 2
  * xSF - Core configuration handler
3 3
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
4
- * Last modification on 2014-09-24
4
+ * Last modification on 2014-10-05
5 5
  *
6 6
  * Partially based on the vio*sf framework
7 7
  */
... ...
@@ -27,9 +27,11 @@ public:
27 27
 	virtual void SetValueString(const std::string &name, const std::string &value) = 0;
28 28
 	template<typename T> void SetValue(const std::string &name, const T &value) { this->SetValueString(name, stringify(value)); }
29 29
 	void SetValue(const std::string &name, const std::string &value) { this->SetValueString(name, value); }
30
-	virtual std::string GetValueString(const std::string &name, const std::string &defaultValue) = 0;
31
-	template<typename T> T GetValue(const std::string &name, const T &defaultValue) { return convertTo<T>(this->GetValueString(name, stringify(defaultValue))); }
32
-	std::string GetValue(const std::string &name, const std::string &defaultValue) { return this->GetValueString(name, defaultValue); }
30
+	virtual std::string GetValueString(const std::string &name, const std::string &defaultValue) const = 0;
31
+	template<typename T> T GetValue(const std::string &name, const T &defaultValue) const { return convertTo<T>(this->GetValueString(name, stringify(defaultValue))); }
32
+	std::string GetValue(const std::string &name, const std::string &defaultValue) const { return this->GetValueString(name, defaultValue); }
33
+	virtual void SetHInstance(HINSTANCE) { }
34
+	virtual HINSTANCE GetHInstance() const { return nullptr; }
33 35
 };
34 36
 
35 37
 class XSFConfig
... ...
@@ -81,6 +83,8 @@ public:
81 83
 	void ResetConfigDefaults(HWND hwndDlg);
82 84
 	void SaveConfigDialog(HWND hwndDlg);
83 85
 	void CopyConfigToMemory(XSFPlayer *xSFPlayer, bool preLoad);
86
+	void SetHInstance(HINSTANCE hInstance);
87
+	HINSTANCE GetHInstance() const;
84 88
 
85 89
 	virtual void About(HWND parent) = 0;
86 90
 
... ...
@@ -1,7 +1,7 @@
1 1
 /*
2 2
  * xSF - Winamp-specification configuration handler
3 3
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
4
- * Last modification on 2014-09-24
4
+ * Last modification on 2014-10-05
5 5
  *
6 6
  * Partially based on the vio*sf framework
7 7
  */
... ...
@@ -18,11 +18,14 @@ class XSFConfigIO_Winamp : public XSFConfigIO
18 18
 protected:
19 19
 	friend class XSFConfigIO;
20 20
 	std::wstring iniFilename;
21
+	HINSTANCE hInst;
21 22
 
22 23
 	XSFConfigIO_Winamp();
23 24
 public:
24 25
 	void SetValueString(const std::string &name, const std::string &value);
25
-	std::string GetValueString(const std::string &name, const std::string &defaultValue);
26
+	std::string GetValueString(const std::string &name, const std::string &defaultValue) const;
27
+	void SetHInstance(HINSTANCE hInstance);
28
+	HINSTANCE GetHInstance() const;
26 29
 };
27 30
 
28 31
 XSFConfigIO *XSFConfigIO::Create()
... ...
@@ -57,7 +60,7 @@ void XSFConfigIO_Winamp::SetValueString(const std::string &name, const std::stri
57 60
 	WritePrivateProfileStringW(ConvertFuncs::StringToWString(XSFConfig::commonName).c_str(), ConvertFuncs::StringToWString(name).c_str(), ConvertFuncs::StringToWString(value).c_str(), this->iniFilename.c_str());
58 61
 }
59 62
 
60
-std::string XSFConfigIO_Winamp::GetValueString(const std::string &name, const std::string &defaultValue)
63
+std::string XSFConfigIO_Winamp::GetValueString(const std::string &name, const std::string &defaultValue) const
61 64
 {
62 65
 	auto value = std::vector<wchar_t>(MAX_PATH / 2);
63 66
 
... ...
@@ -73,3 +76,13 @@ std::string XSFConfigIO_Winamp::GetValueString(const std::string &name, const st
73 76
 
74 77
 	return ConvertFuncs::WStringToString(std::wstring(value.begin(), value.begin() + result));
75 78
 }
79
+
80
+void XSFConfigIO_Winamp::SetHInstance(HINSTANCE hInstance)
81
+{
82
+	this->hInst = hInstance;
83
+}
84
+
85
+HINSTANCE XSFConfigIO_Winamp::GetHInstance() const
86
+{
87
+	return this->hInst;
88
+}
... ...
@@ -1,7 +1,7 @@
1 1
 /*
2 2
  * xSF - Winamp plugin
3 3
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
4
- * Last modification on 2014-09-25
4
+ * Last modification on 2014-10-05
5 5
  *
6 6
  * Partially based on the vio*sf framework
7 7
  */
... ...
@@ -93,6 +93,7 @@ void init()
93 93
 	xSFConfig = XSFConfig::Create();
94 94
 	xSFConfig->LoadConfig();
95 95
 	xSFConfig->GenerateDialogs();
96
+	xSFConfig->SetHInstance(inMod.hDllInstance);
96 97
 }
97 98
 
98 99
 void quit()