-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathFrameHeader.java
More file actions
274 lines (247 loc) · 8.42 KB
/
FrameHeader.java
File metadata and controls
274 lines (247 loc) · 8.42 KB
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
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
/*
* Copyright (C) 2010 Preston Lacey http://javaflacencoder.sourceforge.net/
* All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package javaFlacEncoder;
/**
* This class is used to generate a Frame Header for a FLAC Frame.
*
* @author Preston Lacey
*/
public class FrameHeader {
/** For Debugging: Higher level equals more debug statements */
public static int DEBUG_LEV = 0;
private static final int definedBlockSizes[] = {
-1,
192,
576,
1152,
2304,
4608,
-1,
-1,
256,
512,
1024,
2048,
4096,
8192,
16384,
32768
};
private static final int definedSampleRates[] = {
0,
88200,
176400,
192000,
8000,
16000,
22050,
24000,
32000,
44100,
48000,
96000,
-1,
-1,
-1,
-1
};
/** Maximum size a header can be according to FLAC specification. */
public static final int MAX_HEADER_SIZE = 128;//in bytes
/** Synchronization code used at beginning of frame(low-order 14 bits
* used) */
public static final short syncCode = 0x3FFE;//14 bits used
static final byte reserved = 0;//1 bit used; 0 mandatory value
byte blockingStrategy = 0;//1 bit used; 0=fixed-blocksize. 1=variable
byte blockSize = 0xC;//4 bits used; see format docs
byte sampleRate = 4;//0;//4 bits used; see format docs
//byte channelAssignment = 0;//4 bits used; see format docs
byte sampleSize = 4;//3 bits used; see format docs
static final byte reserved2 = 0;//1 bit used; 0 mandatory value
long frameNumber = 0;//8-56 bits used; UTF-8 coded sample number
int blockSizeMod = 0;//if(blocksize bits == 011x) 8/16 bit (blocksize-1)
int SampleRateMod = 0;//if(sample rate bits == 11xx) 8/16 bit sample rate
byte crc8 = 0;
CRC8 crcCalculator;
/**
* Constructor creates a new FrameHeader object which is ready to
* generate headers. We can't use static functions to do this, since the
* process uses a CRC8 object which must be instantiated.
*
*/
public FrameHeader() {
crcCalculator = new CRC8();
}
/**
* Create the header for a frame with the given parameters. Header data is
* stored out to an EncodedElement, in the proper form for a FLAC stream.
*
* @param fixBlock True to use a fixed block size, false to use variable. At
* this time, this *must* be set to True, as variable block size is
* not yet implemented.
* @param blockSize Block Size of this frame.
* @param sampleRate Sample rate of this frame.
* @param channelAssign Channel assignment used in this frame's encoding.
* See EncodingConfiguration class documentation for
* more information.
* @param sampleSize Bits per sample.
* @param frameNumber For fixed block-size encodings, this is the frame-number
* starting at zero and incrementing by one. For variable
* block encodings, this is the sample number of the
* first sample in the frame.
* @param channelCount Number of channels in the stream.
* @return EncodedElement where the header is saved to.
*/
public EncodedElement createHeader(boolean fixBlock, int blockSize,
int sampleRate, EncodingConfiguration.ChannelConfig channelAssign,
int sampleSize, long frameNumber, int channelCount, EncodedElement result) {
if(DEBUG_LEV > 0 )
System.err.println("FrameHeader::createHeader : Begin");
//EncodedElement result = new EncodedElement();
boolean useEndBlockSize = false;
boolean useEndSampleRate = false;
result.clear(MAX_HEADER_SIZE,0);
int blockingStrat = (fixBlock)? 0:1;
byte[] encodedFrameNumber = UTF8Modified.convertToExtendedUTF8(frameNumber);
//set block size bits
byte encodedBlockSize = encodeBlockSize(blockSize);
if(encodedBlockSize == 0x6 || encodedBlockSize == 0x7)
useEndBlockSize = true;
//set sample rate bits
byte encodedSampleRate = encodeSampleRate(sampleRate);
if(encodedSampleRate >= 12 && encodedSampleRate <= 14)
useEndSampleRate = true;
//set channelAssignment bits
int channelAssignment = 0;
if(channelAssign == EncodingConfiguration.ChannelConfig.INDEPENDENT)
channelAssignment = channelCount-1;
else if(channelAssign == EncodingConfiguration.ChannelConfig.LEFT_SIDE)
channelAssignment = 8;
else if(channelAssign == EncodingConfiguration.ChannelConfig.RIGHT_SIDE)
channelAssignment = 9;
else if(channelAssign == EncodingConfiguration.ChannelConfig.MID_SIDE)
channelAssignment = 10;
//set sample size bits
byte encodedSampleSize = 0;
switch(sampleSize) {
case 8: encodedSampleSize = 0x1; break;
case 12: encodedSampleSize = 0x2; break;
case 16: encodedSampleSize = 0x4; break;
case 20: encodedSampleSize = 0x5; break;
case 24: encodedSampleSize = 0x6; break;
default: encodedSampleSize = 0x0;
}
result.addInt(syncCode,14);
result.addInt(reserved, 1);
result.addInt(blockingStrat, 1);
result.addInt(encodedBlockSize, 4);
result.addInt(encodedSampleRate, 4);
result.addInt(channelAssignment, 4);
result.addInt(encodedSampleSize, 3);
result.addInt(reserved2, 1);
for(int i = 0; i < encodedFrameNumber.length; i++) {
result.addInt(encodedFrameNumber[i], 8);
}
//write blockSize if needed(two formats possible)
if(useEndBlockSize) {
if(encodedBlockSize == 0x6) {
result.addInt(blockSize-1, 8);
}
else {
result.addInt(blockSize-1, 16);
}
}
//write sampleRate if needed(three formats possible)
if(useEndSampleRate) {
switch(encodedSampleRate) {
case 0xC:
result.addInt(sampleRate/1000, 8);
break;
case 0xD:
result.addInt(sampleRate, 16);
break;
case 0xE:
result.addInt(sampleRate/10, 16);
break;
}
}
if(DEBUG_LEV > 20 )
System.err.println("FrameHeader::createHeader : pre-CRC");
crcCalculator.reset();
crcCalculator.updateCRC8(result.getData(), 0, result.getTotalBits()/8);
crc8 = crcCalculator.checksum();
if(DEBUG_LEV > 20 )
System.err.println("FrameHeader::createHeader : post-CRC");
result.addInt(crc8, 8);
if(DEBUG_LEV > 0 )
System.err.println("FrameHeader::createHeader : End");
return result;
}
/**
* Given a block size, select the proper bit settings to use according to
* the FLAC stream.
* @param blockSize
* @return
*/
private static byte encodeBlockSize(int blockSize) {
if(DEBUG_LEV > 0 )
System.err.println("FrameHeader::encodeBlockSize : Begin");
byte value = 0;
int i;
for(i = 0; i < definedBlockSizes.length; i++) {
if(blockSize == definedBlockSizes[i]) {
value = (byte)i;
break;
}
}
if(i >= definedBlockSizes.length) {
if(blockSize <= 255)
value = 0x6;
else
value = 0x7;
}
if(DEBUG_LEV > 0 )
System.err.println("FrameHeader::encodeBlockSize : End");
return value;
}
private static byte encodeSampleRate(int sampleRate) {
if(DEBUG_LEV > 0 )
System.err.println("FrameHeader::encodeSampleRate : Begin");
byte value = 0;
int i;
for(i = 0; i < definedSampleRates.length; i++) {
if(sampleRate == definedSampleRates[i]) {
value = (byte)i;
break;
}
}
if(i >= definedSampleRates.length) {
if(sampleRate % 1000 == 0 && sampleRate < 256000)
value = 0xC;
else if(sampleRate < 65536)
value = 0xD;
else if(sampleRate % 10 == 0 && sampleRate <= 655350)
value = 0xE;
else
value = 0x0;
}
if(DEBUG_LEV > 0 )
System.err.println("FrameHeader::encodeSampleRate : End");
return value;
}
}