Browse code

Fix pitch bend effect on some more songs

Clarissa Walker authored on 2024/09/09 18:43:42
Showing 1 changed files
... ...
@@ -702,7 +702,6 @@ void Track::Run()
702 702
 
703 703
 				case SSEQCommand::SweepPitch:
704 704
 					this->sweepPitch = this->overriding.val(pData, read16);
705
-					this->state.set(ToIntegral(TrackState::PortamentoBit));
706 705
 					// Update here?
707 706
 					break;
708 707
 
Browse code

Fix pitch bend effect on some songs

Clarissa Walker authored on 2024/08/21 15:35:15
Showing 1 changed files
... ...
@@ -697,7 +697,6 @@ void Track::Run()
697 697
 
698 698
 				case SSEQCommand::PortamentoTime:
699 699
 					this->portaTime = this->overriding.val(pData, read8);
700
-					this->state.set(ToIntegral(TrackState::PortamentoBit));
701 700
 					// Update here?
702 701
 					break;
703 702
 
Browse code

Rename SBNKInstrument(Range) to SBNKInstrument(Entry).

(SBNKInstrument -> SBNKInstrumentEntry and SBNKIntrumentRange -> SBNKInstrument)
The old names didn't really make much sense when I started porting the creation tools code to C#, so might as well fix them here too.

