[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.
--- a/README.txt
+++ b/README.txt
@@ -45,14 +45,20 @@
v1.9 - 2014-09-28 - Removed the Cosine, B-Spline, and Osculating
interpolations, added 4-point and 6-point Legrange
interpolations in their place.
- - Updated zlib to v1.28.
+ - Updated zlib to v1.2.8.
+v1.9.1 - 2014-10-05 - Fixed volume issues that stemmed from how FeOS Sound
+ System was handling volume. Utilized some code from the
+ Nintendo DS SDK to help fix this.
+ - Added a clone of DeSmuME's Sound View that only shows up
+ in debug builds, was used to help me identify the above
+ issue to fix it.
This is a Winamp plugin to play NCSF files. NCSF is a PSF-style music format that
uses SDAT files from Nintendo DS ROMs as it's "program".
Contains:
-* in_ncsf.dll - The NCSF Winamp plugin
-* zlib DLL v1.28 - Required by the plugin
+* in_ncsf.dll - The NCSF Winamp plugin
+* zlib DLL v1.2.8 - Required by the plugin
To allow Winamp to use the plugin, place in_ncsf.dll into your Winamp plugins
directory and zlib1.dll into your Winamp directory (NOTE: NOT the plugins
--- a/src/in_ncsf/SSEQPlayer/Channel.cpp
+++ b/src/in_ncsf/SSEQPlayer/Channel.cpp
@@ -1,7 +1,7 @@
/*
* SSEQ Player - Channel structures
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
- * Last modification on 2014-06-17
+ * Last modification on 2014-10-05
*
* Adapted from source code of FeOS Sound System
* By fincs
@@ -71,10 +71,8 @@
void Channel::UpdateVol(const Track &trk)
{
int finalVol = trk.ply->masterVol;
- finalVol += Cnv_Sust(trk.vol);
- finalVol += Cnv_Sust(trk.expr);
- if (finalVol < -AMPL_K)
- finalVol = -AMPL_K;
+ finalVol += Cnv_Scale(trk.vol);
+ finalVol += Cnv_Scale(trk.expr);
this->extAmpl = finalVol;
}
@@ -390,7 +388,7 @@
tmr <<= shift;
}
else
- return 0x10;
+ return 0xFFFF;
if (tmr < 0x10)
return 0x10;
@@ -539,18 +537,19 @@
totalVol += this->velocity;
if (bModulation && this->modType == 1)
totalVol += modParam;
- totalVol += AMPL_K;
- if (totalVol < 0)
+ if (totalVol < -AMPL_K)
+ totalVol = -AMPL_K;
+ else if (totalVol > 0)
totalVol = 0;
cr &= ~(SOUND_VOL(0x7F) | SOUND_VOLDIV(3));
- cr |= SOUND_VOL(static_cast<int>(getvoltbl[totalVol]));
-
- if (totalVol < AMPL_K - 240)
+ cr |= SOUND_VOL(static_cast<int>(getvoltbl[totalVol + AMPL_K]));
+
+ if (totalVol < -240)
cr |= SOUND_VOLDIV(3);
- else if (totalVol < AMPL_K - 120)
+ else if (totalVol < -120)
cr |= SOUND_VOLDIV(2);
- else if (totalVol < AMPL_K - 60)
+ else if (totalVol < -60)
cr |= SOUND_VOLDIV(1);
this->vol = ((cr & SOUND_VOL(0x7F)) << 4) >> calcVolDivShift((cr & SOUND_VOLDIV(3)) >> 8);
--- a/src/in_ncsf/SSEQPlayer/Track.cpp
+++ b/src/in_ncsf/SSEQPlayer/Track.cpp
@@ -1,7 +1,7 @@
/*
* SSEQ Player - Track structure
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
- * Last modification on 2013-04-01
+ * Last modification on 2014-10-05
*
* Adapted from source code of FeOS Sound System
* By fincs
@@ -187,7 +187,7 @@
chn->prio = this->prio;
chn->key = key;
chn->orgKey = bIsPCM ? noteDef->noteNumber : 69;
- chn->velocity = Cnv_Sust(vel);
+ chn->velocity = Cnv_Scale(vel);
chn->pan = static_cast<int>(noteDef->pan) - 64;
chn->modDelayCnt = 0;
chn->modCounter = 0;
@@ -229,7 +229,7 @@
chn->flags.reset();
chn->prio = this->prio;
chn->key = key;
- chn->velocity = Cnv_Sust(vel);
+ chn->velocity = Cnv_Scale(vel);
chn->modDelayCnt = 0;
chn->modCounter = 0;
--- a/src/in_ncsf/SSEQPlayer/common.h
+++ b/src/in_ncsf/SSEQPlayer/common.h
@@ -1,7 +1,7 @@
/*
* SSEQ Player - Common functions
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
- * Last modification on 2014-09-08
+ * Last modification on 2014-10-05
*
* Some code from FeOS Sound System
* By fincs
@@ -159,6 +159,33 @@
return ((fall << 1) + 1) & 0xFFFF;
else
return (0x1E00 / (0x7E - fall)) & 0xFFFF;
+}
+
+// This function actually doesn't come from FSS, I got the lookup table from the Nintendo DS SDK.
+inline int Cnv_Scale(int scale)
+{
+ static const int16_t lut[] =
+ {
+ -32768, -421, -361, -325, -300, -281, -265, -252,
+ -240, -230, -221, -212, -205, -198, -192, -186,
+ -180, -175, -170, -165, -161, -156, -152, -148,
+ -145, -141, -138, -134, -131, -128, -125, -122,
+ -120, -117, -114, -112, -110, -107, -105, -103,
+ -100, -98, -96, -94, -92, -90, -88, -86,
+ -85, -83, -81, -79, -78, -76, -74, -73,
+ -71, -70, -68, -67, -65, -64, -62, -61,
+ -60, -58, -57, -56, -54, -53, -52, -51,
+ -49, -48, -47, -46, -45, -43, -42, -41,
+ -40, -39, -38, -37, -36, -35, -34, -33,
+ -32, -31, -30, -29, -28, -27, -26, -25,
+ -24, -23, -23, -22, -21, -20, -19, -18,
+ -17, -17, -16, -15, -14, -13, -12, -12,
+ -11, -10, -9, -9, -8, -7, -6, -6,
+ -5, -4, -3, -3, -2, -1, -1, 0
+ };
+ if (scale & 0x80)
+ scale = 0x7F;
+ return lut[scale];
}
inline int Cnv_Sust(int sust)
@@ -184,7 +211,7 @@
};
if (sust & 0x80) // Supposedly invalid value...
- sust = 0; // Use apparently correct default
+ sust = 0x7F; // Use apparently correct default
return lut[sust];
}
--- a/src/in_ncsf/XSFConfig_NCSF.cpp
+++ b/src/in_ncsf/XSFConfig_NCSF.cpp
@@ -1,15 +1,17 @@
/*
* xSF - NCSF configuration
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
- * Last modification on 2014-09-28
+ * Last modification on 2014-10-05
*
* Partially based on the vio*sf framework
*/
-#include <bitset>
-#include "XSFPlayer_NCSF.h"
-#include "XSFConfig.h"
+#include "XSFConfig_NCSF.h"
#include "convert.h"
+#ifdef _DEBUG
+# include "resource.h"
+# include <CommCtrl.h>
+#endif
enum
{
@@ -17,31 +19,9 @@
idMutes
};
-class XSFConfig_NCSF : public XSFConfig
-{
-protected:
- static unsigned initInterpolation;
- static std::string initMutes;
-
- friend class XSFConfig;
- unsigned interpolation;
- std::bitset<16> mutes;
-
- XSFConfig_NCSF();
- void LoadSpecificConfig();
- void SaveSpecificConfig();
- void GenerateSpecificDialogs();
- INT_PTR CALLBACK ConfigDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
- void ResetSpecificConfigDefaults(HWND hwndDlg);
- void SaveSpecificConfigDialog(HWND hwndDlg);
- void CopySpecificConfigToMemory(XSFPlayer *xSFPlayer, bool preLoad);
-public:
- void About(HWND parent);
-};
-
unsigned XSFConfig::initSampleRate = 44100;
std::string XSFConfig::commonName = "NCSF Decoder";
-std::string XSFConfig::versionNumber = "1.9";
+std::string XSFConfig::versionNumber = "1.9.1";
unsigned XSFConfig_NCSF::initInterpolation = 4;
std::string XSFConfig_NCSF::initMutes = "0000000000000000";
@@ -51,6 +31,9 @@
}
XSFConfig_NCSF::XSFConfig_NCSF() : XSFConfig(), interpolation(0), mutes()
+#ifdef _DEBUG
+ , soundViewData()
+#endif
{
this->supportedSampleRates.push_back(8000);
this->supportedSampleRates.push_back(11025);
@@ -131,7 +114,7 @@
void XSFConfig_NCSF::CopySpecificConfigToMemory(XSFPlayer *xSFPlayer, bool)
{
- XSFPlayer_NCSF *NCSFPlayer = static_cast<XSFPlayer_NCSF *>(xSFPlayer);
+ auto NCSFPlayer = static_cast<XSFPlayer_NCSF *>(xSFPlayer);
NCSFPlayer->SetInterpolation(this->interpolation);
NCSFPlayer->SetMutes(this->mutes);
}
@@ -142,3 +125,223 @@
"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);
}
+#ifdef _DEBUG
+INT_PTR CALLBACK XSFConfig_NCSF::SoundViewDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ auto data = reinterpret_cast<SoundViewData *>(GetWindowLongW(hwndDlg, DWLP_USER));
+ if (!data && uMsg != WM_INITDIALOG)
+ return false;
+
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ if (!data)
+ {
+ data = reinterpret_cast<SoundViewData *>(lParam);
+ SetWindowLongW(hwndDlg, DWLP_USER, reinterpret_cast<LONG>(data));
+ }
+ data->hDlg = hwndDlg;
+ for (int chanId = 0; chanId < 16; ++chanId)
+ {
+ SendDlgItemMessageW(hwndDlg, IDC_SOUND0VOLBAR + chanId, PBM_SETRANGE, 0, MAKELPARAM(0, 128));
+ SendDlgItemMessageW(hwndDlg, IDC_SOUND0PANBAR + chanId, PBM_SETRANGE, 0, MAKELPARAM(0, 128));
+ SendDlgItemMessageW(hwndDlg, IDC_SOUND0MUTE + chanId, BM_SETCHECK, data->config->mutes[chanId], 0);
+ }
+ break;
+ case WM_CLOSE:
+ case WM_DESTROY:
+ data->config->CloseSoundView();
+ break;
+ case WM_COMMAND:
+ {
+ auto id = GET_WM_COMMAND_ID(wParam, lParam);
+ switch (id)
+ {
+ case IDC_BUTTON_VOLMODE:
+ data->volModeAlternative = !!IsDlgButtonChecked(hwndDlg, IDC_BUTTON_VOLMODE);
+ break;
+ case IDC_SOUND0MUTE:
+ case IDC_SOUND1MUTE:
+ case IDC_SOUND2MUTE:
+ case IDC_SOUND3MUTE:
+ case IDC_SOUND4MUTE:
+ case IDC_SOUND5MUTE:
+ case IDC_SOUND6MUTE:
+ case IDC_SOUND7MUTE:
+ case IDC_SOUND8MUTE:
+ case IDC_SOUND9MUTE:
+ case IDC_SOUND10MUTE:
+ case IDC_SOUND11MUTE:
+ case IDC_SOUND12MUTE:
+ case IDC_SOUND13MUTE:
+ case IDC_SOUND14MUTE:
+ case IDC_SOUND15MUTE:
+ data->config->mutes[id - IDC_SOUND0MUTE] = !!IsDlgButtonChecked(hwndDlg, id);
+ data->config->SaveConfig();
+ data->player->SetMutes(data->config->mutes);
+ break;
+ case IDC_SOUND_UNMUTE_ALL:
+ for (int chanId = 0; chanId < 16; ++chanId)
+ SendDlgItemMessageW(hwndDlg, IDC_SOUND0MUTE + chanId, BM_SETCHECK, false, 0);
+ data->config->mutes.reset();
+ data->config->SaveConfig();
+ data->player->SetMutes(data->config->mutes);
+ break;
+ default:
+ return false;
+ }
+ }
+ break;
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+void XSFConfig_NCSF::CallSoundView(XSFPlayer *xSFPlayer, HINSTANCE hInstance, HWND hwndParent)
+{
+ this->soundViewData.reset(new SoundViewData);
+ this->soundViewData->config = this;
+ this->soundViewData->player = static_cast<XSFPlayer_NCSF *>(xSFPlayer);
+
+ auto hDlg = CreateDialogParamW(hInstance, MAKEINTRESOURCEW(IDD_SOUND_VIEW), hwndParent, XSFConfig_NCSF::SoundViewDialogProc, reinterpret_cast<LPARAM>(this->soundViewData.get()));
+ if (!hDlg)
+ {
+ this->soundViewData.reset();
+ return;
+ }
+
+ ShowWindow(hDlg, SW_SHOW);
+ UpdateWindow(hDlg);
+}
+
+static inline void ProgressSetPosImmediate(HWND hDlg, int nIDDlgItem, int nPos)
+{
+ int nMin = SendDlgItemMessageW(hDlg, nIDDlgItem, PBM_GETRANGE, true, reinterpret_cast<LPARAM>(nullptr));
+ int nMax = SendDlgItemMessageW(hDlg, nIDDlgItem, PBM_GETRANGE, false, reinterpret_cast<LPARAM>(nullptr));
+
+ // get rid of fancy progress animation since Windows Vista
+ // http://stackoverflow.com/questions/1061715/how-do-i-make-tprogressbar-stop-lagging
+ if (nPos < nMax)
+ {
+ SendDlgItemMessageW(hDlg, nIDDlgItem, PBM_SETPOS, nPos + 1, 0);
+ SendDlgItemMessageW(hDlg, nIDDlgItem, PBM_SETPOS, nPos, 0); // This will set Progress backwards and give an instant update
+ }
+ else
+ {
+ SendDlgItemMessageW(hDlg, nIDDlgItem, PBM_SETRANGE32, nMin, nPos + 1);
+ SendDlgItemMessageW(hDlg, nIDDlgItem, PBM_SETPOS, nPos + 1, 0);
+ SendDlgItemMessageW(hDlg, nIDDlgItem, PBM_SETRANGE32, nMin, nPos); // This will also set Progress backwards also so instant update
+ }
+}
+
+static inline int32_t muldiv7(int32_t val, uint8_t mul)
+{
+ return mul == 127 ? val : ((val * mul) >> 7);
+}
+
+void XSFConfig_NCSF::RefreshSoundView()
+{
+ auto player = this->soundViewData->player;
+ auto hDlg = this->soundViewData->hDlg;
+ std::wstring buf;
+ for (size_t chanId = 0; chanId < 16; ++chanId)
+ {
+ auto &chn = player->GetChannel(chanId);
+
+ if (chn.state > CS_START)
+ {
+ ProgressSetPosImmediate(hDlg, IDC_SOUND0PANBAR + chanId, muldiv7(128, chn.reg.panning));
+ uint8_t datashift = chn.reg.volumeDiv;
+ if (datashift == 3)
+ datashift = 4;
+ int32_t vol = muldiv7(128, chn.reg.volumeMul) >> datashift;
+ ProgressSetPosImmediate(hDlg, IDC_SOUND0VOLBAR + chanId, vol);
+
+ if (this->soundViewData->volModeAlternative)
+ buf = wstringify(chn.reg.volumeMul) + L"/" + wstringify(1 << datashift);
+ else
+ buf = wstringify(vol);
+ SetDlgItemTextW(hDlg, IDC_SOUND0VOL + chanId, buf.c_str());
+
+ if (!chn.reg.panning)
+ buf = L"L";
+ else if (chn.reg.panning == 64)
+ buf = L"C";
+ else if (chn.reg.panning == 127)
+ buf = L"R";
+ else if (chn.reg.panning < 64)
+ buf = L"L" + wstringify(64 - chn.reg.panning);
+ else //if (chn.reg.panning > 64)
+ buf = L"R" + wstringify(chn.reg.panning - 64);
+ SetDlgItemTextW(hDlg, IDC_SOUND0PAN + chanId, buf.c_str());
+
+ SetDlgItemTextW(hDlg, IDC_SOUND0HOLD + chanId, L"---");
+ SetDlgItemTextW(hDlg, IDC_SOUND0BUSY + chanId, L"---");
+
+ static const std::wstring modes[] = { L"Manual", L"Loop Infinite", L"One-Shot", L"Prohibited" };
+ SetDlgItemTextW(hDlg, IDC_SOUND0REPEATMODE + chanId, (wstringify(chn.reg.repeatMode) + L" (" + modes[chn.reg.repeatMode] + L")").c_str());
+
+ if (chn.reg.format != 3)
+ {
+ static const std::wstring formats[] = { L"PCM8", L"PCM16", L"IMA-ADPCM" };
+ SetDlgItemTextW(hDlg, IDC_SOUND0FORMAT + chanId, (wstringify(chn.reg.format) + L" (" + formats[chn.reg.format] + L")").c_str());
+ }
+ else
+ {
+ buf = L"3 (";
+ if (chanId < 8)
+ buf += L"PSG/Noise?";
+ else if (chanId < 14)
+ buf += wstringify(chn.reg.waveDuty == 7 ? 0 : 12.5 * (chn.reg.waveDuty + 1)) + L"% Square";
+ else
+ buf += L"Noise";
+ buf += L")";
+ SetDlgItemTextW(hDlg, IDC_SOUND0FORMAT + chanId, buf.c_str());
+ }
+
+ SetDlgItemTextW(hDlg, IDC_SOUND0SAD + chanId, L"---");
+
+ SetDlgItemTextW(hDlg, IDC_SOUND0PNT + chanId, (L"samp #" + wstringify(chn.reg.loopStart)).c_str());
+
+ std::wstring tmpBuf = ConvertFuncs::StringToWString(NumToHexString(chn.reg.timer)).substr(2);
+ buf = L"$" + tmpBuf + L" (";
+ tmpBuf = wstringify((ARM7_CLOCK / 2) / static_cast<double>(0x10000 - chn.reg.timer));
+ if (tmpBuf.find('.') != std::wstring::npos)
+ tmpBuf = tmpBuf.substr(0, tmpBuf.find('.') + 2);
+ buf += tmpBuf + L" Hz)";
+ SetDlgItemTextW(hDlg, IDC_SOUND0TMR + chanId, buf.c_str());
+
+ SetDlgItemTextW(hDlg, IDC_SOUND0POSLEN + chanId, (L"samp #" + wstringify(static_cast<uint32_t>(chn.reg.samplePosition)) + L" / " + wstringify(chn.reg.totalLength)).c_str());
+ }
+ else if (this->soundViewData->channelLastStates[chanId] != CS_NONE)
+ {
+ ProgressSetPosImmediate(hDlg, IDC_SOUND0PANBAR + chanId, 0);
+ ProgressSetPosImmediate(hDlg, IDC_SOUND0VOLBAR + chanId, 0);
+ SetDlgItemTextW(hDlg, IDC_SOUND0VOL + chanId, L"---");
+ SetDlgItemTextW(hDlg, IDC_SOUND0PAN + chanId, L"---");
+ SetDlgItemTextW(hDlg, IDC_SOUND0HOLD + chanId, L"---");
+ SetDlgItemTextW(hDlg, IDC_SOUND0BUSY + chanId, L"---");
+ SetDlgItemTextW(hDlg, IDC_SOUND0REPEATMODE + chanId, L"---");
+ SetDlgItemTextW(hDlg, IDC_SOUND0FORMAT + chanId, L"---");
+ SetDlgItemTextW(hDlg, IDC_SOUND0SAD + chanId, L"---");
+ SetDlgItemTextW(hDlg, IDC_SOUND0PNT + chanId, L"---");
+ SetDlgItemTextW(hDlg, IDC_SOUND0TMR + chanId, L"---");
+ SetDlgItemTextW(hDlg, IDC_SOUND0POSLEN + chanId, L"---");
+ }
+
+ this->soundViewData->channelLastStates[chanId] = chn.state;
+ }
+}
+
+void XSFConfig_NCSF::CloseSoundView()
+{
+ if (this->soundViewData)
+ {
+ DestroyWindow(this->soundViewData->hDlg);
+ this->soundViewData.reset();
+ }
+}
+#endif
+
--- /dev/null
+++ b/src/in_ncsf/XSFConfig_NCSF.h
@@ -1,1 +1,70 @@
+/*
+ * xSF - NCSF configuration
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
+ * Last modification on 2014-10-05
+ *
+ * Partially based on the vio*sf framework
+ */
+#pragma once
+
+#include <bitset>
+#include <memory>
+#include "XSFConfig.h"
+#include "XSFPlayer_NCSF.h"
+#include "windowsh_wrapper.h"
+
+class XSFConfig_NCSF;
+
+#ifdef _DEBUG
+struct SoundViewData
+{
+ XSFConfig_NCSF *config;
+ XSFPlayer_NCSF *player;
+ uint8_t channelLastStates[16];
+ HWND hDlg;
+
+ bool volModeAlternative;
+
+ SoundViewData() : config(nullptr), player(nullptr), hDlg(nullptr), volModeAlternative(false)
+ {
+ std::fill_n(&this->channelLastStates[0], sizeof(this->channelLastStates), CS_START);
+ }
+};
+#endif
+
+class XSFConfig_NCSF : public XSFConfig
+{
+protected:
+ static unsigned initInterpolation;
+ static std::string initMutes;
+
+ friend class XSFConfig;
+ friend struct SoundViewData;
+ unsigned interpolation;
+ std::bitset<16> mutes;
+
+ XSFConfig_NCSF();
+ void LoadSpecificConfig();
+ void SaveSpecificConfig();
+ void GenerateSpecificDialogs();
+ INT_PTR CALLBACK ConfigDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+ void ResetSpecificConfigDefaults(HWND hwndDlg);
+ void SaveSpecificConfigDialog(HWND hwndDlg);
+ void CopySpecificConfigToMemory(XSFPlayer *xSFPlayer, bool preLoad);
+
+#ifdef _DEBUG
+ std::unique_ptr<SoundViewData> soundViewData;
+
+ static INT_PTR CALLBACK SoundViewDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+#endif
+public:
+ void About(HWND parent);
+
+#ifdef _DEBUG
+ void CallSoundView(XSFPlayer *xSFPlayer, HINSTANCE hInstance, HWND hwndParent);
+ void RefreshSoundView();
+ void CloseSoundView();
+#endif
+};
+
--- a/src/in_ncsf/XSFPlayer_NCSF.cpp
+++ b/src/in_ncsf/XSFPlayer_NCSF.cpp
@@ -1,7 +1,7 @@
/*
* xSF - NCSF Player
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
- * Last modification on 2014-09-24
+ * Last modification on 2014-10-05
*
* Partially based on the vio*sf framework
*
@@ -13,12 +13,15 @@
#include <zlib.h>
#include "convert.h"
#include "XSFPlayer_NCSF.h"
+#include "XSFConfig_NCSF.h"
#include "XSFCommon.h"
#include "SSEQPlayer/SDAT.h"
#include "SSEQPlayer/Player.h"
const char *XSFPlayer::WinampDescription = "NCSF Decoder";
const char *XSFPlayer::WinampExts = "ncsf;minincsf\0DS Nitro Composer Sound Format files (*.ncsf;*.minincsf)\0";
+
+extern XSFConfig *xSFConfig;
XSFPlayer *XSFPlayer::Create(const std::string &fn)
{
@@ -115,10 +118,52 @@
}
#endif
+#ifdef _DEBUG
+static HANDLE soundViewThreadHandle = INVALID_HANDLE_VALUE;
+static bool killSoundViewThread;
+
+static DWORD WINAPI soundViewThread(void *b)
+{
+ auto xSFConfig_NCSF = static_cast<XSFConfig_NCSF *>(xSFConfig);
+ xSFConfig_NCSF->CallSoundView(static_cast<XSFPlayer_NCSF *>(b), xSFConfig->GetHInstance(), nullptr);
+ MSG msg;
+ while (!killSoundViewThread)
+ {
+ xSFConfig_NCSF->RefreshSoundView();
+ if (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE))
+ {
+ TranslateMessage(&msg);
+ DispatchMessageW(&msg);
+ }
+ }
+ xSFConfig_NCSF->CloseSoundView();
+ return 0;
+}
+#endif
+
+XSFPlayer_NCSF::~XSFPlayer_NCSF()
+{
+#ifdef _DEBUG
+ killSoundViewThread = true;
+ if (WaitForSingleObject(soundViewThreadHandle, 2000) == WAIT_TIMEOUT)
+ {
+ TerminateThread(soundViewThreadHandle, 0);
+ static_cast<XSFConfig_NCSF *>(xSFConfig)->CloseSoundView();
+ }
+ CloseHandle(soundViewThreadHandle);
+ soundViewThreadHandle = INVALID_HANDLE_VALUE;
+#endif
+}
+
bool XSFPlayer_NCSF::Load()
{
if (!this->LoadNCSF())
return false;
+
+#ifdef _DEBUG
+ killSoundViewThread = false;
+ soundViewThreadHandle = CreateThread(nullptr, 0, soundViewThread, this, 0, nullptr);
+#endif
PseudoFile file;
file.data = &this->sdatData;
@@ -212,3 +257,10 @@
this->mutes = newMutes;
}
+#ifdef _DEBUG
+const Channel &XSFPlayer_NCSF::GetChannel(size_t chanNum) const
+{
+ return this->player.channels[chanNum];
+}
+#endif
+
--- a/src/in_ncsf/XSFPlayer_NCSF.h
+++ b/src/in_ncsf/XSFPlayer_NCSF.h
@@ -1,7 +1,7 @@
/*
* xSF - NCSF Player
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
- * Last modification on 2014-09-24
+ * Last modification on 2014-10-05
*
* Partially based on the vio*sf framework
*
@@ -36,11 +36,15 @@
#ifdef _WIN32
XSFPlayer_NCSF(const std::wstring &filename);
#endif
+ ~XSFPlayer_NCSF();
bool Load();
void GenerateSamples(std::vector<uint8_t> &buf, unsigned offset, unsigned samples);
void Terminate();
void SetInterpolation(unsigned interpolation);
void SetMutes(const std::bitset<16> &newMutes);
+#ifdef _DEBUG
+ const Channel &GetChannel(size_t chanNum) const;
+#endif
};
Binary files /dev/null and b/src/in_ncsf/in_ncsf.rc differ
--- a/src/in_ncsf/in_ncsf.vcxproj
+++ b/src/in_ncsf/in_ncsf.vcxproj
@@ -97,6 +97,7 @@
<ClCompile Include="XSFPlayer_NCSF.cpp" />
</ItemGroup>
<ItemGroup>
+ <ClInclude Include="resource.h" />
<ClInclude Include="SSEQPlayer\Channel.h" />
<ClInclude Include="SSEQPlayer\common.h" />
<ClInclude Include="SSEQPlayer\consts.h" />
@@ -112,6 +113,7 @@
<ClInclude Include="SSEQPlayer\SWAV.h" />
<ClInclude Include="SSEQPlayer\SYMBSection.h" />
<ClInclude Include="SSEQPlayer\Track.h" />
+ <ClInclude Include="XSFConfig_NCSF.h" />
<ClInclude Include="XSFPlayer_NCSF.h" />
</ItemGroup>
<ItemGroup>
@@ -119,6 +121,11 @@
<Project>{9d6d2540-b3dc-462b-bbc0-5b7c32a4d581}</Project>
</ProjectReference>
</ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="in_ncsf.rc">
+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
+ </ResourceCompile>
+ </ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
--- a/src/in_ncsf/in_ncsf.vcxproj.filters
+++ b/src/in_ncsf/in_ncsf.vcxproj.filters
@@ -113,8 +113,19 @@
<ClInclude Include="SSEQPlayer\Track.h">
<Filter>Header Files\SSEQPlayer</Filter>
</ClInclude>
+ <ClInclude Include="resource.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="XSFConfig_NCSF.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
<ClInclude Include="XSFPlayer_NCSF.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="in_ncsf.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
</Project>
Binary files /dev/null and b/src/in_ncsf/resource.h differ
--- a/src/in_xsf_framework/XSFConfig.cpp
+++ b/src/in_xsf_framework/XSFConfig.cpp
@@ -1,7 +1,7 @@
/*
* xSF - Core configuration handler
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
- * Last modification on 2014-09-24
+ * Last modification on 2014-10-05
*
* Partially based on the vio*sf framework
*/
@@ -321,12 +321,12 @@
void XSFConfig::CallConfigDialog(HINSTANCE hInstance, HWND hwndParent)
{
- DialogBoxIndirectParam(hInstance, this->configDialog.GenerateTemplate(), hwndParent, XSFConfig::ConfigDialogProcStatic, reinterpret_cast<LPARAM>(this));
+ DialogBoxIndirectParamW(hInstance, this->configDialog.GenerateTemplate(), hwndParent, XSFConfig::ConfigDialogProcStatic, reinterpret_cast<LPARAM>(this));
}
void XSFConfig::CallInfoDialog(HINSTANCE hInstance, HWND hwndParent)
{
- DialogBoxIndirectParam(hInstance, this->infoDialog.GenerateTemplate(), hwndParent, XSFConfig::InfoDialogProcStatic, reinterpret_cast<LPARAM>(this));
+ DialogBoxIndirectParamW(hInstance, this->infoDialog.GenerateTemplate(), hwndParent, XSFConfig::InfoDialogProcStatic, reinterpret_cast<LPARAM>(this));
}
void XSFConfig::ResetConfigDefaults(HWND hwndDlg)
@@ -370,6 +370,16 @@
this->CopySpecificConfigToMemory(xSFPlayer, preLoad);
}
+void XSFConfig::SetHInstance(HINSTANCE hInstance)
+{
+ this->configIO->SetHInstance(hInstance);
+}
+
+HINSTANCE XSFConfig::GetHInstance() const
+{
+ return this->configIO->GetHInstance();
+}
+
bool XSFConfig::GetPlayInfinitely() const
{
return this->playInfinitely;
--- a/src/in_xsf_framework/XSFConfig.h
+++ b/src/in_xsf_framework/XSFConfig.h
@@ -1,7 +1,7 @@
/*
* xSF - Core configuration handler
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
- * Last modification on 2014-09-24
+ * Last modification on 2014-10-05
*
* Partially based on the vio*sf framework
*/
@@ -27,9 +27,11 @@
virtual void SetValueString(const std::string &name, const std::string &value) = 0;
template<typename T> void SetValue(const std::string &name, const T &value) { this->SetValueString(name, stringify(value)); }
void SetValue(const std::string &name, const std::string &value) { this->SetValueString(name, value); }
- virtual std::string GetValueString(const std::string &name, const std::string &defaultValue) = 0;
- template<typename T> T GetValue(const std::string &name, const T &defaultValue) { return convertTo<T>(this->GetValueString(name, stringify(defaultValue))); }
- std::string GetValue(const std::string &name, const std::string &defaultValue) { return this->GetValueString(name, defaultValue); }
+ virtual std::string GetValueString(const std::string &name, const std::string &defaultValue) const = 0;
+ template<typename T> T GetValue(const std::string &name, const T &defaultValue) const { return convertTo<T>(this->GetValueString(name, stringify(defaultValue))); }
+ std::string GetValue(const std::string &name, const std::string &defaultValue) const { return this->GetValueString(name, defaultValue); }
+ virtual void SetHInstance(HINSTANCE) { }
+ virtual HINSTANCE GetHInstance() const { return nullptr; }
};
class XSFConfig
@@ -81,6 +83,8 @@
void ResetConfigDefaults(HWND hwndDlg);
void SaveConfigDialog(HWND hwndDlg);
void CopyConfigToMemory(XSFPlayer *xSFPlayer, bool preLoad);
+ void SetHInstance(HINSTANCE hInstance);
+ HINSTANCE GetHInstance() const;
virtual void About(HWND parent) = 0;
--- a/src/in_xsf_framework/XSFConfig_Winamp.cpp
+++ b/src/in_xsf_framework/XSFConfig_Winamp.cpp
@@ -1,7 +1,7 @@
/*
* xSF - Winamp-specification configuration handler
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
- * Last modification on 2014-09-24
+ * Last modification on 2014-10-05
*
* Partially based on the vio*sf framework
*/
@@ -18,11 +18,14 @@
protected:
friend class XSFConfigIO;
std::wstring iniFilename;
+ HINSTANCE hInst;
XSFConfigIO_Winamp();
public:
void SetValueString(const std::string &name, const std::string &value);
- std::string GetValueString(const std::string &name, const std::string &defaultValue);
+ std::string GetValueString(const std::string &name, const std::string &defaultValue) const;
+ void SetHInstance(HINSTANCE hInstance);
+ HINSTANCE GetHInstance() const;
};
XSFConfigIO *XSFConfigIO::Create()
@@ -57,7 +60,7 @@
WritePrivateProfileStringW(ConvertFuncs::StringToWString(XSFConfig::commonName).c_str(), ConvertFuncs::StringToWString(name).c_str(), ConvertFuncs::StringToWString(value).c_str(), this->iniFilename.c_str());
}
-std::string XSFConfigIO_Winamp::GetValueString(const std::string &name, const std::string &defaultValue)
+std::string XSFConfigIO_Winamp::GetValueString(const std::string &name, const std::string &defaultValue) const
{
auto value = std::vector<wchar_t>(MAX_PATH / 2);
@@ -74,3 +77,13 @@
return ConvertFuncs::WStringToString(std::wstring(value.begin(), value.begin() + result));
}
+void XSFConfigIO_Winamp::SetHInstance(HINSTANCE hInstance)
+{
+ this->hInst = hInstance;
+}
+
+HINSTANCE XSFConfigIO_Winamp::GetHInstance() const
+{
+ return this->hInst;
+}
+
--- a/src/in_xsf_framework/in_xsf.cpp
+++ b/src/in_xsf_framework/in_xsf.cpp
@@ -1,7 +1,7 @@
/*
* xSF - Winamp plugin
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
- * Last modification on 2014-09-25
+ * Last modification on 2014-10-05
*
* Partially based on the vio*sf framework
*/
@@ -93,6 +93,7 @@
xSFConfig = XSFConfig::Create();
xSFConfig->LoadConfig();
xSFConfig->GenerateDialogs();
+ xSFConfig->SetHInstance(inMod.hDllInstance);
}
void quit()