Updated NCSF player

CQTexperiment
Chris Moeller 2014-11-04 17:56:15 -08:00
parent 9eb0037780
commit 7896e73080
29 changed files with 2842 additions and 1396 deletions

View File

@ -1,220 +0,0 @@
/*
* String class in ANSI (or rather, current Windows code page), UTF-8, and UTF-16
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
* Last modification on 2013-03-25
*/
#ifndef BIGSSTRING_H
#define BIGSSTRING_H
#include <string>
#include <cstring>
#include <cwchar>
#include "UtfConverter.h"
#include "UTFEncodeDecode.h"
class String
{
public:
String(const std::locale &L = std::locale::classic()) : ansi(""), utf8(""), utf16(L""), loc(L) { }
String(const char *new_str, bool is_utf8 = false, const std::locale &L = std::locale::classic()) : ansi(is_utf8 ? DecodeFromUTF8(new_str, L) : new_str), utf8(is_utf8 ? new_str : EncodeToUTF8(new_str, L)),
utf16(UtfConverter::FromUtf8(utf8)), loc(L) { }
String(const std::string &new_str, bool is_utf8 = false, const std::locale &L = std::locale::classic()) : ansi(is_utf8 ? DecodeFromUTF8(new_str, L) : new_str), utf8(is_utf8 ? new_str : EncodeToUTF8(new_str, L)),
utf16(UtfConverter::FromUtf8(utf8)), loc(L) { }
String(const wchar_t *new_wstr, const std::locale &L = std::locale::classic()) : ansi(DecodeFromUTF8(UtfConverter::ToUtf8(new_wstr), L)), utf8(UtfConverter::ToUtf8(new_wstr)), utf16(new_wstr), loc(L) { }
String(const std::wstring &new_wstr, const std::locale &L = std::locale::classic()) : ansi(DecodeFromUTF8(UtfConverter::ToUtf8(new_wstr), L)), utf8(UtfConverter::ToUtf8(new_wstr)), utf16(new_wstr), loc(L) { }
bool empty() const { return this->utf8.empty(); }
std::string GetAnsi() const { return this->ansi; }
const char *GetAnsiC() const { return this->ansi.c_str(); }
std::string GetStr() const { return this->utf8; }
const char *GetStrC() const { return this->utf8.c_str(); }
std::wstring GetWStr() const { return this->utf16; }
const wchar_t *GetWStrC() const { return this->utf16.c_str(); }
bool operator==(const String &str2) const
{
return this->utf8 == str2.utf8;
}
String &operator=(const std::string &new_str)
{
this->ansi = DecodeFromUTF8(new_str, this->loc);
this->utf8 = new_str;
this->utf16 = UtfConverter::FromUtf8(new_str);
return *this;
}
String &operator=(const std::wstring &new_wstr)
{
this->utf8 = UtfConverter::ToUtf8(new_wstr);
this->ansi = DecodeFromUTF8(this->utf8, this->loc);
this->utf16 = new_wstr;
return *this;
}
String &operator=(const String &new_string)
{
if (this != &new_string)
{
this->ansi = new_string.ansi;
this->utf8 = new_string.utf8;
this->utf16 = new_string.utf16;
}
return *this;
}
String &SetISO8859_1(const std::string &new_str)
{
this->ansi = new_str;
this->utf8 = EncodeToUTF8(new_str, this->loc);
this->utf16 = UtfConverter::FromUtf8(this->utf8);
return *this;
}
String operator+(const String &str2) const
{
String new_string = String(*this);
new_string.ansi.append(str2.ansi);
new_string.utf8.append(str2.utf8);
new_string.utf16.append(str2.utf16);
return new_string;
}
String operator+(char chr) const
{
String new_string = String(*this);
char str2[] = { chr, 0 };
new_string.ansi.append(str2);
std::string new_utf8 = EncodeToUTF8(str2, this->loc);
new_string.utf8.append(new_utf8);
new_string.utf16.append(UtfConverter::FromUtf8(new_utf8));
return new_string;
}
String operator+(wchar_t wchr) const
{
String new_string = String(*this);
wchar_t wstr2[] = { wchr, 0 };
std::string new_utf8 = UtfConverter::ToUtf8(wstr2);
new_string.ansi.append(DecodeFromUTF8(new_utf8, this->loc));
new_string.utf8.append(new_utf8);
new_string.utf16.append(wstr2);
return new_string;
}
String operator+(const char *str2) const
{
String new_string = String(*this);
new_string.ansi.append(DecodeFromUTF8(str2, this->loc));
new_string.utf8.append(str2);
new_string.utf16.append(UtfConverter::FromUtf8(str2));
return new_string;
}
String operator+(const std::string &str2) const
{
String new_string = String(*this);
new_string.ansi.append(DecodeFromUTF8(str2, this->loc));
new_string.utf8.append(str2);
new_string.utf16.append(UtfConverter::FromUtf8(str2));
return new_string;
}
String operator+(const wchar_t *wstr2) const
{
String new_string = String(*this);
std::string new_utf8 = UtfConverter::ToUtf8(wstr2);
new_string.ansi.append(DecodeFromUTF8(new_utf8, this->loc));
new_string.utf8.append(new_utf8);
new_string.utf16.append(wstr2);
return new_string;
}
String operator+(const std::wstring &wstr2) const
{
String new_string = String(*this);
std::string new_utf8 = UtfConverter::ToUtf8(wstr2);
new_string.ansi.append(DecodeFromUTF8(new_utf8, this->loc));
new_string.utf8.append(new_utf8);
new_string.utf16.append(wstr2);
return new_string;
}
String &operator+=(const String &str2)
{
if (this != &str2)
{
this->ansi.append(str2.ansi);
this->utf8.append(str2.utf8);
this->utf16.append(str2.utf16);
}
return *this;
}
String &operator+=(char chr)
{
char str2[] = { chr, 0 };
this->ansi.append(str2);
std::string new_utf8 = EncodeToUTF8(str2, this->loc);
this->utf8.append(new_utf8);
this->utf16.append(UtfConverter::FromUtf8(new_utf8));
return *this;
}
String &operator+=(wchar_t wchr)
{
wchar_t wstr2[] = { wchr, 0 };
std::string new_utf8 = UtfConverter::ToUtf8(wstr2);
this->ansi.append(DecodeFromUTF8(new_utf8, this->loc));
this->utf8.append(new_utf8);
this->utf16.append(wstr2);
return *this;
}
String &operator+=(const char *str2)
{
this->ansi.append(DecodeFromUTF8(str2, this->loc));
this->utf8.append(str2);
this->utf16.append(UtfConverter::FromUtf8(str2));
return *this;
}
String &operator+=(const std::string &str2)
{
this->ansi.append(DecodeFromUTF8(str2, this->loc));
this->utf8.append(str2);
this->utf16.append(UtfConverter::FromUtf8(str2));
return *this;
}
String &operator+=(const wchar_t *wstr2)
{
std::string new_utf8 = UtfConverter::ToUtf8(wstr2);
this->ansi.append(DecodeFromUTF8(new_utf8, this->loc));
this->utf8.append(new_utf8);
this->utf16.append(wstr2);
return *this;
}
String &operator+=(const std::wstring &wstr2)
{
std::string new_utf8 = UtfConverter::ToUtf8(wstr2);
this->ansi.append(DecodeFromUTF8(new_utf8, this->loc));
this->utf8.append(new_utf8);
this->utf16.append(wstr2);
return *this;
}
String &AppendISO8859_1(const std::string &str2)
{
this->ansi.append(str2);
std::string new_utf8 = EncodeToUTF8(str2, this->loc);
this->utf8.append(new_utf8);
this->utf16.append(UtfConverter::FromUtf8(new_utf8));
return *this;
}
String Substring(size_t pos = 0, size_t n = std::string::npos) const
{
String new_string = String(*this);
new_string.ansi.substr(pos, n);
new_string.utf8.substr(pos, n);
if (n == std::string::npos)
n = std::wstring::npos;
new_string.utf16.substr(pos, n);
return new_string;
}
void CopyToString(wchar_t *str, bool = false) const
{
wcscpy(str, utf16.c_str());
}
void CopyToString(char *str, bool use_utf8 = false) const
{
strcpy(str, (use_utf8 ? utf8 : ansi).c_str());
}
protected:
std::string ansi, utf8;
std::wstring utf16;
std::locale loc;
};
#endif

View File

