* Use enum class instead of enum (except for the enums for the resource IDs, not really necessary there).
* For NCSF specifically, included a function to convert an enum class to its underlying integral type (as this is needed for use with the std::bitset class).
* Cleanup headers so all the ones needed in a file are explicitly included even if they may possibly be included in another header.
* Used forward declarations in a few spots.
* Explicitly namespaced all (u)int*_t uses (this might seem like overkill, but it helps me see when the standard types are being used with a simple search for std::).
* Made sure it all builds with MinGW-w64 as well (both gcc and clang).
* Removed some std::move from DialogBuilder.cpp based on clang's warnings for that.
* Replaced use of std::copy_n on strings in DialogBuilder.cpp with my CopyToString functions that use wcscpy.
* Replaced CHAR_MIN/CHAR_MAX in eqstr.h and ltstr.h with std::numeric_limits<char>::min/max().
| ... | ... |
@@ -14,9 +14,13 @@ |
| 14 | 14 |
|
| 15 | 15 |
#include <algorithm> |
| 16 | 16 |
#include <bitset> |
| 17 |
+#include <cstddef> |
|
| 17 | 18 |
#include <cstdint> |
| 18 |
-#include "SWAV.h" |
|
| 19 |
-#include "Track.h" |
|
| 19 |
+#include "common.h" |
|
| 20 |
+#include "consts.h" |
|
| 21 |
+ |
|
| 22 |
+struct SWAV; |
|
| 23 |
+struct Track; |
|
| 20 | 24 |
|
| 21 | 25 |
/* |
| 22 | 26 |
* This structure is meant to be similar to what is stored in the actual |
| ... | ... |
@@ -27,41 +31,41 @@ |
| 27 | 31 |
struct NDSSoundRegister |
| 28 | 32 |
{
|
| 29 | 33 |
// Control Register |
| 30 |
- uint8_t volumeMul; |
|
| 31 |
- uint8_t volumeDiv; |
|
| 32 |
- uint8_t panning; |
|
| 33 |
- uint8_t waveDuty; |
|
| 34 |
- uint8_t repeatMode; |
|
| 35 |
- uint8_t format; |
|
| 34 |
+ std::uint8_t volumeMul; |
|
| 35 |
+ std::uint8_t volumeDiv; |
|
| 36 |
+ std::uint8_t panning; |
|
| 37 |
+ std::uint8_t waveDuty; |
|
| 38 |
+ std::uint8_t repeatMode; |
|
| 39 |
+ std::uint8_t format; |
|
| 36 | 40 |
bool enable; |
| 37 | 41 |
|
| 38 | 42 |
// Data Source Register |
| 39 | 43 |
const SWAV *source; |
| 40 | 44 |
|
| 41 | 45 |
// Timer Register |
| 42 |
- uint16_t timer; |
|
| 46 |
+ std::uint16_t timer; |
|
| 43 | 47 |
|
| 44 | 48 |
// PSG Handling, not a DS register |
| 45 |
- uint16_t psgX; |
|
| 46 |
- int16_t psgLast; |
|
| 47 |
- uint32_t psgLastCount; |
|
| 49 |
+ std::uint16_t psgX; |
|
| 50 |
+ std::int16_t psgLast; |
|
| 51 |
+ std::uint32_t psgLastCount; |
|
| 48 | 52 |
|
| 49 | 53 |
// The following are taken from DeSmuME |
| 50 | 54 |
double samplePosition; |
| 51 | 55 |
double sampleIncrease; |
| 52 | 56 |
|
| 53 | 57 |
// Loopstart Register |
| 54 |
- uint32_t loopStart; |
|
| 58 |
+ std::uint32_t loopStart; |
|
| 55 | 59 |
|
| 56 | 60 |
// Length Register |
| 57 |
- uint32_t length; |
|
| 61 |
+ std::uint32_t length; |
|
| 58 | 62 |
|
| 59 |
- uint32_t totalLength; |
|
| 63 |
+ std::uint32_t totalLength; |
|
| 60 | 64 |
|
| 61 | 65 |
NDSSoundRegister(); |
| 62 | 66 |
|
| 63 | 67 |
void ClearControlRegister(); |
| 64 |
- void SetControlRegister(uint32_t reg); |
|
| 68 |
+ void SetControlRegister(std::uint32_t reg); |
|
| 65 | 69 |
}; |
| 66 | 70 |
|
| 67 | 71 |
/* |
| ... | ... |
@@ -72,10 +76,10 @@ struct NDSSoundRegister |
| 72 | 76 |
*/ |
| 73 | 77 |
struct TempSndReg |
| 74 | 78 |
{
|
| 75 |
- uint32_t CR; |
|
| 79 |
+ std::uint32_t CR; |
|
| 76 | 80 |
const SWAV *SOURCE; |
| 77 |
- uint16_t TIMER; |
|
| 78 |
- uint32_t REPEAT_POINT, LENGTH; |
|
| 81 |
+ std::uint16_t TIMER; |
|
| 82 |
+ std::uint32_t REPEAT_POINT, LENGTH; |
|
| 79 | 83 |
|
| 80 | 84 |
TempSndReg(); |
| 81 | 85 |
}; |
| ... | ... |
@@ -95,10 +99,10 @@ struct Player; |
| 95 | 99 |
* accessing the SWAVs samples and also doesn't use 0s before the |
| 96 | 100 |
* start of the SWAV or use 0s after the end of a non-looping SWAV. |
| 97 | 101 |
*/ |
| 98 |
-template<size_t N> struct RingBuffer |
|
| 102 |
+template<std::size_t N> struct RingBuffer |
|
| 99 | 103 |
{
|
| 100 |
- int16_t buffer[N * 2]; |
|
| 101 |
- size_t bufferPos, getPos; |
|
| 104 |
+ std::int16_t buffer[N * 2]; |
|
| 105 |
+ std::size_t bufferPos, getPos; |
|
| 102 | 106 |
|
| 103 | 107 |
RingBuffer() : bufferPos(N / 2), getPos(N / 2) |
| 104 | 108 |
{
|
| ... | ... |
@@ -109,7 +113,7 @@ template<size_t N> struct RingBuffer |
| 109 | 113 |
std::fill_n(&this->buffer[0], N * 2, 0); |
| 110 | 114 |
this->bufferPos = this->getPos = N / 2; |
| 111 | 115 |
} |
| 112 |
- void PushSample(int16_t sample) |
|
| 116 |
+ void PushSample(std::int16_t sample) |
|
| 113 | 117 |
{
|
| 114 | 118 |
this->buffer[this->bufferPos] = sample; |
| 115 | 119 |
if (this->bufferPos >= N) |
| ... | ... |
@@ -120,23 +124,23 @@ template<size_t N> struct RingBuffer |
| 120 | 124 |
if (this->bufferPos >= N * 3 / 2) |
| 121 | 125 |
this->bufferPos -= N; |
| 122 | 126 |
} |
| 123 |
- void PushSamples(const int16_t *samples, size_t size) |
|
| 127 |
+ void PushSamples(const std::int16_t *samples, std::size_t size) |
|
| 124 | 128 |
{
|
| 125 | 129 |
if (this->bufferPos + size > N * 3 / 2) |
| 126 | 130 |
{
|
| 127 |
- size_t free = N * 3 / 2 - this->bufferPos; |
|
| 131 |
+ std::size_t free = N * 3 / 2 - this->bufferPos; |
|
| 128 | 132 |
std::copy_n(&samples[0], free, &this->buffer[this->bufferPos]); |
| 129 | 133 |
std::copy(&samples[free], &samples[size], &this->buffer[N / 2]); |
| 130 | 134 |
} |
| 131 | 135 |
else |
| 132 | 136 |
std::copy_n(&samples[0], size, &this->buffer[this->bufferPos]); |
| 133 |
- size_t rightFree = this->bufferPos < N ? N - this->bufferPos : 0; |
|
| 137 |
+ std::size_t rightFree = this->bufferPos < N ? N - this->bufferPos : 0; |
|
| 134 | 138 |
if (rightFree < size) |
| 135 | 139 |
{
|
| 136 | 140 |
if (!rightFree) |
| 137 | 141 |
{
|
| 138 |
- size_t leftStart = this->bufferPos - N; |
|
| 139 |
- size_t leftSize = std::min(N / 2 - leftStart, size); |
|
| 142 |
+ std::size_t leftStart = this->bufferPos - N; |
|
| 143 |
+ std::size_t leftSize = std::min(N / 2 - leftStart, size); |
|
| 140 | 144 |
std::copy_n(&samples[0], leftSize, &this->buffer[leftStart]); |
| 141 | 145 |
if (leftSize < size) |
| 142 | 146 |
std::copy(&samples[leftSize], &samples[size], &this->buffer[N * 3 / 2]); |
| ... | ... |
@@ -153,7 +157,7 @@ template<size_t N> struct RingBuffer |
| 153 | 157 |
if (this->bufferPos >= N * 3 / 2) |
| 154 | 158 |
this->bufferPos -= N; |
| 155 | 159 |
} |
| 156 |
- const int16_t *GetBuffer() const |
|
| 160 |
+ const std::int16_t *GetBuffer() const |
|
| 157 | 161 |
{
|
| 158 | 162 |
return &this->buffer[this->getPos]; |
| 159 | 163 |
} |
| ... | ... |
@@ -167,35 +171,35 @@ template<size_t N> struct RingBuffer |
| 167 | 171 |
|
| 168 | 172 |
struct Channel |
| 169 | 173 |
{
|
| 170 |
- int8_t chnId; |
|
| 174 |
+ std::int8_t chnId; |
|
| 171 | 175 |
|
| 172 | 176 |
TempSndReg tempReg; |
| 173 |
- uint8_t state; |
|
| 174 |
- int8_t trackId; // -1 = none |
|
| 175 |
- uint8_t prio; |
|
| 177 |
+ ChannelState state; |
|
| 178 |
+ std::int8_t trackId; // -1 = none |
|
| 179 |
+ std::uint8_t prio; |
|
| 176 | 180 |
bool manualSweep; |
| 177 | 181 |
|
| 178 |
- std::bitset<CF_BITS> flags; |
|
| 179 |
- int8_t pan; // -64 .. 63 |
|
| 180 |
- int16_t extAmpl; |
|
| 182 |
+ std::bitset<ToIntegral(ChannelFlag::Bits)> flags; |
|
| 183 |
+ std::int8_t pan; // -64 .. 63 |
|
| 184 |
+ std::int16_t extAmpl; |
|
| 181 | 185 |
|
| 182 |
- int16_t velocity; |
|
| 183 |
- int8_t extPan; |
|
| 184 |
- uint8_t key; |
|
| 186 |
+ std::int16_t velocity; |
|
| 187 |
+ std::int8_t extPan; |
|
| 188 |
+ std::uint8_t key; |
|
| 185 | 189 |
|
| 186 | 190 |
int ampl; // 7 fractionary bits |
| 187 | 191 |
int extTune; // in 64ths of a semitone |
| 188 | 192 |
|
| 189 |
- uint8_t orgKey; |
|
| 193 |
+ std::uint8_t orgKey; |
|
| 190 | 194 |
|
| 191 |
- uint8_t modType, modSpeed, modDepth, modRange; |
|
| 192 |
- uint16_t modDelay, modDelayCnt, modCounter; |
|
| 195 |
+ std::uint8_t modType, modSpeed, modDepth, modRange; |
|
| 196 |
+ std::uint16_t modDelay, modDelayCnt, modCounter; |
|
| 193 | 197 |
|
| 194 |
- uint32_t sweepLen, sweepCnt; |
|
| 195 |
- int16_t sweepPitch; |
|
| 198 |
+ std::uint32_t sweepLen, sweepCnt; |
|
| 199 |
+ std::int16_t sweepPitch; |
|
| 196 | 200 |
|
| 197 |
- uint8_t attackLvl, sustainLvl; |
|
| 198 |
- uint16_t decayRate, releaseRate; |
|
| 201 |
+ std::uint8_t attackLvl, sustainLvl; |
|
| 202 |
+ std::uint16_t decayRate, releaseRate; |
|
| 199 | 203 |
|
| 200 | 204 |
/* |
| 201 | 205 |
* These were originally global variables in FeOS Sound System, but |
| ... | ... |
@@ -203,7 +207,7 @@ struct Channel |
| 203 | 207 |
* into this class. |
| 204 | 208 |
*/ |
| 205 | 209 |
int noteLength; |
| 206 |
- uint16_t vol; |
|
| 210 |
+ std::uint16_t vol; |
|
| 207 | 211 |
|
| 208 | 212 |
const Player *ply; |
| 209 | 213 |
NDSSoundRegister reg; |
| ... | ... |
@@ -234,7 +238,7 @@ struct Channel |
| 234 | 238 |
void Kill(); |
| 235 | 239 |
void UpdateTrack(); |
| 236 | 240 |
void Update(); |
| 237 |
- int32_t Interpolate(); |
|
| 238 |
- int32_t GenerateSample(); |
|
| 241 |
+ std::int32_t Interpolate(); |
|
| 242 |
+ std::int32_t GenerateSample(); |
|
| 239 | 243 |
void IncrementSample(); |
| 240 | 244 |
}; |
(I never remember to update these and besides, GitHub history can show when they were last modified.)
* Fix build with Visual Studio, updating projects to Visual Studio 2019 (as that is what I have installed).
* Changed C++ language standard to C++ 17.
* Add files for in_2sf's spu from Coda's recent commit.
* Add files for zlib now that it is being included as a submodule (removes the need for the zlib DLL as well).
* Remove common.props (due to the aforementioned zlib inclusion as well as the winamp headers also being in the project now).
* Minor NCSF file in the SSEQ player, the check for when to process tracks should've been >=, not >.
| ... | ... |
@@ -21,7 +21,7 @@ |
| 21 | 21 |
|
| 22 | 22 |
/* |
| 23 | 23 |
* This structure is meant to be similar to what is stored in the actual |
| 24 |
- * Nintendo DS's sound registers. Items that were not being used by this |
|
| 24 |
+ * Nintendo DS's sound registers. Items that were not being used by this |
|
| 25 | 25 |
* player have been removed, and items which help the simulated registers |
| 26 | 26 |
* have been added. |
| 27 | 27 |
*/ |
| ... | ... |
@@ -67,7 +67,7 @@ struct NDSSoundRegister |
| 67 | 67 |
|
| 68 | 68 |
/* |
| 69 | 69 |
* From FeOS Sound System, this is temporary storage of what will go into |
| 70 |
- * the Nintendo DS sound registers. It is kept separate as the original code |
|
| 70 |
+ * the Nintendo DS sound registers. It is kept separate as the original code |
|
| 71 | 71 |
* from FeOS Sound System utilized this to hold data prior to passing it into |
| 72 | 72 |
* the DS's registers. |
| 73 | 73 |
*/ |
| ... | ... |
@@ -88,7 +88,7 @@ struct Player; |
| 88 | 88 |
* data, duplicated. The way it is duplicated is done as follows: |
| 89 | 89 |
* the samples are stored in the center of the buffer, and on both |
| 90 | 90 |
* sides is half of the data, the first half being after the data |
| 91 |
- * and the second half before before the data. This in essense |
|
| 91 |
+ * and the second half begin before the data. This in essence |
|
| 92 | 92 |
* mirrors the data while allowing a pointer to always be retrieved |
| 93 | 93 |
* and no extra copies of the buffer are created. Part of the idea |
| 94 | 94 |
* for this came from kode54's original buffer implementation, but |
Sinc mode should not scale the window, just the sinc pulse.
| ... | ... |
@@ -1,7 +1,7 @@ |
| 1 | 1 |
/* |
| 2 | 2 |
* SSEQ Player - Channel structures |
| 3 | 3 |
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com] |
| 4 |
- * Last modification on 2014-09-17 |
|
| 4 |
+ * Last modification on 2014-10-27 |
|
| 5 | 5 |
* |
| 6 | 6 |
* Adapted from source code of FeOS Sound System |
| 7 | 7 |
* By fincs |
| ... | ... |
@@ -220,6 +220,7 @@ struct Channel |
| 220 | 220 |
static const unsigned SINC_WIDTH = 8; |
| 221 | 221 |
static const unsigned SINC_SAMPLES = SINC_RESOLUTION * SINC_WIDTH; |
| 222 | 222 |
static double sinc_lut[SINC_SAMPLES + 1]; |
| 223 |
+ static double window_lut[SINC_SAMPLES + 1]; |
|
| 223 | 224 |
|
| 224 | 225 |
RingBuffer<SINC_WIDTH * 2> ringBuffer; |
| 225 | 226 |
|
| ... | ... |
@@ -210,7 +210,7 @@ struct Channel |
| 210 | 210 |
NDSSoundRegister reg; |
| 211 | 211 |
|
| 212 | 212 |
/* |
| 213 |
- * Lookup tables for the cosine and Lanczos Sinc interpolations, to |
|
| 213 |
+ * Lookup tables for the Sinc interpolation, to |
|
| 214 | 214 |
* avoid the need to call the sin/cos functions all the time. |
| 215 | 215 |
* These are static as they will not change between channels or runs |
| 216 | 216 |
* of the program. |
* Removed Cosine, 4-Point B-Spline, 6-Point B-Spline, and 6-point
Osculating.
* Added 4-Point Legrange and 6-Point Legrange.
* Changed wording of the Sinc interpolation to mention that it is
16-point.
| ... | ... |
@@ -216,11 +216,9 @@ struct Channel |
| 216 | 216 |
* of the program. |
| 217 | 217 |
*/ |
| 218 | 218 |
static bool initializedLUTs; |
| 219 |
- static const unsigned COSINE_RESOLUTION = 8192; |
|
| 220 | 219 |
static const unsigned SINC_RESOLUTION = 8192; |
| 221 | 220 |
static const unsigned SINC_WIDTH = 8; |
| 222 | 221 |
static const unsigned SINC_SAMPLES = SINC_RESOLUTION * SINC_WIDTH; |
| 223 |
- static double cosine_lut[COSINE_RESOLUTION]; |
|
| 224 | 222 |
static double sinc_lut[SINC_SAMPLES + 1]; |
| 225 | 223 |
|
| 226 | 224 |
RingBuffer<SINC_WIDTH * 2> ringBuffer; |
* [2SF] Used more up-to-date asmjit, despite the ugly looking code.
| ... | ... |
@@ -1,7 +1,7 @@ |
| 1 | 1 |
/* |
| 2 | 2 |
* SSEQ Player - Channel structures |
| 3 | 3 |
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com] |
| 4 |
- * Last modification on 2014-09-08 |
|
| 4 |
+ * Last modification on 2014-09-17 |
|
| 5 | 5 |
* |
| 6 | 6 |
* Adapted from source code of FeOS Sound System |
| 7 | 7 |
* By fincs |
| ... | ... |
@@ -13,6 +13,7 @@ |
| 13 | 13 |
|
| 14 | 14 |
#pragma once |
| 15 | 15 |
|
| 16 |
+#include <algorithm> |
|
| 16 | 17 |
#include <bitset> |
| 17 | 18 |
#include <cstdint> |
| 18 | 19 |
#include "SWAV.h" |
| ... | ... |
@@ -153,7 +154,7 @@ template<size_t N> struct RingBuffer |
| 153 | 154 |
if (this->bufferPos >= N * 3 / 2) |
| 154 | 155 |
this->bufferPos -= N; |
| 155 | 156 |
} |
| 156 |
- const int16_t *const GetBuffer() const |
|
| 157 |
+ const int16_t *GetBuffer() const |
|
| 157 | 158 |
{
|
| 158 | 159 |
return &this->buffer[this->getPos]; |
| 159 | 160 |
} |
| ... | ... |
@@ -102,11 +102,11 @@ template<size_t N> struct RingBuffer |
| 102 | 102 |
|
| 103 | 103 |
RingBuffer() : bufferPos(N / 2), getPos(N / 2) |
| 104 | 104 |
{
|
| 105 |
- std::fill(&this->buffer[0], &this->buffer[N * 2], 0); |
|
| 105 |
+ std::fill_n(&this->buffer[0], N * 2, 0); |
|
| 106 | 106 |
} |
| 107 | 107 |
void Clear() |
| 108 | 108 |
{
|
| 109 |
- std::fill(&this->buffer[0], &this->buffer[N * 2], 0); |
|
| 109 |
+ std::fill_n(&this->buffer[0], N * 2, 0); |
|
| 110 | 110 |
this->bufferPos = this->getPos = N / 2; |
| 111 | 111 |
} |
| 112 | 112 |
void PushSample(int16_t sample) |
| ... | ... |
@@ -125,11 +125,11 @@ template<size_t N> struct RingBuffer |
| 125 | 125 |
if (this->bufferPos + size > N * 3 / 2) |
| 126 | 126 |
{
|
| 127 | 127 |
size_t free = N * 3 / 2 - this->bufferPos; |
| 128 |
- std::copy(&samples[0], &samples[free], &this->buffer[this->bufferPos]); |
|
| 128 |
+ std::copy_n(&samples[0], free, &this->buffer[this->bufferPos]); |
|
| 129 | 129 |
std::copy(&samples[free], &samples[size], &this->buffer[N / 2]); |
| 130 | 130 |
} |
| 131 | 131 |
else |
| 132 |
- std::copy(&samples[0], &samples[size], &this->buffer[this->bufferPos]); |
|
| 132 |
+ std::copy_n(&samples[0], size, &this->buffer[this->bufferPos]); |
|
| 133 | 133 |
size_t rightFree = this->bufferPos < N ? N - this->bufferPos : 0; |
| 134 | 134 |
if (rightFree < size) |
| 135 | 135 |
{
|
| ... | ... |
@@ -137,18 +137,18 @@ template<size_t N> struct RingBuffer |
| 137 | 137 |
{
|
| 138 | 138 |
size_t leftStart = this->bufferPos - N; |
| 139 | 139 |
size_t leftSize = std::min(N / 2 - leftStart, size); |
| 140 |
- std::copy(&samples[0], &samples[leftSize], &this->buffer[leftStart]); |
|
| 140 |
+ std::copy_n(&samples[0], leftSize, &this->buffer[leftStart]); |
|
| 141 | 141 |
if (leftSize < size) |
| 142 | 142 |
std::copy(&samples[leftSize], &samples[size], &this->buffer[N * 3 / 2]); |
| 143 | 143 |
} |
| 144 | 144 |
else |
| 145 | 145 |
{
|
| 146 |
- std::copy(&samples[0], &samples[rightFree], &this->buffer[this->bufferPos + N]); |
|
| 146 |
+ std::copy_n(&samples[0], rightFree, &this->buffer[this->bufferPos + N]); |
|
| 147 | 147 |
std::copy(&samples[rightFree], &samples[size], &this->buffer[0]); |
| 148 | 148 |
} |
| 149 | 149 |
} |
| 150 | 150 |
else |
| 151 |
- std::copy(&samples[0], &samples[size], &this->buffer[this->bufferPos + N]); |
|
| 151 |
+ std::copy_n(&samples[0], size, &this->buffer[this->bufferPos + N]); |
|
| 152 | 152 |
this->bufferPos += size; |
| 153 | 153 |
if (this->bufferPos >= N * 3 / 2) |
| 154 | 154 |
this->bufferPos -= N; |
| ... | ... |
@@ -1,7 +1,7 @@ |
| 1 | 1 |
/* |
| 2 | 2 |
* SSEQ Player - Channel structures |
| 3 | 3 |
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com] |
| 4 |
- * Last modification on 2013-05-07 |
|
| 4 |
+ * Last modification on 2014-09-08 |
|
| 5 | 5 |
* |
| 6 | 6 |
* Adapted from source code of FeOS Sound System |
| 7 | 7 |
* By fincs |
| ... | ... |
@@ -11,8 +11,7 @@ |
| 11 | 11 |
* http://desmume.org/ |
| 12 | 12 |
*/ |
| 13 | 13 |
|
| 14 |
-#ifndef SSEQPLAYER_CHANNEL_H |
|
| 15 |
-#define SSEQPLAYER_CHANNEL_H |
|
| 14 |
+#pragma once |
|
| 16 | 15 |
|
| 17 | 16 |
#include <bitset> |
| 18 | 17 |
#include <cstdint> |
| ... | ... |
@@ -240,5 +239,3 @@ struct Channel |
| 240 | 239 |
int32_t GenerateSample(); |
| 241 | 240 |
void IncrementSample(); |
| 242 | 241 |
}; |
| 243 |
- |
|
| 244 |
-#endif |
| ... | ... |
@@ -1,7 +1,7 @@ |
| 1 | 1 |
/* |
| 2 | 2 |
* SSEQ Player - Channel structures |
| 3 | 3 |
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com] |
| 4 |
- * Last modification on 2013-04-26 |
|
| 4 |
+ * Last modification on 2013-05-07 |
|
| 5 | 5 |
* |
| 6 | 6 |
* Adapted from source code of FeOS Sound System |
| 7 | 7 |
* By fincs |
| ... | ... |
@@ -83,6 +83,89 @@ struct TempSndReg |
| 83 | 83 |
|
| 84 | 84 |
struct Player; |
| 85 | 85 |
|
| 86 |
+/* |
|
| 87 |
+ * This creates a ring buffer, which will store N samples of SWAV |
|
| 88 |
+ * data, duplicated. The way it is duplicated is done as follows: |
|
| 89 |
+ * the samples are stored in the center of the buffer, and on both |
|
| 90 |
+ * sides is half of the data, the first half being after the data |
|
| 91 |
+ * and the second half before before the data. This in essense |
|
| 92 |
+ * mirrors the data while allowing a pointer to always be retrieved |
|
| 93 |
+ * and no extra copies of the buffer are created. Part of the idea |
|
| 94 |
+ * for this came from kode54's original buffer implementation, but |
|
| 95 |
+ * this has been designed to make sure that there are no delays in |
|
| 96 |
+ * accessing the SWAVs samples and also doesn't use 0s before the |
|
| 97 |
+ * start of the SWAV or use 0s after the end of a non-looping SWAV. |
|
| 98 |
+ */ |
|
| 99 |
+template<size_t N> struct RingBuffer |
|
| 100 |
+{
|
|
| 101 |
+ int16_t buffer[N * 2]; |
|
| 102 |
+ size_t bufferPos, getPos; |
|
| 103 |
+ |
|
| 104 |
+ RingBuffer() : bufferPos(N / 2), getPos(N / 2) |
|
| 105 |
+ {
|
|
| 106 |
+ std::fill(&this->buffer[0], &this->buffer[N * 2], 0); |
|
| 107 |
+ } |
|
| 108 |
+ void Clear() |
|
| 109 |
+ {
|
|
| 110 |
+ std::fill(&this->buffer[0], &this->buffer[N * 2], 0); |
|
| 111 |
+ this->bufferPos = this->getPos = N / 2; |
|
| 112 |
+ } |
|
| 113 |
+ void PushSample(int16_t sample) |
|
| 114 |
+ {
|
|
| 115 |
+ this->buffer[this->bufferPos] = sample; |
|
| 116 |
+ if (this->bufferPos >= N) |
|
| 117 |
+ this->buffer[this->bufferPos - N] = sample; |
|
| 118 |
+ else |
|
| 119 |
+ this->buffer[this->bufferPos + N] = sample; |
|
| 120 |
+ ++this->bufferPos; |
|
| 121 |
+ if (this->bufferPos >= N * 3 / 2) |
|
| 122 |
+ this->bufferPos -= N; |
|
| 123 |
+ } |
|
| 124 |
+ void PushSamples(const int16_t *samples, size_t size) |
|
| 125 |
+ {
|
|
| 126 |
+ if (this->bufferPos + size > N * 3 / 2) |
|
| 127 |
+ {
|
|
| 128 |
+ size_t free = N * 3 / 2 - this->bufferPos; |
|
| 129 |
+ std::copy(&samples[0], &samples[free], &this->buffer[this->bufferPos]); |
|
| 130 |
+ std::copy(&samples[free], &samples[size], &this->buffer[N / 2]); |
|
| 131 |
+ } |
|
| 132 |
+ else |
|
| 133 |
+ std::copy(&samples[0], &samples[size], &this->buffer[this->bufferPos]); |
|
| 134 |
+ size_t rightFree = this->bufferPos < N ? N - this->bufferPos : 0; |
|
| 135 |
+ if (rightFree < size) |
|
| 136 |
+ {
|
|
| 137 |
+ if (!rightFree) |
|
| 138 |
+ {
|
|
| 139 |
+ size_t leftStart = this->bufferPos - N; |
|
| 140 |
+ size_t leftSize = std::min(N / 2 - leftStart, size); |
|
| 141 |
+ std::copy(&samples[0], &samples[leftSize], &this->buffer[leftStart]); |
|
| 142 |
+ if (leftSize < size) |
|
| 143 |
+ std::copy(&samples[leftSize], &samples[size], &this->buffer[N * 3 / 2]); |
|
| 144 |
+ } |
|
| 145 |
+ else |
|
| 146 |
+ {
|
|
| 147 |
+ std::copy(&samples[0], &samples[rightFree], &this->buffer[this->bufferPos + N]); |
|
| 148 |
+ std::copy(&samples[rightFree], &samples[size], &this->buffer[0]); |
|
| 149 |
+ } |
|
| 150 |
+ } |
|
| 151 |
+ else |
|
| 152 |
+ std::copy(&samples[0], &samples[size], &this->buffer[this->bufferPos + N]); |
|
| 153 |
+ this->bufferPos += size; |
|
| 154 |
+ if (this->bufferPos >= N * 3 / 2) |
|
| 155 |
+ this->bufferPos -= N; |
|
| 156 |
+ } |
|
| 157 |
+ const int16_t *const GetBuffer() const |
|
| 158 |
+ {
|
|
| 159 |
+ return &this->buffer[this->getPos]; |
|
| 160 |
+ } |
|
| 161 |
+ void NextSample() |
|
| 162 |
+ {
|
|
| 163 |
+ ++this->getPos; |
|
| 164 |
+ if (this->getPos >= N * 3 / 2) |
|
| 165 |
+ this->getPos -= N; |
|
| 166 |
+ } |
|
| 167 |
+}; |
|
| 168 |
+ |
|
| 86 | 169 |
struct Channel |
| 87 | 170 |
{
|
| 88 | 171 |
int8_t chnId; |
| ... | ... |
@@ -126,14 +209,6 @@ struct Channel |
| 126 | 209 |
const Player *ply; |
| 127 | 210 |
NDSSoundRegister reg; |
| 128 | 211 |
|
| 129 |
- /* |
|
| 130 |
- * Interpolation history buffer, which contains the maximum number of |
|
| 131 |
- * samples required for any given interpolation mode. Doubled to |
|
| 132 |
- * simplify the case of wrapping. Thanks to kode54 for providing this. |
|
| 133 |
- */ |
|
| 134 |
- uint32_t sampleHistoryPtr; |
|
| 135 |
- int16_t sampleHistory[64]; |
|
| 136 |
- |
|
| 137 | 212 |
/* |
| 138 | 213 |
* Lookup tables for the cosine and Lanczos Sinc interpolations, to |
| 139 | 214 |
* avoid the need to call the sin/cos functions all the time. |
| ... | ... |
@@ -142,11 +217,13 @@ struct Channel |
| 142 | 217 |
*/ |
| 143 | 218 |
static bool initializedLUTs; |
| 144 | 219 |
static const unsigned COSINE_RESOLUTION = 8192; |
| 145 |
- static const unsigned LANCZOS_RESOLUTION = 8192; |
|
| 146 |
- static const unsigned LANCZOS_WIDTH = 8; |
|
| 147 |
- static const unsigned LANCZOS_SAMPLES = LANCZOS_RESOLUTION * LANCZOS_WIDTH; |
|
| 220 |
+ static const unsigned SINC_RESOLUTION = 8192; |
|
| 221 |
+ static const unsigned SINC_WIDTH = 8; |
|
| 222 |
+ static const unsigned SINC_SAMPLES = SINC_RESOLUTION * SINC_WIDTH; |
|
| 148 | 223 |
static double cosine_lut[COSINE_RESOLUTION]; |
| 149 |
- static double lanczos_lut[LANCZOS_SAMPLES + 1]; |
|
| 224 |
+ static double sinc_lut[SINC_SAMPLES + 1]; |
|
| 225 |
+ |
|
| 226 |
+ RingBuffer<SINC_WIDTH * 2> ringBuffer; |
|
| 150 | 227 |
|
| 151 | 228 |
Channel(); |
| 152 | 229 |
|
| ... | ... |
@@ -162,7 +239,6 @@ struct Channel |
| 162 | 239 |
int32_t Interpolate(); |
| 163 | 240 |
int32_t GenerateSample(); |
| 164 | 241 |
void IncrementSample(); |
| 165 |
- void clearHistory(); |
|
| 166 | 242 |
}; |
| 167 | 243 |
|
| 168 | 244 |
#endif |
| ... | ... |
@@ -1,7 +1,7 @@ |
| 1 | 1 |
/* |
| 2 | 2 |
* SSEQ Player - Channel structures |
| 3 | 3 |
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com] |
| 4 |
- * Last modification on 2013-04-23 |
|
| 4 |
+ * Last modification on 2013-04-26 |
|
| 5 | 5 |
* |
| 6 | 6 |
* Adapted from source code of FeOS Sound System |
| 7 | 7 |
* By fincs |
| ... | ... |
@@ -132,7 +132,7 @@ struct Channel |
| 132 | 132 |
* simplify the case of wrapping. Thanks to kode54 for providing this. |
| 133 | 133 |
*/ |
| 134 | 134 |
uint32_t sampleHistoryPtr; |
| 135 |
- int16_t sampleHistory[16]; |
|
| 135 |
+ int16_t sampleHistory[64]; |
|
| 136 | 136 |
|
| 137 | 137 |
/* |
| 138 | 138 |
* Lookup tables for the cosine and Lanczos Sinc interpolations, to |
| ... | ... |
@@ -143,10 +143,10 @@ struct Channel |
| 143 | 143 |
static bool initializedLUTs; |
| 144 | 144 |
static const unsigned COSINE_RESOLUTION = 8192; |
| 145 | 145 |
static const unsigned LANCZOS_RESOLUTION = 8192; |
| 146 |
- static const unsigned LANCZOS_WIDTH = 3; |
|
| 146 |
+ static const unsigned LANCZOS_WIDTH = 8; |
|
| 147 | 147 |
static const unsigned LANCZOS_SAMPLES = LANCZOS_RESOLUTION * LANCZOS_WIDTH; |
| 148 | 148 |
static double cosine_lut[COSINE_RESOLUTION]; |
| 149 |
- static double lanczos_lut[LANCZOS_SAMPLES]; |
|
| 149 |
+ static double lanczos_lut[LANCZOS_SAMPLES + 1]; |
|
| 150 | 150 |
|
| 151 | 151 |
Channel(); |
| 152 | 152 |
|
| ... | ... |
@@ -1,7 +1,7 @@ |
| 1 | 1 |
/* |
| 2 | 2 |
* SSEQ Player - Channel structures |
| 3 | 3 |
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com] |
| 4 |
- * Last modification on 2013-04-18 |
|
| 4 |
+ * Last modification on 2013-04-23 |
|
| 5 | 5 |
* |
| 6 | 6 |
* Adapted from source code of FeOS Sound System |
| 7 | 7 |
* By fincs |
| ... | ... |
@@ -15,10 +15,9 @@ |
| 15 | 15 |
#define SSEQPLAYER_CHANNEL_H |
| 16 | 16 |
|
| 17 | 17 |
#include <bitset> |
| 18 |
-#include <tuple> |
|
| 18 |
+#include <cstdint> |
|
| 19 | 19 |
#include "SWAV.h" |
| 20 | 20 |
#include "Track.h" |
| 21 |
-#include "pstdint.h" |
|
| 22 | 21 |
|
| 23 | 22 |
/* |
| 24 | 23 |
* This structure is meant to be similar to what is stored in the actual |
| ... | ... |
@@ -135,6 +134,20 @@ struct Channel |
| 135 | 134 |
uint32_t sampleHistoryPtr; |
| 136 | 135 |
int16_t sampleHistory[16]; |
| 137 | 136 |
|
| 137 |
+ /* |
|
| 138 |
+ * Lookup tables for the cosine and Lanczos Sinc interpolations, to |
|
| 139 |
+ * avoid the need to call the sin/cos functions all the time. |
|
| 140 |
+ * These are static as they will not change between channels or runs |
|
| 141 |
+ * of the program. |
|
| 142 |
+ */ |
|
| 143 |
+ static bool initializedLUTs; |
|
| 144 |
+ static const unsigned COSINE_RESOLUTION = 8192; |
|
| 145 |
+ static const unsigned LANCZOS_RESOLUTION = 8192; |
|
| 146 |
+ static const unsigned LANCZOS_WIDTH = 3; |
|
| 147 |
+ static const unsigned LANCZOS_SAMPLES = LANCZOS_RESOLUTION * LANCZOS_WIDTH; |
|
| 148 |
+ static double cosine_lut[COSINE_RESOLUTION]; |
|
| 149 |
+ static double lanczos_lut[LANCZOS_SAMPLES]; |
|
| 150 |
+ |
|
| 138 | 151 |
Channel(); |
| 139 | 152 |
|
| 140 | 153 |
void UpdateVol(const Track &trk); |
| ... | ... |
@@ -1,7 +1,7 @@ |
| 1 | 1 |
/* |
| 2 | 2 |
* SSEQ Player - Channel structures |
| 3 | 3 |
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com] |
| 4 |
- * Last modification on 2013-04-02 |
|
| 4 |
+ * Last modification on 2013-04-18 |
|
| 5 | 5 |
* |
| 6 | 6 |
* Adapted from source code of FeOS Sound System |
| 7 | 7 |
* By fincs |
| ... | ... |
@@ -127,6 +127,14 @@ struct Channel |
| 127 | 127 |
const Player *ply; |
| 128 | 128 |
NDSSoundRegister reg; |
| 129 | 129 |
|
| 130 |
+ /* |
|
| 131 |
+ * Interpolation history buffer, which contains the maximum number of |
|
| 132 |
+ * samples required for any given interpolation mode. Doubled to |
|
| 133 |
+ * simplify the case of wrapping. Thanks to kode54 for providing this. |
|
| 134 |
+ */ |
|
| 135 |
+ uint32_t sampleHistoryPtr; |
|
| 136 |
+ int16_t sampleHistory[16]; |
|
| 137 |
+ |
|
| 130 | 138 |
Channel(); |
| 131 | 139 |
|
| 132 | 140 |
void UpdateVol(const Track &trk); |
| ... | ... |
@@ -141,6 +149,7 @@ struct Channel |
| 141 | 149 |
int32_t Interpolate(); |
| 142 | 150 |
int32_t GenerateSample(); |
| 143 | 151 |
void IncrementSample(); |
| 152 |
+ void clearHistory(); |
|
| 144 | 153 |
}; |
| 145 | 154 |
|
| 146 | 155 |
#endif |
| ... | ... |
@@ -1,7 +1,7 @@ |
| 1 | 1 |
/* |
| 2 | 2 |
* SSEQ Player - Channel structures |
| 3 | 3 |
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com] |
| 4 |
- * Last modification on 2013-03-21 |
|
| 4 |
+ * Last modification on 2013-04-02 |
|
| 5 | 5 |
* |
| 6 | 6 |
* Adapted from source code of FeOS Sound System |
| 7 | 7 |
* By fincs |
| ... | ... |
@@ -15,6 +15,7 @@ |
| 15 | 15 |
#define SSEQPLAYER_CHANNEL_H |
| 16 | 16 |
|
| 17 | 17 |
#include <bitset> |
| 18 |
+#include <tuple> |
|
| 18 | 19 |
#include "SWAV.h" |
| 19 | 20 |
#include "Track.h" |
| 20 | 21 |
#include "pstdint.h" |
| ... | ... |
@@ -135,7 +136,7 @@ struct Channel |
| 135 | 136 |
void Kill(); |
| 136 | 137 |
void UpdateTrack(); |
| 137 | 138 |
void Update(); |
| 138 |
- int32_t Interpolate(int32_t a, int32_t b, double ratio); |
|
| 139 |
+ int32_t Interpolate(); |
|
| 139 | 140 |
int32_t GenerateSample(); |
| 140 | 141 |
void IncrementSample(); |
| 141 | 142 |
}; |
| 1 | 1 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,143 @@ |
| 1 |
+/* |
|
| 2 |
+ * SSEQ Player - Channel structures |
|
| 3 |
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com] |
|
| 4 |
+ * Last modification on 2013-03-21 |
|
| 5 |
+ * |
|
| 6 |
+ * Adapted from source code of FeOS Sound System |
|
| 7 |
+ * By fincs |
|
| 8 |
+ * https://github.com/fincs/FSS |
|
| 9 |
+ * |
|
| 10 |
+ * Some code/concepts from DeSmuME |
|
| 11 |
+ * http://desmume.org/ |
|
| 12 |
+ */ |
|
| 13 |
+ |
|
| 14 |
+#ifndef SSEQPLAYER_CHANNEL_H |
|
| 15 |
+#define SSEQPLAYER_CHANNEL_H |
|
| 16 |
+ |
|
| 17 |
+#include <bitset> |
|
| 18 |
+#include "SWAV.h" |
|
| 19 |
+#include "Track.h" |
|
| 20 |
+#include "pstdint.h" |
|
| 21 |
+ |
|
| 22 |
+/* |
|
| 23 |
+ * This structure is meant to be similar to what is stored in the actual |
|
| 24 |
+ * Nintendo DS's sound registers. Items that were not being used by this |
|
| 25 |
+ * player have been removed, and items which help the simulated registers |
|
| 26 |
+ * have been added. |
|
| 27 |
+ */ |
|
| 28 |
+struct NDSSoundRegister |
|
| 29 |
+{
|
|
| 30 |
+ // Control Register |
|
| 31 |
+ uint8_t volumeMul; |
|
| 32 |
+ uint8_t volumeDiv; |
|
| 33 |
+ uint8_t panning; |
|
| 34 |
+ uint8_t waveDuty; |
|
| 35 |
+ uint8_t repeatMode; |
|
| 36 |
+ uint8_t format; |
|
| 37 |
+ bool enable; |
|
| 38 |
+ |
|
| 39 |
+ // Data Source Register |
|
| 40 |
+ const SWAV *source; |
|
| 41 |
+ |
|
| 42 |
+ // Timer Register |
|
| 43 |
+ uint16_t timer; |
|
| 44 |
+ |
|
| 45 |
+ // PSG Handling, not a DS register |
|
| 46 |
+ uint16_t psgX; |
|
| 47 |
+ int16_t psgLast; |
|
| 48 |
+ uint32_t psgLastCount; |
|
| 49 |
+ |
|
| 50 |
+ // The following are taken from DeSmuME |
|
| 51 |
+ double samplePosition; |
|
| 52 |
+ double sampleIncrease; |
|
| 53 |
+ |
|
| 54 |
+ // Loopstart Register |
|
| 55 |
+ uint32_t loopStart; |
|
| 56 |
+ |
|
| 57 |
+ // Length Register |
|
| 58 |
+ uint32_t length; |
|
| 59 |
+ |
|
| 60 |
+ NDSSoundRegister(); |
|
| 61 |
+ |
|
| 62 |
+ void ClearControlRegister(); |
|
| 63 |
+ void SetControlRegister(uint32_t reg); |
|
| 64 |
+}; |
|
| 65 |
+ |
|
| 66 |
+/* |
|
| 67 |
+ * From FeOS Sound System, this is temporary storage of what will go into |
|
| 68 |
+ * the Nintendo DS sound registers. It is kept separate as the original code |
|
| 69 |
+ * from FeOS Sound System utilized this to hold data prior to passing it into |
|
| 70 |
+ * the DS's registers. |
|
| 71 |
+ */ |
|
| 72 |
+struct TempSndReg |
|
| 73 |
+{
|
|
| 74 |
+ uint32_t CR; |
|
| 75 |
+ const SWAV *SOURCE; |
|
| 76 |
+ uint16_t TIMER; |
|
| 77 |
+ uint32_t REPEAT_POINT, LENGTH; |
|
| 78 |
+ |
|
| 79 |
+ TempSndReg(); |
|
| 80 |
+}; |
|
| 81 |
+ |
|
| 82 |
+struct Player; |
|
| 83 |
+ |
|
| 84 |
+struct Channel |
|
| 85 |
+{
|
|
| 86 |
+ int8_t chnId; |
|
| 87 |
+ |
|
| 88 |
+ TempSndReg tempReg; |
|
| 89 |
+ uint8_t state; |
|
| 90 |
+ int8_t trackId; // -1 = none |
|
| 91 |
+ uint8_t prio; |
|
| 92 |
+ bool manualSweep; |
|
| 93 |
+ |
|
| 94 |
+ std::bitset<CF_BITS> flags; |
|
| 95 |
+ int8_t pan; // -64 .. 63 |
|
| 96 |
+ int16_t extAmpl; |
|
| 97 |
+ |
|
| 98 |
+ int16_t velocity; |
|
| 99 |
+ int8_t extPan; |
|
| 100 |
+ uint8_t key; |
|
| 101 |
+ |
|
| 102 |
+ int ampl; // 7 fractionary bits |
|
| 103 |
+ int extTune; // in 64ths of a semitone |
|
| 104 |
+ |
|
| 105 |
+ uint8_t orgKey; |
|
| 106 |
+ |
|
| 107 |
+ uint8_t modType, modSpeed, modDepth, modRange; |
|
| 108 |
+ uint16_t modDelay, modDelayCnt, modCounter; |
|
| 109 |
+ |
|
| 110 |
+ uint32_t sweepLen, sweepCnt; |
|
| 111 |
+ int16_t sweepPitch; |
|
| 112 |
+ |
|
| 113 |
+ uint8_t attackLvl, sustainLvl; |
|
| 114 |
+ uint16_t decayRate, releaseRate; |
|
| 115 |
+ |
|
| 116 |
+ /* |
|
| 117 |
+ * These were originally global variables in FeOS Sound System, but |
|
| 118 |
+ * since they were linked to a certain channel anyways, I moved them |
|
| 119 |
+ * into this class. |
|
| 120 |
+ */ |
|
| 121 |
+ int noteLength; |
|
| 122 |
+ uint16_t vol; |
|
| 123 |
+ |
|
| 124 |
+ const Player *ply; |
|
| 125 |
+ NDSSoundRegister reg; |
|
| 126 |
+ |
|
| 127 |
+ Channel(); |
|
| 128 |
+ |
|
| 129 |
+ void UpdateVol(const Track &trk); |
|
| 130 |
+ void UpdatePan(const Track &trk); |
|
| 131 |
+ void UpdateTune(const Track &trk); |
|
| 132 |
+ void UpdateMod(const Track &trk); |
|
| 133 |
+ void UpdatePorta(const Track &trk); |
|
| 134 |
+ void Release(); |
|
| 135 |
+ void Kill(); |
|
| 136 |
+ void UpdateTrack(); |
|
| 137 |
+ void Update(); |
|
| 138 |
+ int32_t Interpolate(int32_t a, int32_t b, double ratio); |
|
| 139 |
+ int32_t GenerateSample(); |
|
| 140 |
+ void IncrementSample(); |
|
| 141 |
+}; |
|
| 142 |
+ |
|
| 143 |
+#endif |