-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathXasWriter.cpp
122 lines (102 loc) · 4.06 KB
/
XasWriter.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
#include "XasWriter.h"
#include <cstring>
#include <memory>
#include "utility.h"
#include <iostream>
using namespace std;
uint8_t* XasWriter::writeHeader(int& rSize)
{
uint8_t* data = new uint8_t[20];
uint8_t* dataIte = data;
*dataIte++ = 0x04; // XAS codec
*dataIte++ = (input.nChannels - 1) * 4;
bufferWriteValue<uint16_t>(dataIte, BSWAP16(input.sampleRate));
bufferWriteValue<uint32_t>(dataIte, BSWAP32(input.nSamples | (isLoop << 29))); // total samples + flags
if (isLoop) {
bufferWriteValue<uint32_t>(dataIte, 0); // Starting part samples
}
offsetBlockSizeValue = dataIte - data; // first block size
dataIte += 4;
bufferWriteValue<uint32_t>(dataIte, BSWAP32(input.nSamples)); // first (unique) block samples
rSize = dataIte - data;
return data;
}
void XasWriter::writeBlockSizeInHeader(fstream& outFile)
{
auto endOfBlockPos = outFile.tellg();
outFile.seekg(offsetBlockSizeValue, ios::beg);
uint32_t sizeBE = BSWAP32((uint32_t)endOfBlockPos - offsetBlockSizeValue);
outFile.write((char*)&sizeBE, 4);
outFile.seekg(endOfBlockPos);
}
void XasWriter::encodeXasBlock(int16_t* samples, uint8_t* &output, int nSamples)
{
for (unsigned c = 0; c < input.nChannels; c++) {
int16_t* inputSamples = samples + c * nSamples;
int16_t inputSamplesPadded[128];
if (nSamples < 128) {
memset(inputSamplesPadded, 0, sizeof(inputSamplesPadded));
memcpy(inputSamplesPadded, inputSamples, nSamples * 2);
inputSamples = inputSamplesPadded;
}
int16_t startSamples[4][2];
uint8_t encoded[4][16];
EaXaEncoder& encoder = encoders[c];
for (int i = 0; i < 4; i++) { // 128 samples split in 4 groups of 32
startSamples[i][0] = clipInt16(inputSamples[0] + 8) & 0xFFF0;
startSamples[i][1] = clipInt16(inputSamples[1] + 8) & 0xFFF0;
encoder.previousSample = startSamples[i][0];
encoder.currentSample = startSamples[i][1];
encoder.clearErrors();
encoder.encodeSubblock(inputSamples + 2, encoded[i], 30);
inputSamples += 32;
}
int16_t* startSamplesWithInfos = (int16_t*)output;
for (int i = 0; i < 4; i++) {
uint8_t infoByte = encoded[i][0];
*startSamplesWithInfos++ = startSamples[i][0] | (infoByte >> 4); // Coef info
*startSamplesWithInfos++ = startSamples[i][1] | (infoByte & 0x0F); // Shift info
}
output = (uint8_t*)startSamplesWithInfos;
for (int j = 1; j <= 15; j++) {
for (int i = 0; i < 4; i++) {
*output++ = encoded[i][j];
}
}
}
}
bool XasWriter::writeFile(fstream& out)
{
if (input.sampleRate > 0xFFFF) {
cerr << "Sample rate is too big for this format." << endl;
return false;
}
if (input.nSamples & 0xE0000000) {
cerr << "Audio is too long for this format." << endl;
return false;
}
int headerSize;
unique_ptr<uint8_t[]> header(writeHeader(headerSize));
out.write((char*)header.get(), headerSize);
encoders.resize(input.nChannels);
unsigned int codedSamples = 0;
bool lastBlock = false;
unique_ptr<uint8_t[]> block(new uint8_t[76 * input.nChannels]);
unique_ptr<int16_t[]> samples(new int16_t[128 * input.nChannels]);
while (!lastBlock) {
int samplesInBlock = 128;
codedSamples += samplesInBlock;
if (codedSamples >= input.nSamples) {
int toRemove = codedSamples - input.nSamples;
samplesInBlock -= toRemove;
codedSamples = input.nSamples;
lastBlock = true;
}
if (!input.readSamples(samples.get(), samplesInBlock)) return false;
uint8_t* dataIte = block.get();
encodeXasBlock(samples.get(), dataIte, samplesInBlock);
out.write((char*)block.get(), dataIte - block.get());
}
writeBlockSizeInHeader(out);
return true;
}