@ -1,7 +1,7 @@
/*
* SSEQ Player - Channel structures
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
* Last modification on 2013-04-23
* Last modification on 2014-10-23
*
* Adapted from source code of FeOS Sound System
* By fincs
@ -12,7 +12,6 @@
*/
#define _USE_MATH_DEFINES
#include <cstdlib>
#include <cmath>
#include <limits>
#include "Channel.h"
@ -46,8 +45,8 @@ TempSndReg::TempSndReg() : CR(0), SOURCE(nullptr), TIMER(0), REPEAT_POINT(0), LE
}
bool Channel::initializedLUTs = false;
double Channel::cosine_lut[Channel::COSINE_RESOLUTION];
double Channel::lanczos_lut[Channel::LANCZOS_SAMPLES + 1];
double Channel::sinc_lut[Channel::SINC_SAMPLES + 1];
double Channel::window_lut[Channel::SINC_SAMPLES + 1];
#ifndef M_PI
static const double M_PI = 3.14159265358979323846;
@ -73,18 +72,22 @@ Channel::Channel() : chnId(-1), tempReg(), state(CS_NONE), trackId(-1), prio(0),
this->clearHistory();
if (!this->initializedLUTs)
{
for (unsigned i = 0; i < COSINE_RESOLUTION; ++i)
this->cosine_lut[i] = (1.0 - std::cos((static_cast<double>(i) / COSINE_RESOLUTION) * M_PI)) * 0.5;
double dx = static_cast<double>(LANCZOS_WIDTH) / LANCZOS_SAMPLES, x = 0.0;
for (unsigned i = 0; i <= LANCZOS_SAMPLES; ++i, x += dx)
this->lanczos_lut[i] = std::abs(x) < LANCZOS_WIDTH ? sinc(x) * sinc(x / LANCZOS_WIDTH) : 0.0;
double dx = static_cast<double>(SINC_WIDTH) / SINC_SAMPLES, x = 0.0;
for (unsigned i = 0; i <= SINC_SAMPLES; ++i, x += dx)
{
double y = x / SINC_WIDTH;
this->sinc_lut[i] = std::abs(x) < SINC_WIDTH ? sinc(x) : 0.0;
this->window_lut[i] = (0.40897 + 0.5 * std::cos(M_PI * y) + 0.09103 * std::cos(2 * M_PI * y));
}
this->initializedLUTs = true;
}
}
// Original FSS Function: Chn_UpdateVol
void Channel::UpdateVol(const Track &trk)
{
int finalVol = trk.ply->masterVol;
finalVol += trk.ply->sseqVol;
finalVol += Cnv_Sust(trk.vol);
finalVol += Cnv_Sust(trk.expr);
if (finalVol < -AMPL_K)
@ -92,11 +95,13 @@ void Channel::UpdateVol(const Track &trk)
this->extAmpl = finalVol;
}
// Original FSS Function: Chn_UpdatePan
void Channel::UpdatePan(const Track &trk)
{
this->extPan = trk.pan;
}
// Original FSS Function: Chn_UpdateTune
void Channel::UpdateTune(const Track &trk)
{
int tune = (static_cast<int>(this->key) - static_cast<int>(this->orgKey)) * 64;
@ -104,6 +109,7 @@ void Channel::UpdateTune(const Track &trk)
this->extTune = tune;
}
// Original FSS Function: Chn_UpdateMod
void Channel::UpdateMod(const Track &trk)
{
this->modType = trk.modType;
@ -113,6 +119,7 @@ void Channel::UpdateMod(const Track &trk)
this->modDelay = trk.modDelay;
}
// Original FSS Function: Chn_UpdatePorta
void Channel::UpdatePorta(const Track &trk)
{
this->manualSweep = false;
@ -135,11 +142,12 @@ void Channel::UpdatePorta(const Track &trk)
else
{
int sq_time = static_cast<uint32_t>(trk.portaTime) * static_cast<uint32_t>(trk.portaTime);
long abs_sp = std::abs((long)this->sweepPitch);
this->sweepLen = (uint32_t)((abs_sp * sq_time) >> 11);
int abs_sp = std::abs(this->sweepPitch);
this->sweepLen = (abs_sp * sq_time) >> 11;
}
}
// Original FSS Function: Chn_Release
void Channel::Release()
{
this->noteLength = -1;
@ -147,6 +155,7 @@ void Channel::Release()
this->state = CS_RELEASE;
}
// Original FSS Function: Chn_Kill
void Channel::Kill()
{
this->state = CS_NONE;
@ -173,6 +182,7 @@ static inline int getModFlag(int type)
}
}
// Original FSS Function: Chn_UpdateTracks
void Channel::UpdateTrack()
{
if (!this->ply)
@ -182,11 +192,11 @@ void Channel::UpdateTrack()
if (trkn == -1)
return;
auto &trackFlags = this->ply->tracks[trkn].updateFlags;
auto &trk = this->ply->tracks[trkn];
auto &trackFlags = trk.updateFlags;
if (trackFlags.none())
return;
auto &trk = this->ply->tracks[trkn];
if (trackFlags[TUF_LEN])
{
int st = this->state;
@ -405,7 +415,7 @@ static inline uint16_t Timer_Adjust(uint16_t basetmr, int pitch)
tmr <<= shift;
}
else
return 0x10;
return 0xFFFF;
if (tmr < 0x10)
return 0x10;
@ -425,6 +435,7 @@ static inline int calcVolDivShift(int x)
return 4;
}
// Original FSS Function: Snd_UpdChannel
void Channel::Update()
{
// Kill active channels that aren't physically active
@ -457,10 +468,17 @@ void Channel::Update()
this->state = CS_ATTACK;
// Fall down
case CS_ATTACK:
this->ampl = (static_cast<int>(this->ampl) * static_cast<int>(this->attackLvl)) / 255;
{
int newAmpl = this->ampl;
int oldAmpl = this->ampl >> 7;
do
newAmpl = (newAmpl * static_cast<int>(this->attackLvl)) / 256;
while ((newAmpl >> 7) == oldAmpl);
this->ampl = newAmpl;
if (!this->ampl)
this->state = CS_DECAY;
break;
}
case CS_DECAY:
{
this->ampl -= static_cast<int>(this->decayRate);
@ -474,10 +492,11 @@ void Channel::Update()
}
case CS_RELEASE:
this->ampl -= static_cast<int>(this->releaseRate);
if (this->ampl > AMPL_THRESHOLD)
break;
this->Kill();
return;
if (this->ampl <= AMPL_THRESHOLD)
{
this->Kill();
return;
}
}
if (bModulation && this->modDelayCnt < this->modDelay)
@ -504,7 +523,7 @@ void Channel::Update()
modParam = Cnv_Sine(this->modCounter >> 8) * this->modRange * this->modDepth;
if (!this->modType)
modParam = static_cast<int>(static_cast<int64_t>(modParam * 60) >> 14);
modParam = static_cast<int64_t>(modParam * 60) >> 14;
else
// This ugly formula whose exact meaning and workings I cannot figure out is used for volume/pan modulation.
modParam = ((modParam & ~0xFC000000) >> 8) | ((((modParam < 0 ? -1 : 0) << 6) | (static_cast<uint32_t>(modParam) >> 26)) << 18);
@ -555,8 +574,7 @@ void Channel::Update()
if (bModulation && this->modType == 1)
totalVol += modParam;
totalVol += AMPL_K;
if (totalVol < 0)
totalVol = 0;
clamp(totalVol, 0, AMPL_K);
cr &= ~(SOUND_VOL(0x7F) | SOUND_VOLDIV(3));
cr |= SOUND_VOL(static_cast<int>(getvoltbl[totalVol]));
@ -580,10 +598,7 @@ void Channel::Update()
if (bModulation && this->modType == 2)
realPan += modParam;
realPan += 64;
if (realPan < 0)
realPan = 0;
else if (realPan > 127)
realPan = 127;
clamp(realPan, 0, 127);
cr &= ~SOUND_PAN(0x7F);
cr |= SOUND_PAN(realPan);
@ -607,8 +622,8 @@ static const int16_t wavedutytbl[8][8] =
{ -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF }
};
// Linear and Cosine interpolation code originally from DeSmuME
// B-spline and Osculating come from Olli Niemitalo:
// Linear interpolation code originally from DeSmuME
// Legrange comes from Olli Niemitalo:
// http://www.student.oulu.fi/~oniemita/dsp/deip.pdf
int32_t Channel::Interpolate()
{
@ -617,68 +632,51 @@ int32_t Channel::Interpolate()
const auto &data = &this->sampleHistory[this->sampleHistoryPtr + 16];
if (this->ply->interpolation == INTERPOLATION_LANCZOS)
if (this->ply->interpolation == INTERPOLATION_SINC)
{
double kernel[LANCZOS_WIDTH * 2], kernel_sum = 0.0;
int i = LANCZOS_WIDTH, shift = static_cast<int>(std::floor(ratio * LANCZOS_RESOLUTION));
int step = this->reg.sampleIncrease > 1.0 ? static_cast<int>((1.0 / this->reg.sampleIncrease) * LANCZOS_RESOLUTION) : LANCZOS_RESOLUTION;
long shift_adj = shift * step / LANCZOS_RESOLUTION;
for (; i >= -static_cast<int>(LANCZOS_WIDTH - 1); --i)
double kernel[SINC_WIDTH * 2], kernel_sum = 0.0;
int i = SINC_WIDTH, shift = static_cast<int>(std::floor(ratio * SINC_RESOLUTION));
int step = this->reg.sampleIncrease > 1.0 ? static_cast<int>(SINC_RESOLUTION / this->reg.sampleIncrease) : SINC_RESOLUTION;
int shift_adj = shift * step / SINC_RESOLUTION;
const int window_step = SINC_RESOLUTION;
for (; i >= -static_cast<int>(SINC_WIDTH - 1); --i)
{
long pos = i * step;
kernel_sum += kernel[i + LANCZOS_WIDTH - 1] = this->lanczos_lut[std::abs(shift_adj - pos)];
int pos = i * step;
int window_pos = i * window_step;
kernel_sum += kernel[i + SINC_WIDTH - 1] = this->sinc_lut[std::abs(shift_adj - pos)] * this->window_lut[std::abs(shift - window_pos)];
}
double sum = 0.0;
for (i = 0; i < static_cast<int>(LANCZOS_WIDTH * 2); ++i)
sum += data[i - static_cast<int>(LANCZOS_WIDTH) + 1] * kernel[i];
for (i = 0; i < static_cast<int>(SINC_WIDTH * 2); ++i)
sum += data[i - static_cast<int>(SINC_WIDTH) + 1] * kernel[i];
return static_cast<int32_t>(sum / kernel_sum);
}
else if (this->ply->interpolation > INTERPOLATION_COSINE)
else if (this->ply->interpolation > INTERPOLATION_LINEAR)
{
double c0, c1, c2, c3, c4, c5;
if (this->ply->interpolation > INTERPOLATION_4POINTBSPLINE)
if (this->ply->interpolation == INTERPOLATION_6POINTLEGRANGE)
{
if (this->ply->interpolation == INTERPOLATION_6POINTBSPLINE)
{
double ym2py2 = data[-2] + data[2], ym1py1 = data[-1] + data[1];
double y2mym2 = data[2] - data[-2], y1mym1 = data[1] - data[-1];
double sixthym1py1 = 1 / 6.0 * ym1py1;
c0 = 1 / 120.0 * ym2py2 + 13 / 60.0 * ym1py1 + 0.55 * data[0];
c1 = 1 / 24.0 * y2mym2 + 5 / 12.0 * y1mym1;
c2 = 1 / 12.0 * ym2py2 + sixthym1py1 - 0.5 * data[0];
c3 = 1 / 12.0 * y2mym2 - 1 / 6.0 * y1mym1;
c4 = 1 / 24.0 * ym2py2 - sixthym1py1 + 0.25 * data[0];
c5 = 1 / 120.0 * (data[3] - data[-2]) + 1 / 24.0 * (data[-1] - data[2]) + 1 / 12.0 * (data[1] - data[0]);
return static_cast<int32_t>(((((c5 * ratio + c4) * ratio + c3) * ratio + c2) * ratio + c1) * ratio + c0);
}
else // INTERPOLATION_6POINTOSCULATING
{
ratio -= 0.5;
double even1 = data[-2] + data[3], odd1 = data[-2] - data[3];
double even2 = data[-1] + data[2], odd2 = data[-1] - data[2];
double even3 = data[0] + data[1], odd3 = data[0] - data[1];
c0 = 0.01171875 * even1 - 0.09765625 * even2 + 0.5859375 * even3;
c1 = 0.2109375 * odd2 - 281 / 192.0 * odd3 - 13 / 384.0 * odd1;
c2 = 0.40625 * even2 - 17 / 48.0 * even3 - 5 / 96.0 * even1;
c3 = 0.1875 * odd1 - 53 / 48.0 * odd2 + 2.375 * odd3;
c4 = 1 / 48.0 * even1 - 0.0625 * even2 + 1 / 24.0 * even3;
c5 = 25 / 24.0 * odd2 - 25 / 12.0 * odd3 - 5 / 24.0 * odd1;
return static_cast<int32_t>(((((c5 * ratio + c4) * ratio + c3) * ratio + c2) * ratio + c1) * ratio + c0);
}
ratio -= 0.5;
double even1 = data[-2] + data[3], odd1 = data[-2] - data[3];
double even2 = data[-1] + data[2], odd2 = data[-1] - data[2];
double even3 = data[0] + data[1], odd3 = data[0] - data[1];
c0 = 0.01171875 * even1 - 0.09765625 * even2 + 0.5859375 * even3;
c1 = 25 / 384.0 * odd2 - 1.171875 * odd3 - 0.0046875 * odd1;
c2 = 0.40625 * even2 - 17 / 48.0 * even3 - 5 / 96.0 * even1;
c3 = 1 / 48.0 * odd1 - 13 / 48.0 * odd2 + 17 / 24.0 * odd3;
c4 = 1 / 48.0 * even1 - 0.0625 * even2 + 1 / 24.0 * even3;
c5 = 1 / 24.0 * odd2 - 1 / 12.0 * odd3 - 1 / 120.0 * odd1;
return static_cast<int32_t>(((((c5 * ratio + c4) * ratio + c3) * ratio + c2) * ratio + c1) * ratio + c0);
}
else // INTERPOLATION_4POINTBSPLINE
else // INTERPOLATION_4POINTLEAGRANGE
{
double ym1py1 = data[-1] + data[1];
c0 = 1 / 6.0 * ym1py1 + 2 / 3.0 * data[0];
c1 = 0.5 * (data[1] - data[-1]);
c2 = 0.5 * ym1py1 - data[0];
c3 = 0.5 * (data[0] - data[1]) + 1 / 6.0 * (data[2] - data[-1]);
c0 = data[0];
c1 = data[1] - 1 / 3.0 * data[-1] - 0.5 * data[0] - 1 / 6.0 * data[2];
c2 = 0.5 * (data[-1] + data[1]) - data[0];
c3 = 1 / 6.0 * (data[2] - data[-1]) + 0.5 * (data[0] - data[1]);
return static_cast<int32_t>(((c3 * ratio + c2) * ratio + c1) * ratio + c0);
}
}
else if (this->ply->interpolation == INTERPOLATION_COSINE)
return static_cast<int32_t>(data[0] + this->cosine_lut[static_cast<unsigned>(ratio * COSINE_RESOLUTION)] * (data[1] - data[0]));
else // INTERPOLATION_LINEAR
return static_cast<int32_t>(data[0] + ratio * (data[1] - data[0]));
}

View File

@ -1,7 +1,7 @@
/*
* SSEQ Player - Channel structures
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
* Last modification on 2013-04-02
* Last modification on 2014-09-17
*
* Adapted from source code of FeOS Sound System
* By fincs
@ -11,8 +11,7 @@
* http://desmume.org/
*/
#ifndef SSEQPLAYER_CHANNEL_H
#define SSEQPLAYER_CHANNEL_H
#pragma once
#include <bitset>
#include <tuple>
@ -136,18 +135,17 @@ struct Channel
int16_t sampleHistory[64];
/*
* Lookup tables for the cosine and Lanczos Sinc interpolations, to
* Lookup tables for the Sinc interpolation, to
* avoid the need to call the sin/cos functions all the time.
* These are static as they will not change between channels or runs
* of the program.
*/
static bool initializedLUTs;
static const unsigned COSINE_RESOLUTION = 8192;
static const unsigned LANCZOS_RESOLUTION = 8192;
static const unsigned LANCZOS_WIDTH = 8;
static const unsigned LANCZOS_SAMPLES = LANCZOS_RESOLUTION * LANCZOS_WIDTH;
static double cosine_lut[COSINE_RESOLUTION];
static double lanczos_lut[LANCZOS_SAMPLES + 1];
static const unsigned SINC_RESOLUTION = 8192;
static const unsigned SINC_WIDTH = 8;
static const unsigned SINC_SAMPLES = SINC_RESOLUTION * SINC_WIDTH;
static double sinc_lut[SINC_SAMPLES + 1];
static double window_lut[SINC_SAMPLES + 1];
Channel();
@ -165,5 +163,3 @@ struct Channel
void IncrementSample();
void clearHistory();
};
#endif

View File

