-
Notifications
You must be signed in to change notification settings - Fork 3
/
SWAV.cpp
125 lines (110 loc) · 3.31 KB
/
SWAV.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
/*
* SSEQ Player - SDAT SWAV (Waveform/Sample) structure
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
* Last modification on 2013-04-12
*
* Nintendo DS Nitro Composer (SDAT) Specification document found at
* http://www.feshrine.net/hacking/doc/nds-sdat.html
*/
#include "SWAV.h"
static int ima_index_table[] =
{
-1, -1, -1, -1, 2, 4, 6, 8,
-1, -1, -1, -1, 2, 4, 6, 8
};
static int ima_step_table[] =
{
7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
};
SWAV::SWAV() : waveType(0), loop(0), sampleRate(0), time(0), loopOffset(0), nonLoopLength(0), data(), dataptr(nullptr)
{
}
static inline void DecodeADPCMNibble(int32_t nibble, int32_t &stepIndex, int32_t &predictedValue)
{
int32_t step = ima_step_table[stepIndex];
stepIndex += ima_index_table[nibble];
if (stepIndex < 0)
stepIndex = 0;
else if (stepIndex > 88)
stepIndex = 88;
int32_t diff = step >> 3;
if (nibble & 4)
diff += step;
if (nibble & 2)
diff += step >> 1;
if (nibble & 1)
diff += step >> 2;
if (nibble & 8)
predictedValue -= diff;
else
predictedValue += diff;
if (predictedValue < -0x8000)
predictedValue = -0x8000;
else if (predictedValue > 0x7FFF)
predictedValue = 0x7FFF;
}
void SWAV::DecodeADPCM(const uint8_t *origData, uint32_t len)
{
int32_t predictedValue = origData[0] | (origData[1] << 8);
int32_t stepIndex = origData[2] | (origData[3] << 8);
auto finalData = &this->data[0];
for (uint32_t i = 0; i < len; ++i)
{
int32_t nibble = origData[i + 4] & 0x0F;
DecodeADPCMNibble(nibble, stepIndex, predictedValue);
finalData[2 * i] = predictedValue;
nibble = (origData[i + 4] >> 4) & 0x0F;
DecodeADPCMNibble(nibble, stepIndex, predictedValue);
finalData[2 * i + 1] = predictedValue;
}
}
void SWAV::Read(PseudoFile &file)
{
this->waveType = file.ReadLE<uint8_t>();
this->loop = file.ReadLE<uint8_t>();
this->sampleRate = file.ReadLE<uint16_t>();
this->time = file.ReadLE<uint16_t>();
this->loopOffset = file.ReadLE<uint16_t>();
this->nonLoopLength = file.ReadLE<uint32_t>();
uint32_t size = (this->loopOffset + this->nonLoopLength) * 4;
auto origData = std::vector<uint8_t>(size);
file.ReadLE(origData);
// Convert data accordingly
if (!this->waveType)
{
// PCM 8-bit -> PCM signed 16-bit
this->data.resize(size, 0);
for (size_t i = 0; i < size; ++i)
this->data[i] = origData[i] << 8;
this->loopOffset *= 4;
this->nonLoopLength *= 4;
}
else if (this->waveType == 1)
{
// PCM signed 16-bit, no conversion
this->data.resize(size / 2, 0);
for (size_t i = 0; i < size / 2; ++i)
this->data[i] = ReadLE<int16_t>(&origData[2 * i]);
this->loopOffset *= 2;
this->nonLoopLength *= 2;
}
else if (this->waveType == 2)
{
// IMA ADPCM -> PCM signed 16-bit
this->data.resize((size - 4) * 2, 0);
this->DecodeADPCM(&origData[0], size - 4);
if (this->loopOffset)
--this->loopOffset;
this->loopOffset *= 8;
this->nonLoopLength *= 8;
}
this->dataptr = &this->data[0];
}