Some template cleanup:
* Move the ToIntegral function from NCSF specifically to the framework in general, so it can be used in the base framework's code too.
* Use type traits a bit more.
* Move convertTo into the ConvertFuncs class.
--- a/src/in_ncsf/SSEQPlayer/Channel.cpp
+++ b/src/in_ncsf/SSEQPlayer/Channel.cpp
@@ -23,6 +23,7 @@
#include "XSFCommon.h"
#include "common.h"
#include "consts.h"
+#include "convert.h"
NDSSoundRegister::NDSSoundRegister() : volumeMul(0), volumeDiv(0), panning(0), waveDuty(0), repeatMode(0), format(0), enable(false),
source(nullptr), timer(0), psgX(0), psgLast(0), psgLastCount(0), samplePosition(0), sampleIncrease(0), loopStart(0), length(0), totalLength(0)
@@ -123,7 +124,7 @@
this->manualSweep = false;
this->sweepPitch = trk.sweepPitch;
this->sweepCnt = 0;
- if (!trk.state[ToIntegral(TrackState::PortamentoBit)])
+ if (!trk.state[ConvertFuncs::ToIntegral(TrackState::PortamentoBit)])
{
this->sweepLen = 0;
return;
@@ -192,7 +193,7 @@
if (trackFlags.none())
return;
- if (trackFlags[ToIntegral(TrackUpdateFlag::Length)])
+ if (trackFlags[ConvertFuncs::ToIntegral(TrackUpdateFlag::Length)])
{
ChannelState st = this->state;
if (st > ChannelState::Start)
@@ -203,30 +204,30 @@
++this->sweepCnt;
}
}
- if (trackFlags[ToIntegral(TrackUpdateFlag::Volume)])
+ if (trackFlags[ConvertFuncs::ToIntegral(TrackUpdateFlag::Volume)])
{
this->UpdateVol(trk);
- this->flags.set(ToIntegral(ChannelFlag::UpdateVolume));
- }
- if (trackFlags[ToIntegral(TrackUpdateFlag::Pan)])
+ this->flags.set(ConvertFuncs::ToIntegral(ChannelFlag::UpdateVolume));
+ }
+ if (trackFlags[ConvertFuncs::ToIntegral(TrackUpdateFlag::Pan)])
{
this->UpdatePan(trk);
- this->flags.set(ToIntegral(ChannelFlag::UpdatePan));
- }
- if (trackFlags[ToIntegral(TrackUpdateFlag::Timer)])
+ this->flags.set(ConvertFuncs::ToIntegral(ChannelFlag::UpdatePan));
+ }
+ if (trackFlags[ConvertFuncs::ToIntegral(TrackUpdateFlag::Timer)])
{
this->UpdateTune(trk);
- this->flags.set(ToIntegral(ChannelFlag::UpdateTimer));
- }
- if (trackFlags[ToIntegral(TrackUpdateFlag::Modulation)])
+ this->flags.set(ConvertFuncs::ToIntegral(ChannelFlag::UpdateTimer));
+ }
+ if (trackFlags[ConvertFuncs::ToIntegral(TrackUpdateFlag::Modulation)])
{
int oldType = this->modType;
int newType = trk.modType;
this->UpdateMod(trk);
if (oldType != newType)
{
- this->flags.set(ToIntegral(getModFlag(oldType)));
- this->flags.set(ToIntegral(getModFlag(newType)));
+ this->flags.set(ConvertFuncs::ToIntegral(getModFlag(oldType)));
+ this->flags.set(ConvertFuncs::ToIntegral(getModFlag(newType)));
}
}
}
@@ -444,9 +445,9 @@
bool bInStart = this->state == ChannelState::Start;
bool bPitchSweep = this->sweepPitch && this->sweepLen && this->sweepCnt <= this->sweepLen;
bool bModulation = !!this->modDepth;
- bool bVolNeedUpdate = this->flags[ToIntegral(ChannelFlag::UpdateVolume)] || bNotInSustain;
- bool bPanNeedUpdate = this->flags[ToIntegral(ChannelFlag::UpdatePan)] || bInStart;
- bool bTmrNeedUpdate = this->flags[ToIntegral(ChannelFlag::UpdateTimer)] || bInStart || bPitchSweep;
+ bool bVolNeedUpdate = this->flags[ConvertFuncs::ToIntegral(ChannelFlag::UpdateVolume)] || bNotInSustain;
+ bool bPanNeedUpdate = this->flags[ConvertFuncs::ToIntegral(ChannelFlag::UpdatePan)] || bInStart;
+ bool bTmrNeedUpdate = this->flags[ConvertFuncs::ToIntegral(ChannelFlag::UpdateTimer)] || bInStart || bPitchSweep;
int modParam = 0;
switch (this->state)
@@ -548,7 +549,7 @@
tmr = Timer_Adjust(tmr, totalAdj);
this->reg.timer = -tmr;
this->reg.sampleIncrease = (ARM7_CLOCK / static_cast<double>(this->ply->sampleRate * 2)) / (0x10000 - this->reg.timer);
- this->flags.reset(ToIntegral(ChannelFlag::UpdateTimer));
+ this->flags.reset(ConvertFuncs::ToIntegral(ChannelFlag::UpdateTimer));
}
if (bVolNeedUpdate || bPanNeedUpdate)
@@ -576,7 +577,7 @@
this->vol = static_cast<std::uint16_t>(((cr & SOUND_VOL(0x7F)) << 4) >> calcVolDivShift((cr & SOUND_VOLDIV(3)) >> 8));
- this->flags.reset(ToIntegral(ChannelFlag::UpdateVolume));
+ this->flags.reset(ConvertFuncs::ToIntegral(ChannelFlag::UpdateVolume));
}
if (bPanNeedUpdate)
@@ -590,7 +591,7 @@
cr &= ~SOUND_PAN(0x7F);
cr |= SOUND_PAN(realPan);
- this->flags.reset(ToIntegral(ChannelFlag::UpdatePan));
+ this->flags.reset(ConvertFuncs::ToIntegral(ChannelFlag::UpdatePan));
}
this->tempReg.CR = cr;
--- a/src/in_ncsf/SSEQPlayer/Channel.h
+++ b/src/in_ncsf/SSEQPlayer/Channel.h
@@ -18,6 +18,7 @@
#include <cstdint>
#include "common.h"
#include "consts.h"
+#include "convert.h"
struct SWAV;
struct Track;
@@ -179,7 +180,7 @@
std::uint8_t prio;
bool manualSweep;
- std::bitset<ToIntegral(ChannelFlag::Bits)> flags;
+ std::bitset<ConvertFuncs::ToIntegral(ChannelFlag::Bits)> flags;
std::int8_t pan; // -64 .. 63
std::int16_t extAmpl;
--- a/src/in_ncsf/SSEQPlayer/INFOSection.h
+++ b/src/in_ncsf/SSEQPlayer/INFOSection.h
@@ -9,6 +9,7 @@
#pragma once
#include <map>
+#include <type_traits>
#include <cstdint>
#include "INFOEntry.h"
@@ -16,7 +17,7 @@
template<typename T> struct INFORecord
{
- std::map<std::uint32_t, T> entries;
+ std::enable_if_t<std::is_base_of_v<INFOEntry, T>, std::map<std::uint32_t, T>> entries;
INFORecord();
--- a/src/in_ncsf/SSEQPlayer/Player.cpp
+++ b/src/in_ncsf/SSEQPlayer/Player.cpp
@@ -13,6 +13,7 @@
#include "SSEQ.h"
#include "common.h"
#include "consts.h"
+#include "convert.h"
Player::Player() : prio(0), nTracks(0), tempo(0), tempoCount(0), tempoRate(0), masterVol(0), sseqVol(0), sseq(nullptr), allowedChannels(0), sampleRate(0),
interpolation(Interpolation::None)
@@ -96,8 +97,8 @@
static const std::uint8_t arraySizes[] = { sizeof(pcmChnArray), sizeof(psgChnArray), sizeof(noiseChnArray) };
static const std::uint8_t *const arrayArray[] = { pcmChnArray, psgChnArray, noiseChnArray };
- auto chnArray = arrayArray[ToIntegral(type)];
- int arraySize = arraySizes[ToIntegral(type)];
+ auto chnArray = arrayArray[ConvertFuncs::ToIntegral(type)];
+ int arraySize = arraySizes[ConvertFuncs::ToIntegral(type)];
int curChnNo = -1;
for (int i = 0; i < arraySize; ++i)
@@ -133,10 +134,10 @@
for (int i = 0; i < FSS_MAXTRACKS; ++i)
{
Track &thisTrk = this->tracks[i];
- if (!thisTrk.state[ToIntegral(TrackState::AllocateBit)])
+ if (!thisTrk.state[ConvertFuncs::ToIntegral(TrackState::AllocateBit)])
{
thisTrk.Zero();
- thisTrk.state.set(ToIntegral(TrackState::AllocateBit));
+ thisTrk.state.set(ConvertFuncs::ToIntegral(TrackState::AllocateBit));
thisTrk.updateFlags.reset();
return i;
}
--- a/src/in_ncsf/SSEQPlayer/Track.cpp
+++ b/src/in_ncsf/SSEQPlayer/Track.cpp
@@ -19,6 +19,7 @@
#include "Track.h"
#include "common.h"
#include "consts.h"
+#include "convert.h"
Track::Track()
{
@@ -71,8 +72,8 @@
void Track::ClearState()
{
this->state.reset();
- this->state.set(ToIntegral(TrackState::AllocateBit));
- this->state.set(ToIntegral(TrackState::NoteWait));
+ this->state.set(ConvertFuncs::ToIntegral(TrackState::AllocateBit));
+ this->state.set(ConvertFuncs::ToIntegral(TrackState::NoteWait));
this->prio = this->ply->prio + 64;
this->pos = this->startPos;
@@ -253,7 +254,7 @@
chn->UpdatePorta(*this);
this->portaKey = key;
- chn->flags.set(ToIntegral(ChannelFlag::UpdateTimer));
+ chn->flags.set(ConvertFuncs::ToIntegral(ChannelFlag::UpdateTimer));
return i;
}
@@ -493,10 +494,10 @@
void Track::Run()
{
// Indicate "heartbeat" for this track
- this->updateFlags.set(ToIntegral(TrackUpdateFlag::Length));
+ this->updateFlags.set(ConvertFuncs::ToIntegral(TrackUpdateFlag::Length));
// Exit if the track has already ended
- if (this->state[ToIntegral(TrackState::End)])
+ if (this->state[ConvertFuncs::ToIntegral(TrackState::End)])
return;
if (this->wait)
@@ -521,9 +522,9 @@
std::uint8_t key = static_cast<std::uint8_t>(cmd + this->transpose);
int vel = this->overriding.val<std::uint8_t>(pData, read8, true);
int len = this->overriding.val<int>(pData, readvl);
- if (this->state[ToIntegral(TrackState::NoteWait)])
+ if (this->state[ConvertFuncs::ToIntegral(TrackState::NoteWait)])
this->wait = len;
- if (this->state[ToIntegral(TrackState::TieBit)])
+ if (this->state[ConvertFuncs::ToIntegral(TrackState::TieBit)])
this->NoteOnTie(key, vel);
else
this->NoteOn(key, vel, len);
@@ -579,18 +580,18 @@
case SSEQCommand::Pan:
this->pan = this->overriding.val<std::uint8_t>(pData, read8) - 64;
- this->updateFlags.set(ToIntegral(TrackUpdateFlag::Pan));
+ this->updateFlags.set(ConvertFuncs::ToIntegral(TrackUpdateFlag::Pan));
break;
case SSEQCommand::Volume:
this->vol = this->overriding.val<std::uint8_t>(pData, read8);
- this->updateFlags.set(ToIntegral(TrackUpdateFlag::Volume));
+ this->updateFlags.set(ConvertFuncs::ToIntegral(TrackUpdateFlag::Volume));
break;
case SSEQCommand::MasterVolume:
this->ply->masterVol = Cnv_Sust(this->overriding.val<std::uint8_t>(pData, read8));
for (std::uint8_t i = 0; i < this->ply->nTracks; ++i)
- this->ply->tracks[this->ply->trackIds[i]].updateFlags.set(ToIntegral(TrackUpdateFlag::Volume));
+ this->ply->tracks[this->ply->trackIds[i]].updateFlags.set(ConvertFuncs::ToIntegral(TrackUpdateFlag::Volume));
break;
case SSEQCommand::Priority:
@@ -599,17 +600,17 @@
break;
case SSEQCommand::NoteWait:
- this->state.set(ToIntegral(TrackState::NoteWait), !!read8(pData));
+ this->state.set(ConvertFuncs::ToIntegral(TrackState::NoteWait), !!read8(pData));
break;
case SSEQCommand::Tie:
- this->state.set(ToIntegral(TrackState::TieBit), !!read8(pData));
+ this->state.set(ConvertFuncs::ToIntegral(TrackState::TieBit), !!read8(pData));
this->ReleaseAllNotes();
break;
case SSEQCommand::Expression:
this->expr = this->overriding.val<std::uint8_t>(pData, read8);
- this->updateFlags.set(ToIntegral(TrackUpdateFlag::Volume));
+ this->updateFlags.set(ConvertFuncs::ToIntegral(TrackUpdateFlag::Volume));
break;
case SSEQCommand::Tempo:
@@ -617,7 +618,7 @@
break;
case SSEQCommand::End:
- this->state.set(ToIntegral(TrackState::End));
+ this->state.set(ConvertFuncs::ToIntegral(TrackState::End));
return;
case SSEQCommand::LoopStart:
@@ -652,12 +653,12 @@
case SSEQCommand::PitchBend:
this->pitchBend = this->overriding.val<std::int8_t>(pData, read8);
- this->updateFlags.set(ToIntegral(TrackUpdateFlag::Timer));
+ this->updateFlags.set(ConvertFuncs::ToIntegral(TrackUpdateFlag::Timer));
break;
case SSEQCommand::PitchBendRange:
this->pitchBendRange = read8(pData);
- this->updateFlags.set(ToIntegral(TrackUpdateFlag::Timer));
+ this->updateFlags.set(ConvertFuncs::ToIntegral(TrackUpdateFlag::Timer));
break;
//-----------------------------------------------------------------
@@ -686,24 +687,24 @@
case SSEQCommand::PortamentoKey:
this->portaKey = static_cast<std::uint8_t>(read8(pData) + this->transpose);
- this->state.set(ToIntegral(TrackState::PortamentoBit));
+ this->state.set(ConvertFuncs::ToIntegral(TrackState::PortamentoBit));
// Update here?
break;
case SSEQCommand::PortamentoFlag:
- this->state.set(ToIntegral(TrackState::PortamentoBit), !!read8(pData));
+ this->state.set(ConvertFuncs::ToIntegral(TrackState::PortamentoBit), !!read8(pData));
// Update here?
break;
case SSEQCommand::PortamentoTime:
this->portaTime = this->overriding.val<std::uint8_t>(pData, read8);
- this->state.set(ToIntegral(TrackState::PortamentoBit));
+ this->state.set(ConvertFuncs::ToIntegral(TrackState::PortamentoBit));
// Update here?
break;
case SSEQCommand::SweepPitch:
this->sweepPitch = this->overriding.val<std::int16_t>(pData, read16);
- this->state.set(ToIntegral(TrackState::PortamentoBit));
+ this->state.set(ConvertFuncs::ToIntegral(TrackState::PortamentoBit));
// Update here?
break;
@@ -713,27 +714,27 @@
case SSEQCommand::ModulationDepth:
this->modDepth = this->overriding.val<std::uint8_t>(pData, read8);
- this->updateFlags.set(ToIntegral(TrackUpdateFlag::Modulation));
+ this->updateFlags.set(ConvertFuncs::ToIntegral(TrackUpdateFlag::Modulation));
break;
case SSEQCommand::ModulationSpeed:
this->modSpeed = this->overriding.val<std::uint8_t>(pData, read8);
- this->updateFlags.set(ToIntegral(TrackUpdateFlag::Modulation));
+ this->updateFlags.set(ConvertFuncs::ToIntegral(TrackUpdateFlag::Modulation));
break;
case SSEQCommand::ModulationType:
this->modType = read8(pData);
- this->updateFlags.set(ToIntegral(TrackUpdateFlag::Modulation));
+ this->updateFlags.set(ConvertFuncs::ToIntegral(TrackUpdateFlag::Modulation));
break;
case SSEQCommand::ModulationRange:
this->modRange = read8(pData);
- this->updateFlags.set(ToIntegral(TrackUpdateFlag::Modulation));
+ this->updateFlags.set(ConvertFuncs::ToIntegral(TrackUpdateFlag::Modulation));
break;
case SSEQCommand::ModulationDelay:
this->modDelay = this->overriding.val<std::uint16_t>(pData, read16);
- this->updateFlags.set(ToIntegral(TrackUpdateFlag::Modulation));
+ this->updateFlags.set(ConvertFuncs::ToIntegral(TrackUpdateFlag::Modulation));
break;
//-----------------------------------------------------------------
@@ -744,7 +745,7 @@
{
this->overriding() = true;
this->overriding.cmd = read8(pData);
- if ((this->overriding.cmd >= ToIntegral(SSEQCommand::SetVariable) && this->overriding.cmd <= ToIntegral(SSEQCommand::CompareNotEqualTo)) || this->overriding.cmd < 0x80)
+ if ((this->overriding.cmd >= ConvertFuncs::ToIntegral(SSEQCommand::SetVariable) && this->overriding.cmd <= ConvertFuncs::ToIntegral(SSEQCommand::CompareNotEqualTo)) || this->overriding.cmd < 0x80)
this->overriding.extraValue = read8(pData);
std::int16_t minVal = static_cast<std::int16_t>(read16(pData));
std::int16_t maxVal = static_cast<std::int16_t>(read16(pData));
@@ -759,7 +760,7 @@
case SSEQCommand::FromVariable:
this->overriding() = true;
this->overriding.cmd = read8(pData);
- if ((this->overriding.cmd >= ToIntegral(SSEQCommand::SetVariable) && this->overriding.cmd <= ToIntegral(SSEQCommand::CompareNotEqualTo)) || this->overriding.cmd < 0x80)
+ if ((this->overriding.cmd >= ConvertFuncs::ToIntegral(SSEQCommand::SetVariable) && this->overriding.cmd <= ConvertFuncs::ToIntegral(SSEQCommand::CompareNotEqualTo)) || this->overriding.cmd < 0x80)
this->overriding.extraValue = read8(pData);
this->overriding.value = this->ply->variables[read8(pData)];
break;
@@ -774,7 +775,7 @@
{
std::int8_t varNo = this->overriding.val<std::int8_t>(pData, read8, true);
value = this->overriding.val<std::int16_t>(pData, read16);
- if (cmd == ToIntegral(SSEQCommand::DivideVariable) && !value) // Division by 0, skip it to prevent crashing
+ if (cmd == ConvertFuncs::ToIntegral(SSEQCommand::DivideVariable) && !value) // Division by 0, skip it to prevent crashing
break;
this->ply->variables[varNo] = VarFunc(cmd)(this->ply->variables[varNo], static_cast<std::int16_t>(value));
break;
@@ -808,7 +809,7 @@
if (extraByte)
{
int extraCmd = read8(pData);
- if ((extraCmd >= ToIntegral(SSEQCommand::SetVariable) && extraCmd <= ToIntegral(SSEQCommand::CompareNotEqualTo)) || extraCmd < 0x80)
+ if ((extraCmd >= ConvertFuncs::ToIntegral(SSEQCommand::SetVariable) && extraCmd <= ConvertFuncs::ToIntegral(SSEQCommand::CompareNotEqualTo)) || extraCmd < 0x80)
++cmdBytes;
}
*pData += cmdBytes;
@@ -822,7 +823,7 @@
}
}
- if (cmd != ToIntegral(SSEQCommand::Random) && cmd != ToIntegral(SSEQCommand::FromVariable))
+ if (cmd != ConvertFuncs::ToIntegral(SSEQCommand::Random) && cmd != ConvertFuncs::ToIntegral(SSEQCommand::FromVariable))
this->overriding() = false;
}
}
--- a/src/in_ncsf/SSEQPlayer/Track.h
+++ b/src/in_ncsf/SSEQPlayer/Track.h
@@ -14,6 +14,7 @@
#include <cstdint>
#include "common.h"
#include "consts.h"
+#include "convert.h"
struct Player;
@@ -55,7 +56,7 @@
{
std::int8_t trackId;
- std::bitset<ToIntegral(TrackState::Bits)> state;
+ std::bitset<ConvertFuncs::ToIntegral(TrackState::Bits)> state;
std::uint8_t num, prio;
Player *ply;
@@ -82,7 +83,7 @@
std::uint8_t modType, modSpeed, modDepth, modRange;
std::uint16_t modDelay;
- std::bitset<ToIntegral(TrackUpdateFlag::Bits)> updateFlags;
+ std::bitset<ConvertFuncs::ToIntegral(TrackUpdateFlag::Bits)> updateFlags;
Track();
--- a/src/in_ncsf/SSEQPlayer/common.h
+++ b/src/in_ncsf/SSEQPlayer/common.h
@@ -29,7 +29,7 @@
{
}
- template<typename T> T ReadLE()
+ template<typename T> typename std::enable_if_t<std::is_integral_v<T>, T> ReadLE()
{
T finalVal = 0;
for (std::size_t i = 0; i < sizeof(T); ++i)
@@ -37,7 +37,7 @@
return finalVal;
}
- template<typename T, std::size_t N> void ReadLE(T (&arr)[N])
+ template<typename T, std::size_t N> typename std::enable_if_t<std::is_integral_v<T>> ReadLE(T (&arr)[N])
{
for (std::size_t i = 0; i < N; ++i)
arr[i] = this->ReadLE<T>();
@@ -49,7 +49,7 @@
this->pos += N;
}
- template<typename T> void ReadLE(std::vector<T> &arr)
+ template<typename T> typename std::enable_if_t<std::is_integral_v<T>> ReadLE(std::vector<T> &arr)
{
for (std::size_t i = 0, len = arr.size(); i < len; ++i)
arr[i] = this->ReadLE<T>();
@@ -83,7 +83,7 @@
* as little-endian formating.
*/
-template<typename T> inline T ReadLE(const std::uint8_t *arr)
+template<typename T> inline typename std::enable_if_t<std::is_integral_v<T>, T> ReadLE(const std::uint8_t *arr)
{
T finalVal = 0;
for (std::size_t i = 0; i < sizeof(T); ++i)
@@ -97,7 +97,7 @@
* integers are in the format of 0x00, 16-bit integers are in the format of
* 0x0000, and so on.
*/
-template<typename T> inline std::string NumToHexString(const T &num)
+template<typename T> inline typename std::enable_if_t<std::is_integral_v<T>, std::string> NumToHexString(const T &num)
{
std::string hex;
std::uint8_t len = sizeof(T) * 2;
@@ -122,12 +122,6 @@
inline constexpr int REC_GROUP = 5;
inline constexpr int REC_PLAYER2 = 6;
inline constexpr int REC_STRM = 7;
-
-// Comes from https://stackoverflow.com/a/14589519
-template<typename T> inline constexpr auto ToIntegral(const T &e)
-{
- return static_cast<std::underlying_type_t<T>>(e);
-}
template<std::size_t N> inline bool VerifyHeader(std::int8_t (&arr)[N], const std::string &header)
{
--- a/src/in_ncsf/XSFConfig_NCSF.cpp
+++ b/src/in_ncsf/XSFConfig_NCSF.cpp
@@ -312,7 +312,7 @@
}
static const std::wstring states[] = { L"NONE", L"START", L"ATTACK", L"DECAY", L"SUSTAIN", L"RELEASE" };
- SetDlgItemTextW(hDlg, IDC_SOUND0STATE + chanId, states[ToIntegral(chn.state)].c_str());
+ SetDlgItemTextW(hDlg, IDC_SOUND0STATE + chanId, states[ConvertFuncs::ToIntegral(chn.state)].c_str());
SetDlgItemTextW(hDlg, IDC_SOUND0PNT + chanId, (L"samp #" + std::to_wstring(chn.reg.loopStart)).c_str());
--- a/src/in_xsf_framework/XSFCommon.h
+++ b/src/in_xsf_framework/XSFCommon.h
@@ -7,9 +7,10 @@
#pragma once
+#include <fstream>
#include <limits>
-#include <fstream>
#include <string>
+#include <type_traits>
#define _USE_MATH_DEFINES
#include <cmath>
#include <cstddef>
@@ -19,7 +20,7 @@
#include "convert.h"
// Code from http://learningcppisfun.blogspot.com/2010/04/comparing-floating-point-numbers.html
-template<typename T> inline bool fEqual(T x, T y, int N = 1)
+template<typename T> inline typename std::enable_if_t<std::is_floating_point_v<T>, bool> fEqual(T x, T y, int N = 1)
{
T diff = std::abs(x - y);
T tolerance = N * std::numeric_limits<T>::epsilon();
@@ -40,7 +41,7 @@
// Code from the following answer on Stack Overflow:
// http://stackoverflow.com/a/15479212
-template<typename T> inline T NextHighestPowerOf2(T value)
+template<typename T> inline typename std::enable_if_t<std::is_integral_v<T>, T> NextHighestPowerOf2(T value)
{
if (value < 1)
return 1;
--- a/src/in_xsf_framework/XSFConfig.cpp
+++ b/src/in_xsf_framework/XSFConfig.cpp
@@ -270,8 +270,8 @@
dialog->skipSilenceOnStart = ConvertFuncs::MSToString(this->skipSilenceOnStartSec);
dialog->detectSilence = ConvertFuncs::MSToString(this->detectSilenceSec);
dialog->volume = this->volume;
- dialog->replayGain = static_cast<std::underlying_type_t<VolumeType>>(this->volumeType);
- dialog->clipProtect = static_cast<std::underlying_type_t<PeakType>>(this->peakType);
+ dialog->replayGain = ConvertFuncs::ToIntegral(this->volumeType);
+ dialog->clipProtect = ConvertFuncs::ToIntegral(this->peakType);
auto found = std::find(this->supportedSampleRates.begin(), this->supportedSampleRates.end(), this->sampleRate);
dialog->sampleRate = found == this->supportedSampleRates.end() ? 0 : found - this->supportedSampleRates.begin();
dialog->titleFormat = this->titleFormat;
@@ -287,8 +287,8 @@
dialog->skipSilenceOnStart = XSFConfig::initSkipSilenceOnStartSec;
dialog->detectSilence = XSFConfig::initDetectSilenceSec;
dialog->volume = XSFConfig::initVolume;
- dialog->replayGain = static_cast<std::underlying_type_t<VolumeType>>(XSFConfig::initVolumeType);
- dialog->clipProtect = static_cast<std::underlying_type_t<PeakType>>(XSFConfig::initPeakType);
+ dialog->replayGain = ConvertFuncs::ToIntegral(XSFConfig::initVolumeType);
+ dialog->clipProtect = ConvertFuncs::ToIntegral(XSFConfig::initPeakType);
auto found = std::find(this->supportedSampleRates.begin(), this->supportedSampleRates.end(), XSFConfig::initSampleRate);
dialog->sampleRate = found == this->supportedSampleRates.end() ? 0 : found - this->supportedSampleRates.begin();
dialog->titleFormat = XSFConfig::initTitleFormat;
--- a/src/in_xsf_framework/XSFConfig.h
+++ b/src/in_xsf_framework/XSFConfig.h
@@ -26,17 +26,17 @@
// enum versions
template<typename T> typename std::enable_if_t<std::is_enum_v<T>, T> GetValueInternal(const std::string &name, const T &defaultValue) const
{
- return convertTo<T>(this->GetValueString(name, std::to_string(static_cast<std::underlying_type_t<T>>(defaultValue))));
+ return ConvertFuncs::To<T>(this->GetValueString(name, std::to_string(ConvertFuncs::ToIntegral(defaultValue))));
}
template<typename T> typename std::enable_if_t<std::is_enum_v<T>> SetValueInternal(const std::string &name, const T &value)
{
- this->SetValueString(name, std::to_string(static_cast<std::underlying_type_t<T>>(value)));
+ this->SetValueString(name, std::to_string(ConvertFuncs::ToIntegral(value)));
}
// non-enum versions
template<typename T> typename std::enable_if_t<!std::is_enum_v<T> && std::is_arithmetic_v<T>, T> GetValueInternal(const std::string &name, const T &defaultValue) const
{
- return convertTo<T>(this->GetValueString(name, std::to_string(defaultValue)));
+ return ConvertFuncs::To<T>(this->GetValueString(name, std::to_string(defaultValue)));
}
template<typename T> typename std::enable_if_t<!std::is_enum_v<T> && std::is_arithmetic_v<T>> SetValueInternal(const std::string &name, const T &value)
{
--- a/src/in_xsf_framework/XSFFile.cpp
+++ b/src/in_xsf_framework/XSFFile.cpp
@@ -301,24 +301,24 @@
bool hadReplayGain = false;
if (preferredVolumeType == VolumeType::ReplayGainAlbum && !replaygain_album_gain.empty())
{
- gain = convertTo<double>(replaygain_album_gain);
+ gain = ConvertFuncs::To<double>(replaygain_album_gain);
hadReplayGain = true;
}
if (!hadReplayGain && preferredVolumeType != VolumeType::Volume && !replaygain_track_gain.empty())
{
- gain = convertTo<double>(replaygain_track_gain);
+ gain = ConvertFuncs::To<double>(replaygain_track_gain);
hadReplayGain = true;
}
if (hadReplayGain)
{
double vol = std::pow(10.0, gain / 20.0), peak = 1.0;
if (preferredPeakType == PeakType::ReplayGainAlbum && !replaygain_album_peak.empty())
- peak = convertTo<double>(replaygain_album_peak);
+ peak = ConvertFuncs::To<double>(replaygain_album_peak);
else if (preferredPeakType != PeakType::None && !replaygain_track_peak.empty())
- peak = convertTo<double>(replaygain_track_peak);
+ peak = ConvertFuncs::To<double>(replaygain_track_peak);
return !fEqual(peak, 1.0) ? std::min(vol, 1.0 / peak) : vol;
}
- return volume.empty() ? 1.0 : convertTo<double>(volume);
+ return volume.empty() ? 1.0 : ConvertFuncs::To<double>(volume);
}
std::string XSFFile::FormattedTitleOptionalBlock(const std::string &block, bool &hadReplacement, unsigned level) const
--- a/src/in_xsf_framework/XSFFile.h
+++ b/src/in_xsf_framework/XSFFile.h
@@ -61,7 +61,7 @@
std::string GetTagValue(const std::string &name) const;
template<typename T> T GetTagValue(const std::string &name, const T &defaultValue) const
{
- return this->GetTagExists(name) ? convertTo<T>(this->GetTagValue(name)) : defaultValue;
+ return this->GetTagExists(name) ? ConvertFuncs::To<T>(this->GetTagValue(name)) : defaultValue;
}
unsigned long GetLengthMS(unsigned long defaultLength) const;
unsigned long GetFadeMS(unsigned long defaultFade) const;
--- a/src/in_xsf_framework/convert.h
+++ b/src/in_xsf_framework/convert.h
@@ -12,47 +12,6 @@
#include <cmath>
#include <cstddef>
#include "windowsh_wrapper.h"
-
-/*
- * Originally the convert* functions came from the C++ FAQ, Miscellaneous Technical Issues:
- * https://isocpp.org/wiki/faq/misc-technical-issues#convert-string-to-any
- *
- * They have been replaced with a couple functions that use the C++11 std::enable_if
- * construct along with various other type traits constructs to use the proper
- * string conversions.
- */
-template<typename T, typename S> inline typename std::enable_if_t<!std::is_enum_v<T> &&std::is_arithmetic_v<T>, T> convertTo(const std::basic_string<S> &s)
-{
- if (std::is_integral_v<T>)
- {
- if (std::is_unsigned_v<T>)
- {
- if (std::is_same_v<unsigned long long, std::remove_cv_t<T>>)
- return static_cast<T>(std::stoull(s));
- else
- return static_cast<T>(std::stoul(s));
- }
- else if (std::is_same_v<long long, std::remove_cv_t<T>>)
- return static_cast<T>(std::stoll(s));
- else if (std::is_same_v<long, std::remove_cv_t<T>>)
- return static_cast<T>(std::stol(s));
- else
- return static_cast<T>(std::stoi(s));
- }
- else if (std::is_floating_point_v<T>)
- {
- if (std::is_same_v<long double, std::remove_cv_t<T>>)
- return static_cast<T>(std::stold(s));
- else if (std::is_same_v<double, std::remove_cv_t<T>>)
- return static_cast<T>(std::stod(s));
- else
- return static_cast<T>(std::stof(s));
- }
-}
-template<typename T, typename S> inline typename std::enable_if_t<std::is_enum_v<T>, T> convertTo(const std::basic_string<S> &s)
-{
- return static_cast<T>(convertTo<std::underlying_type_t<T>>(s));
-}
// Miscellaneous conversion functions
class ConvertFuncs
@@ -69,8 +28,55 @@
return false;
return true;
}
+public:
+ /*
+ * Originally the convert* functions came from the C++ FAQ, Miscellaneous Technical Issues:
+ * https://isocpp.org/wiki/faq/misc-technical-issues#convert-string-to-any
+ *
+ * They have been replaced with a couple functions that use the C++11 std::enable_if
+ * construct along with various other type traits constructs to use the proper
+ * string conversions.
+ */
+ template<typename T, typename S> static typename std::enable_if_t<!std::is_enum_v<T> && std::is_arithmetic_v<T>, T> To(const std::basic_string<S> &s)
+ {
+ if (std::is_integral_v<T>)
+ {
+ if (std::is_unsigned_v<T>)
+ {
+ if (std::is_same_v<unsigned long long, std::remove_cv_t<T>>)
+ return static_cast<T>(std::stoull(s));
+ else
+ return static_cast<T>(std::stoul(s));
+ }
+ else if (std::is_same_v<long long, std::remove_cv_t<T>>)
+ return static_cast<T>(std::stoll(s));
+ else if (std::is_same_v<long, std::remove_cv_t<T>>)
+ return static_cast<T>(std::stol(s));
+ else
+ return static_cast<T>(std::stoi(s));
+ }
+ else if (std::is_floating_point_v<T>)
+ {
+ if (std::is_same_v<long double, std::remove_cv_t<T>>)
+ return static_cast<T>(std::stold(s));
+ else if (std::is_same_v<double, std::remove_cv_t<T>>)
+ return static_cast<T>(std::stod(s));
+ else
+ return static_cast<T>(std::stof(s));
+ }
+ }
-public:
+ template<typename T, typename S> static typename std::enable_if_t<std::is_enum_v<T>, T> To(const std::basic_string<S> &s)
+ {
+ return static_cast<T>(ConvertFuncs::To<std::underlying_type_t<T>>(s));
+ }
+
+ // Comes from https://stackoverflow.com/a/14589519
+ template<typename T> static constexpr typename std::enable_if_t<std::is_enum_v<T>, std::underlying_type_t<T>> ToIntegral(const T &e)
+ {
+ return static_cast<std::underlying_type_t<T>>(e);
+ }
+
static unsigned long StringToMS(const std::string &time)
{
unsigned long hours = 0, minutes = 0;
@@ -99,13 +105,13 @@
{
if (!ConvertFuncs::IsDigitsOnly(hoursStr))
return 0;
- hours = convertTo<unsigned long>(hoursStr);
+ hours = ConvertFuncs::To<unsigned long>(hoursStr);
}
if (!minutesStr.empty())
{
if (!ConvertFuncs::IsDigitsOnly(minutesStr))
return 0;
- minutes = convertTo<unsigned long>(minutesStr);
+ minutes = ConvertFuncs::To<unsigned long>(minutesStr);
}
if (!secondsStr.empty())
{
@@ -114,7 +120,7 @@
std::size_t comma = secondsStr.find(',');
if (comma != std::string::npos)
secondsStr[comma] = '.';
- seconds = convertTo<double>(secondsStr);
+ seconds = ConvertFuncs::To<double>(secondsStr);
}
seconds += minutes * 60 + hours * 1440;
return static_cast<unsigned long>(std::floor(seconds * 1000 + 0.5));