@ -1,602 +0,0 @@
/*
* Copyright 2001-2004 Unicode, Inc.
*
* Disclaimer
*
* This source code is provided as is by Unicode, Inc. No claims are
* made as to fitness for any particular purpose. No warranties of any
* kind are expressed or implied. The recipient agrees to determine
* applicability of information provided. If this file has been
* purchased on magnetic or optical media from Unicode, Inc., the
* sole remedy for any claim will be exchange of defective media
* within 90 days of receipt.
*
* Limitations on Rights to Redistribute This Code
*
* Unicode, Inc. hereby grants the right to freely use the information
* supplied in this file in the creation of products supporting the
* Unicode Standard, and to make copies of this file in any form
* for internal or external distribution as long as this notice
* remains attached.
*/
/* ---------------------------------------------------------------------
Conversions between UTF32, UTF-16, and UTF-8. Source code file.
Author: Mark E. Davis, 1994.
Rev History: Rick McGowan, fixes & updates May 2001.
Sept 2001: fixed const & error conditions per
mods suggested by S. Parent & A. Lillich.
June 2002: Tim Dodd added detection and handling of incomplete
source sequences, enhanced error detection, added casts
to eliminate compiler warnings.
July 2003: slight mods to back out aggressive FFFE detection.
Jan 2004: updated switches in from-UTF8 conversions.
Oct 2004: updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions.
See the header file "ConvertUTF.h" for complete documentation.
------------------------------------------------------------------------ */
#include "ConvertUTF.h"
static const int halfShift = 10; /* used for shifting by 10 bits */
static const UTF32 halfBase = 0x0010000UL;
static const UTF32 halfMask = 0x3FFUL;
static const UTF32 UNI_SUR_HIGH_START = 0xD800;
static const UTF32 UNI_SUR_HIGH_END = 0xDBFF;
static const UTF32 UNI_SUR_LOW_START = 0xDC00;
static const UTF32 UNI_SUR_LOW_END = 0xDFFF;
/* --------------------------------------------------------------------- */
ConversionResult ConvertUTF32toUTF16(const UTF32 **sourceStart, const UTF32 *sourceEnd, UTF16 **targetStart, UTF16 *targetEnd, ConversionFlags flags)
{
ConversionResult result = conversionOK;
const UTF32 *source = *sourceStart;
UTF16 *target = *targetStart;
while (source < sourceEnd)
{
if (target >= targetEnd)
{
result = targetExhausted;
break;
}
UTF32 ch = *source++;
if (ch <= UNI_MAX_BMP) /* Target is a character <= 0xFFFF */
{
/* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END)
{
if (flags == strictConversion)
{
--source; /* return to the illegal value itself */
result = sourceIllegal;
break;
}
else
*target++ = UNI_REPLACEMENT_CHAR;
}
else
*target++ = static_cast<UTF16>(ch); /* normal case */
}
else if (ch > UNI_MAX_LEGAL_UTF32)
{
if (flags == strictConversion)
result = sourceIllegal;
else
*target++ = UNI_REPLACEMENT_CHAR;
}
else
{
/* target is a character in range 0xFFFF - 0x10FFFF. */
if (target + 1 >= targetEnd)
{
--source; /* Back up source pointer! */
result = targetExhausted;
break;
}
ch -= halfBase;
*target++ = static_cast<UTF16>((ch >> halfShift) + UNI_SUR_HIGH_START);
*target++ = static_cast<UTF16>((ch & halfMask) + UNI_SUR_LOW_START);
}
}
*sourceStart = source;
*targetStart = target;
return result;
}
/* --------------------------------------------------------------------- */
ConversionResult ConvertUTF16toUTF32(const UTF16 **sourceStart, const UTF16 *sourceEnd, UTF32 **targetStart, UTF32 *targetEnd, ConversionFlags flags)
{
ConversionResult result = conversionOK;
const UTF16 *source = *sourceStart;
UTF32 *target = *targetStart;
while (source < sourceEnd)
{
const UTF16 *oldSource = source; /* In case we have to back up because of target overflow. */
UTF32 ch = *source++;
/* If we have a surrogate pair, convert to UTF32 first. */
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END)
{
/* If the 16 bits following the high surrogate are in the source buffer... */
if (source < sourceEnd)
{
UTF32 ch2 = *source;
/* If it's a low surrogate, convert to UTF32. */
if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END)
{
ch = ((ch - UNI_SUR_HIGH_START) << halfShift) + (ch2 - UNI_SUR_LOW_START) + halfBase;
++source;
}
else if (flags == strictConversion) /* it's an unpaired high surrogate */
{
--source; /* return to the illegal value itself */
result = sourceIllegal;
break;
}
}
else /* We don't have the 16 bits following the high surrogate. */
{
--source; /* return to the high surrogate */
result = sourceExhausted;
break;
}
}
else if (flags == strictConversion)
{
/* UTF-16 surrogate values are illegal in UTF-32 */
if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END)
{
--source; /* return to the illegal value itself */
result = sourceIllegal;
break;
}
}
if (target >= targetEnd)
{
source = oldSource; /* Back up source pointer! */
result = targetExhausted;
break;
}
*target++ = ch;
}
*sourceStart = source;
*targetStart = target;
return result;
}
/* --------------------------------------------------------------------- */
/*
* Index into the table below with the first byte of a UTF-8 sequence to
* get the number of trailing bytes that are supposed to follow it.
* Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is
* left as-is for anyone who may want to do such conversion, which was
* allowed in earlier algorithms.
*/
static const char trailingBytesForUTF8[256] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
};
/*
* Magic values subtracted from a buffer value during UTF8 conversion.
* This table contains as many values as there might be trailing bytes
* in a UTF-8 sequence.
*/
static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL, 0x03C82080UL, 0xFA082080UL, 0x82082080UL };
/*
* Once the bits are split out into bytes of UTF-8, this is a mask OR-ed
* into the first byte, depending on how many bytes follow. There are
* as many entries in this table as there are UTF-8 sequence types.
* (I.e., one byte sequence, two byte... etc.). Remember that sequencs
* for *legal* UTF-8 will be 4 or fewer bytes total.
*/
static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
/* --------------------------------------------------------------------- */
/* The interface converts a whole buffer to avoid function-call overhead.
* Constants have been gathered. Loops & conditionals have been removed as
* much as possible for efficiency, in favor of drop-through switches.
* (See "Note A" at the bottom of the file for equivalent code.)
* If your compiler supports it, the "isLegalUTF8" call can be turned
* into an inline function.
*/
/* --------------------------------------------------------------------- */
ConversionResult ConvertUTF16toUTF8(const UTF16 **sourceStart, const UTF16 *sourceEnd, UTF8 **targetStart, UTF8 *targetEnd, ConversionFlags flags)
{
ConversionResult result = conversionOK;
const UTF16 *source = *sourceStart;
UTF8 *target = *targetStart;
while (source < sourceEnd)
{
const UTF32 byteMask = 0xBF, byteMark = 0x80;
const UTF16 *oldSource = source; /* In case we have to back up because of target overflow. */
UTF32 ch = *source++;
/* If we have a surrogate pair, convert to UTF32 first. */
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END)
{
/* If the 16 bits following the high surrogate are in the source buffer... */
if (source < sourceEnd)
{
UTF32 ch2 = *source;
/* If it's a low surrogate, convert to UTF32. */
if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END)
{
ch = ((ch - UNI_SUR_HIGH_START) << halfShift) + (ch2 - UNI_SUR_LOW_START) + halfBase;
++source;
}
else if (flags == strictConversion) /* it's an unpaired high surrogate */
{
--source; /* return to the illegal value itself */
result = sourceIllegal;
break;
}
}
else /* We don't have the 16 bits following the high surrogate. */
{
--source; /* return to the high surrogate */
result = sourceExhausted;
break;
}
}
else if (flags == strictConversion)
{
/* UTF-16 surrogate values are illegal in UTF-32 */
if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END)
{
--source; /* return to the illegal value itself */
result = sourceIllegal;
break;
}
}
/* Figure out how many bytes the result will require */
unsigned short bytesToWrite = 0;
if (ch < 0x80)
bytesToWrite = 1;
else if (ch < 0x800)
bytesToWrite = 2;
else if (ch < 0x10000)
bytesToWrite = 3;
else if (ch < 0x110000)
bytesToWrite = 4;
else
{
bytesToWrite = 3;
ch = UNI_REPLACEMENT_CHAR;
}
target += bytesToWrite;
if (target > targetEnd)
{
source = oldSource; /* Back up source pointer! */
target -= bytesToWrite;
result = targetExhausted;
break;
}
switch (bytesToWrite) /* note: everything falls through. */
{
case 4: *--target = static_cast<UTF8>((ch | byteMark) & byteMask); ch >>= 6;
case 3: *--target = static_cast<UTF8>((ch | byteMark) & byteMask); ch >>= 6;
case 2: *--target = static_cast<UTF8>((ch | byteMark) & byteMask); ch >>= 6;
case 1: *--target = static_cast<UTF8>(ch | firstByteMark[bytesToWrite]);
}
target += bytesToWrite;
}
*sourceStart = source;
*targetStart = target;
return result;
}
/* --------------------------------------------------------------------- */
/*
* Utility routine to tell whether a sequence of bytes is legal UTF-8.
* This must be called with the length pre-determined by the first byte.
* If not calling this from ConvertUTF8to*, then the length can be set by:
* length = trailingBytesForUTF8[*source]+1;
* and the sequence is illegal right away if there aren't that many bytes
* available.
* If presented with a length > 4, this returns false. The Unicode
* definition of UTF-8 goes up to 4-byte sequences.
*/
static bool isLegalUTF8(const UTF8 *source, int length)
{
const UTF8 *srcptr = source + length;
UTF8 a;
switch (length)
{
default: return false;
/* Everything else falls through when "true"... */
case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
case 2: if ((a = (*--srcptr)) > 0xBF) return false;
switch (*source)
{
/* no fall-through in this inner switch */
case 0xE0: if (a < 0xA0) return false; break;
case 0xED: if (a > 0x9F) return false; break;
case 0xF0: if (a < 0x90) return false; break;
case 0xF4: if (a > 0x8F) return false; break;
default: if (a < 0x80) return false;
}
case 1: if (*source >= 0x80 && *source < 0xC2) return false;
}
if (*source > 0xF4)
return false;
return true;
}
/* --------------------------------------------------------------------- */
/*
* Exported function to return whether a UTF-8 sequence is legal or not.
* This is not used here; it's just exported.
*/
bool isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd)
{
int length = trailingBytesForUTF8[*source] + 1;
if (source + length > sourceEnd)
return false;
return isLegalUTF8(source, length);
}
/* --------------------------------------------------------------------- */
ConversionResult ConvertUTF8toUTF16(const UTF8 **sourceStart, const UTF8 *sourceEnd, UTF16 **targetStart, UTF16 *targetEnd, ConversionFlags flags)
{
ConversionResult result = conversionOK;
const UTF8 *source = *sourceStart;
UTF16 *target = *targetStart;
while (source < sourceEnd)
{
UTF32 ch = 0;
unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
if (source + extraBytesToRead >= sourceEnd)
{
result = sourceExhausted;
break;
}
/* Do this check whether lenient or strict */
if (!isLegalUTF8(source, extraBytesToRead + 1))
{
result = sourceIllegal;
break;
}
/*
* The cases all fall through. See "Note A" below.
*/
switch (extraBytesToRead)
{
case 5: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
case 3: ch += *source++; ch <<= 6;
case 2: ch += *source++; ch <<= 6;
case 1: ch += *source++; ch <<= 6;
case 0: ch += *source++;
}
ch -= offsetsFromUTF8[extraBytesToRead];
if (target >= targetEnd)
{
source -= extraBytesToRead + 1; /* Back up source pointer! */
result = targetExhausted;
break;
}
if (ch <= UNI_MAX_BMP) /* Target is a character <= 0xFFFF */
{
/* UTF-16 surrogate values are illegal in UTF-32 */
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END)
{
if (flags == strictConversion)
{
source -= extraBytesToRead + 1; /* return to the illegal value itself */
result = sourceIllegal;
break;
}
else
*target++ = UNI_REPLACEMENT_CHAR;
}
else
*target++ = static_cast<UTF16>(ch); /* normal case */
}
else if (ch > UNI_MAX_UTF16)
{
if (flags == strictConversion)
{
result = sourceIllegal;
source -= extraBytesToRead + 1; /* return to the start */
break; /* Bail out; shouldn't continue */
}
else
*target++ = UNI_REPLACEMENT_CHAR;
}
else
{
/* target is a character in range 0xFFFF - 0x10FFFF. */
if (target + 1 >= targetEnd)
{
source -= extraBytesToRead + 1; /* Back up source pointer! */
result = targetExhausted;
break;
}
ch -= halfBase;
*target++ = static_cast<UTF16>((ch >> halfShift) + UNI_SUR_HIGH_START);
*target++ = static_cast<UTF16>((ch & halfMask) + UNI_SUR_LOW_START);
}
}
*sourceStart = source;
*targetStart = target;
return result;
}
/* --------------------------------------------------------------------- */
ConversionResult ConvertUTF32toUTF8(const UTF32 **sourceStart, const UTF32 *sourceEnd, UTF8 **targetStart, UTF8 *targetEnd, ConversionFlags flags)
{
ConversionResult result = conversionOK;
const UTF32 *source = *sourceStart;
UTF8 *target = *targetStart;
while (source < sourceEnd)
{
const UTF32 byteMask = 0xBF, byteMark = 0x80;
UTF32 ch = *source++;
if (flags == strictConversion)
{
/* UTF-16 surrogate values are illegal in UTF-32 */
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END)
{
--source; /* return to the illegal value itself */
result = sourceIllegal;
break;
}
}
/*
* Figure out how many bytes the result will require. Turn any
* illegally large UTF32 things (> Plane 17) into replacement chars.
*/
unsigned short bytesToWrite = 0;
if (ch < 0x80)
bytesToWrite = 1;
else if (ch < 0x800)
bytesToWrite = 2;
else if (ch < 0x10000)
bytesToWrite = 3;
else if (ch <= UNI_MAX_LEGAL_UTF32)
bytesToWrite = 4;
else
{
bytesToWrite = 3;
ch = UNI_REPLACEMENT_CHAR;
result = sourceIllegal;
}
target += bytesToWrite;
if (target > targetEnd)
{
--source; /* Back up source pointer! */
target -= bytesToWrite;
result = targetExhausted;
break;
}
switch (bytesToWrite) /* note: everything falls through. */
{
case 4: *--target = static_cast<UTF8>((ch | byteMark) & byteMask); ch >>= 6;
case 3: *--target = static_cast<UTF8>((ch | byteMark) & byteMask); ch >>= 6;
case 2: *--target = static_cast<UTF8>((ch | byteMark) & byteMask); ch >>= 6;
case 1: *--target = static_cast<UTF8>(ch | firstByteMark[bytesToWrite]);
}
target += bytesToWrite;
}
*sourceStart = source;
*targetStart = target;
return result;
}
/* --------------------------------------------------------------------- */
ConversionResult ConvertUTF8toUTF32(const UTF8 **sourceStart, const UTF8 *sourceEnd, UTF32 **targetStart, UTF32 *targetEnd, ConversionFlags flags)
{
ConversionResult result = conversionOK;
const UTF8 *source = *sourceStart;
UTF32 *target = *targetStart;
while (source < sourceEnd)
{
UTF32 ch = 0;
unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
if (source + extraBytesToRead >= sourceEnd)
{
result = sourceExhausted;
break;
}
/* Do this check whether lenient or strict */
if (!isLegalUTF8(source, extraBytesToRead + 1))
{
result = sourceIllegal;
break;
}
/*
* The cases all fall through. See "Note A" below.
*/
switch (extraBytesToRead)
{
case 5: ch += *source++; ch <<= 6;
case 4: ch += *source++; ch <<= 6;
case 3: ch += *source++; ch <<= 6;
case 2: ch += *source++; ch <<= 6;
case 1: ch += *source++; ch <<= 6;
case 0: ch += *source++;
}
ch -= offsetsFromUTF8[extraBytesToRead];
if (target >= targetEnd)
{
source -= extraBytesToRead + 1; /* Back up the source pointer! */
result = targetExhausted;
break;
}
if (ch <= UNI_MAX_LEGAL_UTF32)
{
/*
* UTF-16 surrogate values are illegal in UTF-32, and anything
* over Plane 17 (> 0x10FFFF) is illegal.
*/
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END)
{
if (flags == strictConversion)
{
source -= extraBytesToRead + 1; /* return to the illegal value itself */
result = sourceIllegal;
break;
}
else
*target++ = UNI_REPLACEMENT_CHAR;
}
else
*target++ = ch;
}
else /* i.e., ch > UNI_MAX_LEGAL_UTF32 */
{
result = sourceIllegal;
*target++ = UNI_REPLACEMENT_CHAR;
}
}
*sourceStart = source;
*targetStart = target;
return result;
}
/* ---------------------------------------------------------------------
Note A.
The fall-through switches in UTF-8 reading code save a
temp variable, some decrements & conditionals. The switches
are equivalent to the following loop:
{
int tmpBytesToRead = extraBytesToRead+1;
do {
ch += *source++;
--tmpBytesToRead;
if (tmpBytesToRead) ch <<= 6;
} while (tmpBytesToRead > 0);
}
In UTF-8 writing code, the switches on "bytesToWrite" are
similarly unrolled loops.
--------------------------------------------------------------------- */