Naram Qashat authored on 2021/03/21 03:26:56
Showing 1 changed files
... ...
@@ -109,35 +109,35 @@ int Track::NoteOn(int key, int vel, int len)
109 109
 {
110 110
 	auto sbnk = this->ply->sseq->bank;
111 111
 
112
-	if (this->patch >= sbnk->instruments.size())
112
+	if (this->patch >= sbnk->entries.size())
113 113
 		return -1;
114 114
 
115 115
 	bool bIsPCM = true;
116 116
 	Channel *chn = nullptr;
117 117
 	int nCh = -1;
118 118
 
119
-	auto &instrument = sbnk->instruments[this->patch];
120
-	const SBNKInstrumentRange *noteDef = nullptr;
121
-	int fRecord = instrument.record;
119
+	auto &entry = sbnk->entries[this->patch];
120
+	const SBNKInstrument *noteDef = nullptr;
121
+	int fRecord = entry.record;
122 122
 
123 123
 	if (fRecord == 16)
124 124
 	{
125
-		if (!(instrument.ranges[0].lowNote <= key && key <= instrument.ranges[instrument.ranges.size() - 1].highNote))
125
+		if (!(entry.instruments[0].lowNote <= key && key <= entry.instruments[entry.instruments.size() - 1].highNote))
126 126
 			return -1;
127
-		int rn = key - instrument.ranges[0].lowNote;
128
-		noteDef = &instrument.ranges[rn];
127
+		int rn = key - entry.instruments[0].lowNote;
128
+		noteDef = &entry.instruments[rn];
129 129
 		fRecord = noteDef->record;
130 130
 	}
131 131
 	else if (fRecord == 17)
132 132
 	{
133
-		std::size_t reg, ranges;
134
-		for (reg = 0, ranges = instrument.ranges.size(); reg < ranges; ++reg)
135
-			if (key <= instrument.ranges[reg].highNote)
133
+		std::size_t reg, entries;
134
+		for (reg = 0, entries = entry.instruments.size(); reg < entries; ++reg)
135
+			if (key <= entry.instruments[reg].highNote)
136 136
 				break;
137
-		if (reg == ranges)
137
+		if (reg == entries)
138 138
 			return -1;
139 139
 
140
-		noteDef = &instrument.ranges[reg];
140
+		noteDef = &entry.instruments[reg];
141 141
 		fRecord = noteDef->record;
142 142
 	}
143 143
 
... ...
@@ -146,7 +146,7 @@ int Track::NoteOn(int key, int vel, int len)
146 146
 	else if (fRecord == 1)
147 147
 	{
148 148
 		if (!noteDef)
149
-			noteDef = &instrument.ranges[0];
149
+			noteDef = &entry.instruments[0];
150 150
 	}
151 151
 	else if (fRecord < 4)
152 152
 	{
... ...
@@ -155,7 +155,7 @@ int Track::NoteOn(int key, int vel, int len)
155 155
 		// fRecord = 3 -> PSG noise
156 156
 		bIsPCM = false;
157 157
 		if (!noteDef)
158
-			noteDef = &instrument.ranges[0];
158
+			noteDef = &entry.instruments[0];
159 159
 		if (fRecord == 3)
160 160
 		{
161 161
 			nCh = this->ply->ChannelAlloc(ChannelAllocateType::Noise, this->prio);
Browse code

Various changes:

* 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().

Naram Qashat authored on 2021/03/21 03:16:45
Showing 1 changed files
... ...
@@ -7,10 +7,18 @@
7 7
  * https://github.com/fincs/FSS
8 8
  */
9 9
 
10
-#include <cstdlib>
11
-#include "Track.h"
10
+#include <algorithm>
11
+#include <functional>
12
+#include <cstddef>
13
+#include <cstdint>
12 14
 #include "Player.h"
15
+#include "SBNK.h"
16
+#include "SSEQ.h"
17
+#include "SWAR.h"
18
+#include "SWAV.h"
19
+#include "Track.h"
13 20
 #include "common.h"
21
+#include "consts.h"
14 22
 
15 23
 Track::Track()
16 24
 {
... ...
@@ -18,7 +26,7 @@ Track::Track()
18 26
 }
19 27
 
20 28
 // Original FSS Function: Player_InitTrack
21
-void Track::Init(uint8_t handle, Player *player, const uint8_t *dataPos, int n)
29
+void Track::Init(std::uint8_t handle, Player *player, const std::uint8_t *dataPos, int n)
22 30
 {
23 31
 	this->trackId = handle;
24 32
 	this->num = n;
... ...
@@ -63,8 +71,8 @@ void Track::Zero()
63 71
 void Track::ClearState()
64 72
 {
65 73
 	this->state.reset();
66
-	this->state.set(TS_ALLOCBIT);
67
-	this->state.set(TS_NOTEWAIT);
74
+	this->state.set(ToIntegral(TrackState::AllocateBit));
75
+	this->state.set(ToIntegral(TrackState::NoteWait));
68 76
 	this->prio = this->ply->prio + 64;
69 77
 
70 78
 	this->pos = this->startPos;
... ...
@@ -122,7 +130,7 @@ int Track::NoteOn(int key, int vel, int len)
122 130
 	}
123 131
 	else if (fRecord == 17)
124 132
 	{
125
-		size_t reg, ranges;
133
+		std::size_t reg, ranges;
126 134
 		for (reg = 0, ranges = instrument.ranges.size(); reg < ranges; ++reg)
127 135
 			if (key <= instrument.ranges[reg].highNote)
128 136
 				break;
... ...
@@ -150,7 +158,7 @@ int Track::NoteOn(int key, int vel, int len)
150 158
 			noteDef = &instrument.ranges[0];
151 159
 		if (fRecord == 3)
152 160
 		{
153
-			nCh = this->ply->ChannelAlloc(TYPE_NOISE, this->prio);
161
+			nCh = this->ply->ChannelAlloc(ChannelAllocateType::Noise, this->prio);
154 162
 			if (nCh < 0)
155 163
 				return -1;
156 164
 			chn = &this->ply->channels[nCh];
... ...
@@ -158,7 +166,7 @@ int Track::NoteOn(int key, int vel, int len)
158 166
 		}
159 167
 		else
160 168
 		{
161
-			nCh = this->ply->ChannelAlloc(TYPE_PSG, this->prio);
169
+			nCh = this->ply->ChannelAlloc(ChannelAllocateType::PSG, this->prio);
162 170
 			if (nCh < 0)
163 171
 				return -1;
164 172
 			chn = &this->ply->channels[nCh];
... ...
@@ -171,7 +179,7 @@ int Track::NoteOn(int key, int vel, int len)
171 179
 
172 180
 	if (bIsPCM)
173 181
 	{
174
-		nCh = this->ply->ChannelAlloc(TYPE_PCM, this->prio);
182
+		nCh = this->ply->ChannelAlloc(ChannelAllocateType::PCM, this->prio);
175 183
 		if (nCh < 0)
176 184
 			return -1;
177 185
 		chn = &this->ply->channels[nCh];
... ...
@@ -185,7 +193,7 @@ int Track::NoteOn(int key, int vel, int len)
185 193
 		chn->reg.samplePosition = -3;
186 194
 	}
187 195
 
188
-	chn->state = CS_START;
196
+	chn->state = ChannelState::Start;
189 197
 	chn->trackId = this->trackId;
190 198
 	chn->flags.reset();
191 199
 	chn->prio = this->prio;
... ...
@@ -223,7 +231,7 @@ int Track::NoteOnTie(int key, int vel)
223 231
 	for (i = 0; i < 16; ++i)
224 232
 	{
225 233
 		chn = &this->ply->channels[i];
226
-		if (chn->state > CS_NONE && chn->trackId == this->trackId && chn->state != CS_RELEASE)
234
+		if (chn->state > ChannelState::None && chn->trackId == this->trackId && chn->state != ChannelState::Release)
227 235
 			break;
228 236
 	}
229 237
 
... ...
@@ -245,7 +253,7 @@ int Track::NoteOnTie(int key, int vel)
245 253
 	chn->UpdatePorta(*this);
246 254
 
247 255
 	this->portaKey = key;
248
-	chn->flags.set(CF_UPDTMR);
256
+	chn->flags.set(ToIntegral(ChannelFlag::UpdateTimer));
249 257
 
250 258
 	return i;
251 259
 }
... ...
@@ -256,145 +264,145 @@ void Track::ReleaseAllNotes()
256 264
 	for (int i = 0; i < 16; ++i)
257 265
 	{
258 266
 		Channel &chn = this->ply->channels[i];
259
-		if (chn.state > CS_NONE && chn.trackId == this->trackId && chn.state != CS_RELEASE)
267
+		if (chn.state > ChannelState::None && chn.trackId == this->trackId && chn.state != ChannelState::Release)
260 268
 			chn.Release();
261 269
 	}
262 270
 }
263 271
 
264
-enum SseqCommand
272
+enum class SSEQCommand
265 273
 {
266
-	SSEQ_CMD_ALLOCTRACK = 0xFE, // Silently ignored
267
-	SSEQ_CMD_OPENTRACK = 0x93,
268
-
269
-	SSEQ_CMD_REST = 0x80,
270
-	SSEQ_CMD_PATCH = 0x81,
271
-	SSEQ_CMD_PAN = 0xC0,
272
-	SSEQ_CMD_VOL = 0xC1,
273
-	SSEQ_CMD_MASTERVOL = 0xC2,
274
-	SSEQ_CMD_PRIO = 0xC6,
275
-	SSEQ_CMD_NOTEWAIT = 0xC7,
276
-	SSEQ_CMD_TIE = 0xC8,
277
-	SSEQ_CMD_EXPR = 0xD5,
278
-	SSEQ_CMD_TEMPO = 0xE1,
279
-	SSEQ_CMD_END = 0xFF,
280
-
281
-	SSEQ_CMD_GOTO = 0x94,
282
-	SSEQ_CMD_CALL = 0x95,
283
-	SSEQ_CMD_RET = 0xFD,
284
-	SSEQ_CMD_LOOPSTART = 0xD4,
285
-	SSEQ_CMD_LOOPEND = 0xFC,
286
-
287
-	SSEQ_CMD_TRANSPOSE = 0xC3,
288
-	SSEQ_CMD_PITCHBEND = 0xC4,
289
-	SSEQ_CMD_PITCHBENDRANGE = 0xC5,
290
-
291
-	SSEQ_CMD_ATTACK = 0xD0,
292
-	SSEQ_CMD_DECAY = 0xD1,
293
-	SSEQ_CMD_SUSTAIN = 0xD2,
294
-	SSEQ_CMD_RELEASE = 0xD3,
295
-
296
-	SSEQ_CMD_PORTAKEY = 0xC9,
297
-	SSEQ_CMD_PORTAFLAG = 0xCE,
298
-	SSEQ_CMD_PORTATIME = 0xCF,
299
-	SSEQ_CMD_SWEEPPITCH = 0xE3,
300
-
301
-	SSEQ_CMD_MODDEPTH = 0xCA,
302
-	SSEQ_CMD_MODSPEED = 0xCB,
303
-	SSEQ_CMD_MODTYPE = 0xCC,
304
-	SSEQ_CMD_MODRANGE = 0xCD,
305
-	SSEQ_CMD_MODDELAY = 0xE0,
306
-
307
-	SSEQ_CMD_RANDOM = 0xA0,
308
-	SSEQ_CMD_PRINTVAR = 0xD6,
309
-	SSEQ_CMD_IF = 0xA2,
310
-	SSEQ_CMD_FROMVAR = 0xA1,
311
-	SSEQ_CMD_SETVAR = 0xB0,
312
-	SSEQ_CMD_ADDVAR = 0xB1,
313
-	SSEQ_CMD_SUBVAR = 0xB2,
314
-	SSEQ_CMD_MULVAR = 0xB3,
315
-	SSEQ_CMD_DIVVAR = 0xB4,
316
-	SSEQ_CMD_SHIFTVAR = 0xB5,
317
-	SSEQ_CMD_RANDVAR = 0xB6,
318
-	SSEQ_CMD_CMP_EQ = 0xB8,
319
-	SSEQ_CMD_CMP_GE = 0xB9,
320
-	SSEQ_CMD_CMP_GT = 0xBA,
321
-	SSEQ_CMD_CMP_LE = 0xBB,
322
-	SSEQ_CMD_CMP_LT = 0xBC,
323
-	SSEQ_CMD_CMP_NE = 0xBD,
324
-
325
-	SSEQ_CMD_MUTE = 0xD7 // Unsupported
274
+	AllocateTrack = 0xFE, // Silently ignored
275
+	OpenTrack = 0x93,
276
+
277
+	Rest = 0x80,
278
+	Patch = 0x81,
279
+	Pan = 0xC0,
280
+	Volume = 0xC1,
281
+	MasterVolume = 0xC2,
282
+	Priority = 0xC6,
283
+	NoteWait = 0xC7,
284
+	Tie = 0xC8,
285
+	Expression = 0xD5,
286
+	Tempo = 0xE1,
287
+	End = 0xFF,
288
+
289
+	Goto = 0x94,
290
+	Call = 0x95,
291
+	Return = 0xFD,
292
+	LoopStart = 0xD4,
293
+	LoopEnd = 0xFC,
294
+
295
+	Transpose = 0xC3,
296
+	PitchBend = 0xC4,
297
+	PitchBendRange = 0xC5,
298
+
299
+	Attack = 0xD0,
300
+	Decay = 0xD1,
301
+	Sustain = 0xD2,
302
+	Release = 0xD3,
303
+
304
+	PortamentoKey = 0xC9,
305
+	PortamentoFlag = 0xCE,
306
+	PortamentoTime = 0xCF,
307
+	SweepPitch = 0xE3,
308
+
309
+	ModulationDepth = 0xCA,
310
+	ModulationSpeed = 0xCB,
311
+	ModulationType = 0xCC,
312
+	ModulationRange = 0xCD,
313
+	ModulationDelay = 0xE0,
314
+
315
+	Random = 0xA0,
316
+	PrintVariable = 0xD6,
317
+	If = 0xA2,
318
+	FromVariable = 0xA1,
319
+	SetVariable = 0xB0,
320
+	AddVariable = 0xB1,
321
+	SubtractVariable = 0xB2,
322
+	MultiplyVariable = 0xB3,
323
+	DivideVariable = 0xB4,
324
+	ShiftVariable = 0xB5,
325
+	RandomVariable = 0xB6,
326
+	CompareEqualTo = 0xB8,
327
+	CompareGreaterThanOrEqualTo = 0xB9,
328
+	CompareGreaterThan = 0xBA,
329
+	CompareLessThanOrEqualTo = 0xBB,
330
+	CompareLessThan = 0xBC,
331
+	CompareNotEqualTo = 0xBD,
332
+
333
+	Mute = 0xD7 // Unsupported
326 334
 };
327 335
 
328
-static const uint8_t VariableByteCount = 1 << 7;
329
-static const uint8_t ExtraByteOnNoteOrVarOrCmp = 1 << 6;
336
+static const std::uint8_t VariableByteCount = 1 << 7;
337
+static const std::uint8_t ExtraByteOnNoteOrVarOrCmp = 1 << 6;
330 338
 
331
-static inline uint8_t SseqCommandByteCount(int cmd)
339
+static inline std::uint8_t SseqCommandByteCount(int cmd)
332 340
 {
333 341
 	if (cmd < 0x80)
334 342
 		return 1 | VariableByteCount;
335 343
 	else
336
-		switch (cmd)
344
+		switch (static_cast<SSEQCommand>(cmd))
337 345
 		{
338
-			case SSEQ_CMD_REST:
339
-			case SSEQ_CMD_PATCH:
346
+			case SSEQCommand::Rest:
347
+			case SSEQCommand::Patch:
340 348
 				return VariableByteCount;
341 349
 
342
-			case SSEQ_CMD_PAN:
343
-			case SSEQ_CMD_VOL:
344
-			case SSEQ_CMD_MASTERVOL:
345
-			case SSEQ_CMD_PRIO:
346
-			case SSEQ_CMD_NOTEWAIT:
347
-			case SSEQ_CMD_TIE:
348
-			case SSEQ_CMD_EXPR:
349
-			case SSEQ_CMD_LOOPSTART:
350
-			case SSEQ_CMD_TRANSPOSE:
351
-			case SSEQ_CMD_PITCHBEND:
352
-			case SSEQ_CMD_PITCHBENDRANGE:
353
-			case SSEQ_CMD_ATTACK:
354
-			case SSEQ_CMD_DECAY:
355
-			case SSEQ_CMD_SUSTAIN:
356
-			case SSEQ_CMD_RELEASE:
357
-			case SSEQ_CMD_PORTAKEY:
358
-			case SSEQ_CMD_PORTAFLAG:
359
-			case SSEQ_CMD_PORTATIME:
360
-			case SSEQ_CMD_MODDEPTH:
361
-			case SSEQ_CMD_MODSPEED:
362
-			case SSEQ_CMD_MODTYPE:
363
-			case SSEQ_CMD_MODRANGE:
364
-			case SSEQ_CMD_PRINTVAR:
365
-			case SSEQ_CMD_MUTE:
350
+			case SSEQCommand::Pan:
351
+			case SSEQCommand::Volume:
352
+			case SSEQCommand::MasterVolume:
353
+			case SSEQCommand::Priority:
354
+			case SSEQCommand::NoteWait:
355
+			case SSEQCommand::Tie:
356
+			case SSEQCommand::Expression:
357
+			case SSEQCommand::LoopStart:
358
+			case SSEQCommand::Transpose:
359
+			case SSEQCommand::PitchBend:
360
+			case SSEQCommand::PitchBendRange:
361
+			case SSEQCommand::Attack:
362
+			case SSEQCommand::Decay:
363
+			case SSEQCommand::Sustain:
364
+			case SSEQCommand::Release:
365
+			case SSEQCommand::PortamentoKey:
366
+			case SSEQCommand::PortamentoFlag:
367
+			case SSEQCommand::PortamentoTime:
368
+			case SSEQCommand::ModulationDepth:
369
+			case SSEQCommand::ModulationSpeed:
370
+			case SSEQCommand::ModulationType:
371
+			case SSEQCommand::ModulationRange:
372
+			case SSEQCommand::PrintVariable:
373
+			case SSEQCommand::Mute:
366 374
 				return 1;
367 375
 
368
-			case SSEQ_CMD_ALLOCTRACK:
369
-			case SSEQ_CMD_TEMPO:
370
-			case SSEQ_CMD_SWEEPPITCH:
371
-			case SSEQ_CMD_MODDELAY:
376
+			case SSEQCommand::AllocateTrack:
377
+			case SSEQCommand::Tempo:
378
+			case SSEQCommand::SweepPitch:
379
+			case SSEQCommand::ModulationDelay:
372 380
 				return 2;
373 381
 
374
-			case SSEQ_CMD_GOTO:
375
-			case SSEQ_CMD_CALL:
376
-			case SSEQ_CMD_SETVAR:
377
-			case SSEQ_CMD_ADDVAR:
378
-			case SSEQ_CMD_SUBVAR:
379
-			case SSEQ_CMD_MULVAR:
380
-			case SSEQ_CMD_DIVVAR:
381
-			case SSEQ_CMD_SHIFTVAR:
382
-			case SSEQ_CMD_RANDVAR:
383
-			case SSEQ_CMD_CMP_EQ:
384
-			case SSEQ_CMD_CMP_GE:
385
-			case SSEQ_CMD_CMP_GT:
386
-			case SSEQ_CMD_CMP_LE:
387
-			case SSEQ_CMD_CMP_LT:
388
-			case SSEQ_CMD_CMP_NE:
382
+			case SSEQCommand::Goto:
383
+			case SSEQCommand::Call:
384
+			case SSEQCommand::SetVariable:
385
+			case SSEQCommand::AddVariable:
386
+			case SSEQCommand::SubtractVariable:
387
+			case SSEQCommand::MultiplyVariable:
388
+			case SSEQCommand::DivideVariable:
389
+			case SSEQCommand::ShiftVariable:
390
+			case SSEQCommand::RandomVariable:
391
+			case SSEQCommand::CompareEqualTo:
392
+			case SSEQCommand::CompareGreaterThanOrEqualTo:
393
+			case SSEQCommand::CompareGreaterThan:
394
+			case SSEQCommand::CompareLessThanOrEqualTo:
395
+			case SSEQCommand::CompareLessThan:
396
+			case SSEQCommand::CompareNotEqualTo:
389 397
 				return 3;
390 398
 
391
-			case SSEQ_CMD_OPENTRACK:
399
+			case SSEQCommand::OpenTrack:
392 400
 				return 4;
393 401
 
394
-			case SSEQ_CMD_FROMVAR:
402
+			case SSEQCommand::FromVariable:
395 403
 				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
396 404
 
397
-			case SSEQ_CMD_RANDOM:
405
+			case SSEQCommand::Random:
398 406
 				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
399 407
 
400 408
 			default:
... ...
@@ -410,19 +418,19 @@ static std::uint16_t CalcRandom()
410 418
 	return static_cast<std::uint16_t>(RandomU >> 16);
411 419
 }
412 420
 
413
-static auto varFuncSet = [](int16_t, int16_t value) { return value; };
414
-static auto varFuncAdd = [](int16_t var, int16_t value) -> int16_t { return var + value; };
415
-static auto varFuncSub = [](int16_t var, int16_t value) -> int16_t { return var - value; };
416
-static auto varFuncMul = [](int16_t var, int16_t value) -> int16_t { return var * value; };
417
-static auto varFuncDiv = [](int16_t var, int16_t value) -> int16_t { return var / value; };
418
-static auto varFuncShift = [](int16_t var, int16_t value) -> int16_t
421
+static auto varFuncSet = [](std::int16_t, std::int16_t value) { return value; };
422
+static auto varFuncAdd = [](std::int16_t var, std::int16_t value) -> std::int16_t { return var + value; };
423
+static auto varFuncSub = [](std::int16_t var, std::int16_t value) -> std::int16_t { return var - value; };
424
+static auto varFuncMul = [](std::int16_t var, std::int16_t value) -> std::int16_t { return var * value; };
425
+static auto varFuncDiv = [](std::int16_t var, std::int16_t value) -> std::int16_t { return var / value; };
426
+static auto varFuncShift = [](std::int16_t var, std::int16_t value) -> std::int16_t
419 427
 {
420 428
 	if (value < 0)
421 429
 		return var >> -value;
422 430
 	else
423 431
 		return var << value;
424 432
 };
425
-static auto varFuncRand = [](int16_t, int16_t value) -> int16_t
433
+static auto varFuncRand = [](std::int16_t, std::int16_t value) -> std::int16_t
426 434
 {
427 435
 	if (value < 0)
428 436
 		return -(CalcRandom() % (-value + 1));
... ...
@@ -430,51 +438,51 @@ static auto varFuncRand = [](int16_t, int16_t value) -> int16_t
430 438
 		return CalcRandom() % (value + 1);
431 439
 };
432 440
 
433
-static inline std::function<int16_t (int16_t, int16_t)> VarFunc(int cmd)
441
+static inline std::function<std::int16_t (std::int16_t, std::int16_t)> VarFunc(int cmd)
434 442
 {
435
-	switch (cmd)
443
+	switch (static_cast<SSEQCommand>(cmd))
436 444
 	{
437
-		case SSEQ_CMD_SETVAR:
445
+		case SSEQCommand::SetVariable:
438 446
 			return varFuncSet;
439
-		case SSEQ_CMD_ADDVAR:
447
+		case SSEQCommand::AddVariable:
440 448
 			return varFuncAdd;
441
-		case SSEQ_CMD_SUBVAR:
449
+		case SSEQCommand::SubtractVariable:
442 450
 			return varFuncSub;
443
-		case SSEQ_CMD_MULVAR:
451
+		case SSEQCommand::MultiplyVariable:
444 452
 			return varFuncMul;
445
-		case SSEQ_CMD_DIVVAR:
453
+		case SSEQCommand::DivideVariable:
446 454
 			return varFuncDiv;
447
-		case SSEQ_CMD_SHIFTVAR:
455
+		case SSEQCommand::ShiftVariable:
448 456
 			return varFuncShift;
449
-		case SSEQ_CMD_RANDVAR:
457
+		case SSEQCommand::RandomVariable:
450 458
 			return varFuncRand;
451 459
 		default:
452 460
 			return nullptr;
453 461
 	}
454 462
 }
455 463
 
456
-static auto compareFuncEq = [](int16_t a, int16_t b) { return a == b; };
457
-static auto compareFuncGe = [](int16_t a, int16_t b) { return a >= b; };
458
-static auto compareFuncGt = [](int16_t a, int16_t b) { return a > b; };
459
-static auto compareFuncLe = [](int16_t a, int16_t b) { return a <= b; };
460
-static auto compareFuncLt = [](int16_t a, int16_t b) { return a < b; };
461
-static auto compareFuncNe = [](int16_t a, int16_t b) { return a != b; };
464
+static auto compareFuncEq = [](std::int16_t a, std::int16_t b) { return a == b; };
465
+static auto compareFuncGe = [](std::int16_t a, std::int16_t b) { return a >= b; };
466
+static auto compareFuncGt = [](std::int16_t a, std::int16_t b) { return a > b; };
467
+static auto compareFuncLe = [](std::int16_t a, std::int16_t b) { return a <= b; };
468
+static auto compareFuncLt = [](std::int16_t a, std::int16_t b) { return a < b; };
469
+static auto compareFuncNe = [](std::int16_t a, std::int16_t b) { return a != b; };
462 470
 
463
-static inline std::function<bool (int16_t, int16_t)> CompareFunc(int cmd)
471
+static inline std::function<bool (std::int16_t, std::int16_t)> CompareFunc(int cmd)
464 472
 {
465
-	switch (cmd)
473
+	switch (static_cast<SSEQCommand>(cmd))
466 474
 	{
467
-		case SSEQ_CMD_CMP_EQ:
475
+		case SSEQCommand::CompareEqualTo:
468 476
 			return compareFuncEq;
469
-		case SSEQ_CMD_CMP_GE:
477
+		case SSEQCommand::CompareGreaterThanOrEqualTo:
470 478
 			return compareFuncGe;
471
-		case SSEQ_CMD_CMP_GT:
479
+		case SSEQCommand::CompareGreaterThan:
472 480
 			return compareFuncGt;
473
-		case SSEQ_CMD_CMP_LE:
481
+		case SSEQCommand::CompareLessThanOrEqualTo:
474 482
 			return compareFuncLe;
475
-		case SSEQ_CMD_CMP_LT:
483
+		case SSEQCommand::CompareLessThan:
476 484
 			return compareFuncLt;
477
-		case SSEQ_CMD_CMP_NE:
485
+		case SSEQCommand::CompareNotEqualTo:
478 486
 			return compareFuncNe;
479 487
 		default:
480 488
 			return nullptr;
... ...
@@ -485,10 +493,10 @@ static inline std::function<bool (int16_t, int16_t)> CompareFunc(int cmd)
485 493
 void Track::Run()
486 494
 {
487 495
 	// Indicate "heartbeat" for this track
488
-	this->updateFlags.set(TUF_LEN);
496
+	this->updateFlags.set(ToIntegral(TrackUpdateFlag::Length));
489 497
 
490 498
 	// Exit if the track has already ended
491
-	if (this->state[TS_END])
499
+	if (this->state[ToIntegral(TrackState::End)])
492 500
 		return;
493 501
 
494 502
 	if (this->wait)
... ...
@@ -513,9 +521,9 @@ void Track::Run()
513 521
 			int key = cmd + this->transpose;
514 522
 			int vel = this->overriding.val(pData, read8, true);
515 523
 			int len = this->overriding.val(pData, readvl);
516
-			if (this->state[TS_NOTEWAIT])
524
+			if (this->state[ToIntegral(TrackState::NoteWait)])
517 525
 				this->wait = len;
518
-			if (this->state[TS_TIEBIT])
526
+			if (this->state[ToIntegral(TrackState::TieBit)])
519 527
 				this->NoteOnTie(key, vel);
520 528
 			else
521 529
 				this->NoteOn(key, vel, len);
... ...
@@ -523,13 +531,13 @@ void Track::Run()
523 531
 		else
524 532
 		{
525 533
 			int value;
526
-			switch (cmd)
534
+			switch (static_cast<SSEQCommand>(cmd))
527 535
 			{
528 536
 				//-----------------------------------------------------------------
529 537
 				// Main commands
530 538
 				//-----------------------------------------------------------------
531 539
 
532
-				case SSEQ_CMD_OPENTRACK:
540
+				case SSEQCommand::OpenTrack:
533 541
 				{
534 542
 					int tNum = read8(pData);
535 543
 					auto trackPos = &this->ply->sseq->data[read24(pData)];
... ...
@@ -542,91 +550,91 @@ void Track::Run()
542 550
 					break;
543 551
 				}
544 552
 
545
-				case SSEQ_CMD_REST:
553
+				case SSEQCommand::Rest:
546 554
 					this->wait = this->overriding.val(pData, readvl);
547 555
 					break;
548 556
 
549
-				case SSEQ_CMD_PATCH:
557
+				case SSEQCommand::Patch:
550 558
 					this->patch = this->overriding.val(pData, readvl);
551 559
 					break;
552 560
 
553
-				case SSEQ_CMD_GOTO:
561
+				case SSEQCommand::Goto:
554 562
 					*pData = &this->ply->sseq->data[read24(pData)];
555 563
 					break;
556 564
 
557
-				case SSEQ_CMD_CALL:
565
+				case SSEQCommand::Call:
558 566
 					value = read24(pData);
559 567
 					if (this->stackPos < FSS_TRACKSTACKSIZE)
560 568
 					{
561
-						const uint8_t *dest = &this->ply->sseq->data[value];
562
-						this->stack[this->stackPos++] = StackValue(STACKTYPE_CALL, *pData);
569
+						const std::uint8_t *dest = &this->ply->sseq->data[value];
570
+						this->stack[this->stackPos++] = StackValue(StackType::Call, *pData);
563 571
 						*pData = dest;
564 572
 					}
565 573
 					break;
566 574
 
567
-				case SSEQ_CMD_RET:
568
-					if (this->stackPos && this->stack[this->stackPos - 1].type == STACKTYPE_CALL)
575
+				case SSEQCommand::Return:
576
+					if (this->stackPos && this->stack[this->stackPos - 1].type == StackType::Call)
569 577
 						*pData = this->stack[--this->stackPos].dest;
570 578
 					break;
571 579
 
572
-				case SSEQ_CMD_PAN:
580
+				case SSEQCommand::Pan:
573 581
 					this->pan = this->overriding.val(pData, read8) - 64;
574
-					this->updateFlags.set(TUF_PAN);
582
+					this->updateFlags.set(ToIntegral(TrackUpdateFlag::Pan));
575 583
 					break;
576 584
 
577
-				case SSEQ_CMD_VOL:
585
+				case SSEQCommand::Volume:
578 586
 					this->vol = this->overriding.val(pData, read8);
579
-					this->updateFlags.set(TUF_VOL);
587
+					this->updateFlags.set(ToIntegral(TrackUpdateFlag::Volume));
580 588
 					break;
581 589
 
582
-				case SSEQ_CMD_MASTERVOL:
590
+				case SSEQCommand::MasterVolume:
583 591
 					this->ply->masterVol = Cnv_Sust(this->overriding.val(pData, read8));
584
-					for (uint8_t i = 0; i < this->ply->nTracks; ++i)
585
-						this->ply->tracks[this->ply->trackIds[i]].updateFlags.set(TUF_VOL);
592
+					for (std::uint8_t i = 0; i < this->ply->nTracks; ++i)
593
+						this->ply->tracks[this->ply->trackIds[i]].updateFlags.set(ToIntegral(TrackUpdateFlag::Volume));
586 594
 					break;
587 595
 
588
-				case SSEQ_CMD_PRIO:
596
+				case SSEQCommand::Priority:
589 597
 					this->prio = this->ply->prio + read8(pData);
590 598
 					// Update here?
591 599
 					break;
592 600
 
593
-				case SSEQ_CMD_NOTEWAIT:
594
-					this->state.set(TS_NOTEWAIT, !!read8(pData));
601
+				case SSEQCommand::NoteWait:
602
+					this->state.set(ToIntegral(TrackState::NoteWait), !!read8(pData));
595 603
 					break;
596 604
 
597
-				case SSEQ_CMD_TIE:
598
-					this->state.set(TS_TIEBIT, !!read8(pData));
605
+				case SSEQCommand::Tie:
606
+					this->state.set(ToIntegral(TrackState::TieBit), !!read8(pData));
599 607
 					this->ReleaseAllNotes();
600 608
 					break;
601 609
 
602
-				case SSEQ_CMD_EXPR:
610
+				case SSEQCommand::Expression:
603 611
 					this->expr = this->overriding.val(pData, read8);
604
-					this->updateFlags.set(TUF_VOL);
612
+					this->updateFlags.set(ToIntegral(TrackUpdateFlag::Volume));
605 613
 					break;
606 614
 
607
-				case SSEQ_CMD_TEMPO:
615
+				case SSEQCommand::Tempo:
608 616
 					this->ply->tempo = read16(pData);
609 617
 					break;
610 618
 
611
-				case SSEQ_CMD_END:
612
-					this->state.set(TS_END);
619
+				case SSEQCommand::End:
620
+					this->state.set(ToIntegral(TrackState::End));
613 621
 					return;
614 622
 
615
-				case SSEQ_CMD_LOOPSTART:
623
+				case SSEQCommand::LoopStart:
616 624
 					value = this->overriding.val(pData, read8);
617 625
 					if (this->stackPos < FSS_TRACKSTACKSIZE)
618 626
 					{
619 627
 						this->loopCount[this->stackPos] = value;
620
-						this->stack[this->stackPos++] = StackValue(STACKTYPE_LOOP, *pData);
628
+						this->stack[this->stackPos++] = StackValue(StackType::Loop, *pData);
621 629
 					}
622 630
 					break;
623 631
 
624
-				case SSEQ_CMD_LOOPEND:
625
-					if (this->stackPos && this->stack[this->stackPos - 1].type == STACKTYPE_LOOP)
632
+				case SSEQCommand::LoopEnd:
633
+					if (this->stackPos && this->stack[this->stackPos - 1].type == StackType::Loop)
626 634
 					{
627
-						const uint8_t *rPos = this->stack[this->stackPos - 1].dest;
628
-						uint8_t &nR = this->loopCount[this->stackPos - 1];
629
-						uint8_t prevR = nR;
635
+						const std::uint8_t *rPos = this->stack[this->stackPos - 1].dest;
636
+						std::uint8_t &nR = this->loopCount[this->stackPos - 1];
637
+						std::uint8_t prevR = nR;
630 638
 						if (!prevR || --nR)
631 639
 							*pData = rPos;
632 640
 						else
... ...
@@ -638,37 +646,37 @@ void Track::Run()
638 646
 				// Tuning commands
639 647
 				//-----------------------------------------------------------------
640 648
 
641
-				case SSEQ_CMD_TRANSPOSE:
649
+				case SSEQCommand::Transpose:
642 650
 					this->transpose = this->overriding.val(pData, read8);
643 651
 					break;
644 652
 
645
-				case SSEQ_CMD_PITCHBEND:
653
+				case SSEQCommand::PitchBend:
646 654
 					this->pitchBend = this->overriding.val(pData, read8);
647
-					this->updateFlags.set(TUF_TIMER);
655
+					this->updateFlags.set(ToIntegral(TrackUpdateFlag::Timer));
648 656
 					break;
649 657
 
650
-				case SSEQ_CMD_PITCHBENDRANGE:
658
+				case SSEQCommand::PitchBendRange:
651 659
 					this->pitchBendRange = read8(pData);
652
-					this->updateFlags.set(TUF_TIMER);
660
+					this->updateFlags.set(ToIntegral(TrackUpdateFlag::Timer));
653 661
 					break;
654 662
 
655 663
 				//-----------------------------------------------------------------
656 664
 				// Envelope-related commands
657 665
 				//-----------------------------------------------------------------
658 666
 
659
-				case SSEQ_CMD_ATTACK:
667
+				case SSEQCommand::Attack:
660 668
 					this->a = this->overriding.val(pData, read8);
661 669
 					break;
662 670
 
663
-				case SSEQ_CMD_DECAY:
671
+				case SSEQCommand::Decay:
664 672
 					this->d = this->overriding.val(pData, read8);
665 673
 					break;
666 674
 
667
-				case SSEQ_CMD_SUSTAIN:
675
+				case SSEQCommand::Sustain:
668 676
 					this->s = this->overriding.val(pData, read8);
669 677
 					break;
670 678
 
671
-				case SSEQ_CMD_RELEASE:
679
+				case SSEQCommand::Release:
672 680
 					this->r = this->overriding.val(pData, read8);
673 681
 					break;
674 682
 
... ...
@@ -676,26 +684,26 @@ void Track::Run()
676 684
 				// Portamento-related commands
677 685
 				//-----------------------------------------------------------------
678 686
 
679
-				case SSEQ_CMD_PORTAKEY:
687
+				case SSEQCommand::PortamentoKey:
680 688
 					this->portaKey = read8(pData) + this->transpose;
681
-					this->state.set(TS_PORTABIT);
689
+					this->state.set(ToIntegral(TrackState::PortamentoBit));
682 690
 					// Update here?
683 691
 					break;
684 692
 
685
-				case SSEQ_CMD_PORTAFLAG:
686
-					this->state.set(TS_PORTABIT, !!read8(pData));
693
+				case SSEQCommand::PortamentoFlag:
694
+					this->state.set(ToIntegral(TrackState::PortamentoBit), !!read8(pData));
687 695
 					// Update here?
688 696
 					break;
689 697
 
690
-				case SSEQ_CMD_PORTATIME:
698
+				case SSEQCommand::PortamentoTime:
691 699
 					this->portaTime = this->overriding.val(pData, read8);
692
-					this->state.set(TS_PORTABIT);
700
+					this->state.set(ToIntegral(TrackState::PortamentoBit));
693 701
 					// Update here?
694 702
 					break;
695 703
 
696
-				case SSEQ_CMD_SWEEPPITCH:
704
+				case SSEQCommand::SweepPitch:
697 705
 					this->sweepPitch = this->overriding.val(pData, read16);
698
-					this->state.set(TS_PORTABIT);
706
+					this->state.set(ToIntegral(TrackState::PortamentoBit));
699 707
 					// Update here?
700 708
 					break;
701 709
 
... ...
@@ -703,43 +711,43 @@ void Track::Run()
703 711
 				// Modulation-related commands
704 712
 				//-----------------------------------------------------------------
705 713
 
706
-				case SSEQ_CMD_MODDEPTH:
714
+				case SSEQCommand::ModulationDepth:
707 715
 					this->modDepth = this->overriding.val(pData, read8);
708
-					this->updateFlags.set(TUF_MOD);
716
+					this->updateFlags.set(ToIntegral(TrackUpdateFlag::Modulation));
709 717
 					break;
710 718
 
711
-				case SSEQ_CMD_MODSPEED:
719
+				case SSEQCommand::ModulationSpeed:
712 720
 					this->modSpeed = this->overriding.val(pData, read8);
713
-					this->updateFlags.set(TUF_MOD);
721
+					this->updateFlags.set(ToIntegral(TrackUpdateFlag::Modulation));
714 722
 					break;
715 723
 
716
-				case SSEQ_CMD_MODTYPE:
724
+				case SSEQCommand::ModulationType:
717 725
 					this->modType = read8(pData);
718
-					this->updateFlags.set(TUF_MOD);
726
+					this->updateFlags.set(ToIntegral(TrackUpdateFlag::Modulation));
719 727
 					break;
720 728
 
721
-				case SSEQ_CMD_MODRANGE:
729
+				case SSEQCommand::ModulationRange:
722 730
 					this->modRange = read8(pData);
723
-					this->updateFlags.set(TUF_MOD);
731
+					this->updateFlags.set(ToIntegral(TrackUpdateFlag::Modulation));
724 732
 					break;
725 733
 
726
-				case SSEQ_CMD_MODDELAY:
734
+				case SSEQCommand::ModulationDelay:
727 735
 					this->modDelay = this->overriding.val(pData, read16);
728
-					this->updateFlags.set(TUF_MOD);
736
+					this->updateFlags.set(ToIntegral(TrackUpdateFlag::Modulation));
729 737
 					break;
730 738
 
731 739
 				//-----------------------------------------------------------------
732 740
 				// Randomness-related commands
733 741
 				//-----------------------------------------------------------------
734 742
 
735
-				case SSEQ_CMD_RANDOM:
743
+				case SSEQCommand::Random:
736 744
 				{
737 745
 					this->overriding() = true;
738 746
 					this->overriding.cmd = read8(pData);
739
-					if ((this->overriding.cmd >= SSEQ_CMD_SETVAR && this->overriding.cmd <= SSEQ_CMD_CMP_NE) || this->overriding.cmd < 0x80)
747
+					if ((this->overriding.cmd >= ToIntegral(SSEQCommand::SetVariable) && this->overriding.cmd <= ToIntegral(SSEQCommand::CompareNotEqualTo)) || this->overriding.cmd < 0x80)
740 748
 						this->overriding.extraValue = read8(pData);
741
-					int16_t minVal = read16(pData);
742
-					int16_t maxVal = read16(pData);
749
+					std::int16_t minVal = read16(pData);
750
+					std::int16_t maxVal = read16(pData);
743 751
 					this->overriding.value = (CalcRandom() % (maxVal - minVal + 1)) + minVal;
744 752
 					break;
745 753
 				}
... ...
@@ -748,25 +756,25 @@ void Track::Run()
748 756
 				// Variable-related commands
749 757
 				//-----------------------------------------------------------------
750 758
 
751
-				case SSEQ_CMD_FROMVAR:
759
+				case SSEQCommand::FromVariable:
752 760
 					this->overriding() = true;
753 761
 					this->overriding.cmd = read8(pData);
754
-					if ((this->overriding.cmd >= SSEQ_CMD_SETVAR && this->overriding.cmd <= SSEQ_CMD_CMP_NE) || this->overriding.cmd < 0x80)
762
+					if ((this->overriding.cmd >= ToIntegral(SSEQCommand::SetVariable) && this->overriding.cmd <= ToIntegral(SSEQCommand::CompareNotEqualTo)) || this->overriding.cmd < 0x80)
755 763
 						this->overriding.extraValue = read8(pData);
756 764
 					this->overriding.value = this->ply->variables[read8(pData)];
757 765
 					break;
758 766
 
759
-				case SSEQ_CMD_SETVAR:
760
-				case SSEQ_CMD_ADDVAR:
761
-				case SSEQ_CMD_SUBVAR:
762
-				case SSEQ_CMD_MULVAR:
763
-				case SSEQ_CMD_DIVVAR:
764
-				case SSEQ_CMD_SHIFTVAR:
765
-				case SSEQ_CMD_RANDVAR:
767
+				case SSEQCommand::SetVariable:
768
+				case SSEQCommand::AddVariable:
769
+				case SSEQCommand::SubtractVariable:
770
+				case SSEQCommand::MultiplyVariable:
771
+				case SSEQCommand::DivideVariable:
772
+				case SSEQCommand::ShiftVariable:
773
+				case SSEQCommand::RandomVariable:
766 774
 				{
767
-					int8_t varNo = this->overriding.val(pData, read8, true);
775
+					std::int8_t varNo = this->overriding.val(pData, read8, true);
768 776
 					value = this->overriding.val(pData, read16);
769
-					if (cmd == SSEQ_CMD_DIVVAR && !value) // Division by 0, skip it to prevent crashing
777
+					if (cmd == ToIntegral(SSEQCommand::DivideVariable) && !value) // Division by 0, skip it to prevent crashing
770 778
 						break;
771 779
 					this->ply->variables[varNo] = VarFunc(cmd)(this->ply->variables[varNo], value);
772 780
 					break;
... ...
@@ -776,31 +784,31 @@ void Track::Run()
776 784
 				// Conditional-related commands
777 785
 				//-----------------------------------------------------------------
778 786
 
779
-				case SSEQ_CMD_CMP_EQ:
780
-				case SSEQ_CMD_CMP_GE:
781
-				case SSEQ_CMD_CMP_GT:
782
-				case SSEQ_CMD_CMP_LE:
783
-				case SSEQ_CMD_CMP_LT:
784
-				case SSEQ_CMD_CMP_NE:
787
+				case SSEQCommand::CompareEqualTo:
788
+				case SSEQCommand::CompareGreaterThanOrEqualTo:
789
+				case SSEQCommand::CompareGreaterThan:
790
+				case SSEQCommand::CompareLessThanOrEqualTo:
791
+				case SSEQCommand::CompareLessThan:
792
+				case SSEQCommand::CompareNotEqualTo:
785 793
 				{
786
-					int8_t varNo = this->overriding.val(pData, read8, true);
794
+					std::int8_t varNo = this->overriding.val(pData, read8, true);
787 795
 					value = this->overriding.val(pData, read16);
788 796
 					this->lastComparisonResult = CompareFunc(cmd)(this->ply->variables[varNo], value);
789 797
 					break;
790 798
 				}
791 799
 
792
-				case SSEQ_CMD_IF:
800
+				case SSEQCommand::If:
793 801
 					if (!this->lastComparisonResult)
794 802
 					{
795 803
 						int nextCmd = read8(pData);
796
-						uint8_t cmdBytes = SseqCommandByteCount(nextCmd);
804
+						std::uint8_t cmdBytes = SseqCommandByteCount(nextCmd);
797 805
 						bool variableBytes = !!(cmdBytes & VariableByteCount);
798 806
 						bool extraByte = !!(cmdBytes & ExtraByteOnNoteOrVarOrCmp);
799 807
 						cmdBytes &= ~(VariableByteCount | ExtraByteOnNoteOrVarOrCmp);
800 808
 						if (extraByte)
801 809
 						{
802 810
 							int extraCmd = read8(pData);
803
-							if ((extraCmd >= SSEQ_CMD_SETVAR && extraCmd <= SSEQ_CMD_CMP_NE) || extraCmd < 0x80)
811
+							if ((extraCmd >= ToIntegral(SSEQCommand::SetVariable) && extraCmd <= ToIntegral(SSEQCommand::CompareNotEqualTo)) || extraCmd < 0x80)
804 812
 								++cmdBytes;
805 813
 						}
806 814
 						*pData += cmdBytes;
... ...
@@ -814,7 +822,7 @@ void Track::Run()
814 822
 			}
815 823
 		}
816 824
 
817
-		if (cmd != SSEQ_CMD_RANDOM && cmd != SSEQ_CMD_FROMVAR)
825
+		if (cmd != ToIntegral(SSEQCommand::Random) && cmd != ToIntegral(SSEQCommand::FromVariable))
818 826
 			this->overriding() = false;
819 827
 	}
820 828
 }
Browse code

Replace std::rand with RNG based on actual DS RNG.

(This also means the playback of songs with randomness in them will be deterministic now.)

Naram Qashat authored on 2021/03/20 18:46:24
Showing 1 changed files
... ...
@@ -402,6 +402,14 @@ static inline uint8_t SseqCommandByteCount(int cmd)
402 402
 		}
403 403
 }
404 404
 
405
+static std::uint32_t RandomU{ 0x12345678 };
406
+
407
+static std::uint16_t CalcRandom()
408
+{
409
+	RandomU = RandomU * 1664525 + 1013904223;
410
+	return static_cast<std::uint16_t>(RandomU >> 16);
411
+}
412
+
405 413
 static auto varFuncSet = [](int16_t, int16_t value) { return value; };
406 414
 static auto varFuncAdd = [](int16_t var, int16_t value) -> int16_t { return var + value; };
407 415
 static auto varFuncSub = [](int16_t var, int16_t value) -> int16_t { return var - value; };
... ...
@@ -417,9 +425,9 @@ static auto varFuncShift = [](int16_t var, int16_t value) -> int16_t
417 425
 static auto varFuncRand = [](int16_t, int16_t value) -> int16_t
418 426
 {
419 427
 	if (value < 0)
420
-		return -(std::rand() % (-value + 1));
428
+		return -(CalcRandom() % (-value + 1));
421 429
 	else
422
-		return std::rand() % (value + 1);
430
+		return CalcRandom() % (value + 1);
423 431
 };
424 432
 
425 433
 static inline std::function<int16_t (int16_t, int16_t)> VarFunc(int cmd)
... ...
@@ -732,7 +740,7 @@ void Track::Run()
732 740
 						this->overriding.extraValue = read8(pData);
733 741
 					int16_t minVal = read16(pData);
734 742
 					int16_t maxVal = read16(pData);
735
-					this->overriding.value = (std::rand() % (maxVal - minVal + 1)) + minVal;
743
+					this->overriding.value = (CalcRandom() % (maxVal - minVal + 1)) + minVal;
736 744
 					break;
737 745
 				}
738 746
 
Browse code

Replace memcpy/memset with std::copy_n/std::fill_n.

Naram Qashat authored on 2021/03/19 16:25:21
Showing 1 changed files
... ...
@@ -38,7 +38,7 @@ void Track::Zero()
38 38
 	this->startPos = this->pos = nullptr;
39 39
 	std::fill_n(&this->stack[0], FSS_TRACKSTACKSIZE, StackValue());
40 40
 	this->stackPos = 0;
41
-	memset(this->loopCount, 0, sizeof(this->loopCount));
41
+	std::fill_n(&this->loopCount[0], FSS_TRACKSTACKSIZE, 0);
42 42
 	this->overriding() = false;
43 43
 	this->lastComparisonResult = true;
44 44
 
Browse code

Remove last modification date from files.

(I never remember to update these and besides, GitHub history can show when they were last modified.)

Naram Qashat authored on 2021/03/19 10:58:12
Showing 1 changed files
... ...
@@ -1,7 +1,6 @@
1 1
 /*
2 2
  * SSEQ Player - Track structure
3 3
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
4
- * Last modification on 2014-10-23
5 4
  *
6 5
  * Adapted from source code of FeOS Sound System
7 6
  * By fincs
Browse code

[NCSF] Enable portamento when setting those registers.

(Thanks to Coda Highland for the fix.)

Naram Qashat authored on 2020/08/07 23:22:39
Showing 1 changed files
... ...
@@ -682,11 +682,13 @@ void Track::Run()
682 682
 
683 683
 				case SSEQ_CMD_PORTATIME:
684 684
 					this->portaTime = this->overriding.val(pData, read8);
685
+					this->state.set(TS_PORTABIT);
685 686
 					// Update here?
686 687
 					break;
687 688
 
688 689
 				case SSEQ_CMD_SWEEPPITCH:
689 690
 					this->sweepPitch = this->overriding.val(pData, read16);
691
+					this->state.set(TS_PORTABIT);
690 692
 					// Update here?
691 693
 					break;
692 694
 
Browse code

[NCSF] Fix PSG output.

* Changed the base timer and actually utilize the note number from the note definition even for PSG. Thanks to Kurausukun for informing me about the issue and helping to provide a sample to demonstrate the issue.
* Correct the frequency output in the debug sound view (using DeSmuME's method directly resulted in frequencies that were 3 octaves higher than what they should have been).

Naram Qashat authored on 2020/07/31 10:00:12
Showing 1 changed files
... ...
@@ -165,8 +165,7 @@ int Track::NoteOn(int key, int vel, int len)
165 165
 			chn = &this->ply->channels[nCh];
166 166
 			chn->tempReg.CR = SOUND_FORMAT_PSG | SCHANNEL_ENABLE | SOUND_DUTY(noteDef->swav & 0x7);
167 167
 		}
168
-		// TODO: figure out what pNoteDef->tnote means for PSG channels
169
-		chn->tempReg.TIMER = -SOUND_FREQ(440 * 8); // key #69 (A4)
168
+		chn->tempReg.TIMER = -SOUND_FREQ(262 * 8); // key #60 (C4)
170 169
 		chn->reg.samplePosition = -1;
171 170
 		chn->reg.psgX = 0x7FFF;
172 171
 	}
... ...
@@ -192,7 +191,7 @@ int Track::NoteOn(int key, int vel, int len)
192 191
 	chn->flags.reset();
193 192
 	chn->prio = this->prio;
194 193
 	chn->key = key;
195
-	chn->orgKey = bIsPCM ? noteDef->noteNumber : 69;
194
+	chn->orgKey = noteDef->noteNumber;
196 195
 	chn->velocity = Cnv_Sust(vel);
197 196
 	chn->pan = static_cast<int>(noteDef->pan) - 64;
198 197
 	chn->modDelayCnt = 0;
Browse code

[NCSF] Bump version number for the previous fixes.

Naram Qashat authored on 2014/10/23 23:27:37
Showing 1 changed files
... ...
@@ -1,7 +1,7 @@
1 1
 /*
2 2
  * SSEQ Player - Track structure
3 3
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
4
- * Last modification on 2014-10-15
4
+ * Last modification on 2014-10-23
5 5
  *
6 6
  * Adapted from source code of FeOS Sound System
7 7
  * By fincs
Browse code

[NCSF] Documented what FSS functions were originally used.

* Changed default of modDelay to 0.
* Also minor cleanup.

Naram Qashat authored on 2014/10/23 23:19:16
Showing 1 changed files
... ...
@@ -18,6 +18,7 @@ Track::Track()
18 18
 	this->Zero();
19 19
 }
20 20
 
21
+// Original FSS Function: Player_InitTrack
21 22
 void Track::Init(uint8_t handle, Player *player, const uint8_t *dataPos, int n)
22 23
 {
23 24
 	this->trackId = handle;
... ...
@@ -59,6 +60,7 @@ void Track::Zero()
59 60
 	this->updateFlags.reset();
60 61
 }
61 62
 
63
+// Original FSS Function: Track_ClearState
62 64
 void Track::ClearState()
63 65
 {
64 66
 	this->state.reset();
... ...
@@ -84,16 +86,18 @@ void Track::ClearState()
84 86
 	this->modType = 0;
85 87
 	this->modRange = 1;
86 88
 	this->modSpeed = 16;
87
-	this->modDelay = 10;
89
+	this->modDelay = 0;
88 90
 	this->modDepth = 0;
89 91
 }
90 92
 
93
+// Original FSS Function: Track_Free
91 94
 void Track::Free()
92 95
 {
93 96
 	this->state.reset();
94 97
 	this->updateFlags.reset();
95 98
 }
96 99
 
100
+// Original FSS Function: Note_On
97 101
 int Track::NoteOn(int key, int vel, int len)
98 102
 {
99 103
 	auto sbnk = this->ply->sseq->bank;
... ...
@@ -212,6 +216,7 @@ int Track::NoteOn(int key, int vel, int len)
212 216
 	return nCh;
213 217
 }
214 218
 
219
+// Original FSS Function: Note_On_Tie
215 220
 int Track::NoteOnTie(int key, int vel)
216 221
 {
217 222
 	// Find an existing note
... ...
@@ -247,6 +252,7 @@ int Track::NoteOnTie(int key, int vel)
247 252
 	return i;
248 253
 }
249 254
 
255
+// Original FSS Function: Track_ReleaseAllNotes
250 256
 void Track::ReleaseAllNotes()
251 257
 {
252 258
 	for (int i = 0; i < 16; ++i)
... ...
@@ -469,6 +475,7 @@ static inline std::function<bool (int16_t, int16_t)> CompareFunc(int cmd)
469 475
 	}
470 476
 }
471 477
 
478
+// Original FSS Function: Track_Run
472 479
 void Track::Run()
473 480
 {
474 481
 	// Indicate "heartbeat" for this track
Browse code

[NCSF] Reversed the order of the PSG and Noise channel allocations.

This was suggested by fincs as the proper way to fix channels being
cutoff incorrectly.
(Also moved volume assignment so it was less duplicated.)

Naram Qashat authored on 2014/10/23 23:05:57
Showing 1 changed files
... ...
@@ -194,7 +194,6 @@ int Track::NoteOn(int key, int vel, int len)
194 194
 	chn->modDelayCnt = 0;
195 195
 	chn->modCounter = 0;
196 196
 	chn->noteLength = len;
197
-	chn->vol = 0x7FF;
198 197
 	chn->reg.sampleIncrease = 0;
199 198
 
200 199
 	chn->attackLvl = Cnv_Attack(this->a == 0xFF ? noteDef->attackRate : this->a);
Browse code

[NCSF] Partial fix to channels being unintentionally cut off.

Naram Qashat authored on 2014/10/22 19:44:45
Showing 1 changed files
... ...
@@ -194,6 +194,7 @@ int Track::NoteOn(int key, int vel, int len)
194 194
 	chn->modDelayCnt = 0;
195 195
 	chn->modCounter = 0;
196 196
 	chn->noteLength = len;
197
+	chn->vol = 0x7FF;
197 198
 	chn->reg.sampleIncrease = 0;
198 199
 
199 200
 	chn->attackLvl = Cnv_Attack(this->a == 0xFF ? noteDef->attackRate : this->a);
Browse code

[NCSF] One more volume fix, the default volume is 127, not 64.

Naram Qashat authored on 2014/10/18 04:32:32
Showing 1 changed files
... ...
@@ -74,8 +74,7 @@ void Track::ClearState()
74 74
 	this->portaKey = 60;
75 75
 	this->portaTime = 0;
76 76
 	this->sweepPitch = 0;
77
-	this->vol = 64;
78
-	this->expr = 127;
77
+	this->vol = this->expr = 127;
79 78
 	this->pan = 0;
80 79
 	this->pitchBendRange = 2;
81 80
 	this->pitchBend = this->transpose = 0;
Browse code

[NCSF] REALLY remove minor instance of variable shadowing.

Naram Qashat authored on 2014/10/16 01:43:49
Showing 1 changed files
... ...
@@ -520,11 +520,11 @@ void Track::Run()
520 520
 				case SSEQ_CMD_OPENTRACK:
521 521
 				{
522 522
 					int tNum = read8(pData);
523
-					auto startPos = &this->ply->sseq->data[read24(pData)];
523
+					auto trackPos = &this->ply->sseq->data[read24(pData)];
524 524
 					int newTrack = this->ply->TrackAlloc();
525 525
 					if (newTrack != -1)
526 526
 					{
527
-						this->ply->tracks[newTrack].Init(newTrack, this->ply, startPos, tNum);
527
+						this->ply->tracks[newTrack].Init(newTrack, this->ply, trackPos, tNum);
528 528
 						this->ply->trackIds[this->ply->nTracks++] = newTrack;
529 529
 					}
530 530
 					break;
Browse code

[NCSF] Remove minor instance of variable shadowing.

Naram Qashat authored on 2014/10/15 20:28:01
Showing 1 changed files
... ...
@@ -520,11 +520,11 @@ void Track::Run()
520 520
 				case SSEQ_CMD_OPENTRACK:
521 521
 				{
522 522
 					int tNum = read8(pData);
523
-					auto pos = &this->ply->sseq->data[read24(pData)];
523
+					auto startPos = &this->ply->sseq->data[read24(pData)];
524 524
 					int newTrack = this->ply->TrackAlloc();
525 525
 					if (newTrack != -1)
526 526
 					{
527
-						this->ply->tracks[newTrack].Init(newTrack, this->ply, pos, tNum);
527
+						this->ply->tracks[newTrack].Init(newTrack, this->ply, startPos, tNum);
528 528
 						this->ply->trackIds[this->ply->nTracks++] = newTrack;
529 529
 					}
530 530
 					break;
Browse code

[NCSF] Move track allocation into the SSEQ command handler.

This was suggested by fincs after I found some sequences that appeared
to do track allocations later in them than expected originally.

Naram Qashat authored on 2014/10/15 18:03:10
Showing 1 changed files
... ...
@@ -1,7 +1,7 @@
1 1
 /*
2 2
  * SSEQ Player - Track structure
3 3
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
4
- * Last modification on 2014-10-13
4
+ * Last modification on 2014-10-15
5 5
  *
6 6
  * Adapted from source code of FeOS Sound System
7 7
  * By fincs
... ...
@@ -260,6 +260,9 @@ void Track::ReleaseAllNotes()
260 260
 
261 261
 enum SseqCommand
262 262
 {
263
+	SSEQ_CMD_ALLOCTRACK = 0xFE, // Silently ignored
264
+	SSEQ_CMD_OPENTRACK = 0x93,
265
+
263 266
 	SSEQ_CMD_REST = 0x80,
264 267
 	SSEQ_CMD_PATCH = 0x81,
265 268
 	SSEQ_CMD_PAN = 0xC0,
... ...
@@ -359,6 +362,7 @@ static inline uint8_t SseqCommandByteCount(int cmd)
359 362
 			case SSEQ_CMD_MUTE:
360 363
 				return 1;
361 364
 
365
+			case SSEQ_CMD_ALLOCTRACK:
362 366
 			case SSEQ_CMD_TEMPO:
363 367
 			case SSEQ_CMD_SWEEPPITCH:
364 368
 			case SSEQ_CMD_MODDELAY:
... ...
@@ -381,6 +385,9 @@ static inline uint8_t SseqCommandByteCount(int cmd)
381 385
 			case SSEQ_CMD_CMP_NE:
382 386
 				return 3;
383 387
 
388
+			case SSEQ_CMD_OPENTRACK:
389
+				return 4;
390
+
384 391
 			case SSEQ_CMD_FROMVAR:
385 392
 				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
386 393
 
... ...
@@ -510,6 +517,19 @@ void Track::Run()
510 517
 				// Main commands
511 518
 				//-----------------------------------------------------------------
512 519
 
520
+				case SSEQ_CMD_OPENTRACK:
521
+				{
522
+					int tNum = read8(pData);
523
+					auto pos = &this->ply->sseq->data[read24(pData)];
524
+					int newTrack = this->ply->TrackAlloc();
525
+					if (newTrack != -1)
526
+					{
527
+						this->ply->tracks[newTrack].Init(newTrack, this->ply, pos, tNum);
528
+						this->ply->trackIds[this->ply->nTracks++] = newTrack;
529
+					}
530
+					break;
531
+				}
532
+
513 533
 				case SSEQ_CMD_REST:
514 534
 					this->wait = this->overriding.val(pData, readvl);
515 535
 					break;
... ...
@@ -595,15 +615,10 @@ void Track::Run()
595 615
 						const uint8_t *rPos = this->stack[this->stackPos - 1].dest;
596 616
 						uint8_t &nR = this->loopCount[this->stackPos - 1];
597 617
 						uint8_t prevR = nR;
598
-						if (!prevR)
618
+						if (!prevR || --nR)
599 619
 							*pData = rPos;
600 620
 						else
601
-						{
602
-							if (--nR)
603
-								*pData = rPos;
604
-							else
605
-								--this->stackPos;
606
-						}
621
+							--this->stackPos;
607 622
 					}
608 623
 					break;
609 624
 
Browse code

[NCSF] Minor code changes to reduce code duplication.

* Made a function in the Override struct to centralize where it
determines whether to use the override value or not.
* Made a function that returns the number of bytes that a command needs,
and used that to remove all the conditionals for processing a command to
instead handle that within the IF command itself.
Thanks to fincs and Henke37 for the suggestions to do this.

Naram Qashat authored on 2014/10/13 21:21:03
Showing 1 changed files
... ...
@@ -8,7 +8,6 @@
8 8
  * https://github.com/fincs/FSS
9 9
  */
10 10
 
11
-#include <functional>
12 11
 #include <cstdlib>
13 12
 #include "Track.h"
14 13
 #include "Player.h"
... ...
@@ -41,7 +40,7 @@ void Track::Zero()
41 40
 	this->stackPos = 0;
42 41
 	memset(this->loopCount, 0, sizeof(this->loopCount));
43 42
 	this->overriding() = false;
44
-	this->lastComparisonResult = this->processCommand = true;
43
+	this->lastComparisonResult = true;
45 44
 
46 45
 	this->wait = 0;
47 46
 	this->patch = 0;
... ...
@@ -320,6 +319,79 @@ enum SseqCommand
320 319
 	SSEQ_CMD_MUTE = 0xD7 // Unsupported
321 320
 };
322 321
 
322
+static const uint8_t VariableByteCount = 1 << 7;
323
+static const uint8_t ExtraByteOnNoteOrVarOrCmp = 1 << 6;
324
+
325
+static inline uint8_t SseqCommandByteCount(int cmd)
326
+{
327
+	if (cmd < 0x80)
328
+		return 1 | VariableByteCount;
329
+	else
330
+		switch (cmd)
331
+		{
332
+			case SSEQ_CMD_REST:
333
+			case SSEQ_CMD_PATCH:
334
+				return VariableByteCount;
335
+
336
+			case SSEQ_CMD_PAN:
337
+			case SSEQ_CMD_VOL:
338
+			case SSEQ_CMD_MASTERVOL:
339
+			case SSEQ_CMD_PRIO:
340
+			case SSEQ_CMD_NOTEWAIT:
341
+			case SSEQ_CMD_TIE:
342
+			case SSEQ_CMD_EXPR:
343
+			case SSEQ_CMD_LOOPSTART:
344
+			case SSEQ_CMD_TRANSPOSE:
345
+			case SSEQ_CMD_PITCHBEND:
346
+			case SSEQ_CMD_PITCHBENDRANGE:
347
+			case SSEQ_CMD_ATTACK:
348
+			case SSEQ_CMD_DECAY:
349
+			case SSEQ_CMD_SUSTAIN:
350
+			case SSEQ_CMD_RELEASE:
351
+			case SSEQ_CMD_PORTAKEY:
352
+			case SSEQ_CMD_PORTAFLAG:
353
+			case SSEQ_CMD_PORTATIME:
354
+			case SSEQ_CMD_MODDEPTH:
355
+			case SSEQ_CMD_MODSPEED:
356
+			case SSEQ_CMD_MODTYPE:
357
+			case SSEQ_CMD_MODRANGE:
358
+			case SSEQ_CMD_PRINTVAR:
359
+			case SSEQ_CMD_MUTE:
360
+				return 1;
361
+
362
+			case SSEQ_CMD_TEMPO:
363
+			case SSEQ_CMD_SWEEPPITCH:
364
+			case SSEQ_CMD_MODDELAY:
365
+				return 2;
366
+
367
+			case SSEQ_CMD_GOTO:
368
+			case SSEQ_CMD_CALL:
369
+			case SSEQ_CMD_SETVAR:
370
+			case SSEQ_CMD_ADDVAR:
371
+			case SSEQ_CMD_SUBVAR:
372
+			case SSEQ_CMD_MULVAR:
373
+			case SSEQ_CMD_DIVVAR:
374
+			case SSEQ_CMD_SHIFTVAR:
375
+			case SSEQ_CMD_RANDVAR:
376
+			case SSEQ_CMD_CMP_EQ:
377
+			case SSEQ_CMD_CMP_GE:
378
+			case SSEQ_CMD_CMP_GT:
379
+			case SSEQ_CMD_CMP_LE:
380
+			case SSEQ_CMD_CMP_LT:
381
+			case SSEQ_CMD_CMP_NE:
382
+				return 3;
383
+
384
+			case SSEQ_CMD_FROMVAR:
385
+				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
386
+
387
+			case SSEQ_CMD_RANDOM:
388
+				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
389
+
390
+			default:
391
+				return 0;
392
+		}
393
+}
394
+
323 395
 static auto varFuncSet = [](int16_t, int16_t value) { return value; };
324 396
 static auto varFuncAdd = [](int16_t var, int16_t value) -> int16_t { return var + value; };
325 397
 static auto varFuncSub = [](int16_t var, int16_t value) -> int16_t { return var - value; };
... ...
@@ -420,27 +492,14 @@ void Track::Run()
420 492
 		{
421 493
 			// Note on
422 494
 			int key = cmd + this->transpose;
423
-			int vel;
424
-			int len;
425
-			if (this->overriding())
426
-			{
427
-				vel = this->overriding.extraValue;
428
-				len = this->overriding.value;
429
-			}
495
+			int vel = this->overriding.val(pData, read8, true);
496
+			int len = this->overriding.val(pData, readvl);
497
+			if (this->state[TS_NOTEWAIT])
498
+				this->wait = len;
499
+			if (this->state[TS_TIEBIT])
500
+				this->NoteOnTie(key, vel);
430 501
 			else
431
-			{
432
-				vel = read8(pData);
433
-				len = readvl(pData);
434
-			}
435
-			if (this->processCommand)
436
-			{
437
-				if (this->state[TS_NOTEWAIT])
438
-					this->wait = len;
439
-				if (this->state[TS_TIEBIT])
440
-					this->NoteOnTie(key, vel);
441
-				else
442
-					this->NoteOn(key, vel, len);
443
-			}
502
+				this->NoteOn(key, vel, len);
444 503
 		}
445 504
 		else
446 505
 		{
... ...
@@ -452,32 +511,20 @@ void Track::Run()
452 511
 				//-----------------------------------------------------------------
453 512
 
454 513
 				case SSEQ_CMD_REST:
455
-					if (this->overriding())
456
-						value = this->overriding.value;
457
-					else
458
-						value = readvl(pData);
459
-					if (this->processCommand)
460
-						this->wait = value;
514
+					this->wait = this->overriding.val(pData, readvl);
461 515
 					break;
462 516
 
463 517
 				case SSEQ_CMD_PATCH:
464
-					if (this->overriding())
465
-						value = this->overriding.value;
466
-					else
467
-						value = readvl(pData);
468
-					if (this->processCommand)
469
-						this->patch = value;
518
+					this->patch = this->overriding.val(pData, readvl);
470 519
 					break;
471 520
 
472 521
 				case SSEQ_CMD_GOTO:
473
-					value = read24(pData);
474
-					if (this->processCommand)
475
-						*pData = &this->ply->sseq->data[value];
522
+					*pData = &this->ply->sseq->data[read24(pData)];
476 523
 					break;
477 524
 
478 525
 				case SSEQ_CMD_CALL:
479 526
 					value = read24(pData);
480
-					if (this->processCommand && this->stackPos < FSS_TRACKSTACKSIZE)
527
+					if (this->stackPos < FSS_TRACKSTACKSIZE)
481 528
 					{
482 529
 						const uint8_t *dest = &this->ply->sseq->data[value];
483 530
 						this->stack[this->stackPos++] = StackValue(STACKTYPE_CALL, *pData);
... ...
@@ -486,101 +533,56 @@ void Track::Run()
486 533
 					break;
487 534
 
488 535
 				case SSEQ_CMD_RET:
489
-					if (this->processCommand && this->stackPos && this->stack[this->stackPos - 1].type == STACKTYPE_CALL)
536
+					if (this->stackPos && this->stack[this->stackPos - 1].type == STACKTYPE_CALL)
490 537
 						*pData = this->stack[--this->stackPos].dest;
491 538
 					break;
492 539
 
493 540
 				case SSEQ_CMD_PAN:
494
-					if (this->overriding())
495
-						value = this->overriding.value;
496
-					else
497
-						value = read8(pData);
498
-					if (this->processCommand)
499
-					{
500
-						this->pan = value - 64;
501
-						this->updateFlags.set(TUF_PAN);
502
-					}
541
+					this->pan = this->overriding.val(pData, read8) - 64;
542
+					this->updateFlags.set(TUF_PAN);
503 543
 					break;
504 544
 
505 545
 				case SSEQ_CMD_VOL:
506
-					if (this->overriding())
507
-						value = this->overriding.value;
508
-					else
509
-						value = read8(pData);
510
-					if (this->processCommand)
511
-					{
512
-						this->vol = value;
513
-						this->updateFlags.set(TUF_VOL);
514
-					}
546
+					this->vol = this->overriding.val(pData, read8);
547
+					this->updateFlags.set(TUF_VOL);
515 548
 					break;
516 549
 
517 550
 				case SSEQ_CMD_MASTERVOL:
518
-					if (this->overriding())
519
-						value = this->overriding.value;
520
-					else
521
-						value = read8(pData);
522
-					if (this->processCommand)
523
-					{
524
-						this->ply->masterVol = Cnv_Sust(value);
525
-						for (uint8_t i = 0; i < this->ply->nTracks; ++i)
526
-							this->ply->tracks[this->ply->trackIds[i]].updateFlags.set(TUF_VOL);
527
-					}
551
+					this->ply->masterVol = Cnv_Sust(this->overriding.val(pData, read8));
552
+					for (uint8_t i = 0; i < this->ply->nTracks; ++i)
553
+						this->ply->tracks[this->ply->trackIds[i]].updateFlags.set(TUF_VOL);
528 554
 					break;
529 555
 
530 556
 				case SSEQ_CMD_PRIO:
531
-					value = read8(pData);
532
-					if (this->processCommand)
533
-						this->prio = this->ply->prio + value;
557
+					this->prio = this->ply->prio + read8(pData);
534 558
 					// Update here?
535 559
 					break;
536 560
 
537 561
 				case SSEQ_CMD_NOTEWAIT:
538
-					value = read8(pData);
539
-					if (this->processCommand)
540
-						this->state.set(TS_NOTEWAIT, !!value);
562
+					this->state.set(TS_NOTEWAIT, !!read8(pData));
541 563
 					break;
542 564
 
543 565
 				case SSEQ_CMD_TIE:
544
-					value = read8(pData);
545
-					if (this->processCommand)
546
-					{
547
-						this->state.set(TS_TIEBIT, !!value);
548
-						this->ReleaseAllNotes();
549
-					}
566
+					this->state.set(TS_TIEBIT, !!read8(pData));
567
+					this->ReleaseAllNotes();
550 568
 					break;
551 569
 
552 570
 				case SSEQ_CMD_EXPR:
553
-					if (this->overriding())
554
-						value = this->overriding.value;
555
-					else
556
-						value = read8(pData);
557
-					if (this->processCommand)
558
-					{
559
-						this->expr = value;
560
-						this->updateFlags.set(TUF_VOL);
561
-					}
571
+					this->expr = this->overriding.val(pData, read8);
572
+					this->updateFlags.set(TUF_VOL);
562 573
 					break;
563 574
 
564 575
 				case SSEQ_CMD_TEMPO:
565
-					value = read16(pData);
566
-					if (this->processCommand)
567
-						this->ply->tempo = value;
576
+					this->ply->tempo = read16(pData);
568 577
 					break;
569 578
 
570 579
 				case SSEQ_CMD_END:
571
-					if (this->processCommand)
572
-					{
573
-						this->state.set(TS_END);
574
-						return;
575
-					}
576
-					break;
580
+					this->state.set(TS_END);
581
+					return;
577 582
 
578 583
 				case SSEQ_CMD_LOOPSTART:
579
-					if (this->overriding())
580
-						value = this->overriding.value;
581
-					else
582
-						value = read8(pData);
583
-					if (this->processCommand && this->stackPos < FSS_TRACKSTACKSIZE)
584
+					value = this->overriding.val(pData, read8);
585
+					if (this->stackPos < FSS_TRACKSTACKSIZE)
584 586
 					{
585 587
 						this->loopCount[this->stackPos] = value;
586 588
 						this->stack[this->stackPos++] = StackValue(STACKTYPE_LOOP, *pData);
... ...
@@ -588,7 +590,7 @@ void Track::Run()
588 590
 					break;
589 591
 
590 592
 				case SSEQ_CMD_LOOPEND:
591
-					if (this->processCommand && this->stackPos && this->stack[this->stackPos - 1].type == STACKTYPE_LOOP)
593
+					if (this->stackPos && this->stack[this->stackPos - 1].type == STACKTYPE_LOOP)
592 594
 					{
593 595
 						const uint8_t *rPos = this->stack[this->stackPos - 1].dest;
594 596
 						uint8_t &nR = this->loopCount[this->stackPos - 1];
... ...
@@ -610,33 +612,17 @@ void Track::Run()
610 612
 				//-----------------------------------------------------------------
611 613
 
612 614
 				case SSEQ_CMD_TRANSPOSE:
613
-					if (this->overriding())
614
-						value = this->overriding.value;
615
-					else
616
-						value = read8(pData);
617
-					if (this->processCommand)
618
-						this->transpose = value;
615
+					this->transpose = this->overriding.val(pData, read8);
619 616
 					break;
620 617
 
621 618
 				case SSEQ_CMD_PITCHBEND:
622
-					if (this->overriding())
623
-						value = this->overriding.value;
624
-					else
625
-						value = read8(pData);
626
-					if (this->processCommand)
627
-					{
628
-						this->pitchBend = value;
629
-						this->updateFlags.set(TUF_TIMER);
630
-					}
619
+					this->pitchBend = this->overriding.val(pData, read8);
620
+					this->updateFlags.set(TUF_TIMER);
631 621
 					break;
632 622
 
633 623
 				case SSEQ_CMD_PITCHBENDRANGE:
634
-					value = read8(pData);
635
-					if (this->processCommand)
636
-					{
637
-						this->pitchBendRange = value;
638
-						this->updateFlags.set(TUF_TIMER);
639
-					}
624
+					this->pitchBendRange = read8(pData);
625
+					this->updateFlags.set(TUF_TIMER);
640 626
 					break;
641 627
 
642 628
 				//-----------------------------------------------------------------
... ...
@@ -644,39 +630,19 @@ void Track::Run()
644 630
 				//-----------------------------------------------------------------
645 631
 
646 632
 				case SSEQ_CMD_ATTACK:
647
-					if (this->overriding())
648
-						value = this->overriding.value;
649
-					else
650
-						value = read8(pData);
651
-					if (this->processCommand)
652
-						this->a = value;
633
+					this->a = this->overriding.val(pData, read8);
653 634
 					break;
654 635
 
655 636
 				case SSEQ_CMD_DECAY:
656
-					if (this->overriding())
657
-						value = this->overriding.value;
658
-					else
659
-						value = read8(pData);
660
-					if (this->processCommand)
661
-						this->d = value;
637
+					this->d = this->overriding.val(pData, read8);
662 638
 					break;
663 639
 
664 640
 				case SSEQ_CMD_SUSTAIN:
665
-					if (this->overriding())
666
-						value = this->overriding.value;
667
-					else
668
-						value = read8(pData);
669
-					if (this->processCommand)
670
-						this->s = value;
641
+					this->s = this->overriding.val(pData, read8);
671 642
 					break;
672 643
 
673 644
 				case SSEQ_CMD_RELEASE:
674
-					if (this->overriding())
675
-						value = this->overriding.value;
676
-					else
677
-						value = read8(pData);
678
-					if (this->processCommand)
679
-						this->r = value;
645
+					this->r = this->overriding.val(pData, read8);
680 646
 					break;
681 647
 
682 648
 				//-----------------------------------------------------------------
... ...
@@ -684,41 +650,23 @@ void Track::Run()
684 650
 				//-----------------------------------------------------------------
685 651
 
686 652
 				case SSEQ_CMD_PORTAKEY:
687
-					value = read8(pData);
688
-					if (this->processCommand)
689
-					{
690
-						this->portaKey = value + this->transpose;
691
-						this->state.set(TS_PORTABIT);
692
-						// Update here?
693
-					}
653
+					this->portaKey = read8(pData) + this->transpose;
654
+					this->state.set(TS_PORTABIT);
655
+					// Update here?
694 656
 					break;
695 657
 
696 658
 				case SSEQ_CMD_PORTAFLAG:
697
-					value = read8(pData);
698
-					if (this->processCommand)
699
-					{
700
-						this->state.set(TS_PORTABIT, !!value);
701
-						// Update here?
702
-					}
659
+					this->state.set(TS_PORTABIT, !!read8(pData));
660
+					// Update here?
703 661
 					break;
704 662
 
705 663
 				case SSEQ_CMD_PORTATIME:
706
-					if (this->overriding())
707
-						value = this->overriding.value;
708
-					else
709
-						value = read8(pData);
710
-					if (this->processCommand)
711
-						this->portaTime = value;
664
+					this->portaTime = this->overriding.val(pData, read8);
712 665
 					// Update here?
713 666
 					break;
714 667
 
715 668
 				case SSEQ_CMD_SWEEPPITCH:
716
-					if (this->overriding())
717
-						value = this->overriding.value;
718
-					else
719
-						value = read16(pData);
720
-					if (this->processCommand)
721
-						this->sweepPitch = value;
669
+					this->sweepPitch = this->overriding.val(pData, read16);
722 670
 					// Update here?
723 671
 					break;
724 672
 
... ...
@@ -727,57 +675,28 @@ void Track::Run()
727 675
 				//-----------------------------------------------------------------
728 676
 
729 677
 				case SSEQ_CMD_MODDEPTH:
730
-					if (this->overriding())
731
-						value = this->overriding.value;
732
-					else
733
-						value = read8(pData);
734
-					if (this->processCommand)
735
-					{
736
-						this->modDepth = value;
737
-						this->updateFlags.set(TUF_MOD);
738
-					}
678
+					this->modDepth = this->overriding.val(pData, read8);
679
+					this->updateFlags.set(TUF_MOD);
739 680
 					break;
740 681
 
741 682
 				case SSEQ_CMD_MODSPEED:
742
-					if (this->overriding())
743
-						value = this->overriding.value;
744
-					else
745
-						value = read8(pData);
746
-					if (this->processCommand)
747
-					{
748
-						this->modSpeed = value;
749
-						this->updateFlags.set(TUF_MOD);
750
-					}
683
+					this->modSpeed = this->overriding.val(pData, read8);
684
+					this->updateFlags.set(TUF_MOD);
751 685
 					break;
752 686
 
753 687
 				case SSEQ_CMD_MODTYPE:
754
-					value = read8(pData);
755
-					if (this->processCommand)
756
-					{
757
-						this->modType = value;
758
-						this->updateFlags.set(TUF_MOD);
759
-					}
688
+					this->modType = read8(pData);
689
+					this->updateFlags.set(TUF_MOD);
760 690
 					break;
761 691
 
762 692
 				case SSEQ_CMD_MODRANGE:
763
-					value = read8(pData);
764
-					if (this->processCommand)
765
-					{
766
-						this->modRange = value;
767
-						this->updateFlags.set(TUF_MOD);
768
-					}
693
+					this->modRange = read8(pData);
694
+					this->updateFlags.set(TUF_MOD);
769 695
 					break;
770 696
 
771 697
 				case SSEQ_CMD_MODDELAY:
772
-					if (this->overriding())
773
-						value = this->overriding.value;
774
-					else
775
-						value = read16(pData);
776
-					if (this->processCommand)
777
-					{
778
-						this->modDelay = value;
779
-						this->updateFlags.set(TUF_MOD);
780
-					}
698
+					this->modDelay = this->overriding.val(pData, read16);
699
+					this->updateFlags.set(TUF_MOD);
781 700
 					break;
782 701
 
783 702
 				//-----------------------------------------------------------------
... ...
@@ -786,8 +705,7 @@ void Track::Run()
786 705
 
787 706
 				case SSEQ_CMD_RANDOM:
788 707
 				{
789
-					if (this->processCommand)
790
-						this->overriding() = true;
708
+					this->overriding() = true;
791 709
 					this->overriding.cmd = read8(pData);
792 710
 					if ((this->overriding.cmd >= SSEQ_CMD_SETVAR && this->overriding.cmd <= SSEQ_CMD_CMP_NE) || this->overriding.cmd < 0x80)
793 711
 						this->overriding.extraValue = read8(pData);
... ...
@@ -802,8 +720,7 @@ void Track::Run()
802 720
 				//-----------------------------------------------------------------
803 721
 
804 722
 				case SSEQ_CMD_FROMVAR:
805
-					if (this->processCommand)
806
-						this->overriding() = true;
723
+					this->overriding() = true;
807 724
 					this->overriding.cmd = read8(pData);
808 725
 					if ((this->overriding.cmd >= SSEQ_CMD_SETVAR && this->overriding.cmd <= SSEQ_CMD_CMP_NE) || this->overriding.cmd < 0x80)
809 726
 						this->overriding.extraValue = read8(pData);
... ...
@@ -818,21 +735,11 @@ void Track::Run()
818 735
 				case SSEQ_CMD_SHIFTVAR:
819 736
 				case SSEQ_CMD_RANDVAR:
820 737
 				{
821
-					int8_t varNo;
822
-					if (this->overriding())
823
-					{
824
-						varNo = this->overriding.extraValue;
825
-						value = this->overriding.value;
826
-					}
827
-					else
828
-					{
829
-						varNo = read8(pData);
830
-						value = read16(pData);
831
-					}
738
+					int8_t varNo = this->overriding.val(pData, read8, true);
739
+					value = this->overriding.val(pData, read16);
832 740
 					if (cmd == SSEQ_CMD_DIVVAR && !value) // Division by 0, skip it to prevent crashing
833 741
 						break;
834
-					if (this->processCommand)
835
-						this->ply->variables[varNo] = VarFunc(cmd)(this->ply->variables[varNo], value);
742
+					this->ply->variables[varNo] = VarFunc(cmd)(this->ply->variables[varNo], value);
836 743
 					break;
837 744
 				}
838 745
 
... ...
@@ -847,38 +754,38 @@ void Track::Run()
847 754
 				case SSEQ_CMD_CMP_LT:
848 755
 				case SSEQ_CMD_CMP_NE:
849 756
 				{
850
-					int8_t varNo;
851
-					if (this->overriding())
852
-					{
853
-						varNo = this->overriding.extraValue;
854
-						value = this->overriding.value;
855
-					}
856
-					else
857
-					{
858
-						varNo = read8(pData);
859
-						value = read16(pData);
860
-					}
861
-					if (this->processCommand)
862
-						this->lastComparisonResult = CompareFunc(cmd)(this->ply->variables[varNo], value);
757
+					int8_t varNo = this->overriding.val(pData, read8, true);
758
+					value = this->overriding.val(pData, read16);
759
+					this->lastComparisonResult = CompareFunc(cmd)(this->ply->variables[varNo], value);
863 760
 					break;
864 761
 				}
865 762
 
866 763
 				case SSEQ_CMD_IF:
867
-					this->processCommand = this->lastComparisonResult;
868
-					break;
869
-
870
-				case SSEQ_CMD_PRINTVAR:
871
-					++*pData;
764
+					if (!this->lastComparisonResult)
765
+					{
766
+						int nextCmd = read8(pData);
767
+						uint8_t cmdBytes = SseqCommandByteCount(nextCmd);
768
+						bool variableBytes = !!(cmdBytes & VariableByteCount);
769
+						bool extraByte = !!(cmdBytes & ExtraByteOnNoteOrVarOrCmp);
770
+						cmdBytes &= ~(VariableByteCount | ExtraByteOnNoteOrVarOrCmp);
771
+						if (extraByte)
772
+						{
773
+							int extraCmd = read8(pData);
774
+							if ((extraCmd >= SSEQ_CMD_SETVAR && extraCmd <= SSEQ_CMD_CMP_NE) || extraCmd < 0x80)
775
+								++cmdBytes;
776
+						}
777
+						*pData += cmdBytes;
778
+						if (variableBytes)
779
+							readvl(pData);
780
+					}
872 781
 					break;
873 782
 
874
-				case SSEQ_CMD_MUTE: // UNSUPPORTED
875
-					++*pData;
783
+				default:
784
+					*pData += SseqCommandByteCount(cmd);
876 785
 			}
877 786
 		}
878 787
 
879 788
 		if (cmd != SSEQ_CMD_RANDOM && cmd != SSEQ_CMD_FROMVAR)
880 789
 			this->overriding() = false;
881
-		if (cmd != SSEQ_CMD_IF)
882
-			this->processCommand = true;
883 790
 	}
884 791
 }
Browse code

[NCSF] Implemented the random, variable, and conditional commands. Also fixed loop counter.

Naram Qashat authored on 2014/10/13 18:00:29
Showing 1 changed files
... ...
@@ -1,13 +1,15 @@
1 1
 /*
2 2
  * SSEQ Player - Track structure
3 3
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
4
- * Last modification on 2014-10-05
4
+ * Last modification on 2014-10-13
5 5
  *
6 6
  * Adapted from source code of FeOS Sound System
7 7
  * By fincs
8 8
  * https://github.com/fincs/FSS
9 9
  */
10 10
 
11
+#include <functional>
12
+#include <cstdlib>
11 13
 #include "Track.h"
12 14
 #include "Player.h"
13 15
 #include "common.h"
... ...
@@ -35,9 +37,11 @@ void Track::Zero()
35 37
 	this->ply = nullptr;
36 38
 
37 39
 	this->startPos = this->pos = nullptr;
38
-	memset(this->stack, 0, sizeof(this->stack));
40
+	std::fill_n(&this->stack[0], FSS_TRACKSTACKSIZE, StackValue());
39 41
 	this->stackPos = 0;
40 42
 	memset(this->loopCount, 0, sizeof(this->loopCount));
43
+	this->overriding() = false;
44
+	this->lastComparisonResult = this->processCommand = true;
41 45
 
42 46
 	this->wait = 0;
43 47
 	this->patch = 0;
... ...
@@ -298,11 +302,95 @@ enum SseqCommand
298 302
 	SSEQ_CMD_RANDOM = 0xA0,
299 303
 	SSEQ_CMD_PRINTVAR = 0xD6,
300 304
 	SSEQ_CMD_IF = 0xA2,
301
-	SSEQ_CMD_UNSUP1 = 0xA1,
302
-	SSEQ_CMD_UNSUP2_LO = 0xB0,
303
-	SSEQ_CMD_UNSUP2_HI = 0xBD
305
+	SSEQ_CMD_FROMVAR = 0xA1,
306
+	SSEQ_CMD_SETVAR = 0xB0,
307
+	SSEQ_CMD_ADDVAR = 0xB1,
308
+	SSEQ_CMD_SUBVAR = 0xB2,
309
+	SSEQ_CMD_MULVAR = 0xB3,
310
+	SSEQ_CMD_DIVVAR = 0xB4,
311
+	SSEQ_CMD_SHIFTVAR = 0xB5,
312
+	SSEQ_CMD_RANDVAR = 0xB6,
313
+	SSEQ_CMD_CMP_EQ = 0xB8,
314
+	SSEQ_CMD_CMP_GE = 0xB9,
315
+	SSEQ_CMD_CMP_GT = 0xBA,
316
+	SSEQ_CMD_CMP_LE = 0xBB,
317
+	SSEQ_CMD_CMP_LT = 0xBC,
318
+	SSEQ_CMD_CMP_NE = 0xBD,
319
+
320
+	SSEQ_CMD_MUTE = 0xD7 // Unsupported
304 321
 };
305 322
 
323
+static auto varFuncSet = [](int16_t, int16_t value) { return value; };
324
+static auto varFuncAdd = [](int16_t var, int16_t value) -> int16_t { return var + value; };
325
+static auto varFuncSub = [](int16_t var, int16_t value) -> int16_t { return var - value; };
326
+static auto varFuncMul = [](int16_t var, int16_t value) -> int16_t { return var * value; };
327
+static auto varFuncDiv = [](int16_t var, int16_t value) -> int16_t { return var / value; };
328
+static auto varFuncShift = [](int16_t var, int16_t value) -> int16_t
329
+{
330
+	if (value < 0)
331
+		return var >> -value;
332
+	else
333
+		return var << value;
334
+};
335
+static auto varFuncRand = [](int16_t, int16_t value) -> int16_t
336
+{
337
+	if (value < 0)
338
+		return -(std::rand() % (-value + 1));
339
+	else
340
+		return std::rand() % (value + 1);
341
+};
342
+
343
+static inline std::function<int16_t (int16_t, int16_t)> VarFunc(int cmd)
344
+{
345
+	switch (cmd)
346
+	{
347
+		case SSEQ_CMD_SETVAR:
348
+			return varFuncSet;
349
+		case SSEQ_CMD_ADDVAR:
350
+			return varFuncAdd;
351
+		case SSEQ_CMD_SUBVAR:
352
+			return varFuncSub;
353
+		case SSEQ_CMD_MULVAR:
354
+			return varFuncMul;
355
+		case SSEQ_CMD_DIVVAR:
356
+			return varFuncDiv;
357
+		case SSEQ_CMD_SHIFTVAR:
358
+			return varFuncShift;
359
+		case SSEQ_CMD_RANDVAR:
360
+			return varFuncRand;
361
+		default:
362
+			return nullptr;
363
+	}
364
+}
365
+
366
+static auto compareFuncEq = [](int16_t a, int16_t b) { return a == b; };
367
+static auto compareFuncGe = [](int16_t a, int16_t b) { return a >= b; };
368
+static auto compareFuncGt = [](int16_t a, int16_t b) { return a > b; };
369
+static auto compareFuncLe = [](int16_t a, int16_t b) { return a <= b; };
370
+static auto compareFuncLt = [](int16_t a, int16_t b) { return a < b; };
371
+static auto compareFuncNe = [](int16_t a, int16_t b) { return a != b; };
372
+
373
+static inline std::function<bool (int16_t, int16_t)> CompareFunc(int cmd)
374
+{
375
+	switch (cmd)
376
+	{
377
+		case SSEQ_CMD_CMP_EQ:
378
+			return compareFuncEq;
379
+		case SSEQ_CMD_CMP_GE:
380
+			return compareFuncGe;
381
+		case SSEQ_CMD_CMP_GT:
382
+			return compareFuncGt;
383
+		case SSEQ_CMD_CMP_LE:
384
+			return compareFuncLe;
385
+		case SSEQ_CMD_CMP_LT:
386
+			return compareFuncLt;
387
+		case SSEQ_CMD_CMP_NE:
388
+			return compareFuncNe;
389
+		default:
390
+			return nullptr;
391
+	}
392
+}
393
+
306 394
 void Track::Run()
307 395
 {
308 396
 	// Indicate "heartbeat" for this track
... ...
@@ -323,21 +411,40 @@ void Track::Run()
323 411
 
324 412
 	while (!this->wait)
325 413
 	{
326
-		int cmd = read8(pData);
414
+		int cmd;
415
+		if (this->overriding())
416
+			cmd = this->overriding.cmd;
417
+		else
418
+			cmd = read8(pData);
327 419
 		if (cmd < 0x80)
328 420
 		{
329 421
 			// Note on
330 422
 			int key = cmd + this->transpose;
331
-			int vel = read8(pData);
332
-			int len = readvl(pData);
333
-			if (this->state[TS_NOTEWAIT])
334
-				this->wait = len;
335
-			if (this->state[TS_TIEBIT])
336
-				this->NoteOnTie(key, vel);
423
+			int vel;
424
+			int len;
425
+			if (this->overriding())
426
+			{
427
+				vel = this->overriding.extraValue;
428
+				len = this->overriding.value;
429
+			}
337 430
 			else
338
-				this->NoteOn(key, vel, len);
431
+			{
432
+				vel = read8(pData);
433
+				len = readvl(pData);
434
+			}
435
+			if (this->processCommand)
436
+			{
437
+				if (this->state[TS_NOTEWAIT])
438
+					this->wait = len;
439
+				if (this->state[TS_TIEBIT])
440
+					this->NoteOnTie(key, vel);
441
+				else
442
+					this->NoteOn(key, vel, len);
443
+			}
339 444
 		}
340 445
 		else
446
+		{
447
+			int value;
341 448
 			switch (cmd)
342 449
 			{
343 450
 				//-----------------------------------------------------------------
... ...
@@ -345,86 +452,156 @@ void Track::Run()
345 452
 				//-----------------------------------------------------------------
346 453
 
347 454
 				case SSEQ_CMD_REST:
348
-					this->wait = readvl(pData);
455
+					if (this->overriding())
456
+						value = this->overriding.value;
457
+					else
458
+						value = readvl(pData);
459
+					if (this->processCommand)
460
+						this->wait = value;
349 461
 					break;
350 462
 
351 463
 				case SSEQ_CMD_PATCH:
352
-					this->patch = readvl(pData);
464
+					if (this->overriding())
465
+						value = this->overriding.value;
466
+					else
467
+						value = readvl(pData);
468
+					if (this->processCommand)
469
+						this->patch = value;
353 470
 					break;
354 471
 
355 472
 				case SSEQ_CMD_GOTO:
356
-					*pData = &this->ply->sseq->data[read24(pData)];
473
+					value = read24(pData);
474
+					if (this->processCommand)
475
+						*pData = &this->ply->sseq->data[value];
357 476
 					break;
358 477
 
359 478
 				case SSEQ_CMD_CALL:
360
-				{
361
-					const uint8_t *dest = &this->ply->sseq->data[read24(pData)];
362
-					this->stack[this->stackPos++] = *pData;
363
-					*pData = dest;
479
+					value = read24(pData);
480
+					if (this->processCommand && this->stackPos < FSS_TRACKSTACKSIZE)
481
+					{
482
+						const uint8_t *dest = &this->ply->sseq->data[value];
483
+						this->stack[this->stackPos++] = StackValue(STACKTYPE_CALL, *pData);
484
+						*pData = dest;
485
+					}
364 486
 					break;
365
-				}
366 487
 
367 488
 				case SSEQ_CMD_RET:
368
-					*pData = this->stack[--this->stackPos];
489
+					if (this->processCommand && this->stackPos && this->stack[this->stackPos - 1].type == STACKTYPE_CALL)
490
+						*pData = this->stack[--this->stackPos].dest;
369 491
 					break;
370 492
 
371 493
 				case SSEQ_CMD_PAN:
372
-					this->pan = read8(pData) - 64;
373
-					this->updateFlags.set(TUF_PAN);
494
+					if (this->overriding())
495
+						value = this->overriding.value;
496
+					else
497
+						value = read8(pData);
498
+					if (this->processCommand)
499
+					{
500
+						this->pan = value - 64;
501
+						this->updateFlags.set(TUF_PAN);
502
+					}
374 503
 					break;
375 504
 
376 505
 				case SSEQ_CMD_VOL:
377
-					this->vol = read8(pData);
378
-					this->updateFlags.set(TUF_VOL);
506
+					if (this->overriding())
507
+						value = this->overriding.value;
508
+					else
509
+						value = read8(pData);
510
+					if (this->processCommand)
511
+					{
512
+						this->vol = value;
513
+						this->updateFlags.set(TUF_VOL);
514
+					}
379 515
 					break;
380 516
 
381 517
 				case SSEQ_CMD_MASTERVOL:
382
-					this->ply->masterVol = Cnv_Sust(read8(pData));
383
-					for (uint8_t i = 0; i < this->ply->nTracks; ++i)
384
-						this->ply->tracks[this->ply->trackIds[i]].updateFlags.set(TUF_VOL);
518
+					if (this->overriding())
519
+						value = this->overriding.value;
520
+					else
521
+						value = read8(pData);
522
+					if (this->processCommand)
523
+					{
524
+						this->ply->masterVol = Cnv_Sust(value);
525
+						for (uint8_t i = 0; i < this->ply->nTracks; ++i)
526
+							this->ply->tracks[this->ply->trackIds[i]].updateFlags.set(TUF_VOL);
527
+					}
385 528
 					break;
386 529
 
387 530
 				case SSEQ_CMD_PRIO:
388
-					this->prio = this->ply->prio + read8(pData);
531
+					value = read8(pData);
532
+					if (this->processCommand)
533
+						this->prio = this->ply->prio + value;
389 534
 					// Update here?
390 535
 					break;
391 536
 
392 537
 				case SSEQ_CMD_NOTEWAIT:
393
-					this->state.set(TS_NOTEWAIT, !!read8(pData));
538
+					value = read8(pData);
539
+					if (this->processCommand)
540
+						this->state.set(TS_NOTEWAIT, !!value);
394 541
 					break;
395 542
 
396 543
 				case SSEQ_CMD_TIE:
397
-					this->state.set(TS_TIEBIT, !!read8(pData));
398
-					this->ReleaseAllNotes();
544
+					value = read8(pData);
545
+					if (this->processCommand)
546
+					{
547
+						this->state.set(TS_TIEBIT, !!value);
548
+						this->ReleaseAllNotes();
549
+					}
399 550
 					break;
400 551
 
401 552
 				case SSEQ_CMD_EXPR:
402
-					this->expr = read8(pData);
403
-					this->updateFlags.set(TUF_VOL);
553
+					if (this->overriding())
554
+						value = this->overriding.value;
555
+					else
556
+						value = read8(pData);
557
+					if (this->processCommand)
558
+					{
559
+						this->expr = value;
560
+						this->updateFlags.set(TUF_VOL);
561
+					}
404 562
 					break;
405 563
 
406 564
 				case SSEQ_CMD_TEMPO:
407
-					this->ply->tempo = read16(pData);
565
+					value = read16(pData);
566
+					if (this->processCommand)
567
+						this->ply->tempo = value;
408 568
 					break;
409 569
 
410 570
 				case SSEQ_CMD_END:
411
-					this->state.set(TS_END);
412
-					return;
571
+					if (this->processCommand)
572
+					{
573
+						this->state.set(TS_END);
574
+						return;
575
+					}
576
+					break;
413 577
 
414 578
 				case SSEQ_CMD_LOOPSTART:
415
-					this->loopCount[this->stackPos] = read8(pData);
416
-					this->stack[this->stackPos++] = *pData;
579
+					if (this->overriding())
580
+						value = this->overriding.value;
581
+					else
582
+						value = read8(pData);
583
+					if (this->processCommand && this->stackPos < FSS_TRACKSTACKSIZE)
584
+					{
585
+						this->loopCount[this->stackPos] = value;
586
+						this->stack[this->stackPos++] = StackValue(STACKTYPE_LOOP, *pData);
587
+					}
417 588
 					break;
418 589
 
419 590
 				case SSEQ_CMD_LOOPEND:
420
-					if (this->stackPos)
591
+					if (this->processCommand && this->stackPos && this->stack[this->stackPos - 1].type == STACKTYPE_LOOP)
421 592
 					{
422
-						const uint8_t *rPos = this->stack[this->stackPos - 1];
593
+						const uint8_t *rPos = this->stack[this->stackPos - 1].dest;
423 594
 						uint8_t &nR = this->loopCount[this->stackPos - 1];
424 595
 						uint8_t prevR = nR;
425
-						if (prevR && !--nR)
426
-							--this->stackPos;
427
-						*pData = rPos;
596
+						if (!prevR)
597
+							*pData = rPos;
598
+						else
599
+						{
600
+							if (--nR)
601
+								*pData = rPos;
602
+							else
603
+								--this->stackPos;
604
+						}
428 605
 					}
429 606
 					break;
430 607
 
... ...
@@ -433,17 +610,33 @@ void Track::Run()
433 610
 				//-----------------------------------------------------------------
434 611
 
435 612
 				case SSEQ_CMD_TRANSPOSE:
436
-					this->transpose = read8(pData);
613
+					if (this->overriding())
614
+						value = this->overriding.value;
615
+					else
616
+						value = read8(pData);
617
+					if (this->processCommand)
618
+						this->transpose = value;
437 619
 					break;
438 620
 
439 621
 				case SSEQ_CMD_PITCHBEND:
440
-					this->pitchBend = read8(pData);
441
-					this->updateFlags.set(TUF_TIMER);
622
+					if (this->overriding())
623
+						value = this->overriding.value;
624
+					else
625
+						value = read8(pData);
626
+					if (this->processCommand)
627
+					{
628
+						this->pitchBend = value;
629
+						this->updateFlags.set(TUF_TIMER);
630
+					}
442 631
 					break;
443 632
 
444 633
 				case SSEQ_CMD_PITCHBENDRANGE:
445
-					this->pitchBendRange = read8(pData);
446
-					this->updateFlags.set(TUF_TIMER);
634
+					value = read8(pData);
635
+					if (this->processCommand)
636
+					{
637
+						this->pitchBendRange = value;
638
+						this->updateFlags.set(TUF_TIMER);
639
+					}
447 640
 					break;
448 641
 
449 642
 				//-----------------------------------------------------------------
... ...
@@ -451,19 +644,39 @@ void Track::Run()
451 644
 				//-----------------------------------------------------------------
452 645
 
453 646
 				case SSEQ_CMD_ATTACK:
454
-					this->a = read8(pData);
647
+					if (this->overriding())
648
+						value = this->overriding.value;
649
+					else
650
+						value = read8(pData);
651
+					if (this->processCommand)
652
+						this->a = value;
455 653
 					break;
456 654
 
457 655
 				case SSEQ_CMD_DECAY:
458
-					this->d = read8(pData);
656
+					if (this->overriding())
657
+						value = this->overriding.value;
658
+					else
659
+						value = read8(pData);
660
+					if (this->processCommand)
661
+						this->d = value;
459 662
 					break;
460 663
 
461 664
 				case SSEQ_CMD_SUSTAIN:
462
-					this->s = read8(pData);
665
+					if (this->overriding())
666
+						value = this->overriding.value;
667
+					else
668
+						value = read8(pData);
669
+					if (this->processCommand)
670
+						this->s = value;
463 671
 					break;
464 672
 
465 673
 				case SSEQ_CMD_RELEASE:
466
-					this->r = read8(pData);
674
+					if (this->overriding())
675
+						value = this->overriding.value;
676
+					else
677
+						value = read8(pData);
678
+					if (this->processCommand)
679
+						this->r = value;
467 680
 					break;
468 681
 
469 682
 				//-----------------------------------------------------------------
... ...
@@ -471,23 +684,41 @@ void Track::Run()
471 684
 				//-----------------------------------------------------------------
472 685
 
473 686
 				case SSEQ_CMD_PORTAKEY:
474
-					this->portaKey = read8(pData) + this->transpose;
475
-					this->state.set(TS_PORTABIT);
476
-					// Update here?
687
+					value = read8(pData);
688
+					if (this->processCommand)
689
+					{
690
+						this->portaKey = value + this->transpose;
691
+						this->state.set(TS_PORTABIT);
692
+						// Update here?
693
+					}
477 694
 					break;
478 695
 
479 696
 				case SSEQ_CMD_PORTAFLAG:
480
-					this->state.set(TS_PORTABIT, !!read8(pData));
481
-					// Update here?
697
+					value = read8(pData);
698
+					if (this->processCommand)
699
+					{
700
+						this->state.set(TS_PORTABIT, !!value);
701
+						// Update here?
702
+					}
482 703
 					break;
483 704
 
484 705
 				case SSEQ_CMD_PORTATIME:
485
-					this->portaTime = read8(pData);
706
+					if (this->overriding())
707
+						value = this->overriding.value;
708
+					else
709
+						value = read8(pData);
710
+					if (this->processCommand)
711
+						this->portaTime = value;
486 712
 					// Update here?
487 713
 					break;
488 714
 
489 715
 				case SSEQ_CMD_SWEEPPITCH:
490
-					this->sweepPitch = read16(pData);
716
+					if (this->overriding())
717
+						value = this->overriding.value;
718
+					else
719
+						value = read16(pData);
720
+					if (this->processCommand)
721
+						this->sweepPitch = value;
491 722
 					// Update here?
492 723
 					break;
493 724
 
... ...
@@ -496,57 +727,158 @@ void Track::Run()
496 727
 				//-----------------------------------------------------------------
497 728
 
498 729
 				case SSEQ_CMD_MODDEPTH:
499
-					this->modDepth = read8(pData);
500
-					this->updateFlags.set(TUF_MOD);
730
+					if (this->overriding())
731
+						value = this->overriding.value;
732
+					else
733
+						value = read8(pData);
734
+					if (this->processCommand)
735
+					{
736
+						this->modDepth = value;
737
+						this->updateFlags.set(TUF_MOD);
738
+					}
501 739
 					break;
502 740
 
503 741
 				case SSEQ_CMD_MODSPEED:
504
-					this->modSpeed = read8(pData);
505
-					this->updateFlags.set(TUF_MOD);
742
+					if (this->overriding())
743
+						value = this->overriding.value;
744
+					else
745
+						value = read8(pData);
746
+					if (this->processCommand)
747
+					{
748
+						this->modSpeed = value;
749
+						this->updateFlags.set(TUF_MOD);
750
+					}
506 751
 					break;
507 752
 
508 753
 				case SSEQ_CMD_MODTYPE:
509
-					this->modType = read8(pData);
510
-					this->updateFlags.set(TUF_MOD);
754
+					value = read8(pData);
755
+					if (this->processCommand)
756
+					{
757
+						this->modType = value;
758
+						this->updateFlags.set(TUF_MOD);
759
+					}
511 760
 					break;
512 761
 
513 762
 				case SSEQ_CMD_MODRANGE:
514
-					this->modRange = read8(pData);
515
-					this->updateFlags.set(TUF_MOD);
763
+					value = read8(pData);
764
+					if (this->processCommand)
765
+					{
766
+						this->modRange = value;
767
+						this->updateFlags.set(TUF_MOD);
768
+					}
516 769
 					break;
517 770
 
518 771
 				case SSEQ_CMD_MODDELAY:
519
-					this->modDelay = read16(pData);
520
-					this->updateFlags.set(TUF_MOD);
772
+					if (this->overriding())
773
+						value = this->overriding.value;
774
+					else
775
+						value = read16(pData);
776
+					if (this->processCommand)
777
+					{
778
+						this->modDelay = value;
779
+						this->updateFlags.set(TUF_MOD);
780
+					}
521 781
 					break;
522 782
 
523 783
 				//-----------------------------------------------------------------
524
-				// Variable-related commands
784
+				// Randomness-related commands
525 785
 				//-----------------------------------------------------------------
526 786
 
527
-				case SSEQ_CMD_RANDOM: // TODO
528
-					*pData += 5;
787
+				case SSEQ_CMD_RANDOM:
788
+				{
789
+					if (this->processCommand)
790
+						this->overriding() = true;
791
+					this->overriding.cmd = read8(pData);
792
+					if ((this->overriding.cmd >= SSEQ_CMD_SETVAR && this->overriding.cmd <= SSEQ_CMD_CMP_NE) || this->overriding.cmd < 0x80)
793
+						this->overriding.extraValue = read8(pData);
794
+					int16_t minVal = read16(pData);
795
+					int16_t maxVal = read16(pData);
796
+					this->overriding.value = (std::rand() % (maxVal - minVal + 1)) + minVal;
529 797
 					break;
798
+				}
530 799
 
531
-				case SSEQ_CMD_PRINTVAR: // TODO
532
-					*pData += 1;
800
+				//-----------------------------------------------------------------
801
+				// Variable-related commands
802
+				//-----------------------------------------------------------------
803
+
804
+				case SSEQ_CMD_FROMVAR:
805
+					if (this->processCommand)
806
+						this->overriding() = true;
807
+					this->overriding.cmd = read8(pData);
808
+					if ((this->overriding.cmd >= SSEQ_CMD_SETVAR && this->overriding.cmd <= SSEQ_CMD_CMP_NE) || this->overriding.cmd < 0x80)
809
+						this->overriding.extraValue = read8(pData);
810
+					this->overriding.value = this->ply->variables[read8(pData)];
811
+					break;
812
+
813
+				case SSEQ_CMD_SETVAR:
814
+				case SSEQ_CMD_ADDVAR:
815
+				case SSEQ_CMD_SUBVAR:
816
+				case SSEQ_CMD_MULVAR:
817
+				case SSEQ_CMD_DIVVAR:
818
+				case SSEQ_CMD_SHIFTVAR:
819
+				case SSEQ_CMD_RANDVAR:
820
+				{
821
+					int8_t varNo;
822
+					if (this->overriding())
823
+					{
824
+						varNo = this->overriding.extraValue;
825
+						value = this->overriding.value;
826
+					}
827
+					else
828
+					{
829
+						varNo = read8(pData);
830
+						value = read16(pData);
831
+					}
832
+					if (cmd == SSEQ_CMD_DIVVAR && !value) // Division by 0, skip it to prevent crashing
833
+						break;
834
+					if (this->processCommand)
835
+						this->ply->variables[varNo] = VarFunc(cmd)(this->ply->variables[varNo], value);
533 836
 					break;
837
+				}
534 838
 
535
-				case SSEQ_CMD_UNSUP1: // TODO
839
+				//-----------------------------------------------------------------
840
+				// Conditional-related commands
841
+				//-----------------------------------------------------------------
842
+
843
+				case SSEQ_CMD_CMP_EQ:
844
+				case SSEQ_CMD_CMP_GE:
845
+				case SSEQ_CMD_CMP_GT:
846
+				case SSEQ_CMD_CMP_LE:
847
+				case SSEQ_CMD_CMP_LT:
848
+				case SSEQ_CMD_CMP_NE:
536 849
 				{
537
-					int t = read8(pData);
538
-					if (t >= SSEQ_CMD_UNSUP2_LO && t <= SSEQ_CMD_UNSUP2_HI)
539
-						*pData += 1;
540
-					*pData += 1;
850
+					int8_t varNo;
851
+					if (this->overriding())
852
+					{
853
+						varNo = this->overriding.extraValue;
854
+						value = this->overriding.value;
855
+					}
856
+					else
857
+					{
858
+						varNo = read8(pData);
859
+						value = read16(pData);
860
+					}
861
+					if (this->processCommand)
862
+						this->lastComparisonResult = CompareFunc(cmd)(this->ply->variables[varNo], value);
541 863
 					break;
542 864
 				}
543 865
 
544
-				case SSEQ_CMD_IF: // TODO
866
+				case SSEQ_CMD_IF:
867
+					this->processCommand = this->lastComparisonResult;
868
+					break;
869
+
870
+				case SSEQ_CMD_PRINTVAR:
871
+					++*pData;
545 872
 					break;
546 873
 
547
-				default:
548
-					if (cmd >= SSEQ_CMD_UNSUP2_LO && cmd <= SSEQ_CMD_UNSUP2_HI) // TODO
549
-						*pData += 3;
874
+				case SSEQ_CMD_MUTE: // UNSUPPORTED
875
+					++*pData;
550 876
 			}
877
+		}
878
+
879
+		if (cmd != SSEQ_CMD_RANDOM && cmd != SSEQ_CMD_FROMVAR)
880
+			this->overriding() = false;
881
+		if (cmd != SSEQ_CMD_IF)
882
+			this->processCommand = true;
551 883
 	}
552 884
 }
Browse code

[NCSF] Removed the Cnv_Scale function as it seemed to cause sounds to be too loud in some cases.

Naram Qashat authored on 2014/10/05 20:17:36
Showing 1 changed files
... ...
@@ -187,7 +187,7 @@ int Track::NoteOn(int key, int vel, int len)
187 187
 	chn->prio = this->prio;
188 188
 	chn->key = key;
189 189
 	chn->orgKey = bIsPCM ? noteDef->noteNumber : 69;
190
-	chn->velocity = Cnv_Scale(vel);
190
+	chn->velocity = Cnv_Sust(vel);
191 191
 	chn->pan = static_cast<int>(noteDef->pan) - 64;
192 192
 	chn->modDelayCnt = 0;
193 193
 	chn->modCounter = 0;
... ...
@@ -229,7 +229,7 @@ int Track::NoteOnTie(int key, int vel)
229 229
 	chn->flags.reset();
230 230
 	chn->prio = this->prio;
231 231
 	chn->key = key;
232
-	chn->velocity = Cnv_Scale(vel);
232
+	chn->velocity = Cnv_Sust(vel);
233 233
 	chn->modDelayCnt = 0;
234 234
 	chn->modCounter = 0;
235 235
 
Browse code

[NCSF] Fix volume issues with a little help from the Nintendo DS SDK.

Also added a clone of DeSmuME's Sound View that is only build during a
debug build, which helped to identify the above issues.

Naram Qashat authored on 2014/10/05 20:00:09
Showing 1 changed files
... ...
@@ -1,7 +1,7 @@
1 1
 /*
2 2
  * SSEQ Player - Track structure
3 3
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
4
- * Last modification on 2013-04-01
4
+ * Last modification on 2014-10-05
5 5
  *
6 6
  * Adapted from source code of FeOS Sound System
7 7
  * By fincs
... ...
@@ -187,7 +187,7 @@ int Track::NoteOn(int key, int vel, int len)
187 187
 	chn->prio = this->prio;
188 188
 	chn->key = key;
189 189
 	chn->orgKey = bIsPCM ? noteDef->noteNumber : 69;
190
-	chn->velocity = Cnv_Sust(vel);
190
+	chn->velocity = Cnv_Scale(vel);
191 191
 	chn->pan = static_cast<int>(noteDef->pan) - 64;
192 192
 	chn->modDelayCnt = 0;
193 193
 	chn->modCounter = 0;
... ...
@@ -229,7 +229,7 @@ int Track::NoteOnTie(int key, int vel)
229 229
 	chn->flags.reset();
230 230
 	chn->prio = this->prio;
231 231
 	chn->key = key;
232
-	chn->velocity = Cnv_Sust(vel);
232
+	chn->velocity = Cnv_Scale(vel);
233 233
 	chn->modDelayCnt = 0;
234 234
 	chn->modCounter = 0;
235 235
 
Browse code

Corrected issue with terminating the SSEQ player by actually making it stop properly.

Naram Qashat authored on 2013/04/02 03:03:26
Showing 1 changed files
... ...
@@ -1,7 +1,7 @@
1 1
 /*
2 2
  * SSEQ Player - Track structure
3 3
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
4
- * Last modification on 2013-03-30
4
+ * Last modification on 2013-04-01
5 5
  *
6 6
  * Adapted from source code of FeOS Sound System
7 7
  * By fincs
... ...
@@ -86,6 +86,12 @@ void Track::ClearState()
86 86
 	this->modDepth = 0;
87 87
 }
88 88
 
89
+void Track::Free()
90
+{
91
+	this->state.reset();
92
+	this->updateFlags.reset();
93
+}
94
+
89 95
 int Track::NoteOn(int key, int vel, int len)
90 96
 {
91 97
 	auto sbnk = this->ply->sseq->bank;
Browse code

Cleanup of some warnings, updating modification dates, using nullptr instead of NULL in some cases.

Naram Qashat authored on 2013/03/30 16:17:42
Showing 1 changed files
... ...
@@ -1,7 +1,7 @@
1 1
 /*
2 2
  * SSEQ Player - Track structure
3 3
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
4
- * Last modification on 2013-03-25
4
+ * Last modification on 2013-03-30
5 5
  *
6 6
  * Adapted from source code of FeOS Sound System
7 7
  * By fincs
... ...
@@ -32,9 +32,9 @@ void Track::Zero()
32 32
 
33 33
 	this->state.reset();
34 34
 	this->num = this->prio = 0;
35
-	this->ply = NULL;
35
+	this->ply = nullptr;
36 36
 
37
-	this->startPos = this->pos = NULL;
37
+	this->startPos = this->pos = nullptr;
38 38
 	memset(this->stack, 0, sizeof(this->stack));
39 39
 	this->stackPos = 0;
40 40
 	memset(this->loopCount, 0, sizeof(this->loopCount));
... ...
@@ -94,11 +94,11 @@ int Track::NoteOn(int key, int vel, int len)
94 94
 		return -1;
95 95
 
96 96
 	bool bIsPCM = true;
97
-	Channel *chn;
98
-	int nCh;
97
+	Channel *chn = nullptr;
98
+	int nCh = -1;
99 99
 
100 100
 	auto &instrument = sbnk->instruments[this->patch];
101
-	const SBNKInstrumentRange *noteDef = NULL;
101
+	const SBNKInstrumentRange *noteDef = nullptr;
102 102
 	int fRecord = instrument.record;
103 103
 
104 104
 	if (fRecord == 16)
... ...
@@ -208,7 +208,7 @@ int Track::NoteOnTie(int key, int vel)
208 208
 {
209 209
 	// Find an existing note
210 210
 	int i;
211
-	Channel *chn;
211
+	Channel *chn = nullptr;
212 212
 	for (i = 0; i < 16; ++i)
213 213
 	{
214 214
 		chn = &this->ply->channels[i];
Browse code

Import actual code.

Naram Qashat authored on 2013/03/26 02:41:19
Showing 1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,546 @@
1
+/*
2
+ * SSEQ Player - Track structure
3
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
4
+ * Last modification on 2013-03-25
5
+ *
6
+ * Adapted from source code of FeOS Sound System
7
+ * By fincs
8
+ * https://github.com/fincs/FSS
9
+ */
10
+
11
+#include "Track.h"
12
+#include "Player.h"
13
+#include "common.h"
14
+
15
+Track::Track()
16
+{
17
+	this->Zero();
18
+}
19
+
20
+void Track::Init(uint8_t handle, Player *player, const uint8_t *dataPos, int n)
21
+{
22
+	this->trackId = handle;
23
+	this->num = n;
24
+	this->ply = player;
25
+	this->startPos = dataPos;
26
+	this->ClearState();
27
+}
28
+
29
+void Track::Zero()
30
+{
31
+	this->trackId = -1;
32
+
33
+	this->state.reset();
34
+	this->num = this->prio = 0;
35
+	this->ply = NULL;
36
+
37
+	this->startPos = this->pos = NULL;
38
+	memset(this->stack, 0, sizeof(this->stack));
39
+	this->stackPos = 0;
40
+	memset(this->loopCount, 0, sizeof(this->loopCount));
41
+
42
+	this->wait = 0;
43
+	this->patch = 0;
44
+	this->portaKey = this->portaTime = 0;
45
+	this->sweepPitch = 0;
46
+	this->vol = this->expr = 0;
47
+	this->pan = 0;
48
+	this->pitchBendRange = 0;
49
+	this->pitchBend = this->transpose = 0;
50
+
51
+	this->a = this->d = this->s = this->r = 0;
52
+
53
+	this->modType = this->modSpeed = this->modDepth = this->modRange = 0;
54
+	this->modDelay = 0;
55
+
56
+	this->updateFlags.reset();
57
+}
58
+
59
+void Track::ClearState()
60
+{
61
+	this->state.reset();
62
+	this->state.set(TS_ALLOCBIT);
63
+	this->state.set(TS_NOTEWAIT);
64
+	this->prio = this->ply->prio + 64;
65
+
66
+	this->pos = this->startPos;
67
+	this->stackPos = 0;
68
+
69
+	this->wait = 0;
70
+	this->patch = 0;
71
+	this->portaKey = 60;
72
+	this->portaTime = 0;
73
+	this->sweepPitch = 0;
74
+	this->vol = 64;
75
+	this->expr = 127;
76
+	this->pan = 0;
77
+	this->pitchBendRange = 2;
78
+	this->pitchBend = this->transpose = 0;
79
+
80
+	this->a = this->d = this->s = this->r = 0xFF;
81
+
82
+	this->modType = 0;
83
+	this->modRange = 1;
84
+	this->modSpeed = 16;
85
+	this->modDelay = 10;
86
+	this->modDepth = 0;
87
+}
88
+
89
+int Track::NoteOn(int key, int vel, int len)
90
+{
91
+	auto sbnk = this->ply->sseq->bank;
92
+
93
+	if (this->patch >= sbnk->instruments.size())
94
+		return -1;
95
+
96
+	bool bIsPCM = true;
97
+	Channel *chn;
98
+	int nCh;
99
+
100
+	auto &instrument = sbnk->instruments[this->patch];
101
+	const SBNKInstrumentRange *noteDef = NULL;
102
+	int fRecord = instrument.record;
103
+
104
+	if (fRecord == 16)
105
+	{
106
+		if (!(instrument.ranges[0].lowNote <= key && key <= instrument.ranges[instrument.ranges.size() - 1].highNote))
107
+			return -1;
108
+		int rn = key - instrument.ranges[0].lowNote;
109
+		noteDef = &instrument.ranges[rn];
110
+		fRecord = noteDef->record;
111
+	}
112
+	else if (fRecord == 17)
113
+	{
114
+		size_t reg, ranges;
115
+		for (reg = 0, ranges = instrument.ranges.size(); reg < ranges; ++reg)
116
+			if (key <= instrument.ranges[reg].highNote)
117
+				break;
118
+		if (reg == ranges)
119
+			return -1;
120
+
121
+		noteDef = &instrument.ranges[reg];
122
+		fRecord = noteDef->record;
123
+	}
124
+
125
+	if (!fRecord)
126
+		return -1;
127
+	else if (fRecord == 1)
128
+	{
129
+		if (!noteDef)
130
+			noteDef = &instrument.ranges[0];
131
+	}
132
+	else if (fRecord < 4)
133
+	{
134
+		// PSG
135
+		// fRecord = 2 -> PSG tone, pNoteDef->wavid -> PSG duty
136
+		// fRecord = 3 -> PSG noise
137
+		bIsPCM = false;
138
+		if (!noteDef)
139
+			noteDef = &instrument.ranges[0];
140
+		if (fRecord == 3)
141
+		{
142
+			nCh = this->ply->ChannelAlloc(TYPE_NOISE, this->prio);
143
+			if (nCh < 0)
144
+				return -1;
145
+			chn = &this->ply->channels[nCh];
146
+			chn->tempReg.CR = SOUND_FORMAT_PSG | SCHANNEL_ENABLE;
147
+		}
148
+		else
149
+		{
150
+			nCh = this->ply->ChannelAlloc(TYPE_PSG, this->prio);
151
+			if (nCh < 0)
152
+				return -1;
153
+			chn = &this->ply->channels[nCh];
154
+			chn->tempReg.CR = SOUND_FORMAT_PSG | SCHANNEL_ENABLE | SOUND_DUTY(noteDef->swav & 0x7);
155
+		}
156
+		// TODO: figure out what pNoteDef->tnote means for PSG channels
157
+		chn->tempReg.TIMER = -SOUND_FREQ(440 * 8); // key #69 (A4)
158
+		chn->reg.samplePosition = -1;
159
+		chn->reg.psgX = 0x7FFF;
160
+	}
161
+
162
+	if (bIsPCM)
163
+	{
164
+		nCh = this->ply->ChannelAlloc(TYPE_PCM, this->prio);
165
+		if (nCh < 0)
166
+			return -1;
167
+		chn = &this->ply->channels[nCh];
168
+
169
+		auto swav = &sbnk->waveArc[noteDef->swar]->swavs.find(noteDef->swav)->second;
170
+		chn->tempReg.CR = SOUND_FORMAT(swav->waveType & 3) | SOUND_LOOP(!!swav->loop) | SCHANNEL_ENABLE;
171
+		chn->tempReg.SOURCE = swav;
172
+		chn->tempReg.TIMER = swav->time;
173
+		chn->tempReg.REPEAT_POINT = swav->loopOffset;
174
+		chn->tempReg.LENGTH = swav->nonLoopLength;
175
+		chn->reg.samplePosition = -3;
176
+	}
177
+
178
+	chn->state = CS_START;
179
+	chn->trackId = this->trackId;
180
+	chn->flags.reset();
181
+	chn->prio = this->prio;
182
+	chn->key = key;
183
+	chn->orgKey = bIsPCM ? noteDef->noteNumber : 69;
184
+	chn->velocity = Cnv_Sust(vel);
185
+	chn->pan = static_cast<int>(noteDef->pan) - 64;
186
+	chn->modDelayCnt = 0;
187
+	chn->modCounter = 0;
188
+	chn->noteLength = len;
189
+	chn->reg.sampleIncrease = 0;
190
+
191
+	chn->attackLvl = Cnv_Attack(this->a == 0xFF ? noteDef->attackRate : this->a);
192
+	chn->decayRate = Cnv_Fall(this->d == 0xFF ? noteDef->decayRate : this->d);
193
+	chn->sustainLvl = this->s == 0xFF ? noteDef->sustainLevel : this->s;
194
+	chn->releaseRate = Cnv_Fall(this->r == 0xFF ? noteDef->releaseRate : this->r);
195
+
196
+	chn->UpdateVol(*this);
197
+	chn->UpdatePan(*this);
198
+	chn->UpdateTune(*this);
199
+	chn->UpdateMod(*this);
200
+	chn->UpdatePorta(*this);
201
+
202
+	this->portaKey = key;
203
+
204
+	return nCh;
205
+}
206
+
207
+int Track::NoteOnTie(int key, int vel)
208
+{
209
+	// Find an existing note
210
+	int i;
211
+	Channel *chn;
212
+	for (i = 0; i < 16; ++i)
213
+	{
214
+		chn = &this->ply->channels[i];
215
+		if (chn->state > CS_NONE && chn->trackId == this->trackId && chn->state != CS_RELEASE)
216
+			break;
217
+	}
218
+
219
+	if (i == 16)
220
+		// Can't find note -> create an endless one
221
+		return this->NoteOn(key, vel, -1);
222
+
223
+	chn->flags.reset();
224
+	chn->prio = this->prio;
225
+	chn->key = key;
226
+	chn->velocity = Cnv_Sust(vel);
227
+	chn->modDelayCnt = 0;
228
+	chn->modCounter = 0;
229
+
230
+	chn->UpdateVol(*this);
231
+	//chn->UpdatePan(*this);
232
+	chn->UpdateTune(*this);
233
+	chn->UpdateMod(*this);
234
+	chn->UpdatePorta(*this);
235
+
236
+	this->portaKey = key;
237
+	chn->flags.set(CF_UPDTMR);
238
+
239
+	return i;
240
+}
241
+
242
+void Track::ReleaseAllNotes()
243
+{
244
+	for (int i = 0; i < 16; ++i)
245
+	{
246
+		Channel &chn = this->ply->channels[i];
247
+		if (chn.state > CS_NONE && chn.trackId == this->trackId && chn.state != CS_RELEASE)
248
+			chn.Release();
249
+	}
250
+}
251
+
252
+enum SseqCommand
253
+{
254
+	SSEQ_CMD_REST = 0x80,
255
+	SSEQ_CMD_PATCH = 0x81,
256
+	SSEQ_CMD_PAN = 0xC0,
257
+	SSEQ_CMD_VOL = 0xC1,
258
+	SSEQ_CMD_MASTERVOL = 0xC2,
259
+	SSEQ_CMD_PRIO = 0xC6,
260
+	SSEQ_CMD_NOTEWAIT = 0xC7,
261
+	SSEQ_CMD_TIE = 0xC8,
262
+	SSEQ_CMD_EXPR = 0xD5,
263
+	SSEQ_CMD_TEMPO = 0xE1,
264
+	SSEQ_CMD_END = 0xFF,
265
+
266
+	SSEQ_CMD_GOTO = 0x94,
267
+	SSEQ_CMD_CALL = 0x95,
268
+	SSEQ_CMD_RET = 0xFD,
269
+	SSEQ_CMD_LOOPSTART = 0xD4,
270
+	SSEQ_CMD_LOOPEND = 0xFC,
271
+
272
+	SSEQ_CMD_TRANSPOSE = 0xC3,
273
+	SSEQ_CMD_PITCHBEND = 0xC4,
274
+	SSEQ_CMD_PITCHBENDRANGE = 0xC5,
275
+
276
+	SSEQ_CMD_ATTACK = 0xD0,
277
+	SSEQ_CMD_DECAY = 0xD1,
278
+	SSEQ_CMD_SUSTAIN = 0xD2,
279
+	SSEQ_CMD_RELEASE = 0xD3,
280
+
281
+	SSEQ_CMD_PORTAKEY = 0xC9,
282
+	SSEQ_CMD_PORTAFLAG = 0xCE,
283
+	SSEQ_CMD_PORTATIME = 0xCF,
284
+	SSEQ_CMD_SWEEPPITCH = 0xE3,
285
+
286
+	SSEQ_CMD_MODDEPTH = 0xCA,
287
+	SSEQ_CMD_MODSPEED = 0xCB,
288
+	SSEQ_CMD_MODTYPE = 0xCC,
289
+	SSEQ_CMD_MODRANGE = 0xCD,
290
+	SSEQ_CMD_MODDELAY = 0xE0,
291
+
292
+	SSEQ_CMD_RANDOM = 0xA0,
293
+	SSEQ_CMD_PRINTVAR = 0xD6,
294
+	SSEQ_CMD_IF = 0xA2,
295
+	SSEQ_CMD_UNSUP1 = 0xA1,
296
+	SSEQ_CMD_UNSUP2_LO = 0xB0,
297
+	SSEQ_CMD_UNSUP2_HI = 0xBD
298
+};
299
+
300
+void Track::Run()
301
+{
302
+	// Indicate "heartbeat" for this track
303
+	this->updateFlags.set(TUF_LEN);
304
+
305
+	// Exit if the track has already ended
306
+	if (this->state[TS_END])
307
+		return;
308
+
309
+	if (this->wait)
310
+	{
311
+		--this->wait;
312
+		if (this->wait)
313
+			return;
314
+	}
315
+
316
+	auto pData = &this->pos;
317
+
318
+	while (!this->wait)
319
+	{
320
+		int cmd = read8(pData);
321
+		if (cmd < 0x80)
322
+		{
323
+			// Note on
324
+			int key = cmd + this->transpose;
325
+			int vel = read8(pData);
326
+			int len = readvl(pData);
327
+			if (this->state[TS_NOTEWAIT])
328
+				this->wait = len;
329
+			if (this->state[TS_TIEBIT])
330
+				this->NoteOnTie(key, vel);
331
+			else
332
+				this->NoteOn(key, vel, len);
333
+		}
334
+		else
335
+			switch (cmd)
336
+			{
337
+				//-----------------------------------------------------------------
338
+				// Main commands
339
+				//-----------------------------------------------------------------
340
+
341
+				case SSEQ_CMD_REST:
342
+					this->wait = readvl(pData);
343
+					break;
344
+
345
+				case SSEQ_CMD_PATCH:
346
+					this->patch = readvl(pData);
347
+					break;
348
+
349
+				case SSEQ_CMD_GOTO:
350
+					*pData = &this->ply->sseq->data[read24(pData)];
351
+					break;
352
+
353
+				case SSEQ_CMD_CALL:
354
+				{
355
+					const uint8_t *dest = &this->ply->sseq->data[read24(pData)];
356
+					this->stack[this->stackPos++] = *pData;
357
+					*pData = dest;
358
+					break;
359
+				}
360
+
361
+				case SSEQ_CMD_RET:
362
+					*pData = this->stack[--this->stackPos];
363
+					break;
364
+
365
+				case SSEQ_CMD_PAN:
366
+					this->pan = read8(pData) - 64;
367
+					this->updateFlags.set(TUF_PAN);
368
+					break;
369
+
370
+				case SSEQ_CMD_VOL:
371
+					this->vol = read8(pData);
372
+					this->updateFlags.set(TUF_VOL);
373
+					break;
374
+
375
+				case SSEQ_CMD_MASTERVOL:
376
+					this->ply->masterVol = Cnv_Sust(read8(pData));
377
+					for (uint8_t i = 0; i < this->ply->nTracks; ++i)
378
+						this->ply->tracks[this->ply->trackIds[i]].updateFlags.set(TUF_VOL);
379
+					break;
380
+
381
+				case SSEQ_CMD_PRIO:
382
+					this->prio = this->ply->prio + read8(pData);
383
+					// Update here?
384
+					break;
385
+
386
+				case SSEQ_CMD_NOTEWAIT:
387
+					this->state.set(TS_NOTEWAIT, !!read8(pData));
388
+					break;
389
+
390
+				case SSEQ_CMD_TIE:
391
+					this->state.set(TS_TIEBIT, !!read8(pData));
392
+					this->ReleaseAllNotes();
393
+					break;
394
+
395
+				case SSEQ_CMD_EXPR:
396
+					this->expr = read8(pData);
397
+					this->updateFlags.set(TUF_VOL);
398
+					break;
399
+
400
+				case SSEQ_CMD_TEMPO:
401
+					this->ply->tempo = read16(pData);
402
+					break;
403
+
404
+				case SSEQ_CMD_END:
405
+					this->state.set(TS_END);
406
+					return;
407
+
408
+				case SSEQ_CMD_LOOPSTART:
409
+					this->loopCount[this->stackPos] = read8(pData);
410
+					this->stack[this->stackPos++] = *pData;
411
+					break;
412
+
413
+				case SSEQ_CMD_LOOPEND:
414
+					if (this->stackPos)
415
+					{
416
+						const uint8_t *rPos = this->stack[this->stackPos - 1];
417
+						uint8_t &nR = this->loopCount[this->stackPos - 1];
418
+						uint8_t prevR = nR;
419
+						if (prevR && !--nR)
420
+							--this->stackPos;
421
+						*pData = rPos;
422
+					}
423
+					break;
424
+
425
+				//-----------------------------------------------------------------
426
+				// Tuning commands
427
+				//-----------------------------------------------------------------
428
+
429
+				case SSEQ_CMD_TRANSPOSE:
430
+					this->transpose = read8(pData);
431
+					break;
432
+
433
+				case SSEQ_CMD_PITCHBEND:
434
+					this->pitchBend = read8(pData);
435
+					this->updateFlags.set(TUF_TIMER);
436
+					break;
437
+
438
+				case SSEQ_CMD_PITCHBENDRANGE:
439
+					this->pitchBendRange = read8(pData);
440
+					this->updateFlags.set(TUF_TIMER);
441
+					break;
442
+
443
+				//-----------------------------------------------------------------
444
+				// Envelope-related commands
445
+				//-----------------------------------------------------------------
446
+
447
+				case SSEQ_CMD_ATTACK:
448
+					this->a = read8(pData);
449
+					break;
450
+
451
+				case SSEQ_CMD_DECAY:
452
+					this->d = read8(pData);
453
+					break;
454
+
455
+				case SSEQ_CMD_SUSTAIN:
456
+					this->s = read8(pData);
457
+					break;
458
+
459
+				case SSEQ_CMD_RELEASE:
460
+					this->r = read8(pData);
461
+					break;
462
+
463
+				//-----------------------------------------------------------------
464
+				// Portamento-related commands
465
+				//-----------------------------------------------------------------
466
+
467
+				case SSEQ_CMD_PORTAKEY:
468
+					this->portaKey = read8(pData) + this->transpose;
469
+					this->state.set(TS_PORTABIT);
470
+					// Update here?
471
+					break;
472
+
473
+				case SSEQ_CMD_PORTAFLAG:
474
+					this->state.set(TS_PORTABIT, !!read8(pData));
475
+					// Update here?
476
+					break;
477
+
478
+				case SSEQ_CMD_PORTATIME:
479
+					this->portaTime = read8(pData);
480
+					// Update here?
481
+					break;
482
+
483
+				case SSEQ_CMD_SWEEPPITCH:
484
+					this->sweepPitch = read16(pData);
485
+					// Update here?
486
+					break;
487
+
488
+				//-----------------------------------------------------------------
489
+				// Modulation-related commands
490
+				//-----------------------------------------------------------------
491
+
492
+				case SSEQ_CMD_MODDEPTH:
493
+					this->modDepth = read8(pData);
494
+					this->updateFlags.set(TUF_MOD);
495
+					break;
496
+
497
+				case SSEQ_CMD_MODSPEED:
498
+					this->modSpeed = read8(pData);
499
+					this->updateFlags.set(TUF_MOD);
500
+					break;
501
+
502
+				case SSEQ_CMD_MODTYPE:
503
+					this->modType = read8(pData);
504
+					this->updateFlags.set(TUF_MOD);
505
+					break;
506
+
507
+				case SSEQ_CMD_MODRANGE:
508
+					this->modRange = read8(pData);
509
+					this->updateFlags.set(TUF_MOD);
510
+					break;
511
+
512
+				case SSEQ_CMD_MODDELAY:
513
+					this->modDelay = read16(pData);
514
+					this->updateFlags.set(TUF_MOD);
515
+					break;
516
+
517
+				//-----------------------------------------------------------------
518
+				// Variable-related commands
519
+				//-----------------------------------------------------------------
520
+
521
+				case SSEQ_CMD_RANDOM: // TODO
522
+					*pData += 5;
523
+					break;
524
+
525
+				case SSEQ_CMD_PRINTVAR: // TODO
526
+					*pData += 1;
527
+					break;
528
+
529
+				case SSEQ_CMD_UNSUP1: // TODO
530
+				{
531
+					int t = read8(pData);
532
+					if (t >= SSEQ_CMD_UNSUP2_LO && t <= SSEQ_CMD_UNSUP2_HI)
533
+						*pData += 1;
534
+					*pData += 1;
535
+					break;
536
+				}
537
+
538
+				case SSEQ_CMD_IF: // TODO
539
+					break;
540
+
541
+				default:
542
+					if (cmd >= SSEQ_CMD_UNSUP2_LO && cmd <= SSEQ_CMD_UNSUP2_HI) // TODO
543
+						*pData += 3;
544
+			}
545
+	}
546
+}