-
Notifications
You must be signed in to change notification settings - Fork 6
/
utils.h
178 lines (151 loc) · 5.74 KB
/
utils.h
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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
//Some functions used by brstm.h, brstm_encode.h and other parts of the OpenRevolution libraries
//Copyright (C) 2020 IC
//Bool endian: 0 = little endian, 1 = big endian
#pragma once
#include <math.h>
//TODO: Do not use global variables for slicing function results
unsigned char* brstm_slice;
char* brstm_slicestring;
long brstm_clamp(long value, long min, long max) {
return value <= min ? min : value >= max ? max : value;
}
long brstm_clamp16(long value) {
return value <= -32768 ? -32768 : value >= 32767 ? 32767 : value;
}
//Get slice of data
unsigned char* brstm_getSlice(const unsigned char* data,unsigned long start,unsigned long length) {
delete[] brstm_slice;
brstm_slice = new unsigned char[length];
for(unsigned int i=0;i<length;i++) {
brstm_slice[i]=data[i+start];
}
return brstm_slice;
}
//Get slice and convert it to a number
unsigned long brstm_getSliceAsNumber(const unsigned char* data,unsigned long start,unsigned long length,bool endian) {
if(length>4) {length=4;}
unsigned long number=0;
unsigned char* bytes=brstm_getSlice(data,start,length);
unsigned char pos;
if(endian) {
pos=length-1; //Read as big endian
} else {
pos = 0; //Read as little endian
}
unsigned long pw=1; //Multiply by 1,256,65536...
for(unsigned int i=0;i<length;i++) {
if(i>0) {pw*=256;}
number+=bytes[pos]*pw;
if(endian) {pos--;} else {pos++;}
}
return number;
}
//Get slice as signed 16 bit number
signed int brstm_getSliceAsInt16Sample(const unsigned char * data,unsigned long start,bool endian) {
unsigned long number=0;
unsigned char bytes[2]={data[start],data[start+1]};
unsigned char little=bytes[endian];
signed char big=bytes[!endian];
number=little+big*256;
return number;
}
//Get slice as a null terminated string
char* brstm_getSliceAsString(const unsigned char* data,unsigned long start,unsigned long length) {
unsigned char slicestr[length+1];
unsigned char* bytes=brstm_getSlice(data,start,length);
for(unsigned int i=0;i<length;i++) {
slicestr[i]=bytes[i];
if(slicestr[i]=='\0') {slicestr[i]=' ';}
}
slicestr[length]='\0';
delete[] brstm_slice;
brstm_slicestring = new char[length+1];
for(unsigned int i=0;i<length+1;i++) {
brstm_slicestring[i]=slicestr[i];
}
return brstm_slicestring;
}
#define PACKET_NIBBLES 16
#define PACKET_SAMPLES 14
#define PACKET_BYTES 8
unsigned int brstm_getBytesForAdpcmSamples(int samples) {
int extraBytes = 0;
int packets = samples / PACKET_SAMPLES;
int extraSamples = samples % PACKET_SAMPLES;
if (extraSamples != 0) {
extraBytes = (extraSamples / 2) + (extraSamples % 2) + 1;
}
return PACKET_BYTES * packets + extraBytes;
}
int32_t brstm_getSamplesForAdpcmNibbles(int32_t nibbles) {
int32_t whole_frames = nibbles/16;
int32_t remainder = nibbles%16;
if (remainder>0) return whole_frames*14+remainder-2;
else return whole_frames*14;
}
//Encoder utils
void brstm_encoder_writebytes(unsigned char* buf,const unsigned char* data,unsigned int bytes,unsigned long& off) {
for(unsigned int i=0;i<bytes;i++) {
buf[i+off] = data[i];
}
off += bytes;
}
void brstm_encoder_writebytes_i(unsigned char* buf,unsigned char* data,unsigned int bytes,unsigned long& off) {
brstm_encoder_writebytes(buf,data,bytes,off);
delete[] data;
}
void brstm_encoder_writebyte(unsigned char* buf,const unsigned char data,unsigned long& off) {
unsigned char arr[1] = {data};
brstm_encoder_writebytes(buf,arr,1,off);
}
//Returns integer as big endian bytes
//TODO: Improve the speed of this function and brstm_encoder_getByteInt16
// while keeping compatibility with both Little-endian and Big-endian machines
//TODO: Do not use a global variable for storing the result
unsigned char* brstm_encoder_ByteInt;
unsigned char* brstm_encoder_getByteUint(uint64_t num,uint8_t bytes,bool BOM) {
delete[] brstm_encoder_ByteInt;
brstm_encoder_ByteInt = new unsigned char[bytes];
unsigned long pwr;
unsigned char pwn = bytes-1;
for(unsigned char i = 0; i < bytes; i++) {
pwr = pow(256,pwn--);
unsigned int pos = (BOM ? i : abs(i-bytes+1));
brstm_encoder_ByteInt[pos]=0;
while(num >= pwr) {
brstm_encoder_ByteInt[pos]++;
num -= pwr;
}
}
return brstm_encoder_ByteInt;
}
unsigned char* brstm_encoder_getByteInt16(int16_t num, bool BOM) {
return brstm_encoder_getByteUint((uint16_t)num,2,BOM);
}
char brstm_encoder_nextspinner(char& spinner) {
switch(spinner) {
case '/': spinner = '-'; break;
case '-': spinner = '\\'; break;
case '\\': spinner = '|'; break;
case '|': spinner = '/'; break;
}
return spinner;
}
//Calculates block sizes and sample counts
void brstm_encoder_calculateStandardBlockInfo(Brstm* brstmi) {
brstmi->blocks_samples = (brstmi->codec == 2 ? 14336 : brstmi->codec == 1 ? 4096 : 8192);
brstmi->blocks_size = 8192;
brstmi->total_blocks = brstmi->total_samples / brstmi->blocks_samples;
if(brstmi->total_samples % brstmi->blocks_samples != 0) brstmi->total_blocks++;
//Final block
brstmi->final_block_samples = brstmi->total_samples % brstmi->blocks_samples;
if(brstmi->final_block_samples == 0) brstmi->final_block_samples = brstmi->blocks_samples;
brstmi->final_block_size = (
brstmi->codec == 2 ? brstm_getBytesForAdpcmSamples(brstmi->final_block_samples)
: brstmi->codec == 1 ? brstmi->final_block_samples * 2
: brstmi->final_block_samples
);
//Padded final block size
brstmi->final_block_size_p = brstmi->final_block_size;
while(brstmi->final_block_size_p % 0x20 != 0) {brstmi->final_block_size_p++;}
}