View File

@ -1,134 +0,0 @@
/*
* Copyright 2001-2004 Unicode, Inc.
*
* Disclaimer
*
* This source code is provided as is by Unicode, Inc. No claims are
* made as to fitness for any particular purpose. No warranties of any
* kind are expressed or implied. The recipient agrees to determine
* applicability of information provided. If this file has been
* purchased on magnetic or optical media from Unicode, Inc., the
* sole remedy for any claim will be exchange of defective media
* within 90 days of receipt.
*
* Limitations on Rights to Redistribute This Code
*
* Unicode, Inc. hereby grants the right to freely use the information
* supplied in this file in the creation of products supporting the
* Unicode Standard, and to make copies of this file in any form
* for internal or external distribution as long as this notice
* remains attached.
*/
/* ---------------------------------------------------------------------
Conversions between UTF32, UTF-16, and UTF-8. Header file.
Several funtions are included here, forming a complete set of
conversions between the three formats. UTF-7 is not included
here, but is handled in a separate source file.
Each of these routines takes pointers to input buffers and output
buffers. The input buffers are const.
Each routine converts the text between *sourceStart and sourceEnd,
putting the result into the buffer between *targetStart and
targetEnd. Note: the end pointers are *after* the last item: e.g.
*(sourceEnd - 1) is the last item.
The return result indicates whether the conversion was successful,
and if not, whether the problem was in the source or target buffers.
(Only the first encountered problem is indicated.)
After the conversion, *sourceStart and *targetStart are both
updated to point to the end of last text successfully converted in
the respective buffers.
Input parameters:
sourceStart - pointer to a pointer to the source buffer.
The contents of this are modified on return so that
it points at the next thing to be converted.
targetStart - similarly, pointer to pointer to the target buffer.
sourceEnd, targetEnd - respectively pointers to the ends of the
two buffers, for overflow checking only.
These conversion functions take a ConversionFlags argument. When this
flag is set to strict, both irregular sequences and isolated surrogates
will cause an error. When the flag is set to lenient, both irregular
sequences and isolated surrogates are converted.
Whether the flag is strict or lenient, all illegal sequences will cause
an error return. This includes sequences such as: <F4 90 80 80>, <C0 80>,
or <A0> in UTF-8, and values above 0x10FFFF in UTF-32. Conformant code
must check for illegal sequences.
When the flag is set to lenient, characters over 0x10FFFF are converted
to the replacement character; otherwise (when the flag is set to strict)
they constitute an error.
Output parameters:
The value "sourceIllegal" is returned from some routines if the input
sequence is malformed. When "sourceIllegal" is returned, the source
value will point to the illegal value that caused the problem. E.g.,
in UTF-8 when a sequence is malformed, it points to the start of the
malformed sequence.
Author: Mark E. Davis, 1994.
Rev History: Rick McGowan, fixes & updates May 2001.
Fixes & updates, Sept 2001.
------------------------------------------------------------------------ */
#ifndef _CONVERTUTF_H_
#define _CONVERTUTF_H_
/* ---------------------------------------------------------------------
The following 4 definitions are compiler-specific.
The C standard does not guarantee that wchar_t has at least
16 bits, so wchar_t is no less portable than unsigned short!
All should be unsigned values to avoid sign extension during
bit mask & shift operations.
------------------------------------------------------------------------ */
typedef unsigned long UTF32; /* at least 32 bits */
typedef unsigned short UTF16; /* at least 16 bits */
typedef unsigned char UTF8; /* typically 8 bits */
/* Some fundamental constants */
static const UTF32 UNI_REPLACEMENT_CHAR = 0x0000FFFD;
static const UTF32 UNI_MAX_BMP = 0x0000FFFF;
static const UTF32 UNI_MAX_UTF16 = 0x0010FFFF;
static const UTF32 UNI_MAX_UTF32 = 0x7FFFFFFF;
static const UTF32 UNI_MAX_LEGAL_UTF32 = 0x0010FFFF;
enum ConversionResult
{
conversionOK, /* conversion successful */
sourceExhausted, /* partial character in source, but hit end */
targetExhausted, /* insuff. room in target for conversion */
sourceIllegal /* source sequence is illegal/malformed */
};
enum ConversionFlags
{
strictConversion,
lenientConversion
};
ConversionResult ConvertUTF8toUTF16(const UTF8 **, const UTF8 *, UTF16 **, UTF16 *, ConversionFlags);
ConversionResult ConvertUTF16toUTF8(const UTF16 **, const UTF16 *, UTF8 **, UTF8 *, ConversionFlags);
ConversionResult ConvertUTF8toUTF32(const UTF8 **, const UTF8 *, UTF32 **, UTF32 *, ConversionFlags);
ConversionResult ConvertUTF32toUTF8(const UTF32 **, const UTF32 *, UTF8 **, UTF8 *, ConversionFlags);
ConversionResult ConvertUTF16toUTF32(const UTF16 **, const UTF16 *, UTF32 **, UTF32 *, ConversionFlags);
ConversionResult ConvertUTF32toUTF16(const UTF32 **, const UTF32 *, UTF16 **, UTF16 *, ConversionFlags);
bool isLegalUTF8Sequence(const UTF8 *, const UTF8 *);
/* --------------------------------------------------------------------- */
#endif

View File

@ -1,14 +1,13 @@
/*
* SSEQ Player - SDAT FAT (File Allocation Table) Section structures
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
* Last modification on 2013-03-21
* Last modification on 2014-09-08
*
* Nintendo DS Nitro Composer (SDAT) Specification document found at
* http://www.feshrine.net/hacking/doc/nds-sdat.html
*/
#ifndef SSEQPLAYER_FATSECTION_H
#define SSEQPLAYER_FATSECTION_H
#pragma once
#include "common.h"
@ -29,5 +28,3 @@ struct FATSection
void Read(PseudoFile &file);
};
#endif

View File

@ -1,14 +1,13 @@
/*
* SSEQ Player - SDAT INFO Entry structures
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
* Last modification on 2013-03-21
* Last modification on 2014-09-08
*
* Nintendo DS Nitro Composer (SDAT) Specification document found at
* http://www.feshrine.net/hacking/doc/nds-sdat.html
*/
#ifndef SSEQPLAYER_INFOENTRY_H
#define SSEQPLAYER_INFOENTRY_H
#pragma once
#include "common.h"
@ -50,5 +49,3 @@ struct INFOEntryWAVEARC : INFOEntry
void Read(PseudoFile &file);
};
#endif

View File

@ -1,14 +1,13 @@
/*
* SSEQ Player - SDAT INFO Section structures
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
* Last modification on 2013-03-21
* Last modification on 2014-09-08
*
* Nintendo DS Nitro Composer (SDAT) Specification document found at
* http://www.feshrine.net/hacking/doc/nds-sdat.html
*/
#ifndef SSEQPLAYER_INFOSECTION_H
#define SSEQPLAYER_INFOSECTION_H
#pragma once
#include <map>
#include "INFOEntry.h"
@ -33,5 +32,3 @@ struct INFOSection
void Read(PseudoFile &file);
};
#endif

View File

@ -1,14 +1,13 @@
/*
* SSEQ Player - Nintendo DS Standard Header structure
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
* Last modification on 2013-03-21
* Last modification on 2014-09-08
*
* Nintendo DS Nitro Composer (SDAT) Specification document found at
* http://www.feshrine.net/hacking/doc/nds-sdat.html
*/
#ifndef SSEQPLAYER_NDSSTDHEADER_H
#define SSEQPLAYER_NDSSTDHEADER_H
#pragma once
#include "common.h"
@ -22,5 +21,3 @@ struct NDSStdHeader
void Read(PseudoFile &file);
void Verify(const std::string &typeToCheck, uint32_t magicToCheck);
};
#endif

View File

