| ... | ... |
@@ -76,7 +76,7 @@ std::vector<int16_t> AdpcmDecoder::decode(const std::vector<char>& data, uint32_ |
| 76 | 76 |
} |
| 77 | 77 |
std::vector<int16_t> sample; |
| 78 | 78 |
sample.reserve(length << 1); |
| 79 |
- for (int i = 0; i < length; i++) {
|
|
| 79 |
+ for (uint32_t i = 0; i < length; i++) {
|
|
| 80 | 80 |
sample.push_back(getNextSample(data[offset + i] & 0x0f)); |
| 81 | 81 |
sample.push_back(getNextSample(uint8_t(data[offset + i] & 0xf0) >> 4)); |
| 82 | 82 |
} |
| 1 | 1 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,84 @@ |
| 1 |
+#include "adpcmdecoder.h" |
|
| 2 |
+#include <iostream> |
|
| 3 |
+ |
|
| 4 |
+template <typename T, typename T2> |
|
| 5 |
+static inline T clamp(T2 value, T lower, T upper) |
|
| 6 |
+{
|
|
| 7 |
+ return value < lower ? lower : (value > upper ? upper : value); |
|
| 8 |
+} |
|
| 9 |
+ |
|
| 10 |
+template <typename T, typename Container> |
|
| 11 |
+static inline T parseInt(const Container& buffer, int offset) |
|
| 12 |
+{
|
|
| 13 |
+ uint64_t result = 0; |
|
| 14 |
+ for (int i = sizeof(T) - 1; i >= 0; --i) {
|
|
| 15 |
+ result = (result << 8) | uint8_t(buffer[offset + i]); |
|
| 16 |
+ } |
|
| 17 |
+ return T(result); |
|
| 18 |
+} |
|
| 19 |
+ |
|
| 20 |
+static const int16_t adpcmIndex[] = { -1, -1, -1, -1, 2, 4, 6, 8, };
|
|
| 21 |
+ |
|
| 22 |
+static const int16_t adpcmStep[] = {
|
|
| 23 |
+ 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, |
|
| 24 |
+ 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, |
|
| 25 |
+ 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, |
|
| 26 |
+ 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, |
|
| 27 |
+ 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, |
|
| 28 |
+ 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, |
|
| 29 |
+ 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, |
|
| 30 |
+ 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, |
|
| 31 |
+ 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767, |
|
| 32 |
+}; |
|
| 33 |
+static const int16_t maxAdpcmStep = (sizeof(adpcmStep) >> 1) - 1; |
|
| 34 |
+ |
|
| 35 |
+AdpcmDecoder::AdpcmDecoder(int16_t initialPredictor, int16_t initialStep) |
|
| 36 |
+: predictor(initialPredictor), index(clamp<int8_t>(initialStep, 0, maxAdpcmStep)) |
|
| 37 |
+{
|
|
| 38 |
+ // initializers only |
|
| 39 |
+} |
|
| 40 |
+ |
|
| 41 |
+int16_t AdpcmDecoder::getNextSample(uint8_t value) |
|
| 42 |
+{
|
|
| 43 |
+ int16_t step = adpcmStep[index]; |
|
| 44 |
+ int32_t delta = step >> 3; |
|
| 45 |
+ if (value & 0x04) delta += step; |
|
| 46 |
+ if (value & 0x02) delta += step >> 1; |
|
| 47 |
+ if (value & 0x01) delta += step >> 2; |
|
| 48 |
+ if (value & 0x08) delta = -delta; |
|
| 49 |
+ /* |
|
| 50 |
+ // This implementation is simpler and obeys the spec, but it suffers from low-bit rounding |
|
| 51 |
+ // errors that introduce a slow DC drift that causes looping to produce pops. |
|
| 52 |
+ int32_t delta = (int32_t(value & 0x08 ? -step : step) * ((value << 1 & 0x0f) + 0x01)) >> 3; |
|
| 53 |
+ */ |
|
| 54 |
+ if (predictor + delta == -0x8000) {
|
|
| 55 |
+ predictor = -0x8000; |
|
| 56 |
+ } else {
|
|
| 57 |
+ predictor = clamp<int16_t>(predictor + delta, -0x7fff, 0x7fff); |
|
| 58 |
+ } |
|
| 59 |
+ index = clamp<int8_t>(index + adpcmIndex[value & 0x07], 0, maxAdpcmStep); |
|
| 60 |
+ return predictor; |
|
| 61 |
+} |
|
| 62 |
+ |
|
| 63 |
+std::vector<int16_t> AdpcmDecoder::decodeFile(const std::vector<char>& data, uint32_t offset, uint32_t length) |
|
| 64 |
+{
|
|
| 65 |
+ if (!length) {
|
|
| 66 |
+ length = data.size() - offset; |
|
| 67 |
+ } |
|
| 68 |
+ AdpcmDecoder adpcm(parseInt<int16_t>(data, offset), parseInt<int16_t>(data, offset + 2)); |
|
| 69 |
+ return adpcm.decode(data, offset + 4, length - 4); |
|
| 70 |
+} |
|
| 71 |
+ |
|
| 72 |
+std::vector<int16_t> AdpcmDecoder::decode(const std::vector<char>& data, uint32_t offset, uint32_t length) |
|
| 73 |
+{
|
|
| 74 |
+ if (!length) {
|
|
| 75 |
+ length = data.size() - offset; |
|
| 76 |
+ } |
|
| 77 |
+ std::vector<int16_t> sample; |
|
| 78 |
+ sample.reserve(length << 1); |
|
| 79 |
+ for (int i = 0; i < length; i++) {
|
|
| 80 |
+ sample.push_back(getNextSample(data[offset + i] & 0x0f)); |
|
| 81 |
+ sample.push_back(getNextSample(uint8_t(data[offset + i] & 0xf0) >> 4)); |
|
| 82 |
+ } |
|
| 83 |
+ return sample; |
|
| 84 |
+} |