]> git.nihav.org Git - nihav.git/blob - nihav-qt/src/codecs/qdmc.rs
use proper audio buffer truncation function
[nihav.git] / nihav-qt / src / codecs / qdmc.rs
1 use nihav_core::codecs::*;
2 use nihav_core::io::byteio::*;
3 use nihav_core::io::bitreader::*;
4 use nihav_core::io::codebook::*;
5 use nihav_codec_support::dsp::fft::*;
6 use super::qdmcommon::*;
7
8 const MAX_NOISE_BANDS: usize = 19;
9 const MAX_FRAME_SIZE: usize = 8192;
10
11 struct QdmcDecoder {
12 ainfo: NAAudioInfo,
13 chmap: NAChannelMap,
14 noise_val_cb: Codebook<u8>,
15 noise_seg_cb: Codebook<u8>,
16 amp_cb: Codebook<u8>,
17 amp_diff_cb: Codebook<u8>,
18 freq_diff_cb: Codebook<u8>,
19 phase_diff_cb: Codebook<u8>,
20 sin_tab: [f32; 512],
21 tone_tab: [[f32; 32]; 5],
22 rng: RNG,
23 fft: FFT,
24 fft_buf: [[FFTComplex; MAX_FRAME_SIZE * 2]; 2],
25 noise_tab: [[f32; 256]; MAX_NOISE_BANDS],
26 tmp: [f32; MAX_FRAME_SIZE],
27 sbuf: [FFTComplex; 512],
28 delay: [[f32; 512]; 2],
29
30 noise: [[[u8; 16]; MAX_NOISE_BANDS]; 2],
31 tones: [Vec<Tone>; 5],
32
33 order: u8,
34 frame_bits: u8,
35 samples: usize,
36 frm_bytes: usize,
37 noise_cat: usize,
38 sf_len: usize,
39 }
40
41 fn def_cb_map(idx: usize) -> u8 { idx as u8 }
42 fn noise_val_cb_map(idx: usize) -> u8 { NOISE_VAL_SYMS[idx] }
43 fn noise_seg_cb_map(idx: usize) -> u8 { NOISE_SEG_SYMS[idx] }
44
45 impl QdmcDecoder {
46 fn new() -> Self {
47 let mut cbr = TableCodebookDescReader::new(&NOISE_VAL_CODES, &NOISE_VAL_BITS, noise_val_cb_map);
48 let noise_val_cb = Codebook::new(&mut cbr, CodebookMode::LSB).unwrap();
49 let mut cbr = TableCodebookDescReader::new(&NOISE_SEG_CODES, &NOISE_SEG_BITS, noise_seg_cb_map);
50 let noise_seg_cb = Codebook::new(&mut cbr, CodebookMode::LSB).unwrap();
51 let mut cbr = TableCodebookDescReader::new(&FREQ_DIFF_CODES, &FREQ_DIFF_BITS, def_cb_map);
52 let freq_diff_cb = Codebook::new(&mut cbr, CodebookMode::LSB).unwrap();
53 let mut cbr = TableCodebookDescReader::new(&AMP_CODES, &AMP_BITS, def_cb_map);
54 let amp_cb = Codebook::new(&mut cbr, CodebookMode::LSB).unwrap();
55 let mut cbr = TableCodebookDescReader::new(&AMP_DIFF_CODES, &AMP_DIFF_BITS, def_cb_map);
56 let amp_diff_cb = Codebook::new(&mut cbr, CodebookMode::LSB).unwrap();
57 let mut cbr = TableCodebookDescReader::new(&PHASE_DIFF_CODES, &PHASE_DIFF_BITS, def_cb_map);
58 let phase_diff_cb = Codebook::new(&mut cbr, CodebookMode::LSB).unwrap();
59
60 let mut sin_tab = [0.0f32; 512];
61 for (i, tab) in sin_tab.iter_mut().enumerate() {
62 *tab = (2.0 * (i as f32) * std::f32::consts::PI / 512.0).sin();
63 }
64
65 let mut tone_tab = [[0.0; 32]; 5];
66 for group in 0..5 {
67 for i in 0..(1 << (5 - group)) {
68 tone_tab[group][i] = sin_tab[((i + 1) << (group + 3)) & 0x1FF];
69 }
70 }
71
72 Self {
73 ainfo: NAAudioInfo::new(0, 1, SND_F32P_FORMAT, 1),
74 chmap: NAChannelMap::new(),
75 noise_val_cb, noise_seg_cb, freq_diff_cb, amp_cb, amp_diff_cb, phase_diff_cb,
76 sin_tab, tone_tab,
77 noise: [[[0; 16]; MAX_NOISE_BANDS]; 2],
78 tones: [Vec::with_capacity(MAX_TONES),
79 Vec::with_capacity(MAX_TONES),
80 Vec::with_capacity(MAX_TONES),
81 Vec::with_capacity(MAX_TONES),
82 Vec::with_capacity(MAX_TONES)],
83 rng: RNG::new(),
84 fft: FFTBuilder::new_fft(256, false),
85 fft_buf: [[FFTC_ZERO; MAX_FRAME_SIZE * 2]; 2],
86 noise_tab: [[0.0; 256]; MAX_NOISE_BANDS],
87 tmp: [0.0; MAX_FRAME_SIZE],
88 sbuf: [FFTC_ZERO; 512],
89 delay: [[0.0; 512]; 2],
90
91 order: 0,
92 frame_bits: 0,
93 samples: 0,
94 frm_bytes: 0,
95 noise_cat: 0,
96 sf_len: 0,
97 }
98 }
99 fn fill_noise_table(&mut self) {
100 let noise_bands = NOISE_SUBBANDS[self.noise_cat];
101 self.noise_tab = [[0.0; 256]; MAX_NOISE_BANDS];
102 for band in 0..(noise_bands.len() - 2) {
103 let prev = noise_bands[band];
104 let cur = noise_bands[band + 1];
105 let next = noise_bands[band + 2];
106
107 let noise = &mut self.noise_tab[band];
108 for i in prev..cur {
109 noise[i] = ((i - prev) as f32) / ((cur - prev) as f32);
110 }
111 for i in cur..next {
112 noise[i] = ((next - i) as f32) / ((next - cur) as f32);
113 }
114 }
115 }
116 fn read_noise_data(&mut self, br: &mut BitReader, ch: usize) -> DecoderResult<()> {
117 let noise_bands = NOISE_SUBBANDS[self.noise_cat];
118 for band in 0..(noise_bands.len() - 2) {
119 let val = br.read_code(&self.noise_val_cb)? as i32;
120 let mut last = to_signed(val);
121 validate!(last >= 0);
122 self.noise[ch][band][0] = last as u8;
123 let mut idx = 1;
124 while idx < 16 {
125 let len = (br.read_code_long(&self.noise_seg_cb)? as usize) + 1;
126 let val = br.read_code(&self.noise_val_cb)? as i32;
127 let val = to_signed(val) + last;
128 validate!(val >= 0);
129 validate!(len + idx <= 16);
130 for i in 1..=len {
131 self.noise[ch][band][idx] = (last + (i as i32) * (val - last) / (len as i32) - 1) as u8;
132 idx += 1;
133 }
134 last = val;
135 }
136 }
137 Ok(())
138 }
139 fn read_wave_data(&mut self, br: &mut BitReader) -> DecoderResult<()> {
140 for tone in self.tones.iter_mut() {
141 tone.clear();
142 }
143 for group in 0..5 {
144 let group_size = 1 << (self.frame_bits - group - 1);
145 let group_bits = 4 - group;
146 let mut freq = 1;
147 let mut off = 0;
148 let mut pos2 = 0;
149 while freq < group_size {
150 let diff = br.read_code_long(&self.freq_diff_cb)?;
151 freq += diff as usize;
152 while freq >= group_size - 1 {
153 freq -= group_size - 2;
154 off += 1 << group_bits;
155 pos2 += group_size;
156 }
157 if pos2 >= (1 << self.frame_bits) {
158 break;
159 }
160 let stereo_mode = if self.chmap.num_channels() > 1 { br.read(2)? as u8 } else { 0 };
161 let amp = br.read_code(&self.amp_cb)? as u8;
162 let phase = br.read(3)? as u8;
163 let (amp2, phase2) = if (stereo_mode & 2) != 0 {
164 (br.read_code(&self.amp_diff_cb)? as u8,
165 br.read_code(&self.phase_diff_cb)? as u8)
166 } else { (0, 0) };
167 if (freq >> group_bits) + 1 < self.sf_len {
168 validate!(self.tones[group as usize].len() < MAX_TONES);
169 self.tones[group as usize].push(Tone {
170 offset: off, ch: stereo_mode & 1, phase,
171 freq: freq as u16, amp_idx: amp
172 });
173 if (stereo_mode & 2) != 0 {
174 validate!(self.tones[group as usize].len() < MAX_TONES);
175 let phase = phase.wrapping_sub(phase2) & 7;
176 let amp_idx = amp.wrapping_sub(amp2) & 0x3F;
177 self.tones[group as usize].push(Tone {
178 offset: off, ch: !stereo_mode & 1, phase,
179 freq: freq as u16, amp_idx
180 });
181 }
182 }
183 freq += 1;
184 }
185 }
186 Ok(())
187 }
188 fn add_noise(&mut self, ch: usize, sf: usize) {
189 let noise_bands = NOISE_SUBBANDS[self.noise_cat];
190 self.tmp = [0.0; MAX_FRAME_SIZE];
191 for band in 0..(noise_bands.len() - 2) {
192 if noise_bands[band] >= self.sf_len {
193 break;
194 }
195 let scale = SCALES[(self.noise[ch][band][sf >> 1] & 0x3F) as usize] / 32768.0;
196 let start = noise_bands[band];
197 let end = noise_bands[band + 2].min(self.sf_len);
198 let linscale = &self.noise_tab[band];
199 for i in start..end {
200 self.tmp[i] += scale * linscale[i];
201 }
202 }
203
204 for i in 2..self.sf_len - 1 {
205 let im = -self.rng.next_float() * self.tmp[i];
206 let re = self.rng.next_float() * self.tmp[i];
207 let noise = FFTComplex { re, im };
208 self.fft_buf[ch][sf * self.sf_len + i] += noise;
209 self.fft_buf[ch][sf * self.sf_len + i + 1] -= noise;
210 }
211 }
212 fn add_tones(&mut self, sf: usize, start_idx: &mut [usize; 5]) {
213 for group in 0..5 {
214 let group_bits = 4 - group;
215 let group_size = (1 << (group_bits + 1)) - 1;
216 for tone in self.tones[group].iter().skip(start_idx[group]) {
217 if (tone.offset as usize) > sf {
218 break;
219 }
220 start_idx[group] += 1;
221
222 let pos = (tone.freq >> group_bits) as usize;
223 let scale = SCALES[(tone.amp_idx & 0x3F) as usize] / 32768.0;
224 let mut phase_idx = ((tone.phase as usize) * 64).wrapping_sub((2 * pos + 1) * 128) & 0x1FF;
225 for i in 0..group_size {
226 phase_idx = phase_idx.wrapping_add((2 * (tone.freq as usize) + 1) << (7 - group_bits));
227 let factor = scale * self.tone_tab[group][i];
228 let re = factor * self.sin_tab[(phase_idx + 128) & 0x1FF];
229 let im = -factor * self.sin_tab[ phase_idx & 0x1FF];
230 let val = FFTComplex { re, im };
231 let ch = tone.ch as usize;
232 self.fft_buf[ch][(sf + i) * self.sf_len + pos] += val;
233 self.fft_buf[ch][(sf + i) * self.sf_len + pos + 1] -= val;
234 }
235 }
236 }
237 }
238 fn synth_channel(&mut self, ch: usize, subframe: usize, dst: &mut [f32]) {
239 let sf_len = self.sf_len;
240 self.sbuf = [FFTC_ZERO; 512];
241 self.sbuf[..sf_len].copy_from_slice(&self.fft_buf[ch][subframe * sf_len..][..sf_len]);
242 self.fft.do_fft_inplace(&mut self.sbuf);
243 dst[..sf_len].copy_from_slice(&self.delay[ch][..sf_len]);
244 for (dst, src) in dst.iter_mut().take(sf_len).zip(self.sbuf.iter()) {
245 *dst += src.re;
246 }
247 for (dst, src) in self.delay[ch].iter_mut().take(sf_len).zip(self.sbuf.iter().skip(sf_len)) {
248 *dst = src.re;
249 }
250 }
251 }
252
253 impl NADecoder for QdmcDecoder {
254 fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
255 if let NACodecTypeInfo::Audio(ainfo) = info.get_properties() {
256 if let Some(edata) = info.get_extradata() {
257 validate!(edata.len() >= 36);
258 let mut mr = MemoryReader::new_read(edata.as_slice());
259 let mut br = ByteReader::new(&mut mr);
260 let size = br.read_u32be()? as usize;
261 validate!(size >= 36 && size <= edata.len());
262 let tag = br.read_tag()?;
263 validate!(&tag == b"QDCA");
264 let ver = br.read_u32be()?;
265 validate!(ver == 1);
266 let channels = br.read_u32be()? as usize;
267 validate!(channels == 2 || channels == 1);
268 let srate = br.read_u32be()?;
269 let full_bitrate = br.read_u32be()?;
270 let frame_len = br.read_u32be()? as usize;
271 let packet_size = br.read_u32be()? as usize;
272 validate!(packet_size > 0 && (packet_size & (packet_size - 1)) == 0);
273 validate!(frame_len == packet_size * 32);
274 let bytes_per_frame = br.read_u32be()? as usize;
275 validate!(bytes_per_frame > 6);
276
277 self.order = (31 - (packet_size.leading_zeros() & 31)) as u8;
278 self.frame_bits = self.order + 5;
279 self.samples = frame_len;
280 self.frm_bytes = bytes_per_frame;
281 self.sf_len = packet_size;
282
283 let srate = if ainfo.get_sample_rate() != 0 {
284 ainfo.get_sample_rate()
285 } else { srate };
286 self.ainfo = NAAudioInfo::new(srate, channels as u8, SND_F32P_FORMAT, 1);
287 self.chmap = NAChannelMap::from_str(if channels == 1 { "C" } else { "L,R" }).unwrap();
288 let (mut bitrate, fbits) = if srate >= 32000 {
289 (28000, 13)
290 } else if srate >= 16000 {
291 (20000, 12)
292 } else {
293 (16000, 11)
294 };
295 if channels == 2 {
296 bitrate += bitrate / 2;
297 }
298 let idx = ((full_bitrate * 3 + bitrate / 2) / bitrate) as usize;
299 self.noise_cat = NOISE_BAND_SELECTOR[idx.min(NOISE_BAND_SELECTOR.len() - 1)];
300 validate!(frame_len == (1 << fbits));
301
302 self.fft_buf = [[FFTC_ZERO; MAX_FRAME_SIZE * 2]; 2];
303 self.fft = FFTBuilder::new_fft(packet_size * 2, false);
304
305 self.fill_noise_table();
306 } else {
307 return Err(DecoderError::InvalidData);
308 }
309
310 Ok(())
311 } else {
312 Err(DecoderError::InvalidData)
313 }
314 }
315 fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
316 let info = pkt.get_stream().get_info();
317 if let NACodecTypeInfo::Audio(_) = info.get_properties() {
318 let pktbuf = pkt.get_buffer();
319 validate!(pktbuf.len() == self.frm_bytes);
320 validate!(&pktbuf[..3] == b"QMC" && pktbuf[3] == 1);
321 let checksum = u16::from(pktbuf[4]) + u16::from(pktbuf[5]) * 256;
322 let mut sum = 0xE2u16;
323 for el in pktbuf.iter().skip(6) {
324 sum = sum.wrapping_add(u16::from(*el));
325 }
326 validate!(sum == checksum);
327
328 let channels = self.chmap.num_channels();
329 let abuf = alloc_audio_buffer(self.ainfo, self.samples, self.chmap.clone())?;
330 let mut adata = abuf.get_abuf_f32().unwrap();
331 let mut off = [adata.get_offset(0), adata.get_offset(1)];
332 let dst = adata.get_data_mut().unwrap();
333
334 let mut br = BitReader::new(&pktbuf[6..], BitReaderMode::LE);
335 for ch in 0..channels {
336 self.read_noise_data(&mut br, ch)?;
337 }
338 self.read_wave_data(&mut br)?;
339
340 let mut tone_start = [0; 5];
341 for subframe in 0..32 {
342 for ch in 0..channels {
343 self.add_noise(ch, subframe);
344 }
345 self.add_tones(subframe, &mut tone_start);
346 for ch in 0..channels {
347 self.synth_channel(ch, subframe, &mut dst[off[ch]..]);
348 off[ch] += self.sf_len;
349 }
350 }
351 for ch in 0..channels {
352 let mut chunks = self.fft_buf[ch].chunks_mut(1 << self.frame_bits);
353 let first = chunks.next().unwrap();
354 let second = chunks.next().unwrap();
355 first.copy_from_slice(&second);
356 for el in second.iter_mut() {
357 *el = FFTC_ZERO;
358 }
359 }
360
361 let mut frm = NAFrame::new_from_pkt(pkt, info.replace_info(NACodecTypeInfo::Audio(self.ainfo)), abuf);
362 frm.set_duration(Some(self.samples as u64));
363 frm.set_keyframe(false);
364 Ok(frm.into_ref())
365 } else {
366 Err(DecoderError::InvalidData)
367 }
368 }
369 fn flush(&mut self) {
370 self.fft_buf = [[FFTC_ZERO; MAX_FRAME_SIZE * 2]; 2];
371 self.delay = [[0.0; 512]; 2];
372 }
373 }
374
375 impl NAOptionHandler for QdmcDecoder {
376 fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
377 fn set_options(&mut self, _options: &[NAOption]) { }
378 fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
379 }
380
381 pub fn get_decoder() -> Box<dyn NADecoder + Send> {
382 Box::new(QdmcDecoder::new())
383 }
384
385 #[cfg(test)]
386 mod test {
387 use nihav_core::codecs::RegisteredDecoders;
388 use nihav_core::demuxers::RegisteredDemuxers;
389 use nihav_codec_support::test::dec_video::*;
390 use crate::qt_register_all_decoders;
391 use nihav_commonfmt::generic_register_all_demuxers;
392 #[test]
393 fn test_qdmc() {
394 let mut dmx_reg = RegisteredDemuxers::new();
395 generic_register_all_demuxers(&mut dmx_reg);
396 let mut dec_reg = RegisteredDecoders::new();
397 qt_register_all_decoders(&mut dec_reg);
398
399 test_decoding("mov", "qdesign-music", "assets/QT/rumcoke.mov", Some(32), &dmx_reg, &dec_reg,
400 ExpectedTestResult::Decodes);
401 }
402 }
403
404 const NOISE_VAL_BITS: [u8; 27] = [
405 12, 2, 3, 2, 3, 3, 5, 5,
406 6, 7, 7, 9, 7, 10, 9, 11,
407 9, 9, 9, 9, 9, 9, 9, 9,
408 10, 10, 12
409 ];
410 const NOISE_VAL_CODES: [u16; 27] = [
411 0xC7A, 0x000, 0x001, 0x003, 0x005, 0x006, 0x012, 0x00A,
412 0x022, 0x01A, 0x002, 0x0FA, 0x03A, 0x35A, 0x1C2, 0x07A,
413 0x1FA, 0x17A, 0x0DA, 0x142, 0x0C2, 0x042, 0x1DA, 0x05A,
414 0x15A, 0x27A, 0x47A
415 ];
416 const NOISE_VAL_SYMS: [u8; 27] = [
417 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
418 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36
419 ];
420
421 const NOISE_SEG_BITS: [u8; 12] = [ 10, 1, 2, 4, 4, 4, 6, 7, 9, 10, 8, 5 ];
422 const NOISE_SEG_CODES: [u16; 12] = [
423 0x30B, 0x000, 0x001, 0x003, 0x007, 0x00F, 0x02B, 0x04B,
424 0x00B, 0x10B, 0x08B, 0x01B
425 ];
426 const NOISE_SEG_SYMS: [u8; 12] = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 13, 17 ];
427
428 const FREQ_DIFF_BITS: [u8; 47] = [
429 18, 2, 4, 4, 5, 4, 4, 5, 5, 4, 5, 5, 5, 5, 6, 6,
430 6, 6, 6, 7, 7, 6, 7, 6, 6, 6, 7, 7, 7, 7, 7, 8,
431 9, 9, 8, 9, 11, 11, 12, 12, 13, 12, 14, 15, 18, 16, 17
432 ];
433 const FREQ_DIFF_CODES: [u32; 47] = [
434 0x2AD46, 0x00001, 0x00000, 0x00003, 0x0000C, 0x0000A, 0x00007, 0x00018,
435 0x00012, 0x0000E, 0x00004, 0x00016, 0x0000F, 0x0001C, 0x00008, 0x00022,
436 0x00026, 0x00002, 0x0003B, 0x00034, 0x00074, 0x0001F, 0x00014, 0x0002B,
437 0x0001B, 0x0003F, 0x00028, 0x00054, 0x00006, 0x0004B, 0x0000B, 0x00068,
438 0x000E8, 0x00046, 0x000C6, 0x001E8, 0x00146, 0x00346, 0x00546, 0x00746,
439 0x01D46, 0x00F46, 0x00D46, 0x06D46, 0x0AD46, 0x02D46, 0x1AD46
440 ];
441
442 const AMP_BITS: [u8; 28] = [
443 13, 7, 8, 9, 10, 10, 10, 10, 10, 9, 8, 7, 6, 5, 4, 3,
444 3, 2, 3, 3, 4, 5, 7, 8, 9, 11, 12, 13
445 ];
446 const AMP_CODES: [u16; 28] = [
447 0x1EC6, 0x0006, 0x00C2, 0x0142, 0x0242, 0x0246, 0x00C6, 0x0046,
448 0x0042, 0x0146, 0x00A2, 0x0062, 0x0026, 0x0016, 0x000E, 0x0005,
449 0x0004, 0x0003, 0x0000, 0x0001, 0x000A, 0x0012, 0x0002, 0x0022,
450 0x01C6, 0x02C6, 0x06C6, 0x0EC6
451 ];
452
453 const AMP_DIFF_BITS: [u8; 9] = [ 8, 2, 1, 3, 4, 5, 6, 7, 8 ];
454 const AMP_DIFF_CODES: [u8; 9] = [
455 0xFE, 0x00, 0x01, 0x02, 0x06, 0x0E, 0x1E, 0x3E, 0x7E
456 ];
457
458 const PHASE_DIFF_BITS: [u8; 9] = [ 6, 2, 2, 4, 4, 6, 5, 4, 2 ];
459 const PHASE_DIFF_CODES: [u8; 9] = [
460 0x35, 0x02, 0x00, 0x01, 0x0D, 0x15, 0x05, 0x09, 0x03
461 ];
462
463 const NOISE_BAND_SELECTOR: [usize; 5] = [ 4, 3, 2, 1, 0 ];
464 const NOISE_SUBBANDS: [&[usize]; 5] = [
465 &[ 0, 1, 2, 4, 6, 8, 12, 16, 24, 32, 48, 56, 64, 80, 96, 120, 144, 176, 208, 240, 256 ],
466 &[ 0, 2, 4, 8, 16, 24, 32, 48, 56, 64, 80, 104, 128, 160, 208, 256 ],
467 &[ 0, 2, 4, 8, 16, 32, 48, 64, 80, 112, 160, 208, 256 ],
468 &[ 0, 4, 8, 16, 32, 48, 64, 96, 144, 208, 256 ],
469 &[ 0, 4, 16, 32, 64, 256 ]
470 ];
471
472 const SCALES: [f32; 64] = [
473 1.1875, 1.6835938, 2.375, 3.3671875, 4.75, 6.734375, 9.5, 13.46875,
474 19.0, 26.9375, 38.0, 53.875, 76.0, 107.75, 152.0, 215.5,
475 304.0, 431.0, 608.0, 862.0, 1216.0, 1724.0, 2432.0, 3448.0,
476 4864.0, 6896.0, 9728.0, 13792.0, 19456.0, 27584.0, 38912.0, 55168.0,
477 77824.0, 110336.0, 155648.0, 220672.0, 311296.0, 441344.0, 622592.0, 882688.0,
478 1245184.0, 1765376.0, 2490368.0, 3530752.0, 4980736.0, 7061504.0, 0.0, 0.0,
479 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
480 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
481 ];