@ -1,7 +1,7 @@
/*
* SSEQ Player - Player structure
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
* Last modification on 2013-04-01
* Last modification on 2014-10-23
*
* Adapted from source code of FeOS Sound System
* By fincs
@ -11,13 +11,23 @@
#include "Player.h"
#include "common.h"
Player::Player() : prio(0), nTracks(0), tempo(0), tempoCount(0), tempoRate(0), masterVol(0), sseq(nullptr), sampleRate(0), interpolation(INTERPOLATION_NONE)
#if (defined(__GNUC__) || defined(__clang__)) && !defined(_LIBCPP_VERSION)
std::locale::id std::codecvt<char16_t, char, mbstate_t>::id;
std::locale::id std::codecvt<char32_t, char, mbstate_t>::id;
#endif
Player::Player() : prio(0), nTracks(0), tempo(0), tempoCount(0), tempoRate(0), masterVol(0), sseqVol(0), sseq(nullptr), sampleRate(0), interpolation(INTERPOLATION_NONE)
{
memset(this->trackIds, 0, sizeof(this->trackIds));
for (size_t i = 0; i < 16; ++i)
{
this->channels[i].chnId = i;
this->channels[i].ply = this;
}
memset(this->variables, -1, sizeof(this->variables));
}
// Original FSS Function: Player_Setup
bool Player::Setup(const SSEQ *sseqToPlay)
{
this->sseq = sseqToPlay;
@ -30,21 +40,7 @@ bool Player::Setup(const SSEQ *sseqToPlay)
this->nTracks = 1;
this->trackIds[0] = firstTrack;
auto pData = &this->sseq->data[0];
if (*pData == 0xFE)
for (pData += 3; *pData == 0x93; ) // Prepare extra tracks
{
++pData;
int tNum = read8(&pData);
auto pos = &this->sseq->data[read24(&pData)];
int newTrack = this->TrackAlloc();
if (newTrack == -1)
continue;
this->tracks[newTrack].Init(newTrack, this, pos, tNum);
this->trackIds[this->nTracks++] = newTrack;
}
this->tracks[firstTrack].startPos = this->tracks[firstTrack].pos = pData;
this->tracks[firstTrack].startPos = this->tracks[firstTrack].pos = &this->sseq->data[0];
this->secondsPerSample = 1.0 / this->sampleRate;
@ -53,16 +49,19 @@ bool Player::Setup(const SSEQ *sseqToPlay)
return true;
}
// Original FSS Function: Player_ClearState
void Player::ClearState()
{
this->tempo = 120;
this->tempoCount = 0;
this->tempoRate = 0x100;
this->masterVol = 0; // this is actually the highest level
memset(this->variables, -1, sizeof(this->variables));
this->secondsIntoPlayback = 0;
this->secondsUntilNextClock = SecondsPerClockCycle;
}
// Original FSS Function: Player_FreeTracks
void Player::FreeTracks()
{
for (uint8_t i = 0; i < this->nTracks; ++i)
@ -70,6 +69,7 @@ void Player::FreeTracks()
this->nTracks = 0;
}
// Original FSS Function: Player_Stop
void Player::Stop(bool bKillSound)
{
this->ClearState();
@ -92,11 +92,12 @@ void Player::Stop(bool bKillSound)
this->FreeTracks();
}
// Original FSS Function: Chn_Alloc
int Player::ChannelAlloc(int type, int priority)
{
static const uint8_t pcmChnArray[] = { 4, 5, 6, 7, 2, 0, 3, 1, 8, 9, 10, 11, 14, 12, 15, 13 };
static const uint8_t psgChnArray[] = { 13, 12, 11, 10, 9, 8 };
static const uint8_t noiseChnArray[] = { 15, 14 };
static const uint8_t psgChnArray[] = { 8, 9, 10, 11, 12, 13 };
static const uint8_t noiseChnArray[] = { 14, 15 };
static const uint8_t arraySizes[] = { sizeof(pcmChnArray), sizeof(psgChnArray), sizeof(noiseChnArray) };
static const uint8_t *const arrayArray[] = { pcmChnArray, psgChnArray, noiseChnArray };
@ -121,13 +122,13 @@ int Player::ChannelAlloc(int type, int priority)
if (curChnNo == -1 || priority < this->channels[curChnNo].prio)
return -1;
this->channels[curChnNo].ply = this;
this->channels[curChnNo].noteLength = -1;
this->channels[curChnNo].vol = 0;
this->channels[curChnNo].vol = 0x7FF;
this->channels[curChnNo].clearHistory();
return curChnNo;
}
// Original FSS Function: Track_Alloc
int Player::TrackAlloc()
{
for (int i = 0; i < FSS_MAXTRACKS; ++i)
@ -144,6 +145,7 @@ int Player::TrackAlloc()
return -1;
}
// Original FSS Function: Player_Run
void Player::Run()
{
while (this->tempoCount > 240)
@ -163,6 +165,7 @@ void Player::UpdateTracks()
this->tracks[i].updateFlags.reset();
}
// Original FSS Function: Snd_Timer
void Player::Timer()
{
this->UpdateTracks();
@ -173,14 +176,6 @@ void Player::Timer()
this->Run();
}
template<typename T1, typename T2> static inline void clamp(T1 &valueToClamp, const T2 &minValue, const T2 &maxValue)
{
if (valueToClamp < minValue)
valueToClamp = minValue;
else if (valueToClamp > maxValue)
valueToClamp = maxValue;
}
static inline int32_t muldiv7(int32_t val, uint8_t mul)
{
return mul == 127 ? val : ((val * mul) >> 7);
@ -219,9 +214,6 @@ void Player::GenerateSamples(std::vector<uint8_t> &buf, unsigned offset, unsigne
}
}
leftChannel = muldiv7(leftChannel, 127 - this->masterVol);
rightChannel = muldiv7(rightChannel, 127 - this->masterVol);
clamp(leftChannel, -0x8000, 0x7FFF);
clamp(rightChannel, -0x8000, 0x7FFF);

View File

@ -1,15 +1,14 @@
/*
* SSEQ Player - Player structure
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
* Last modification on 2013-04-01
* Last modification on 2014-10-18
*
* Adapted from source code of FeOS Sound System
* By fincs
* https://github.com/fincs/FSS
*/
#ifndef SSEQPLAYER_PLAYER_H
#define SSEQPLAYER_PLAYER_H
#pragma once
#include <memory>
#include <bitset>
@ -22,13 +21,14 @@ struct Player
{
uint8_t prio, nTracks;
uint16_t tempo, tempoCount, tempoRate /* 8.8 fixed point */;
int16_t masterVol;
int16_t masterVol, sseqVol;
const SSEQ *sseq;
uint8_t trackIds[FSS_TRACKCOUNT];
Track tracks[FSS_MAXTRACKS];
Channel channels[16];
int16_t variables[32];
uint32_t sampleRate;
Interpolation interpolation;
@ -50,5 +50,3 @@ struct Player
std::bitset<16> mutes;
void GenerateSamples(std::vector<uint8_t> &buf, unsigned offset, unsigned samples);
};
#endif

View File

@ -1,14 +1,13 @@
/*
* SSEQ Player - SDAT SBNK (Sound Bank) structures
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
* Last modification on 2013-03-21
* Last modification on 2014-09-08
*
* Nintendo DS Nitro Composer (SDAT) Specification document found at
* http://www.feshrine.net/hacking/doc/nds-sdat.html
*/
#ifndef SSEQPLAYER_SBNK_H
#define SSEQPLAYER_SBNK_H
#pragma once
#include "SWAR.h"
#include "INFOEntry.h"
@ -57,5 +56,3 @@ struct SBNK
void Read(PseudoFile &file);
};
#endif

View File

@ -1,14 +1,13 @@
/*
* SSEQ Player - SDAT structure
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
* Last modification on 2013-03-30
* Last modification on 2014-09-08
*
* Nintendo DS Nitro Composer (SDAT) Specification document found at
* http://www.feshrine.net/hacking/doc/nds-sdat.html
*/
#ifndef SSEQPLAYER_SDAT_H
#define SSEQPLAYER_SDAT_H
#pragma once
#include <memory>
#include "SSEQ.h"
@ -27,5 +26,3 @@ private:
SDAT(const SDAT &);
SDAT &operator=(const SDAT &);
};
#endif

View File

@ -1,14 +1,13 @@
/*
* SSEQ Player - SDAT SSEQ (Sequence) structure
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
* Last modification on 2013-03-21
* Last modification on 2014-09-08
*
* Nintendo DS Nitro Composer (SDAT) Specification document found at
* http://www.feshrine.net/hacking/doc/nds-sdat.html
*/
#ifndef SSEQPLAYER_SSEQ_H
#define SSEQPLAYER_SSEQ_H
#pragma once
#include "SBNK.h"
#include "INFOEntry.h"
@ -28,5 +27,3 @@ struct SSEQ
void Read(PseudoFile &file);
};
#endif

View File

@ -1,14 +1,13 @@
/*
* SSEQ Player - SDAT SWAR (Wave Archive) structures
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
* Last modification on 2013-03-21
* Last modification on 2014-09-08
*
* Nintendo DS Nitro Composer (SDAT) Specification document found at
* http://www.feshrine.net/hacking/doc/nds-sdat.html
*/
#ifndef SSEQPLAYER_SWAR_H
#define SSEQPLAYER_SWAR_H
#pragma once
#include <map>
#include "SWAV.h"
@ -29,5 +28,3 @@ struct SWAR
void Read(PseudoFile &file);
};
#endif

View File

@ -1,7 +1,7 @@
/*
* SSEQ Player - SDAT SWAV (Waveform/Sample) structure
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
* Last modification on 2013-04-10
* Last modification on 2013-04-12
*
* Nintendo DS Nitro Composer (SDAT) Specification document found at
* http://www.feshrine.net/hacking/doc/nds-sdat.html
@ -62,20 +62,21 @@ static inline void DecodeADPCMNibble(int32_t nibble, int32_t &stepIndex, int32_t
predictedValue = 0x7FFF;
}
void SWAV::DecodeADPCM(const std::vector<uint8_t> &origData)
void SWAV::DecodeADPCM(const uint8_t *origData, uint32_t len)
{
int32_t predictedValue = origData[0] | (origData[1] << 8);
int32_t stepIndex = origData[2] | (origData[3] << 8);
auto finalData = &this->data[0];
for (long i = 0, len = origData.size() - 4; i < len; ++i)
for (uint32_t i = 0; i < len; ++i)
{
int32_t nibble = origData[i + 4] & 0x0F;
DecodeADPCMNibble(nibble, stepIndex, predictedValue);
this->data[2 * i] = predictedValue;
finalData[2 * i] = predictedValue;
nibble = (origData[i + 4] >> 4) & 0x0F;
DecodeADPCMNibble(nibble, stepIndex, predictedValue);
this->data[2 * i + 1] = predictedValue;
finalData[2 * i + 1] = predictedValue;
}
}
@ -114,7 +115,7 @@ void SWAV::Read(PseudoFile &file)
{
// IMA ADPCM -> PCM signed 16-bit
this->data.resize((origData.size() - 4) * 2, 0);
this->DecodeADPCM(origData);
this->DecodeADPCM(&origData[0], origData.size() - 4);
--this->loopOffset;
this->loopOffset *= 8;
this->nonLoopLength *= 8;

View File

@ -1,14 +1,13 @@
/*
* SSEQ Player - SDAT SWAV (Waveform/Sample) structure
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
* Last modification on 2013-04-10
* Last modification on 2014-09-08
*
* Nintendo DS Nitro Composer (SDAT) Specification document found at
* http://www.feshrine.net/hacking/doc/nds-sdat.html
*/
#ifndef SSEQPLAYER_SWAV_H
#define SSEQPLAYER_SWAV_H
#pragma once
#include "common.h"
@ -26,7 +25,5 @@ struct SWAV
SWAV();
void Read(PseudoFile &file);
void DecodeADPCM(const std::vector<uint8_t> &data);
void DecodeADPCM(const uint8_t *origData, uint32_t len);
};
#endif

View File

@ -1,14 +1,13 @@
/*
* SSEQ Player - SDAT SYMB (Symbol/Filename) Section structures
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
* Last modification on 2013-03-21
* Last modification on 2014-09-08
*
* Nintendo DS Nitro Composer (SDAT) Specification document found at
* http://www.feshrine.net/hacking/doc/nds-sdat.html
*/
#ifndef SSEQPLAYER_SYMBSECTION_H
#define SSEQPLAYER_SYMBSECTION_H
#pragma once
#include <map>
#include "common.h"
@ -35,5 +34,3 @@ struct SYMBSection
void Read(PseudoFile &file);
};
#endif

View File

