Added new interpolation methods, added version number in plugin description.
--- 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 2013-03-30
+ * Last modification on 2013-04-02
*
* Adapted from source code of FeOS Sound System
* By fincs
@@ -576,17 +576,97 @@
static const double M_PI = 3.14159265358979323846;
#endif
-int32_t Channel::Interpolate(int32_t a, int32_t b, double ratio)
-{
- float ratiof = static_cast<float>(ratio);
- ratiof -= static_cast<int32_t>(ratiof);
- if (this->ply->interpolation == INTERPOLATION_COSINE)
- {
- double ratio2 = (1.0 - std::cos(ratiof * M_PI)) * 0.5;
- return static_cast<int32_t>((1 - ratio2) * a + ratio2 * b);
- }
+// Linear and Cosine interpolation code originally from DeSmuME
+// B-spline, Hermite, and Optimal come from Olli Niemitalo:
+// http://www.student.oulu.fi/~oniemita/dsp/deip.pdf
+int32_t Channel::Interpolate()
+{
+ double ratio = this->reg.samplePosition;
+ ratio -= static_cast<int32_t>(ratio);
+
+ uint32_t loc = static_cast<uint32_t>(this->reg.samplePosition);
+ const auto &data = &this->reg.source->data[loc];
+ int32_t a = data[0], b;
+ if (loc + 1 < this->reg.loopStart + this->reg.length)
+ b = data[1];
else
- return static_cast<int32_t>((1 - ratiof) * a + ratiof * b);
+ {
+ if (loc)
+ {
+ int32_t am1 = data[-1];
+ b = 2 * a - am1;
+ }
+ else
+ b = a;
+ }
+
+ if (this->ply->interpolation == INTERPOLATION_BSPLINE || this->ply->interpolation == INTERPOLATION_HERMITE || this->ply->interpolation == INTERPOLATION_OPTIMAL)
+ {
+ int32_t c, z;
+ if (loc + 2 < this->reg.loopStart + this->reg.length)
+ c = data[2];
+ else
+ {
+ if (loc)
+ {
+ int32_t am1 = data[-1];
+ c = 3 * a - 2 * am1;
+ }
+ else
+ c = a;
+ }
+ if (loc)
+ z = data[-1];
+ else
+ {
+ if (loc + 1 < this->reg.loopStart + this->reg.length)
+ {
+ int32_t ap1 = data[1];
+ z = 2 * a - ap1;
+ }
+ else
+ z = a;
+ }
+
+ double c0, c1, c2, c3;
+
+ if (this->ply->interpolation == INTERPOLATION_BSPLINE)
+ {
+ double zpb = z + b;
+ c0 = 1 / 6.0 * zpb + 2 / 3.0 * a;
+ c1 = 0.5 * (b - z);
+ c2 = 0.5 * zpb - a;
+ c3 = 0.5 * (a - b) + 1 / 6.0 * (c - z);
+ return static_cast<int32_t>(((c3 * ratio + c2) * ratio + c1) * ratio + c0);
+ }
+ if (this->ply->interpolation == INTERPOLATION_HERMITE)
+ {
+ c0 = a;
+ c1 = 0.5 * (b - z);
+ c2 = z - 2.5 * a + 2 * b - 0.5 * c;
+ c3 = 0.5 * (c - z) + 1.5 * (a - b);
+ return static_cast<int32_t>(((c3 * ratio + c2) * ratio + c1) * ratio + c0);
+ }
+ else
+ {
+ ratio -= 0.5;
+ double even1 = b + a, odd1 = b - a;
+ double even2 = c + z, odd2 = c - z;
+ c0 = even1 * 0.46835497211269561 + even2 * 0.03164502784253309;
+ c1 = odd1 * 0.56001293337091440 + odd2 * 0.14666238593949288;
+ c2 = even1 * -0.250038759826233691 + even2 * 0.25003876124297131;
+ c3 = odd1 * -0.49949850957839148 + odd2 * 0.16649935475113800;
+ double c4 = even1 * 0.00016095224137360 + even2 * -0.00016095810460478;
+ return static_cast<int32_t>((((c4 * ratio + c3) * ratio + c2) * ratio + c1) * ratio + c0);
+ }
+ }
+ else if (this->ply->interpolation == INTERPOLATION_COSINE)
+ {
+ double ratio2 = (1.0 - std::cos(ratio * M_PI)) * 0.5;
+ return static_cast<int32_t>(a + ratio2 * (b - a));
+ }
+ else
+ return static_cast<int32_t>(a + ratio * (b - a));
}
int32_t Channel::GenerateSample()
@@ -599,16 +679,7 @@
if (this->ply->interpolation == INTERPOLATION_NONE)
return this->reg.source->data[static_cast<uint32_t>(this->reg.samplePosition)];
else
- {
- uint32_t loc = static_cast<uint32_t>(this->reg.samplePosition);
- int32_t a = this->reg.source->data[loc], b;
- if (loc < static_cast<uint32_t>(this->reg.loopStart + this->reg.length - 1))
- {
- b = this->reg.source->data[loc + 1];
- a = this->Interpolate(a, b, this->reg.samplePosition);
- }
- return a;
- }
+ return this->Interpolate();
}
else
{
--- a/src/in_ncsf/SSEQPlayer/Channel.h
+++ b/src/in_ncsf/SSEQPlayer/Channel.h
@@ -1,7 +1,7 @@
/*
* SSEQ Player - Channel structures
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
- * Last modification on 2013-03-21
+ * Last modification on 2013-04-02
*
* Adapted from source code of FeOS Sound System
* By fincs
@@ -15,6 +15,7 @@
#define SSEQPLAYER_CHANNEL_H
#include <bitset>
+#include <tuple>
#include "SWAV.h"
#include "Track.h"
#include "pstdint.h"
@@ -135,7 +136,7 @@
void Kill();
void UpdateTrack();
void Update();
- int32_t Interpolate(int32_t a, int32_t b, double ratio);
+ int32_t Interpolate();
int32_t GenerateSample();
void IncrementSample();
};
--- a/src/in_ncsf/SSEQPlayer/consts.h
+++ b/src/in_ncsf/SSEQPlayer/consts.h
@@ -1,7 +1,7 @@
/*
* SSEQ Player - Constants/Macros
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
- * Last modification on 2013-03-21
+ * Last modification on 2013-04-02
*
* Adapted from source code of FeOS Sound System
* By fincs
@@ -51,7 +51,7 @@
inline uint32_t SOUND_FORMAT(int n) { return n << 29; }
const uint32_t SCHANNEL_ENABLE = BIT(31);
-enum Interpolation { INTERPOLATION_NONE, INTERPOLATION_LINEAR, INTERPOLATION_COSINE };
+enum Interpolation { INTERPOLATION_NONE, INTERPOLATION_LINEAR, INTERPOLATION_COSINE, INTERPOLATION_BSPLINE, INTERPOLATION_HERMITE, INTERPOLATION_OPTIMAL };
#endif
--- a/src/in_ncsf/XSFConfig_NCSF.cpp
+++ b/src/in_ncsf/XSFConfig_NCSF.cpp
@@ -1,7 +1,7 @@
/*
* xSF - NCSF configuration
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
- * Last modification on 2013-03-25
+ * Last modification on 2013-04-02
*
* Partially based on the vio*sf framework
*/
@@ -42,8 +42,8 @@
unsigned XSFConfig::initSampleRate = 44100;
std::wstring XSFConfig::commonName = L"NCSF Decoder";
-std::wstring XSFConfig::versionNumber = L"1.0";
-unsigned XSFConfig_NCSF::initInterpolation = 2;
+std::wstring XSFConfig::versionNumber = L"1.1";
+unsigned XSFConfig_NCSF::initInterpolation = 5;
std::wstring XSFConfig_NCSF::initMutes = L"0000000000000000";
XSFConfig *XSFConfig::Create()
@@ -82,7 +82,7 @@
void XSFConfig_NCSF::GenerateSpecificDialogs()
{
this->configDialog.AddLabelControl(DialogLabelBuilder(L"Interpolation").WithSize(50, 8).InGroup(L"Output").WithRelativePositionToSibling(RelativePosition::FROM_BOTTOMLEFT, Point<short>(0, 10), 2).IsLeftJustified());
- this->configDialog.AddComboBoxControl(DialogComboBoxBuilder().WithSize(78, 14).InGroup(L"Output").WithRelativePositionToSibling(RelativePosition::FROM_TOPRIGHT, Point<short>(5, -3)).WithID(idInterpolation).
+ this->configDialog.AddComboBoxControl(DialogComboBoxBuilder().WithSize(90, 14).InGroup(L"Output").WithRelativePositionToSibling(RelativePosition::FROM_TOPRIGHT, Point<short>(5, -3)).WithID(idInterpolation).
IsDropDownList().WithTabStop());
this->configDialog.AddLabelControl(DialogLabelBuilder(L"Mute").WithSize(50, 8).InGroup(L"Output").WithRelativePositionToSibling(RelativePosition::FROM_BOTTOMLEFT, Point<short>(0, 10), 2).IsLeftJustified());
this->configDialog.AddListBoxControl(DialogListBoxBuilder().WithSize(78, 45).WithExactHeight().InGroup(L"Output").WithRelativePositionToSibling(RelativePosition::FROM_TOPRIGHT, Point<short>(5, -3)).WithID(idMutes).
@@ -98,6 +98,9 @@
SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"No Interpolation"));
SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"Linear Interpolation"));
SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"Cosine Interpolation"));
+ SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"B-spline Interpolation"));
+ SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"Hermite Interpolation"));
+ SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"Optimal Interpolation"));
SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_SETCURSEL, this->interpolation, 0);
// Mutes
for (int x = 0, numMutes = this->mutes.size(); x < numMutes; ++x)
--- 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 2013-03-30
+ * Last modification on 2013-04-02
*
* Partially based on the vio*sf framework
*/
@@ -46,6 +46,12 @@
XSFConfig::XSFConfig() : playInfinitely(false), skipSilenceOnStartSec(0), detectSilenceSec(0), defaultLength(0), defaultFade(0), volume(0.0), volumeType(VOLUMETYPE_NONE), peakType(PEAKTYPE_NONE),
sampleRate(0), titleFormat(L""), configDialog(), configDialogProperty(), infoDialog(), supportedSampleRates(), configIO(XSFConfigIO::Create())
{
+}
+
+const String &XSFConfig::CommonNameWithVersion()
+{
+ static const auto commonNameWithVersion = String(XSFConfig::commonName + L" v" + XSFConfig::versionNumber);
+ return commonNameWithVersion;
}
std::wstring XSFConfig::GetTextFromWindow(HWND hwnd)
--- 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 2013-03-30
+ * Last modification on 2013-04-02
*
* Partially based on the vio*sf framework
*/
@@ -69,6 +69,7 @@
static std::wstring versionNumber;
// The Create function is not defined in XSFConfig.cpp, it should be defined in your own config's source and return a pointer to your config's class.
static XSFConfig *Create();
+ static const String &CommonNameWithVersion();
virtual ~XSFConfig() { }
void LoadConfig();
--- 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 2013-03-30
+ * Last modification on 2013-04-02
*
* Partially based on the vio*sf framework
*/
@@ -258,7 +258,7 @@
In_Module inMod =
{
IN_VER,
- const_cast<char *>(XSFPlayer::WinampDescription), /* Unsafe but Winamp's SDK requires this */
+ const_cast<char *>(XSFConfig::CommonNameWithVersion().GetStrC()), /* Unsafe but Winamp's SDK requires this */
nullptr, /* Filled by Winamp */
nullptr, /* Filled by Winamp */
const_cast<char *>(XSFPlayer::WinampExts), /* Unsafe but Winamp's SDK requires this */