1
1
Fork 0
mirror of https://github.com/QB64-Phoenix-Edition/QB64pe.git synced 2024-07-09 23:35:13 +00:00

Merge pull request #329 from a740g/audio-fixes-improvements

RAD v1 support
This commit is contained in:
Samuel Gomes 2023-04-06 18:25:22 +05:30 committed by GitHub
commit 3046d97845
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 1547 additions and 1080 deletions

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -10,11 +10,7 @@
*/
#include <stdint.h>
#include <cstdint>
//==================================================================================================
// The error strings are all supplied here in case you want to translate them to another language
@ -41,7 +37,138 @@ const char *g_RADPattBadEffect = "Pattern contains a bad effect and/or parameter
const char *g_RADBadRiffNum = "Tune file contains a bad riff index.";
const char *g_RADExtraBytes = "Tune file contains extra bytes.";
//=============================================================================
// Validate a RAD V1 file. -Lachesis
//=============================================================================
static const char *RADValidate10(const void *data, const uint8_t *end) {
const uint8_t *start = (const uint8_t *)data;
const uint8_t *pos = start;
uint16_t pattern_offsets[32];
uint32_t i;
bool pattern_used[32] = {false};
bool last_line;
bool last_note;
// NOTE: an extra byte was allocated and set to null so some extra tracks
// would pass this, so bump the end pointer.
end++;
// Description
pos += 17;
if (*(pos++) & 0x80) {
do {
if (pos >= end)
return g_RADTruncated;
} while (*(pos++));
}
// Instruments
while (true) {
uint8_t num = *(pos++);
if (num) {
pos += 11;
if (pos >= end)
return g_RADTruncated;
} else
break;
}
// Order list
uint8_t num_orders = *(pos++);
if (num_orders > 128)
return g_RADOrderListTooLarge;
if (pos + num_orders >= end)
return g_RADTruncated;
for (i = 0; i < num_orders; i++) {
uint8_t order = *(pos++);
// Jump marker
if (order & 0x80) {
order &= 0x7F;
if (order >= num_orders)
return g_RADBadJumpMarker;
}
// Pattern number
else {
if (order >= 32)
return g_RADBadOrderEntry;
// Mark used patterns for validation.
// TODO: possibly walk through the order list instead so unreached
// orders don't have their patterns marked used.
pattern_used[order] = true;
}
}
// Pattern offset table
if (pos + 64 >= end)
return g_RADTruncated;
for (i = 0; i < 32; i++) {
// Ignore offsets to unused patterns- usually they will already be
// zero, but "blue_ad.rad" has unused garbage patterns that will fail
// validation despite the track otherwise working fine.
pattern_offsets[i] = pattern_used[i] ? (pos[0] | (pos[1] << 8)) : 0;
pos += 2;
if (pattern_used[i] && (start + pattern_offsets[i] >= end))
return g_RADPattTruncated;
}
// Patterns
for (i = 0; i < 32; i++) {
if (!pattern_offsets[i])
continue;
pos = start + pattern_offsets[i];
do {
// Line number
uint8_t line_num = *(pos++);
if ((line_num & 0x7F) >= 64)
return g_RADPattBadLineNum;
last_line = (line_num & 0x80) ? true : false;
do {
if (pos + 2 >= end)
return g_RADPattTruncated;
// Channel
uint8_t channel = *(pos++);
if ((channel & 0x7F) >= 9)
return g_RADPattBadChanNum;
last_note = (channel & 0x80) ? true : false;
uint8_t b1 = *(pos++);
uint8_t b2 = *(pos++);
// Note
uint8_t note = (b1 & 0x0F);
if (note == 13 || note == 14)
return g_RADPattBadNoteNum;
// Instrument
// uint8_t inst = ((b1 & 0x80) >> 4) | ((b2 & 0xF0) >> 1);
// Effect
uint8_t fx = (b2 & 0x0F);
if (fx) {
// Parameter
// uint8_t param = *pos;
pos++;
}
} while (!last_note);
} while (!last_line);
}
return 0;
}
//==================================================================================================
// Validate a RAD V2 (file format 2.1) tune file. Note, this uses no C++ standard library code.
@ -86,7 +213,7 @@ static const char *RADCheckPattern(const uint8_t *&s, const uint8_t *e, bool rif
return g_RADPattTruncated;
uint8_t note = *s++;
uint8_t notenum = note & 15;
uint8_t octave = (note >> 4) & 7;
// uint8_t octave = (note >> 4) & 7;
if (notenum == 0 || notenum == 13 || notenum == 14)
return g_RADPattBadNoteNum;
}
@ -121,14 +248,16 @@ static const char *RADCheckPattern(const uint8_t *&s, const uint8_t *e, bool rif
return 0;
}
//--------------------------------------------------------------------------------------------------
const char *RADValidate(const void *data, size_t data_size) {
const uint8_t *s = (const uint8_t *)data;
const uint8_t *e = s + data_size;
uint8_t version;
// Check header
if (data_size < 16)
if (data_size < 17)
return g_RADNotATuneFile;
const char *hdrtxt = "RAD by REALiTY!!";
@ -137,7 +266,10 @@ const char *RADValidate(const void *data, size_t data_size) {
return g_RADNotATuneFile;
// Check version
if (s >= e || *s++ != 0x21)
version = *(s++);
if (version == 0x10)
return RADValidate10(data, e);
if (version != 0x21)
return g_RADNotAVersion21Tune;
// Check flags
@ -148,7 +280,8 @@ const char *RADValidate(const void *data, size_t data_size) {
if (flags & 0x80)
return g_RADBadFlags; // Bit 7 is unused
if (flags & 0x40) {
// NOTE: the vanilla validator incorrectly checks 0x40 here.
if (flags & 0x20) {
if (s + 2 > e)
return g_RADTruncated;
uint16_t bpm = s[0] | (uint16_t(s[1]) << 8);
@ -201,7 +334,9 @@ const char *RADValidate(const void *data, size_t data_size) {
return g_RADTruncated;
if (s[2] >> 4)
return g_RADUnknownMIDIVersion;
s += 6;
// NOTE the vanilla validator skips 6 bytes here as if the algorithm
// byte was already skipped. It wasn't, so skip 7 instead.
s += 7;
} else {

File diff suppressed because it is too large Load diff