@ -1,13 +1,14 @@
/*
* SSEQ Player - Track structure
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
* Last modification on 2013-04-01
* Last modification on 2014-10-23
*
* Adapted from source code of FeOS Sound System
* By fincs
* https://github.com/fincs/FSS
*/
#include <cstdlib>
#include "Track.h"
#include "Player.h"
#include "common.h"
@ -17,6 +18,7 @@ Track::Track()
this->Zero();
}
// Original FSS Function: Player_InitTrack
void Track::Init(uint8_t handle, Player *player, const uint8_t *dataPos, int n)
{
this->trackId = handle;
@ -35,9 +37,11 @@ void Track::Zero()
this->ply = nullptr;
this->startPos = this->pos = nullptr;
memset(this->stack, 0, sizeof(this->stack));
std::fill_n(&this->stack[0], FSS_TRACKSTACKSIZE, StackValue());
this->stackPos = 0;
memset(this->loopCount, 0, sizeof(this->loopCount));
this->overriding() = false;
this->lastComparisonResult = true;
this->wait = 0;
this->patch = 0;
@ -56,6 +60,7 @@ void Track::Zero()
this->updateFlags.reset();
}
// Original FSS Function: Track_ClearState
void Track::ClearState()
{
this->state.reset();
@ -71,8 +76,7 @@ void Track::ClearState()
this->portaKey = 60;
this->portaTime = 0;
this->sweepPitch = 0;
this->vol = 64;
this->expr = 127;
this->vol = this->expr = 127;
this->pan = 0;
this->pitchBendRange = 2;
this->pitchBend = this->transpose = 0;
@ -82,16 +86,18 @@ void Track::ClearState()
this->modType = 0;
this->modRange = 1;
this->modSpeed = 16;
this->modDelay = 10;
this->modDelay = 0;
this->modDepth = 0;
}
// Original FSS Function: Track_Free
void Track::Free()
{
this->state.reset();
this->updateFlags.reset();
}
// Original FSS Function: Note_On
int Track::NoteOn(int key, int vel, int len)
{
auto sbnk = this->ply->sseq->bank;
@ -210,6 +216,7 @@ int Track::NoteOn(int key, int vel, int len)
return nCh;
}
// Original FSS Function: Note_On_Tie
int Track::NoteOnTie(int key, int vel)
{
// Find an existing note
@ -245,6 +252,7 @@ int Track::NoteOnTie(int key, int vel)
return i;
}
// Original FSS Function: Track_ReleaseAllNotes
void Track::ReleaseAllNotes()
{
for (int i = 0; i < 16; ++i)
@ -257,6 +265,9 @@ void Track::ReleaseAllNotes()
enum SseqCommand
{
SSEQ_CMD_ALLOCTRACK = 0xFE, // Silently ignored
SSEQ_CMD_OPENTRACK = 0x93,
SSEQ_CMD_REST = 0x80,
SSEQ_CMD_PATCH = 0x81,
SSEQ_CMD_PAN = 0xC0,
@ -298,11 +309,173 @@ enum SseqCommand
SSEQ_CMD_RANDOM = 0xA0,
SSEQ_CMD_PRINTVAR = 0xD6,
SSEQ_CMD_IF = 0xA2,
SSEQ_CMD_UNSUP1 = 0xA1,
SSEQ_CMD_UNSUP2_LO = 0xB0,
SSEQ_CMD_UNSUP2_HI = 0xBD
SSEQ_CMD_FROMVAR = 0xA1,
SSEQ_CMD_SETVAR = 0xB0,
SSEQ_CMD_ADDVAR = 0xB1,
SSEQ_CMD_SUBVAR = 0xB2,
SSEQ_CMD_MULVAR = 0xB3,
SSEQ_CMD_DIVVAR = 0xB4,
SSEQ_CMD_SHIFTVAR = 0xB5,
SSEQ_CMD_RANDVAR = 0xB6,
SSEQ_CMD_CMP_EQ = 0xB8,
SSEQ_CMD_CMP_GE = 0xB9,
SSEQ_CMD_CMP_GT = 0xBA,
SSEQ_CMD_CMP_LE = 0xBB,
SSEQ_CMD_CMP_LT = 0xBC,
SSEQ_CMD_CMP_NE = 0xBD,
SSEQ_CMD_MUTE = 0xD7 // Unsupported
};
static const uint8_t VariableByteCount = 1 << 7;
static const uint8_t ExtraByteOnNoteOrVarOrCmp = 1 << 6;
static inline uint8_t SseqCommandByteCount(int cmd)
{
if (cmd < 0x80)
return 1 | VariableByteCount;
else
switch (cmd)
{
case SSEQ_CMD_REST:
case SSEQ_CMD_PATCH:
return VariableByteCount;
case SSEQ_CMD_PAN:
case SSEQ_CMD_VOL:
case SSEQ_CMD_MASTERVOL:
case SSEQ_CMD_PRIO:
case SSEQ_CMD_NOTEWAIT:
case SSEQ_CMD_TIE:
case SSEQ_CMD_EXPR:
case SSEQ_CMD_LOOPSTART:
case SSEQ_CMD_TRANSPOSE:
case SSEQ_CMD_PITCHBEND:
case SSEQ_CMD_PITCHBENDRANGE:
case SSEQ_CMD_ATTACK:
case SSEQ_CMD_DECAY:
case SSEQ_CMD_SUSTAIN:
case SSEQ_CMD_RELEASE:
case SSEQ_CMD_PORTAKEY:
case SSEQ_CMD_PORTAFLAG:
case SSEQ_CMD_PORTATIME:
case SSEQ_CMD_MODDEPTH:
case SSEQ_CMD_MODSPEED:
case SSEQ_CMD_MODTYPE:
case SSEQ_CMD_MODRANGE:
case SSEQ_CMD_PRINTVAR:
case SSEQ_CMD_MUTE:
return 1;
case SSEQ_CMD_ALLOCTRACK:
case SSEQ_CMD_TEMPO:
case SSEQ_CMD_SWEEPPITCH:
case SSEQ_CMD_MODDELAY:
return 2;
case SSEQ_CMD_GOTO:
case SSEQ_CMD_CALL:
case SSEQ_CMD_SETVAR:
case SSEQ_CMD_ADDVAR:
case SSEQ_CMD_SUBVAR:
case SSEQ_CMD_MULVAR:
case SSEQ_CMD_DIVVAR:
case SSEQ_CMD_SHIFTVAR:
case SSEQ_CMD_RANDVAR:
case SSEQ_CMD_CMP_EQ:
case SSEQ_CMD_CMP_GE:
case SSEQ_CMD_CMP_GT:
case SSEQ_CMD_CMP_LE:
case SSEQ_CMD_CMP_LT:
case SSEQ_CMD_CMP_NE:
return 3;
case SSEQ_CMD_OPENTRACK:
return 4;
case SSEQ_CMD_FROMVAR:
return 1 | ExtraByteOnNoteOrVarOrCmp; // Technically 2 bytes with an additional 1, leaving 1 off because we will be reading it to determine if the additional byte is needed
case SSEQ_CMD_RANDOM:
return 4 | ExtraByteOnNoteOrVarOrCmp; // Technically 5 bytes with an additional 1, leaving 1 off because we will be reading it to determine if the additional byte is needed
default:
return 0;
}
}
static auto varFuncSet = [](int16_t, int16_t value) { return value; };
static auto varFuncAdd = [](int16_t var, int16_t value) -> int16_t { return var + value; };
static auto varFuncSub = [](int16_t var, int16_t value) -> int16_t { return var - value; };
static auto varFuncMul = [](int16_t var, int16_t value) -> int16_t { return var * value; };
static auto varFuncDiv = [](int16_t var, int16_t value) -> int16_t { return var / value; };
static auto varFuncShift = [](int16_t var, int16_t value) -> int16_t
{
if (value < 0)
return var >> -value;
else
return var << value;
};
static auto varFuncRand = [](int16_t, int16_t value) -> int16_t
{
if (value < 0)
return -(std::rand() % (-value + 1));
else
return std::rand() % (value + 1);
};
static inline std::function<int16_t (int16_t, int16_t)> VarFunc(int cmd)
{
switch (cmd)
{
case SSEQ_CMD_SETVAR:
return varFuncSet;
case SSEQ_CMD_ADDVAR:
return varFuncAdd;
case SSEQ_CMD_SUBVAR:
return varFuncSub;
case SSEQ_CMD_MULVAR:
return varFuncMul;
case SSEQ_CMD_DIVVAR:
return varFuncDiv;
case SSEQ_CMD_SHIFTVAR:
return varFuncShift;
case SSEQ_CMD_RANDVAR:
return varFuncRand;
default:
return nullptr;
}
}
static auto compareFuncEq = [](int16_t a, int16_t b) { return a == b; };
static auto compareFuncGe = [](int16_t a, int16_t b) { return a >= b; };
static auto compareFuncGt = [](int16_t a, int16_t b) { return a > b; };
static auto compareFuncLe = [](int16_t a, int16_t b) { return a <= b; };
static auto compareFuncLt = [](int16_t a, int16_t b) { return a < b; };
static auto compareFuncNe = [](int16_t a, int16_t b) { return a != b; };
static inline std::function<bool (int16_t, int16_t)> CompareFunc(int cmd)
{
switch (cmd)
{
case SSEQ_CMD_CMP_EQ:
return compareFuncEq;
case SSEQ_CMD_CMP_GE:
return compareFuncGe;
case SSEQ_CMD_CMP_GT:
return compareFuncGt;
case SSEQ_CMD_CMP_LE:
return compareFuncLe;
case SSEQ_CMD_CMP_LT:
return compareFuncLt;
case SSEQ_CMD_CMP_NE:
return compareFuncNe;
default:
return nullptr;
}
}
// Original FSS Function: Track_Run
void Track::Run()
{
// Indicate "heartbeat" for this track
@ -323,13 +496,17 @@ void Track::Run()
while (!this->wait)
{
int cmd = read8(pData);
int cmd;
if (this->overriding())
cmd = this->overriding.cmd;
else
cmd = read8(pData);
if (cmd < 0x80)
{
// Note on
int key = cmd + this->transpose;
int vel = read8(pData);
int len = readvl(pData);
int vel = this->overriding.val(pData, read8, true);
int len = this->overriding.val(pData, readvl);
if (this->state[TS_NOTEWAIT])
this->wait = len;
if (this->state[TS_TIEBIT])
@ -338,18 +515,33 @@ void Track::Run()
this->NoteOn(key, vel, len);
}
else
{
int value;
switch (cmd)
{
//-----------------------------------------------------------------
// Main commands
//-----------------------------------------------------------------
case SSEQ_CMD_OPENTRACK:
{
int tNum = read8(pData);
auto trackPos = &this->ply->sseq->data[read24(pData)];
int newTrack = this->ply->TrackAlloc();
if (newTrack != -1)
{
this->ply->tracks[newTrack].Init(newTrack, this->ply, trackPos, tNum);
this->ply->trackIds[this->ply->nTracks++] = newTrack;
}
break;
}
case SSEQ_CMD_REST:
this->wait = readvl(pData);
this->wait = this->overriding.val(pData, readvl);
break;
case SSEQ_CMD_PATCH:
this->patch = readvl(pData);
this->patch = this->overriding.val(pData, readvl);
break;
case SSEQ_CMD_GOTO:
@ -357,29 +549,32 @@ void Track::Run()
break;
case SSEQ_CMD_CALL:
{
const uint8_t *dest = &this->ply->sseq->data[read24(pData)];
this->stack[this->stackPos++] = *pData;
*pData = dest;
value = read24(pData);
if (this->stackPos < FSS_TRACKSTACKSIZE)
{
const uint8_t *dest = &this->ply->sseq->data[value];
this->stack[this->stackPos++] = StackValue(STACKTYPE_CALL, *pData);
*pData = dest;
}
break;
}
case SSEQ_CMD_RET:
*pData = this->stack[--this->stackPos];
if (this->stackPos && this->stack[this->stackPos - 1].type == STACKTYPE_CALL)
*pData = this->stack[--this->stackPos].dest;
break;
case SSEQ_CMD_PAN:
this->pan = read8(pData) - 64;
this->pan = this->overriding.val(pData, read8) - 64;
this->updateFlags.set(TUF_PAN);
break;
case SSEQ_CMD_VOL:
this->vol = read8(pData);
this->vol = this->overriding.val(pData, read8);
this->updateFlags.set(TUF_VOL);
break;
case SSEQ_CMD_MASTERVOL:
this->ply->masterVol = Cnv_Sust(read8(pData));
this->ply->masterVol = Cnv_Sust(this->overriding.val(pData, read8));
for (uint8_t i = 0; i < this->ply->nTracks; ++i)
this->ply->tracks[this->ply->trackIds[i]].updateFlags.set(TUF_VOL);
break;
@ -399,7 +594,7 @@ void Track::Run()
break;
case SSEQ_CMD_EXPR:
this->expr = read8(pData);
this->expr = this->overriding.val(pData, read8);
this->updateFlags.set(TUF_VOL);
break;
@ -412,19 +607,24 @@ void Track::Run()
return;
case SSEQ_CMD_LOOPSTART:
this->loopCount[this->stackPos] = read8(pData);
this->stack[this->stackPos++] = *pData;
value = this->overriding.val(pData, read8);
if (this->stackPos < FSS_TRACKSTACKSIZE)
{
this->loopCount[this->stackPos] = value;
this->stack[this->stackPos++] = StackValue(STACKTYPE_LOOP, *pData);
}
break;
case SSEQ_CMD_LOOPEND:
if (this->stackPos)
if (this->stackPos && this->stack[this->stackPos - 1].type == STACKTYPE_LOOP)
{
const uint8_t *rPos = this->stack[this->stackPos - 1];
const uint8_t *rPos = this->stack[this->stackPos - 1].dest;
uint8_t &nR = this->loopCount[this->stackPos - 1];
uint8_t prevR = nR;
if (prevR && !--nR)
if (!prevR || --nR)
*pData = rPos;
else
--this->stackPos;
*pData = rPos;
}
break;
@ -433,11 +633,11 @@ void Track::Run()
//-----------------------------------------------------------------
case SSEQ_CMD_TRANSPOSE:
this->transpose = read8(pData);
this->transpose = this->overriding.val(pData, read8);
break;
case SSEQ_CMD_PITCHBEND:
this->pitchBend = read8(pData);
this->pitchBend = this->overriding.val(pData, read8);
this->updateFlags.set(TUF_TIMER);
break;
@ -451,19 +651,19 @@ void Track::Run()
//-----------------------------------------------------------------
case SSEQ_CMD_ATTACK:
this->a = read8(pData);
this->a = this->overriding.val(pData, read8);
break;
case SSEQ_CMD_DECAY:
this->d = read8(pData);
this->d = this->overriding.val(pData, read8);
break;
case SSEQ_CMD_SUSTAIN:
this->s = read8(pData);
this->s = this->overriding.val(pData, read8);
break;
case SSEQ_CMD_RELEASE:
this->r = read8(pData);
this->r = this->overriding.val(pData, read8);
break;
//-----------------------------------------------------------------
@ -482,12 +682,12 @@ void Track::Run()
break;
case SSEQ_CMD_PORTATIME:
this->portaTime = read8(pData);
this->portaTime = this->overriding.val(pData, read8);
// Update here?
break;
case SSEQ_CMD_SWEEPPITCH:
this->sweepPitch = read16(pData);
this->sweepPitch = this->overriding.val(pData, read16);
// Update here?
break;
@ -496,12 +696,12 @@ void Track::Run()
//-----------------------------------------------------------------
case SSEQ_CMD_MODDEPTH:
this->modDepth = read8(pData);
this->modDepth = this->overriding.val(pData, read8);
this->updateFlags.set(TUF_MOD);
break;
case SSEQ_CMD_MODSPEED:
this->modSpeed = read8(pData);
this->modSpeed = this->overriding.val(pData, read8);
this->updateFlags.set(TUF_MOD);
break;
@ -516,37 +716,97 @@ void Track::Run()
break;
case SSEQ_CMD_MODDELAY:
this->modDelay = read16(pData);
this->modDelay = this->overriding.val(pData, read16);
this->updateFlags.set(TUF_MOD);
break;
//-----------------------------------------------------------------
// Randomness-related commands
//-----------------------------------------------------------------
case SSEQ_CMD_RANDOM:
{
this->overriding() = true;
this->overriding.cmd = read8(pData);
if ((this->overriding.cmd >= SSEQ_CMD_SETVAR && this->overriding.cmd <= SSEQ_CMD_CMP_NE) || this->overriding.cmd < 0x80)
this->overriding.extraValue = read8(pData);
int16_t minVal = read16(pData);
int16_t maxVal = read16(pData);
this->overriding.value = (std::rand() % (maxVal - minVal + 1)) + minVal;
break;
}
//-----------------------------------------------------------------
// Variable-related commands
//-----------------------------------------------------------------
case SSEQ_CMD_RANDOM: // TODO
*pData += 5;
case SSEQ_CMD_FROMVAR:
this->overriding() = true;
this->overriding.cmd = read8(pData);
if ((this->overriding.cmd >= SSEQ_CMD_SETVAR && this->overriding.cmd <= SSEQ_CMD_CMP_NE) || this->overriding.cmd < 0x80)
this->overriding.extraValue = read8(pData);
this->overriding.value = this->ply->variables[read8(pData)];
break;
case SSEQ_CMD_PRINTVAR: // TODO
*pData += 1;
break;
case SSEQ_CMD_UNSUP1: // TODO
case SSEQ_CMD_SETVAR:
case SSEQ_CMD_ADDVAR:
case SSEQ_CMD_SUBVAR:
case SSEQ_CMD_MULVAR:
case SSEQ_CMD_DIVVAR:
case SSEQ_CMD_SHIFTVAR:
case SSEQ_CMD_RANDVAR:
{
int t = read8(pData);
if (t >= SSEQ_CMD_UNSUP2_LO && t <= SSEQ_CMD_UNSUP2_HI)
*pData += 1;
*pData += 1;
int8_t varNo = this->overriding.val(pData, read8, true);
value = this->overriding.val(pData, read16);
if (cmd == SSEQ_CMD_DIVVAR && !value) // Division by 0, skip it to prevent crashing
break;
this->ply->variables[varNo] = VarFunc(cmd)(this->ply->variables[varNo], value);
break;
}
case SSEQ_CMD_IF: // TODO
//-----------------------------------------------------------------
// Conditional-related commands
//-----------------------------------------------------------------
case SSEQ_CMD_CMP_EQ:
case SSEQ_CMD_CMP_GE:
case SSEQ_CMD_CMP_GT:
case SSEQ_CMD_CMP_LE:
case SSEQ_CMD_CMP_LT:
case SSEQ_CMD_CMP_NE:
{
int8_t varNo = this->overriding.val(pData, read8, true);
value = this->overriding.val(pData, read16);
this->lastComparisonResult = CompareFunc(cmd)(this->ply->variables[varNo], value);
break;
}
case SSEQ_CMD_IF:
if (!this->lastComparisonResult)
{
int nextCmd = read8(pData);
uint8_t cmdBytes = SseqCommandByteCount(nextCmd);
bool variableBytes = !!(cmdBytes & VariableByteCount);
bool extraByte = !!(cmdBytes & ExtraByteOnNoteOrVarOrCmp);
cmdBytes &= ~(VariableByteCount | ExtraByteOnNoteOrVarOrCmp);
if (extraByte)
{
int extraCmd = read8(pData);
if ((extraCmd >= SSEQ_CMD_SETVAR && extraCmd <= SSEQ_CMD_CMP_NE) || extraCmd < 0x80)
++cmdBytes;
}
*pData += cmdBytes;
if (variableBytes)
readvl(pData);
}
break;
default:
if (cmd >= SSEQ_CMD_UNSUP2_LO && cmd <= SSEQ_CMD_UNSUP2_HI) // TODO
*pData += 3;
*pData += SseqCommandByteCount(cmd);
}
}
if (cmd != SSEQ_CMD_RANDOM && cmd != SSEQ_CMD_FROMVAR)
this->overriding() = false;
}
}

View File

@ -1,21 +1,55 @@
/*
* SSEQ Player - Track structure
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
* Last modification on 2013-04-01
* Last modification on 2014-10-13
*
* Adapted from source code of FeOS Sound System
* By fincs
* https://github.com/fincs/FSS
*/
#ifndef SSEQPLAYER_TRACK_H
#define SSEQPLAYER_TRACK_H
#pragma once
#include <functional>
#include <bitset>
#include "consts.h"
struct Player;
enum StackType
{
STACKTYPE_CALL,
STACKTYPE_LOOP
};
struct StackValue
{
StackType type;
const uint8_t *dest;
StackValue() : type(STACKTYPE_CALL), dest(nullptr) { }
StackValue(StackType newType, const uint8_t *newDest) : type(newType), dest(newDest) { }
};
struct Override
{
bool overriding;
int cmd;
int value;
int extraValue;
Override() : overriding(false) { }
bool operator()() const { return this->overriding; }
bool &operator()() { return this->overriding; }
int val(const uint8_t **pData, std::function<int (const uint8_t **)> reader, bool returnExtra = false)
{
if (this->overriding)
return returnExtra ? this->extraValue : this->value;
else
return reader(pData);
}
};
struct Track
{
int8_t trackId;
@ -26,9 +60,11 @@ struct Track
const uint8_t *startPos;
const uint8_t *pos;
const uint8_t *stack[FSS_TRACKSTACKSIZE];
StackValue stack[FSS_TRACKSTACKSIZE];
uint8_t stackPos;
uint8_t loopCount[FSS_TRACKSTACKSIZE];
Override overriding;
bool lastComparisonResult;
int wait;
uint16_t patch;
@ -58,5 +94,3 @@ struct Track
void ReleaseAllNotes();
void Run();
};
#endif

View File

@ -1,29 +0,0 @@
// original code is from here: http://www.codeproject.com/Tips/197097/Converting-ANSI-to-Unicode-and-back
// License: The Code Project Open License (CPOL) http://www.codeproject.com/info/cpol10.aspx
#include "UTFEncodeDecode.h"
#include "UtfConverter.h"
std::string EncodeToUTF8(const std::string &source, const std::locale &L)
{
try
{
return UtfConverter::ToUtf8(cp_converter<>(L).widen(source));
}
catch (const std::runtime_error &)
{
return "";
}
}
std::string DecodeFromUTF8(const std::string &source, const std::locale &L)
{
try
{
return cp_converter<>(L).narrow(UtfConverter::FromUtf8(source));
}
catch (const std::runtime_error &)
{
return "";
}
}

View File

@ -1,63 +0,0 @@
// original code is from here: http://www.codeproject.com/Tips/197097/Converting-ANSI-to-Unicode-and-back
// License: The Code Project Open License (CPOL) http://www.codeproject.com/info/cpol10.aspx
#ifndef UTFENCODEDECODE_H
#define UTFENCODEDECODE_H
#include <string>
#include <locale>
#include <sstream>
#include <stdexcept>
std::string EncodeToUTF8(const std::string &, const std::locale & = std::locale::classic());
std::string DecodeFromUTF8(const std::string &, const std::locale & = std::locale::classic());
template<size_t buf_size = 100> class cp_converter
{
const std::locale loc;
public:
cp_converter(const std::locale &L = std::locale::classic()) : loc(L) { }
inline std::wstring widen(const std::string &in)
{
return this->convert<char, wchar_t>(in);
}
inline std::string narrow(const std::wstring &in)
{
return this->convert<wchar_t, char>(in);
}
private:
typedef std::codecvt<wchar_t, char, mbstate_t> codecvt_facet;
// widen
inline codecvt_facet::result cv(const codecvt_facet &facet, mbstate_t &s, const char *f1, const char *l1, const char *&n1, wchar_t *f2, wchar_t *l2, wchar_t *&n2) const
{
return facet.in(s, f1, l1, n1, f2, l2, n2);
}
// narrow
inline codecvt_facet::result cv(const codecvt_facet &facet, mbstate_t &s, const wchar_t *f1, const wchar_t *l1, const wchar_t *&n1, char *f2, char *l2, char *&n2) const
{
return facet.out(s, f1, l1, n1, f2, l2, n2);
}
template<class ct_in, class ct_out> std::basic_string<ct_out> convert(const std::basic_string<ct_in> &in)
{
auto &facet = std::use_facet<codecvt_facet>(this->loc);
std::basic_stringstream<ct_out> os;
ct_out buf[buf_size];
mbstate_t state = {0};
codecvt_facet::result result;
const ct_in *ipc = &in[0];
do
{
ct_out *opc = nullptr;
result = this->cv(facet, state, ipc, &in[0] + in.length(), ipc, buf, buf + buf_size, opc);
os << std::basic_string<ct_out>(buf, opc - buf);
} while (ipc < &in[0] + in.length() && result != codecvt_facet::error);
if (result != codecvt_facet::ok)
throw std::runtime_error("result is not ok!");
return os.str();
}
};
#endif

View File

@ -1,69 +0,0 @@
// original code is from here: http://www.codeproject.com/Articles/17573/Convert-Between-std-string-and-std-wstring-UTF-8-a
// License: The Code Project Open License (CPOL) http://www.codeproject.com/info/cpol10.aspx
#include <string>
#include <vector>
#include <stdexcept>
#include "ConvertUTF.h"
namespace UtfConverter
{
std::wstring FromUtf8(const std::string &utf8string)
{
auto widesize = utf8string.length();
auto result = std::vector<wchar_t>(widesize + 1, L'\0');
auto orig = std::vector<char>(widesize + 1, '\0');
std::copy(utf8string.begin(), utf8string.end(), orig.begin());
auto *sourcestart = reinterpret_cast<const UTF8 *>(&orig[0]), *sourceend = sourcestart + widesize;
ConversionResult res;
if (sizeof(wchar_t) == 2)
{
auto *targetstart = reinterpret_cast<UTF16 *>(&result[0]), *targetend = targetstart + widesize;
res = ConvertUTF8toUTF16(&sourcestart, sourceend, &targetstart, targetend, strictConversion);
*targetstart = 0;
unsigned end = targetstart - reinterpret_cast<UTF16 *>(&result[0]);
result.erase(result.begin() + end, result.end());
}
else if (sizeof(wchar_t) == 4)
{
auto *targetstart = reinterpret_cast<UTF32 *>(&result[0]), *targetend = targetstart + widesize;
res = ConvertUTF8toUTF32(&sourcestart, sourceend, &targetstart, targetend, strictConversion);
*targetstart = 0;
unsigned long end = targetstart - reinterpret_cast<UTF32 *>(&result[0]);
result.erase(result.begin() + end, result.end());
}
else
throw std::runtime_error("UtfConverter::FromUtf8: sizeof(wchar_t) is not 2 or 4.");
if (res != conversionOK)
throw std::runtime_error("UtfConverter::FromUtf8: Conversion failed.");
return std::wstring(result.begin(), result.end());
}
std::string ToUtf8(const std::wstring &widestring)
{
auto widesize = widestring.length(), utf8size = (sizeof(wchar_t) == 2 ? 3 : 4) * widesize + 1;
auto result = std::vector<char>(utf8size, '\0');
auto orig = std::vector<wchar_t>(widesize + 1, L'\0');
std::copy(widestring.begin(), widestring.end(), orig.begin());
auto *targetstart = reinterpret_cast<UTF8 *>(&result[0]), *targetend = targetstart + utf8size;
ConversionResult res;
if (sizeof(wchar_t) == 2)
{
auto *sourcestart = reinterpret_cast<const UTF16 *>(&orig[0]), *sourceend = sourcestart + widesize;
res = ConvertUTF16toUTF8(&sourcestart, sourceend, &targetstart, targetend, strictConversion);
}
else if (sizeof(wchar_t) == 4)
{
auto *sourcestart = reinterpret_cast<const UTF32 *>(&orig[0]), *sourceend = sourcestart + widesize;
res = ConvertUTF32toUTF8(&sourcestart, sourceend, &targetstart, targetend, strictConversion);
}
else
throw std::runtime_error("UtfConverter::ToUtf8: sizeof(wchar_t) is not 2 or 4.");
if (res != conversionOK)
throw std::runtime_error("UtfConverter::ToUtf8: Conversion failed.");
*targetstart = 0;
auto end = targetstart - reinterpret_cast<UTF8 *>(&result[0]);
result.erase(result.begin() + end, result.end());
return std::string(result.begin(), result.end());
}
}

View File

@ -1,15 +0,0 @@
// original code is from here: http://www.codeproject.com/Articles/17573/Convert-Between-std-string-and-std-wstring-UTF-8-a
// License: The Code Project Open License (CPOL) http://www.codeproject.com/info/cpol10.aspx
#ifndef UTFCONVERTER_H
#define UTFCONVERTER_H
#include <string>
namespace UtfConverter
{
std::wstring FromUtf8(const std::string &);
std::string ToUtf8(const std::wstring &);
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,15 +1,14 @@
/*
* SSEQ Player - Common functions
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
* Last modification on 2013-03-3
* Last modification on 2014-10-18
*
* Some code from FeOS Sound System
* By fincs
* https://github.com/fincs/FSS
*/
#ifndef SSEQPLAYER_COMMON_H
#define SSEQPLAYER_COMMON_H
#pragma once
#include <string>
#include <vector>
@ -143,11 +142,15 @@ inline int Cnv_Attack(int attk)
0x5C, 0x64, 0x6D, 0x74, 0x7B, 0x7F, 0x84, 0x89, 0x8F
};
if (attk & 0x80) // Supposedly invalid value...
attk = 0; // Use apparently correct default
return attk >= 0x6D ? lut[0x7F - attk] : 0xFF - attk;
}
inline int Cnv_Fall(int fall)
{
if (fall & 0x80) // Supposedly invalid value...
fall = 0; // Use apparently correct default
if (fall == 0x7F)
return 0xFFFF;
else if (fall == 0x7E)
@ -158,6 +161,33 @@ inline int Cnv_Fall(int fall)
return (0x1E00 / (0x7E - fall)) & 0xFFFF;
}
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) // Supposedly invalid value...
scale = 0x7F; // Use apparently correct default
return lut[scale];
}
inline int Cnv_Sust(int sust)
{
static const int16_t lut[] =
@ -180,6 +210,8 @@ inline int Cnv_Sust(int sust)
-10, -8, -7, -6, -4, -3, -1, 0
};
if (sust & 0x80) // Supposedly invalid value...
sust = 0x7F; // Use apparently correct default
return lut[sust];
}
@ -238,4 +270,11 @@ inline int readvl(const uint8_t **ppData)
return x;
}
#endif
// Clamp a value between a minimum and maximum value
template<typename T1, typename T2> inline void clamp(T1 &valueToClamp, const T2 &minValue, const T2 &maxValue)
{
if (valueToClamp < minValue)
valueToClamp = minValue;
else if (valueToClamp > maxValue)
valueToClamp = maxValue;
}

