mirror of
https://github.com/kevinbentley/Descent3.git
synced 2025-01-22 11:28:56 +00:00
dd32f4e3ed
Logically adecode/aencode belongs to AudioEncode.
1081 lines
32 KiB
C++
1081 lines
32 KiB
C++
/*
|
|
* Descent 3
|
|
* Copyright (C) 2024 Parallax Software
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <cassert>
|
|
#include <cmath>
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
|
|
#include "aencode.h"
|
|
|
|
struct BitsEncoder {
|
|
FILE *m_outFile; // var50 | offset 0x10
|
|
uint32_t m_bitData; // var4C | offset 0x14
|
|
uint32_t m_bitCount; // var48 | offset 0x18
|
|
|
|
void WriteBits(int32_t val, uint32_t numBits) {
|
|
assert((numBits + m_bitCount) <= 32);
|
|
m_bitData |= static_cast<uint32_t>(val << m_bitCount);
|
|
m_bitCount += numBits;
|
|
|
|
while (m_bitCount >= 8) {
|
|
uint8_t v = m_bitData & 0xFF;
|
|
putc(v, m_outFile);
|
|
|
|
m_bitData >>= 8;
|
|
m_bitCount -= 8;
|
|
}
|
|
}
|
|
|
|
void Flush() {
|
|
while (m_bitCount >= 8) {
|
|
uint8_t v = m_bitData & 0xFF;
|
|
putc(v, m_outFile);
|
|
|
|
m_bitData >>= 8;
|
|
m_bitCount -= 8;
|
|
}
|
|
|
|
if (m_bitCount > 0) {
|
|
uint8_t v = m_bitData & 0xFF;
|
|
putc(v, m_outFile);
|
|
m_bitCount = 0;
|
|
m_bitData = 0;
|
|
}
|
|
}
|
|
};
|
|
|
|
struct Encoder {
|
|
ReadSampleFunction *m_reader; // var60 | offset 0x00
|
|
void *m_pReaderData; // var5C | offset 0x04
|
|
uint32_t m_sampleCount; // var58 | offset 0x08
|
|
float m_volume; // var54 | offset 0x0C
|
|
BitsEncoder m_bits; // var50 - var48 | offset 0x10 - 0x18
|
|
int8_t m_levels; // var44* | offset 0x1C
|
|
int8_t m_pad[3]; // 43, 42, 41
|
|
int32_t m_numColumns; // var40 | offset 0x20
|
|
int32_t m_samples_per_subband; // var3C | offset 0x24
|
|
int32_t m_samplesPerBlock; // var38 | offset 0x28
|
|
int32_t m_adjustedSamplesTimeNumColumns; // var34 | offset 0x2C
|
|
float **m_levelSlots; // var30 | offset 0x30
|
|
float *m_pCurrBlockData; // var2C | offset 0x34
|
|
int32_t m_blockSamplesRemaining; // var28 | offset 0x38
|
|
int32_t m_bandWriteEnabled; // var24 | offset 0x3C
|
|
int32_t m_finishedReading; // var20 | offset 0x40
|
|
int32_t m_someVal; // var1C | offset 0x44
|
|
float *m_lo_filter; // var18 | offset 0x48
|
|
float *m_hi_filter; // var14 | offset 0x4C
|
|
uint32_t *m_pFormatIdPerColumn; // var10 | offset 0x50
|
|
int32_t m_currBlockBitPower; // var0C | offset 0x54
|
|
int32_t m_currBlockBitValue; // var08 | offset 0x58
|
|
int32_t m_threshold; // var04 | offset 0x5C
|
|
};
|
|
|
|
typedef void (*WriteBandFunc)(Encoder &enc, int32_t colIndex, uint32_t packerId);
|
|
void WriteBand_Fmt0(Encoder &enc, int32_t colIndex, uint32_t packerId);
|
|
void WriteBand_Fmt3_16(Encoder &enc, int32_t colIndex, uint32_t packerId);
|
|
void WriteBand_Fmt17(Encoder &enc, int32_t colIndex, uint32_t packerId);
|
|
void WriteBand_Fmt18(Encoder &enc, int32_t colIndex, uint32_t packerId);
|
|
void WriteBand_Fmt19(Encoder &enc, int32_t colIndex, uint32_t packerId);
|
|
void WriteBand_Fmt20(Encoder &enc, int32_t colIndex, uint32_t packerId);
|
|
void WriteBand_Fmt21(Encoder &enc, int32_t colIndex, uint32_t packerId);
|
|
void WriteBand_Fmt22(Encoder &enc, int32_t colIndex, uint32_t packerId);
|
|
void WriteBand_Fmt23(Encoder &enc, int32_t colIndex, uint32_t packerId);
|
|
void WriteBand_Fmt24(Encoder &enc, int32_t colIndex, uint32_t packerId);
|
|
void WriteBand_Fmt26(Encoder &enc, int32_t colIndex, uint32_t packerId);
|
|
void WriteBand_Fmt27(Encoder &enc, int32_t colIndex, uint32_t packerId);
|
|
void WriteBand_Fmt29(Encoder &enc, int32_t colIndex, uint32_t packerId);
|
|
|
|
WriteBandFunc WriteBand_tbl[] = {WriteBand_Fmt0,
|
|
NULL,
|
|
NULL,
|
|
WriteBand_Fmt3_16,
|
|
WriteBand_Fmt3_16,
|
|
WriteBand_Fmt3_16,
|
|
WriteBand_Fmt3_16,
|
|
WriteBand_Fmt3_16,
|
|
WriteBand_Fmt3_16,
|
|
WriteBand_Fmt3_16,
|
|
WriteBand_Fmt3_16,
|
|
WriteBand_Fmt3_16,
|
|
WriteBand_Fmt3_16,
|
|
WriteBand_Fmt3_16,
|
|
WriteBand_Fmt3_16,
|
|
WriteBand_Fmt3_16,
|
|
WriteBand_Fmt3_16,
|
|
WriteBand_Fmt17,
|
|
WriteBand_Fmt18,
|
|
WriteBand_Fmt19,
|
|
WriteBand_Fmt20,
|
|
WriteBand_Fmt21,
|
|
WriteBand_Fmt22,
|
|
WriteBand_Fmt23,
|
|
WriteBand_Fmt24,
|
|
NULL,
|
|
WriteBand_Fmt26,
|
|
WriteBand_Fmt27,
|
|
NULL,
|
|
WriteBand_Fmt29,
|
|
NULL,
|
|
NULL};
|
|
|
|
float std_lo_filter[] = {
|
|
-0.0012475221f, -0.0024950907f, 0.0087309526f, 0.019957958f, -0.050528999f, -0.12055097f, 0.29304558f, 0.70617616f,
|
|
};
|
|
|
|
float std_hi_filter[] = {
|
|
0.0012475221f, -0.0024950907f, -0.0087309526f, 0.019957958f, 0.050528999f, -0.12055097f, -0.29304558f, 0.70617616f,
|
|
};
|
|
|
|
const float T911 = -32767.0f;
|
|
const float T913 = 32767.0f;
|
|
const float T1266 = 0.0f;
|
|
|
|
void WriteBand_Fmt0(Encoder &enc, int32_t colIndex, uint32_t formatId) {}
|
|
|
|
void WriteBand_Fmt3_16(Encoder &enc, int32_t colIndex, uint32_t formatId) {
|
|
const float currBlockValue = float(enc.m_currBlockBitValue);
|
|
const float halfCurrBlockValue = currBlockValue * 0.5f;
|
|
const int32_t minValue = (int32_t)ceilf(-32767.0f / currBlockValue);
|
|
const int32_t maxValue = (int32_t)floorf(32767.0f / currBlockValue);
|
|
|
|
float *pColumnData = &enc.m_levelSlots[enc.m_levels][colIndex];
|
|
for (int32_t i = 0; i < enc.m_samples_per_subband; ++i) {
|
|
int32_t val = (int32_t)floorf((*pColumnData + halfCurrBlockValue) / currBlockValue);
|
|
if (minValue > val) {
|
|
val = minValue;
|
|
} else if (val > maxValue) {
|
|
val = maxValue;
|
|
}
|
|
|
|
pColumnData += enc.m_numColumns;
|
|
enc.m_bits.WriteBits(val + (1 << (formatId - 1)), formatId);
|
|
}
|
|
}
|
|
|
|
void WriteBand_Fmt17(Encoder &enc, int32_t colIndex, uint32_t formatId) {
|
|
const float currBitValue = static_cast<float>(enc.m_currBlockBitValue);
|
|
const float halfCurrBitValue = currBitValue * 0.5f;
|
|
const int32_t minValue = (int32_t)ceilf(-32767.0f / currBitValue);
|
|
const int32_t maxValue = (int32_t)floorf(32767.0f / currBitValue);
|
|
|
|
const float *pCurrSample = &enc.m_levelSlots[enc.m_levels][colIndex];
|
|
int32_t currSampleIndex = enc.m_samples_per_subband;
|
|
while (currSampleIndex) {
|
|
--currSampleIndex;
|
|
int32_t val = (int32_t)floorf((*pCurrSample + halfCurrBitValue) / currBitValue);
|
|
if (minValue > val) {
|
|
val = minValue;
|
|
} else if (maxValue < val) {
|
|
val = maxValue;
|
|
}
|
|
|
|
pCurrSample += enc.m_numColumns;
|
|
if (val == 0) {
|
|
if (currSampleIndex != 0 && !(int)floorf((*pCurrSample + halfCurrBitValue) / currBitValue)) {
|
|
enc.m_bits.WriteBits(0, 1);
|
|
|
|
if (currSampleIndex == 0)
|
|
return;
|
|
--currSampleIndex;
|
|
pCurrSample += enc.m_numColumns;
|
|
continue;
|
|
}
|
|
|
|
enc.m_bits.WriteBits(1, 2);
|
|
continue;
|
|
}
|
|
|
|
enc.m_bits.WriteBits(3, 2);
|
|
enc.m_bits.WriteBits((val == 1) ? 1 : 0, 1);
|
|
}
|
|
}
|
|
|
|
void WriteBand_Fmt18(Encoder &enc, int32_t colIndex, uint32_t formatId) {
|
|
const float currBlockBitValue = static_cast<float>(enc.m_currBlockBitValue);
|
|
const float halfCurrBlockBitValue = enc.m_currBlockBitValue * 0.5f;
|
|
const int32_t minValue = (int32_t)ceilf(-32767.0f / currBlockBitValue);
|
|
const int32_t maxValue = (int32_t)floorf(32767.0f / currBlockBitValue);
|
|
|
|
const float *pCurrSample = &enc.m_levelSlots[enc.m_levels][colIndex];
|
|
int32_t currSampleIndex = enc.m_samples_per_subband;
|
|
while (currSampleIndex) {
|
|
--currSampleIndex;
|
|
int32_t val = (int32_t)floorf((*pCurrSample + halfCurrBlockBitValue) / currBlockBitValue);
|
|
if (minValue > val) {
|
|
val = minValue;
|
|
} else if (val > maxValue) {
|
|
val = maxValue;
|
|
}
|
|
|
|
pCurrSample += enc.m_numColumns;
|
|
|
|
if (!val) {
|
|
enc.m_bits.WriteBits(0, 1);
|
|
continue;
|
|
}
|
|
|
|
enc.m_bits.WriteBits(1, 1);
|
|
enc.m_bits.WriteBits((val == 1) ? 1 : 0, 1);
|
|
}
|
|
}
|
|
|
|
void WriteBand_Fmt19(Encoder &enc, int32_t colIndex, uint32_t formatId) {
|
|
const float currBlockBitValue = static_cast<float>(enc.m_currBlockBitValue);
|
|
const float halfCurrBlockBitValue = currBlockBitValue * 0.5f;
|
|
const int32_t minValue = (int32_t)ceilf(-32767.0f / currBlockBitValue);
|
|
const int32_t maxValue = (int32_t)floorf(32767.0f / currBlockBitValue);
|
|
|
|
const float *pCurrSample = &enc.m_levelSlots[enc.m_levels][colIndex];
|
|
int32_t currSampleIndex = enc.m_samples_per_subband;
|
|
while (currSampleIndex) {
|
|
--currSampleIndex;
|
|
int32_t workingVal = (int32_t)floorf((*pCurrSample + halfCurrBlockBitValue) / currBlockBitValue);
|
|
if (minValue > workingVal) {
|
|
workingVal = minValue;
|
|
} else if (maxValue < workingVal) {
|
|
workingVal = maxValue;
|
|
}
|
|
pCurrSample += enc.m_numColumns;
|
|
int32_t baseValue = workingVal + 1;
|
|
if (currSampleIndex) {
|
|
--currSampleIndex;
|
|
workingVal = (int32_t)floorf((*pCurrSample + halfCurrBlockBitValue) / currBlockBitValue);
|
|
if (minValue > workingVal) {
|
|
workingVal = minValue;
|
|
} else if (maxValue < workingVal) {
|
|
workingVal = maxValue;
|
|
}
|
|
pCurrSample += enc.m_numColumns;
|
|
} else {
|
|
workingVal = 0;
|
|
}
|
|
|
|
baseValue += workingVal * 3 + 3;
|
|
if (currSampleIndex) {
|
|
--currSampleIndex;
|
|
workingVal = (int32_t)floorf((*pCurrSample + halfCurrBlockBitValue) / currBlockBitValue);
|
|
if (minValue > workingVal) {
|
|
workingVal = minValue;
|
|
} else if (maxValue < workingVal) {
|
|
workingVal = maxValue;
|
|
}
|
|
pCurrSample += enc.m_numColumns;
|
|
} else {
|
|
workingVal = 0;
|
|
}
|
|
|
|
enc.m_bits.WriteBits(workingVal * 9 + 9 + baseValue, 5);
|
|
}
|
|
}
|
|
|
|
void WriteBand_Fmt20(Encoder &enc, int32_t colIndex, uint32_t formatId) {
|
|
const float currBlockValue = static_cast<float>(enc.m_currBlockBitValue);
|
|
const float halfCurrBlockValue = currBlockValue * 0.5f;
|
|
const int32_t minValue = (int32_t)ceilf(-32767.0f / currBlockValue);
|
|
const int32_t maxValue = (int32_t)floorf(32767.0f / currBlockValue);
|
|
|
|
const float *pCurrSample = &enc.m_levelSlots[enc.m_levels][colIndex];
|
|
int32_t currSampleIndex = enc.m_samples_per_subband;
|
|
while (currSampleIndex) {
|
|
--currSampleIndex;
|
|
int32_t val = (int32_t)floorf((*pCurrSample + halfCurrBlockValue) / currBlockValue);
|
|
if (minValue > val) {
|
|
val = minValue;
|
|
} else if (maxValue < val) {
|
|
val = maxValue;
|
|
}
|
|
|
|
pCurrSample += enc.m_numColumns;
|
|
if (val == 0) {
|
|
if (currSampleIndex != 0 && !(int32_t)floorf((*pCurrSample + halfCurrBlockValue) / currBlockValue)) {
|
|
enc.m_bits.WriteBits(0, 1);
|
|
|
|
if (currSampleIndex == 0)
|
|
return;
|
|
--currSampleIndex;
|
|
pCurrSample += enc.m_numColumns;
|
|
continue;
|
|
}
|
|
enc.m_bits.WriteBits(1, 2);
|
|
continue;
|
|
}
|
|
enc.m_bits.WriteBits(3, 2);
|
|
if (val < 0) {
|
|
val += 2;
|
|
} else {
|
|
++val;
|
|
}
|
|
|
|
enc.m_bits.WriteBits(val, 2);
|
|
}
|
|
}
|
|
|
|
void WriteBand_Fmt21(Encoder &enc, int32_t colIndex, uint32_t formatId) {
|
|
const float currBlockValue = static_cast<float>(enc.m_currBlockBitValue);
|
|
const float halfCurrBlockValue = currBlockValue * 0.5f;
|
|
const int32_t minValue = (int32_t)ceilf(-32767.0f / currBlockValue);
|
|
const int32_t maxValue = (int32_t)floorf(32767.0f / currBlockValue);
|
|
|
|
const float *pCurrSample = &enc.m_levelSlots[enc.m_levels][colIndex];
|
|
int32_t currSampleIndex = enc.m_samples_per_subband;
|
|
while (currSampleIndex) {
|
|
--currSampleIndex;
|
|
int32_t val = (int32_t)floorf((*pCurrSample + halfCurrBlockValue) / currBlockValue);
|
|
if (minValue > val) {
|
|
val = minValue;
|
|
} else if (maxValue < val) {
|
|
val = maxValue;
|
|
}
|
|
|
|
pCurrSample += enc.m_numColumns;
|
|
if (!val) {
|
|
enc.m_bits.WriteBits(0, 1);
|
|
continue;
|
|
}
|
|
enc.m_bits.WriteBits(1, 1);
|
|
|
|
if (val < 0) {
|
|
val += 2;
|
|
} else {
|
|
++val;
|
|
}
|
|
|
|
enc.m_bits.WriteBits(val, 2);
|
|
}
|
|
}
|
|
|
|
void WriteBand_Fmt22(Encoder &enc, int32_t colIndex, uint32_t formatId) {
|
|
const float currBlockValue = static_cast<float>(enc.m_currBlockBitValue);
|
|
const float halfCurrBlockValue = currBlockValue * 0.5f;
|
|
const int32_t minValue = (int32_t)ceilf(-32767.0f / currBlockValue);
|
|
const int32_t maxValue = (int32_t)floorf(32767.0f / currBlockValue);
|
|
|
|
const float *pCurrSample = &enc.m_levelSlots[enc.m_levels][colIndex];
|
|
|
|
int32_t currSampleIndex = enc.m_samples_per_subband;
|
|
while (currSampleIndex) {
|
|
--currSampleIndex;
|
|
int32_t workingVal = (int32_t)floorf((*pCurrSample + halfCurrBlockValue) / currBlockValue);
|
|
if (minValue > workingVal) {
|
|
workingVal = minValue;
|
|
} else if (maxValue < workingVal) {
|
|
workingVal = maxValue;
|
|
}
|
|
|
|
int32_t baseValue = workingVal + 2;
|
|
pCurrSample += enc.m_numColumns;
|
|
if (currSampleIndex) {
|
|
--currSampleIndex;
|
|
workingVal = (int32_t)floorf((*pCurrSample + halfCurrBlockValue) / currBlockValue);
|
|
if (minValue > workingVal) {
|
|
workingVal = minValue;
|
|
} else if (maxValue < workingVal) {
|
|
workingVal = maxValue;
|
|
}
|
|
pCurrSample += enc.m_numColumns;
|
|
} else {
|
|
workingVal = 0;
|
|
}
|
|
|
|
baseValue += workingVal * 5 + 10;
|
|
if (currSampleIndex) {
|
|
--currSampleIndex;
|
|
workingVal = (int32_t)floorf((*pCurrSample + halfCurrBlockValue) / currBlockValue);
|
|
if (minValue > workingVal) {
|
|
workingVal = minValue;
|
|
} else if (maxValue < workingVal) {
|
|
workingVal = maxValue;
|
|
}
|
|
pCurrSample += enc.m_numColumns;
|
|
} else {
|
|
workingVal = 0;
|
|
}
|
|
|
|
enc.m_bits.WriteBits(workingVal * 25 + 50 + baseValue, 7);
|
|
}
|
|
}
|
|
|
|
void WriteBand_Fmt23(Encoder &enc, int32_t colIndex, uint32_t formatId) {
|
|
const float currBlockValue = static_cast<float>(enc.m_currBlockBitValue);
|
|
const float halfCurrBlockValue = currBlockValue * 0.5f;
|
|
const int32_t minValue = (int32_t)ceilf(-32767.0f / currBlockValue);
|
|
const int32_t maxValue = (int32_t)floorf(32767.0f / currBlockValue);
|
|
|
|
const float *pCurrSample = &enc.m_levelSlots[enc.m_levels][colIndex];
|
|
int32_t currSampleIndex = enc.m_samples_per_subband;
|
|
while (currSampleIndex) {
|
|
--currSampleIndex;
|
|
|
|
int32_t val = (int32_t)floorf((*pCurrSample + halfCurrBlockValue) / currBlockValue);
|
|
if (minValue > val) {
|
|
val = minValue;
|
|
} else if (maxValue < val) {
|
|
val = maxValue;
|
|
}
|
|
|
|
pCurrSample += enc.m_numColumns;
|
|
if (!val) {
|
|
if (currSampleIndex != 0) {
|
|
if (!(int32_t)floorf((*pCurrSample + halfCurrBlockValue) / currBlockValue)) {
|
|
enc.m_bits.WriteBits(0, 1);
|
|
|
|
if (currSampleIndex == 0)
|
|
return;
|
|
--currSampleIndex;
|
|
|
|
pCurrSample += enc.m_numColumns;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
enc.m_bits.WriteBits(1, 2);
|
|
continue;
|
|
}
|
|
|
|
enc.m_bits.WriteBits(3, 2);
|
|
|
|
if (val != -1 && val != 1) {
|
|
enc.m_bits.WriteBits(1, 1);
|
|
|
|
if (val < 0) {
|
|
val += 3;
|
|
}
|
|
|
|
enc.m_bits.WriteBits(val, 2);
|
|
continue;
|
|
}
|
|
|
|
enc.m_bits.WriteBits(0, 1);
|
|
enc.m_bits.WriteBits((val == 1) ? 1 : 0, 1);
|
|
}
|
|
}
|
|
|
|
void WriteBand_Fmt24(Encoder &enc, int32_t colIndex, uint32_t formatId) {
|
|
const float currBlockBitValue = static_cast<float>(enc.m_currBlockBitValue);
|
|
const float halfCurrBlockBitValue = currBlockBitValue * 0.5f;
|
|
const int32_t minValue = (int32_t)ceilf(-32767.0f / currBlockBitValue);
|
|
const int32_t maxValue = (int32_t)floorf(32767.0f / currBlockBitValue);
|
|
|
|
const float *pCurrSample = &enc.m_levelSlots[enc.m_levels][colIndex];
|
|
int32_t currSampleIndex = enc.m_samples_per_subband;
|
|
while (currSampleIndex) {
|
|
--currSampleIndex;
|
|
int32_t val = (int32_t)floorf((*pCurrSample + halfCurrBlockBitValue) / currBlockBitValue);
|
|
if (minValue > val) {
|
|
val = minValue;
|
|
} else if (maxValue < val) {
|
|
val = maxValue;
|
|
}
|
|
|
|
pCurrSample += enc.m_numColumns;
|
|
if (!val) {
|
|
enc.m_bits.WriteBits(0, 1);
|
|
continue;
|
|
}
|
|
|
|
enc.m_bits.WriteBits(1, 1);
|
|
|
|
if (val != -1 && val != 1) {
|
|
enc.m_bits.WriteBits(1, 1);
|
|
|
|
if (val < 0) {
|
|
val += 3;
|
|
}
|
|
enc.m_bits.WriteBits(val, 2);
|
|
continue;
|
|
}
|
|
|
|
enc.m_bits.WriteBits(0, 1);
|
|
enc.m_bits.WriteBits((val == 1) ? 1 : 0, 1);
|
|
}
|
|
}
|
|
|
|
void WriteBand_Fmt26(Encoder &enc, int32_t colIndex, uint32_t formatId) {
|
|
const float currBlockValue = static_cast<float>(enc.m_currBlockBitValue);
|
|
const float halfCurrBlockValue = currBlockValue * 0.5f;
|
|
const int32_t minValue = static_cast<int32_t>(ceilf(-32767.0f / currBlockValue));
|
|
const int32_t maxValue = static_cast<int32_t>(floorf(32767.0f / currBlockValue));
|
|
const float *pColumnData = &enc.m_levelSlots[enc.m_levels][colIndex];
|
|
|
|
int32_t currSampleIdx = enc.m_samples_per_subband;
|
|
while (currSampleIdx) {
|
|
--currSampleIdx;
|
|
|
|
int32_t val = (int32_t)floorf((*pColumnData + halfCurrBlockValue) / currBlockValue);
|
|
if (minValue > val) {
|
|
val = minValue;
|
|
} else if (maxValue < val) {
|
|
val = maxValue;
|
|
}
|
|
|
|
pColumnData += enc.m_numColumns;
|
|
if (!val) {
|
|
if (currSampleIdx) {
|
|
int32_t testVal = (int32_t)floorf((*pColumnData + halfCurrBlockValue) / currBlockValue);
|
|
if (!testVal) {
|
|
enc.m_bits.WriteBits(0, 1);
|
|
|
|
if (currSampleIdx == 0)
|
|
return;
|
|
|
|
--currSampleIdx;
|
|
pColumnData += enc.m_numColumns;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
enc.m_bits.WriteBits(1, 2);
|
|
continue;
|
|
}
|
|
|
|
enc.m_bits.WriteBits(3, 2);
|
|
|
|
if (val >= 0) {
|
|
val += 3;
|
|
} else {
|
|
val += 4;
|
|
}
|
|
|
|
enc.m_bits.WriteBits(val, 3);
|
|
}
|
|
}
|
|
|
|
void WriteBand_Fmt27(Encoder &enc, int32_t colIndex, uint32_t formatId) {
|
|
const float currBlockValue = static_cast<float>(enc.m_currBlockBitValue);
|
|
const float halfCurrBlockValue = currBlockValue * 0.5f;
|
|
const int32_t minValue = (int32_t)ceilf(-32767.0f / currBlockValue);
|
|
const int32_t maxValue = (int32_t)floorf(32767.0f / currBlockValue);
|
|
|
|
const float *pCurrSample = &enc.m_levelSlots[enc.m_levels][colIndex];
|
|
int32_t currSampleIndex = enc.m_samples_per_subband;
|
|
while (currSampleIndex) {
|
|
--currSampleIndex;
|
|
int32_t val = (int32_t)floorf((*pCurrSample + halfCurrBlockValue) / currBlockValue);
|
|
if (val < minValue) {
|
|
val = minValue;
|
|
} else if (maxValue < val) {
|
|
val = maxValue;
|
|
}
|
|
|
|
pCurrSample += enc.m_numColumns;
|
|
if (!val) {
|
|
enc.m_bits.WriteBits(0, 1);
|
|
continue;
|
|
}
|
|
|
|
enc.m_bits.WriteBits(1, 1);
|
|
|
|
if (val < 0) {
|
|
val += 4;
|
|
} else {
|
|
val += 3;
|
|
}
|
|
|
|
enc.m_bits.WriteBits(val, 3);
|
|
}
|
|
}
|
|
|
|
void WriteBand_Fmt29(Encoder &enc, int32_t colIndex, uint32_t formatId) {
|
|
const float currBitValue = (float)enc.m_currBlockBitValue;
|
|
const float halfCurrBitValue = currBitValue * 0.5f;
|
|
const int32_t minValue = (int32_t)ceilf(-32767.0f / currBitValue);
|
|
const int32_t maxValue = (int32_t)floorf(32767.0f / currBitValue);
|
|
|
|
const float *pColumnData = &enc.m_levelSlots[enc.m_levels][colIndex];
|
|
int32_t currSampleIndex = enc.m_samples_per_subband;
|
|
while (currSampleIndex) {
|
|
--currSampleIndex;
|
|
|
|
int32_t val = (int32_t)floorf((*pColumnData + halfCurrBitValue) / currBitValue);
|
|
if (minValue > val) {
|
|
val = minValue;
|
|
} else if (maxValue < val) {
|
|
val = maxValue;
|
|
}
|
|
|
|
int32_t baseValue = val + 5;
|
|
pColumnData += enc.m_numColumns;
|
|
if (currSampleIndex != 0) {
|
|
--currSampleIndex;
|
|
|
|
val = (int32_t)floorf((*pColumnData + halfCurrBitValue) / currBitValue);
|
|
if (minValue > val) {
|
|
val = minValue;
|
|
} else if (maxValue < val) {
|
|
val = maxValue;
|
|
}
|
|
|
|
pColumnData += enc.m_numColumns;
|
|
} else {
|
|
val = 0;
|
|
}
|
|
|
|
enc.m_bits.WriteBits(11 * val + 55 + baseValue, 7);
|
|
}
|
|
}
|
|
|
|
int ReadSample_init(Encoder &enc, ReadSampleFunction *read, void *data) {
|
|
enc.m_reader = read;
|
|
enc.m_pReaderData = data;
|
|
return 1;
|
|
}
|
|
|
|
int bits_init(BitsEncoder &bits, FILE *out) {
|
|
bits.m_outFile = out;
|
|
bits.m_bitData = 0;
|
|
bits.m_bitCount = 0;
|
|
return 1;
|
|
}
|
|
|
|
int SetupEncoder(Encoder &enc, int someVal, float std_lo_filter[], float std_hi_filter[], int8_t levels,
|
|
int samples_per_subband) {
|
|
enc.m_someVal = someVal;
|
|
enc.m_lo_filter = std_lo_filter;
|
|
enc.m_hi_filter = std_hi_filter;
|
|
enc.m_levels = levels;
|
|
enc.m_numColumns = 1 << levels;
|
|
enc.m_samples_per_subband = samples_per_subband;
|
|
enc.m_samplesPerBlock = samples_per_subband * enc.m_numColumns;
|
|
|
|
int adjustedSomeVal = (((someVal < -1) ? (someVal + 1) : (someVal)) + 1) >> 1;
|
|
enc.m_adjustedSamplesTimeNumColumns = adjustedSomeVal * (enc.m_numColumns - 1);
|
|
enc.m_levelSlots = reinterpret_cast<float **>(malloc(sizeof(float *) * (levels + 1)));
|
|
if (enc.m_levelSlots == NULL)
|
|
return 0;
|
|
|
|
if (levels >= 0) {
|
|
for (int8_t i = 0; i <= levels; ++i) {
|
|
int extraSamples = 0;
|
|
if (i != levels) {
|
|
extraSamples = (someVal - 1) << i;
|
|
}
|
|
|
|
float *blockData = reinterpret_cast<float *>(malloc((enc.m_samplesPerBlock + extraSamples) * sizeof(float)));
|
|
enc.m_levelSlots[i] = blockData;
|
|
if (blockData == NULL)
|
|
return 0;
|
|
|
|
memset(blockData, 0, (enc.m_samplesPerBlock + extraSamples) * sizeof(float));
|
|
enc.m_levelSlots[i] += extraSamples;
|
|
}
|
|
}
|
|
|
|
enc.m_pFormatIdPerColumn = reinterpret_cast<uint32_t *>(malloc(enc.m_numColumns * sizeof(uint32_t)));
|
|
if (enc.m_pFormatIdPerColumn == NULL)
|
|
return 0;
|
|
|
|
enc.m_sampleCount = 0;
|
|
|
|
int32_t edxOffset =
|
|
((enc.m_samplesPerBlock * sizeof(float) * 25) - enc.m_adjustedSamplesTimeNumColumns) % enc.m_samplesPerBlock;
|
|
enc.m_pCurrBlockData = enc.m_levelSlots[0] + edxOffset;
|
|
enc.m_blockSamplesRemaining = enc.m_samplesPerBlock - edxOffset;
|
|
enc.m_bandWriteEnabled = 0;
|
|
enc.m_finishedReading = 0;
|
|
return 1;
|
|
}
|
|
|
|
void DestroyEncoder(Encoder &enc) {
|
|
if (enc.m_levelSlots != NULL) {
|
|
for (int i = 0; i <= enc.m_levels; ++i) {
|
|
if (enc.m_levelSlots[i] != 0) {
|
|
int extraSamples = 0;
|
|
if (enc.m_levels != i) {
|
|
extraSamples = (enc.m_someVal - 1) << i;
|
|
}
|
|
|
|
free(enc.m_levelSlots[i] - extraSamples);
|
|
}
|
|
}
|
|
|
|
free(enc.m_levelSlots);
|
|
}
|
|
|
|
if (enc.m_pFormatIdPerColumn != NULL) {
|
|
free(enc.m_pFormatIdPerColumn);
|
|
}
|
|
}
|
|
|
|
void transform_subband(Encoder &enc, float *pD0, float *pD1, int32_t subBandCount, int32_t sampleCount) {
|
|
if (sampleCount <= 0)
|
|
return;
|
|
|
|
const int32_t var_8 = (enc.m_someVal - 1) >> 1;
|
|
const int32_t edx = var_8 * subBandCount;
|
|
pD0 -= edx;
|
|
|
|
for (int i = 0; i < sampleCount; ++i) {
|
|
float *pFilter = (i & 1) ? enc.m_hi_filter : enc.m_lo_filter;
|
|
float *ebx = pD0 - edx;
|
|
float *eax = pD0 + edx;
|
|
|
|
float var_4 = 0.0f;
|
|
if (var_8 > 0) {
|
|
for (int32_t ebp = var_8; ebp != 0; --ebp) {
|
|
var_4 += (*eax + *ebx) * *pFilter++;
|
|
ebx += subBandCount;
|
|
eax -= subBandCount;
|
|
}
|
|
}
|
|
|
|
*pD1 = (*ebx * *pFilter) + var_4;
|
|
pD1 += subBandCount;
|
|
pD0 += subBandCount;
|
|
}
|
|
}
|
|
|
|
void transform_all(Encoder &enc) {
|
|
if (enc.m_levels <= 0)
|
|
return;
|
|
|
|
int32_t subBandCount = 1;
|
|
int32_t sampleCount = enc.m_samplesPerBlock;
|
|
for (int i = 0; i < enc.m_levels; ++i) {
|
|
float *levelDataEBX = enc.m_levelSlots[i];
|
|
float *levelDataEBP = enc.m_levelSlots[i + 1];
|
|
|
|
for (int sbc = 0; sbc < subBandCount; ++sbc) {
|
|
transform_subband(enc, levelDataEBX++, levelDataEBP++, subBandCount, sampleCount);
|
|
}
|
|
|
|
subBandCount += subBandCount;
|
|
sampleCount >>= 1;
|
|
}
|
|
}
|
|
|
|
int32_t calc_bits(Encoder &enc, int32_t val) {
|
|
static uint32_t calc_bits_data[] = {0x00, 0x13, 0x16, 0x03, 0x1D, 0x00};
|
|
|
|
int32_t bitPower = 3;
|
|
int32_t result = enc.m_numColumns * 5 + 20;
|
|
|
|
float halfVal = float(val) * 0.5f;
|
|
float *var_18 = enc.m_levelSlots[enc.m_levels];
|
|
float *var_8 = enc.m_levelSlots[enc.m_levels];
|
|
|
|
for (int32_t var_1C = 0; var_1C < enc.m_numColumns; ++var_1C) {
|
|
int32_t minValue = 0x10000;
|
|
int32_t maxValue = -0x10000;
|
|
if (enc.m_samples_per_subband > 0) {
|
|
float *pSlotData = var_8;
|
|
for (int ebp = enc.m_samples_per_subband; ebp != 0; --ebp) {
|
|
int32_t testVal = (int32_t)floor((*pSlotData + halfVal) / float(val));
|
|
if (minValue > testVal) {
|
|
minValue = testVal;
|
|
}
|
|
|
|
if (maxValue < testVal) {
|
|
maxValue = testVal;
|
|
}
|
|
|
|
pSlotData += enc.m_numColumns;
|
|
}
|
|
}
|
|
|
|
int32_t absMaxVal = abs(minValue);
|
|
if (absMaxVal < maxValue) {
|
|
absMaxVal = maxValue;
|
|
} else if (absMaxVal < -maxValue) {
|
|
absMaxVal = -maxValue;
|
|
}
|
|
|
|
if (absMaxVal == 0) {
|
|
minValue = 0;
|
|
enc.m_pFormatIdPerColumn[var_1C] = 0;
|
|
} else if (absMaxVal <= 4) {
|
|
int32_t ebx = 1;
|
|
int32_t var_28 = absMaxVal * 3 + 14;
|
|
if (absMaxVal != 1) {
|
|
ebx = ((absMaxVal - 2) < 1) ? 2 : 3;
|
|
}
|
|
|
|
minValue = 0;
|
|
maxValue = 0;
|
|
for (int ebp = 0; ebp < enc.m_samples_per_subband; ++ebp) {
|
|
int32_t v = (int)floor((var_18[(ebp * enc.m_numColumns) + var_1C] + halfVal) / float(val));
|
|
if (v) {
|
|
if (ebx != 1) {
|
|
if (v == -1 || v == 1) {
|
|
minValue += 4;
|
|
maxValue += 3;
|
|
} else {
|
|
minValue += ebx + 2;
|
|
maxValue += ebx + 1;
|
|
}
|
|
} else {
|
|
minValue += 3;
|
|
maxValue += 2;
|
|
}
|
|
} else if ((enc.m_samples_per_subband - 1) <= ebp) {
|
|
minValue += 2;
|
|
++maxValue;
|
|
} else {
|
|
int32_t v = (int)floor((var_18[((ebp + 1) * enc.m_numColumns) + var_1C] + halfVal) / float(val));
|
|
if (v) {
|
|
minValue += 2;
|
|
++maxValue;
|
|
} else {
|
|
++minValue;
|
|
maxValue += 2;
|
|
++ebp;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (minValue > maxValue) {
|
|
minValue = maxValue;
|
|
++var_28;
|
|
}
|
|
|
|
int32_t ecx;
|
|
if (absMaxVal != 4) {
|
|
ecx = ((enc.m_samples_per_subband + 2) / 3) * ((absMaxVal * 2) + 3);
|
|
} else {
|
|
ecx = (((enc.m_samples_per_subband < -1) ? (enc.m_samples_per_subband + 2) : (enc.m_samples_per_subband + 1)) >>
|
|
1) *
|
|
7;
|
|
}
|
|
|
|
if (minValue > ecx) {
|
|
minValue = ecx;
|
|
var_28 = calc_bits_data[absMaxVal];
|
|
}
|
|
|
|
enc.m_pFormatIdPerColumn[var_1C] = var_28;
|
|
} else if (minValue >= -5 && maxValue <= 5) {
|
|
minValue =
|
|
(((enc.m_samples_per_subband < -1) ? (enc.m_samples_per_subband + 2) : (enc.m_samples_per_subband + 1)) >>
|
|
1) *
|
|
7;
|
|
enc.m_pFormatIdPerColumn[var_1C] = 0x1D;
|
|
} else {
|
|
int32_t eax = 0;
|
|
if (minValue < 0) {
|
|
eax = ~minValue;
|
|
}
|
|
|
|
if (maxValue > 0 && ((uint32_t)(eax) < (uint32_t)(maxValue))) {
|
|
eax = maxValue;
|
|
}
|
|
|
|
minValue = 1;
|
|
while (eax) {
|
|
eax >>= 1;
|
|
++minValue;
|
|
}
|
|
|
|
if (bitPower < (minValue - 1)) {
|
|
bitPower = minValue - 1;
|
|
}
|
|
enc.m_pFormatIdPerColumn[var_1C] = minValue;
|
|
minValue *= enc.m_samples_per_subband;
|
|
}
|
|
|
|
result += minValue;
|
|
++var_8;
|
|
}
|
|
|
|
enc.m_currBlockBitPower = bitPower;
|
|
enc.m_currBlockBitValue = val;
|
|
return result;
|
|
}
|
|
|
|
void DetermineStep(Encoder &enc) {
|
|
int32_t lo = 1;
|
|
int32_t hi = 0x7FFF;
|
|
|
|
do {
|
|
const int32_t midPoint = (lo + hi) >> 1;
|
|
int32_t errorAmt = calc_bits(enc, midPoint);
|
|
if (enc.m_threshold < errorAmt) {
|
|
lo = midPoint + 1;
|
|
} else {
|
|
hi = midPoint - 1;
|
|
}
|
|
} while (hi >= lo);
|
|
|
|
if (enc.m_currBlockBitValue != lo) {
|
|
calc_bits(enc, lo);
|
|
}
|
|
}
|
|
|
|
void WriteBands(Encoder &enc) {
|
|
enc.m_bits.WriteBits(enc.m_currBlockBitPower, 4);
|
|
enc.m_bits.WriteBits(enc.m_currBlockBitValue, 16);
|
|
|
|
for (int i = 0; i < enc.m_numColumns; ++i) {
|
|
const uint32_t formatId = enc.m_pFormatIdPerColumn[i];
|
|
enc.m_bits.WriteBits(formatId, 5);
|
|
// int32_t currPos = ftell(enc.m_bits.m_outFile);
|
|
WriteBand_tbl[formatId](enc, i, formatId);
|
|
}
|
|
}
|
|
|
|
void shift_transform_levels(Encoder &enc) {
|
|
int32_t levelCount = enc.m_someVal - 1;
|
|
for (int i = 0; i < enc.m_levels; ++i, levelCount += levelCount) {
|
|
float *pDst = enc.m_levelSlots[i] - levelCount;
|
|
float *pSrc = pDst + enc.m_samplesPerBlock;
|
|
memcpy(pDst, pSrc, levelCount * sizeof(float));
|
|
}
|
|
}
|
|
|
|
void ProcessBlock(Encoder &enc) {
|
|
transform_all(enc);
|
|
|
|
if (enc.m_bandWriteEnabled != 0) {
|
|
DetermineStep(enc);
|
|
|
|
WriteBands(enc);
|
|
}
|
|
|
|
shift_transform_levels(enc);
|
|
|
|
enc.m_blockSamplesRemaining += enc.m_samplesPerBlock;
|
|
enc.m_pCurrBlockData -= enc.m_samplesPerBlock;
|
|
}
|
|
|
|
void EncodeSample(Encoder &enc) {
|
|
int32_t sample = 0;
|
|
if (enc.m_finishedReading == 0) {
|
|
sample = (*enc.m_reader)(enc.m_pReaderData);
|
|
if (sample == ReadSampleEof) {
|
|
enc.m_finishedReading = 1;
|
|
return;
|
|
}
|
|
|
|
++enc.m_sampleCount;
|
|
}
|
|
|
|
*enc.m_pCurrBlockData++ = enc.m_volume * float(sample);
|
|
|
|
if (--enc.m_blockSamplesRemaining == 0) {
|
|
ProcessBlock(enc);
|
|
}
|
|
}
|
|
|
|
void EncodeFlush(Encoder &enc) {
|
|
if (enc.m_samplesPerBlock == enc.m_blockSamplesRemaining) {
|
|
// no data in the block
|
|
return;
|
|
}
|
|
|
|
// Zero out the remaining data in the block
|
|
while (enc.m_blockSamplesRemaining != 0) {
|
|
*enc.m_pCurrBlockData++ = 0.0f;
|
|
--enc.m_blockSamplesRemaining;
|
|
}
|
|
|
|
// Send it off for processing
|
|
ProcessBlock(enc);
|
|
}
|
|
|
|
int32_t AudioEncode(ReadSampleFunction *read, void *data, unsigned channels, unsigned sample_rate, float volume,
|
|
FILE *out, int levels, int samples_per_subband, float comp_ratio) {
|
|
Encoder enc;
|
|
memset(&enc, 0, sizeof(enc));
|
|
|
|
if (!ReadSample_init(enc, read, data)) {
|
|
DestroyEncoder(enc);
|
|
return 0;
|
|
}
|
|
|
|
if (!bits_init(enc.m_bits, out)) {
|
|
DestroyEncoder(enc);
|
|
return 0;
|
|
}
|
|
|
|
enc.m_volume = volume;
|
|
if (!SetupEncoder(enc, 0xF, std_lo_filter, std_hi_filter, levels, samples_per_subband)) {
|
|
DestroyEncoder(enc);
|
|
return 0;
|
|
}
|
|
|
|
enc.m_threshold = (int32_t)(float(enc.m_samplesPerBlock) * comp_ratio * 16.0f);
|
|
|
|
int32_t originalPosVAR64 = ftell(out);
|
|
|
|
// Header
|
|
enc.m_bits.WriteBits(0x97, 8);
|
|
enc.m_bits.WriteBits(0x28, 8);
|
|
enc.m_bits.WriteBits(0x03, 8);
|
|
|
|
// Version
|
|
enc.m_bits.WriteBits(1, 8);
|
|
|
|
// Sample Count (Placeholder 32bits for now)
|
|
enc.m_bits.WriteBits(0, 8);
|
|
enc.m_bits.WriteBits(0, 8);
|
|
enc.m_bits.WriteBits(0, 8);
|
|
enc.m_bits.WriteBits(0, 8);
|
|
|
|
// Number of channels
|
|
enc.m_bits.WriteBits(channels, 16);
|
|
|
|
// Sample Rate
|
|
enc.m_bits.WriteBits(sample_rate, 16);
|
|
|
|
// Levels
|
|
enc.m_bits.WriteBits(levels, 4);
|
|
|
|
// Samples per Sub-band (rows)
|
|
enc.m_bits.WriteBits(samples_per_subband, 12);
|
|
|
|
enc.m_bandWriteEnabled = 0;
|
|
|
|
int32_t esi = enc.m_adjustedSamplesTimeNumColumns;
|
|
while (esi) {
|
|
EncodeSample(enc);
|
|
--esi;
|
|
}
|
|
|
|
enc.m_bandWriteEnabled = 1;
|
|
|
|
while (!enc.m_finishedReading) {
|
|
EncodeSample(enc);
|
|
}
|
|
|
|
esi = enc.m_adjustedSamplesTimeNumColumns;
|
|
while (esi) {
|
|
EncodeSample(enc);
|
|
--esi;
|
|
}
|
|
|
|
EncodeFlush(enc);
|
|
|
|
/////////////
|
|
// NOTE: The Interplay one doesn't do this ... but it should as there
|
|
// may be bits left in the bit processor that should go out
|
|
enc.m_bits.Flush();
|
|
/////////////
|
|
|
|
// Go back and write the Sample Count out proper
|
|
int32_t endPos = ftell(out);
|
|
fseek(out, originalPosVAR64 + 4, SEEK_SET);
|
|
putc((enc.m_sampleCount >> 0) & 0xFF, out);
|
|
putc((enc.m_sampleCount >> 8) & 0xFF, out);
|
|
putc((enc.m_sampleCount >> 16) & 0xFF, out);
|
|
putc((enc.m_sampleCount >> 24) & 0xFF, out);
|
|
fseek(out, endPos, SEEK_SET);
|
|
|
|
DestroyEncoder(enc);
|
|
return endPos;
|
|
}
|