View File

@ -1,7 +1,7 @@
/*
* SSEQ Player - Constants/Macros
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
* Last modification on 2013-04-12
* Last modification on 2014-09-08
*
* Adapted from source code of FeOS Sound System
* By fincs
@ -11,8 +11,7 @@
* http://devkitpro.org/
*/
#ifndef SSEQPLAYER_CONSTS_H
#define SSEQPLAYER_CONSTS_H
#pragma once
#include <cstdint>
@ -55,11 +54,7 @@ enum Interpolation
{
INTERPOLATION_NONE,
INTERPOLATION_LINEAR,
INTERPOLATION_COSINE,
INTERPOLATION_4POINTBSPLINE,
INTERPOLATION_6POINTOSCULATING,
INTERPOLATION_6POINTBSPLINE,
INTERPOLATION_LANCZOS
INTERPOLATION_4POINTLEGRANGE,
INTERPOLATION_6POINTLEGRANGE,
INTERPOLATION_SINC
};
#endif

View File

@ -1,20 +1,24 @@
/*
* Common conversion functions
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
* Last modification on 2013-03-30
* Last modification on 2014-09-24
*/
#ifndef _CONVERT_H_
#define _CONVERT_H_
#pragma once
#include <stdexcept>
#include <string>
#include <sstream>
#include <typeinfo>
#include <locale>
#if (defined(__GNUC__) || defined(__clang__)) && !defined(_LIBCPP_VERSION)
# include "wstring_convert.h"
# include "codecvt.h"
#else
# include <codecvt>
#endif
#include <vector>
#include <cmath>
#include "BigSString.h"
/*
* The following exception class and the *stringify and convert* functions are
@ -130,7 +134,7 @@ public:
static unsigned long StringToMS(const std::wstring &time)
{
return ConvertFuncs::StringToMS(String(time).GetAnsi());
return ConvertFuncs::StringToMS(ConvertFuncs::WStringToString(time));
}
static std::string MSToString(unsigned long time)
@ -149,8 +153,18 @@ public:
static std::wstring MSToWString(unsigned long time)
{
return String(ConvertFuncs::MSToString(time)).GetWStr();
return ConvertFuncs::StringToWString(ConvertFuncs::MSToString(time));
}
static std::wstring StringToWString(const std::string &str)
{
static std::wstring_convert<std::codecvt_utf8<wchar_t>> conv;
return conv.from_bytes(str);
}
static std::string WStringToString(const std::wstring &wstr)
{
static std::wstring_convert<std::codecvt_utf8<wchar_t>> conv;
return conv.to_bytes(wstr);
}
};
#endif

View File

@ -0,0 +1,183 @@
// This comes from llvm's libcxx project. I've copied the code from there (with very minor modifications) for use with GCC and Clang when libcxx isn't being used.
#if (defined(__GNUC__) || defined(__clang__)) && !defined(_LIBCPP_VERSION)
#pragma once
#include <memory>
#include <string>
#include <locale>
namespace std
{
template<class _Codecvt, class _Elem = wchar_t, class _Wide_alloc = allocator<_Elem>, class _Byte_alloc = allocator<char>> class wstring_convert
{
public:
typedef basic_string<char, char_traits<char>, _Byte_alloc> byte_string;
typedef basic_string<_Elem, char_traits<_Elem>, _Wide_alloc> wide_string;
typedef typename _Codecvt::state_type state_type;
typedef typename wide_string::traits_type::int_type int_type;
private:
byte_string __byte_err_string_;
wide_string __wide_err_string_;
_Codecvt *__cvtptr_;
state_type __cvtstate_;
size_t __cvtcount_;
wstring_convert(const wstring_convert &__wc);
wstring_convert& operator=(const wstring_convert &__wc);
public:
wstring_convert(_Codecvt *__pcvt = new _Codecvt) : __cvtptr_(__pcvt), __cvtstate_(), __cvtcount_(0) { }
wstring_convert(_Codecvt *__pcvt, state_type __state) : __cvtptr_(__pcvt), __cvtstate_(__state), __cvtcount_(0) { }
wstring_convert(const byte_string &__byte_err, const wide_string &__wide_err = wide_string()) : __byte_err_string_(__byte_err), __wide_err_string_(__wide_err), __cvtptr_(new _Codecvt), __cvtstate_(), __cvtcount_(0) { }
wstring_convert(wstring_convert &&__wc) : __byte_err_string_(move(__wc.__byte_err_string_)), __wide_err_string_(move(__wc.__wide_err_string_)), __cvtptr_(__wc.__cvtptr_), __cvtstate_(__wc.__cvtstate_), __cvtcount_(__wc.__cvtstate_)
{
__wc.__cvtptr_ = nullptr;
}
~wstring_convert() { delete this->__cvtptr_; }
wide_string from_bytes(char __byte) { return from_bytes(&__byte, &__byte + 1); }
wide_string from_bytes(const char *__ptr) { return from_bytes(__ptr, __ptr + char_traits<char>::length(__ptr)); }
wide_string from_bytes(const byte_string &__str) { return from_bytes(__str.data(), __str.data() + __str.size()); }
wide_string from_bytes(const char *__frm, const char *__frm_end)
{
this->__cvtcount_ = 0;
if (this->__cvtptr_)
{
wide_string __ws(2 * (__frm_end - __frm), _Elem());
if (__frm != __frm_end)
__ws.resize(__ws.capacity());
auto __r = codecvt_base::ok;
auto __st = this->__cvtstate_;
if (__frm != __frm_end)
{
auto __to = &__ws[0];
auto __to_end = __to + __ws.size();
const char *__frm_nxt;
do
{
_Elem *__to_nxt;
__r = this->__cvtptr_->in(__st, __frm, __frm_end, __frm_nxt, __to, __to_end, __to_nxt);
this->__cvtcount_ += __frm_nxt - __frm;
if (__frm_nxt == __frm)
__r = codecvt_base::error;
else if (__r == codecvt_base::noconv)
{
__ws.resize(__to - &__ws[0]);
// This only gets executed if _Elem is char
__ws.append(reinterpret_cast<const _Elem *>(__frm), reinterpret_cast<const _Elem *>(__frm_end));
__frm = __frm_nxt;
__r = codecvt_base::ok;
}
else if (__r == codecvt_base::ok)
{
__ws.resize(__to_nxt - &__ws[0]);
__frm = __frm_nxt;
}
else if (__r == codecvt_base::partial)
{
ptrdiff_t __s = __to_nxt - &__ws[0];
__ws.resize(2 * __s);
__to = &__ws[0] + __s;
__to_end = &__ws[0] + __ws.size();
__frm = __frm_nxt;
}
} while (__r == codecvt_base::partial && __frm_nxt < __frm_end);
}
if (__r == codecvt_base::ok)
return __ws;
}
if (this->__wide_err_string_.empty())
throw range_error("wstring_convert: from_bytes error");
return this->__wide_err_string_;
}
byte_string to_bytes(_Elem __wchar) { return to_bytes(&__wchar, &__wchar + 1); }
byte_string to_bytes(const _Elem *__wptr) { return to_bytes(__wptr, __wptr + char_traits<_Elem>::length(__wptr)); }
byte_string to_bytes(const wide_string &__wstr) { return to_bytes(__wstr.data(), __wstr.data() + __wstr.size()); }
byte_string to_bytes(const _Elem *__frm, const _Elem *__frm_end)
{
this->__cvtcount_ = 0;
if (this->__cvtptr_)
{
byte_string __bs(2 * (__frm_end - __frm), char());
if (__frm != __frm_end)
__bs.resize(__bs.capacity());
auto __r = codecvt_base::ok;
auto __st = this->__cvtstate_;
if (__frm != __frm_end)
{
auto __to = &__bs[0];
auto __to_end = __to + __bs.size();
const _Elem *__frm_nxt;
do
{
char *__to_nxt;
__r = this->__cvtptr_->out(__st, __frm, __frm_end, __frm_nxt, __to, __to_end, __to_nxt);
this->__cvtcount_ += __frm_nxt - __frm;
if (__frm_nxt == __frm)
__r = codecvt_base::error;
else if (__r == codecvt_base::noconv)
{
__bs.resize(__to - &__bs[0]);
// This only gets executed if _Elem is char
__bs.append(reinterpret_cast<const char *>(__frm), reinterpret_cast<const char *>(__frm_end));
__frm = __frm_nxt;
__r = codecvt_base::ok;
}
else if (__r == codecvt_base::ok)
{
__bs.resize(__to_nxt - &__bs[0]);
__frm = __frm_nxt;
}
else if (__r == codecvt_base::partial)
{
ptrdiff_t __s = __to_nxt - &__bs[0];
__bs.resize(2 * __s);
__to = &__bs[0] + __s;
__to_end = &__bs[0] + __bs.size();
__frm = __frm_nxt;
}
} while (__r == codecvt_base::partial && __frm_nxt < __frm_end);
}
if (__r == codecvt_base::ok)
{
auto __s = __bs.size();
__bs.resize(__bs.capacity());
auto __to = &__bs[0] + __s;
auto __to_end = __to + __bs.size();
do
{
char *__to_nxt;
__r = this->__cvtptr_->unshift(__st, __to, __to_end, __to_nxt);
if (__r == codecvt_base::noconv)
{
__bs.resize(__to - &__bs[0]);
__r = codecvt_base::ok;
}
else if (__r == codecvt_base::ok)
__bs.resize(__to_nxt - &__bs[0]);
else if (__r == codecvt_base::partial)
{
ptrdiff_t __sp = __to_nxt - &__bs[0];
__bs.resize(2 * __sp);
__to = &__bs[0] + __sp;
__to_end = &__bs[0] + __bs.size();
}
} while (__r == codecvt_base::partial);
if (__r == codecvt_base::ok)
return __bs;
}
}
if (this->__byte_err_string_.empty())
throw range_error("wstring_convert: to_bytes error");
return this->__byte_err_string_;
}
size_t converted() const noexcept { return this->__cvtcount_; }
state_type state() const { return this->__cvtstate_; }
};
}
#endif