game: fix VMD audio decoding for stereo cases
[nihav.git] / nihav-game / src / codecs / vmd.rs
CommitLineData
9895bd7b
KS
1use nihav_core::codecs::*;
2use nihav_core::io::byteio::*;
b4d5b851 3use nihav_codec_support::codecs::HAMShuffler;
9895bd7b 4use std::str::FromStr;
f45dfcf7 5use std::sync::Arc;
9895bd7b
KS
6
7macro_rules! lz_op {
8 (read; $dst:ident, $dpos:expr, $window:ident, $wpos:expr, $br:expr, $dst_size:expr) => {
9 validate!($dpos < $dst_size);
10 let b = $br.read_byte()?;
11 $dst[$dpos] = b;
12 $dpos += 1;
13 $window[$wpos] = b;
14 $wpos = ($wpos + 1) & 0xFFF;
15 };
16 (copy; $dst:ident, $dpos:expr, $window:ident, $wpos:expr, $off:expr, $dst_size:expr) => {
17 let b = $window[$off];
18 validate!($dpos < $dst_size);
19 $dst[$dpos] = b;
20 $dpos += 1;
21 $window[$wpos] = b;
22 $wpos = ($wpos + 1) & 0xFFF;
23 $off = ($off + 1) & 0xFFF;
24 };
25}
26fn lz_unpack(br: &mut ByteReader, dst: &mut [u8]) -> DecoderResult<()> {
27 let mut window: [u8; 0x1000] = [0x20; 0x1000];
28
29 let dst_size = br.read_u32le()? as usize;
30 validate!(dst_size <= dst.len());
31 let mut pos;
32 let esc_len;
33 if br.peek_u32le()? == 0x56781234 {
34 br.read_skip(4)?;
35 pos = 0x111;
36 esc_len = 15;
37 } else {
38 pos = 0xFEE;
39 esc_len = 255;
40 }
41
42 let mut opos = 0;
43 while br.left() > 0 && opos < dst_size {
44 let op = br.read_byte()?;
45 if (op == 0xFF) && (br.left() > 8) {
46 for _ in 0..8 {
47 lz_op!(read; dst, opos, window, pos, br, dst_size);
48 }
49 } else {
50 for i in 0..8 {
51 if opos == dst_size { break; }
52 let is_literal = ((op >> i) & 1) != 0;
53 if is_literal {
54 lz_op!(read; dst, opos, window, pos, br, dst_size);
55 } else {
56 let b0 = br.read_byte()? as usize;
57 let b1 = br.read_byte()? as usize;
58 let mut off = b0 | ((b1 & 0xF0) << 4);
59 let mut len = b1 & 0xF;
60 if len == esc_len {
61 len = (br.read_byte()? as usize) + esc_len;
62 }
63 for _ in 0..len+3 {
64 lz_op!(copy; dst, opos, window, pos, off, dst_size);
65 }
66 }
67 }
68 }
69 }
70 Ok(())
71}
72
73fn rle_unpack(br: &mut ByteReader, len: usize, dst: &mut [u8]) -> DecoderResult<()> {
74 let end = br.tell() + (len as u64);
75 let mut dpos = 0;
76 if (len & 1) != 0 {
77 dst[dpos] = br.read_byte()?;
78 dpos += 1;
79 }
80 while dpos < dst.len() && br.tell() < end {
81 let val = br.read_byte()?;
82 let len = ((val & 0x7F) as usize) * 2;
83 validate!(dpos + len <= dst.len());
84 if (val & 0x80) != 0 {
85 let dst = &mut dst[dpos..][..len];
86 br.read_buf(dst)?;
87 } else {
88 let val = br.read_byte()?;
89 for i in 0..len {
90 dst[dpos + i] = val;
91 }
92 }
93 dpos += len;
94 }
95 Ok(())
96}
97
98fn decode_frame_data(br: &mut ByteReader, dst: &mut [u8], mut dpos: usize, stride: usize, w: usize, h: usize, method: u8) -> DecoderResult<bool> {
99 match method {
100 1 => {
101 for _ in 0..h {
102 let mut x = 0;
103 while x < w {
104 let val = br.read_byte()?;
105 let len = ((val & 0x7F) as usize) + 1;
106 validate!(x + len <= w);
107 if (val & 0x80) != 0 {
108 let pix = &mut dst[dpos + x..][..len];
109 br.read_buf(pix)?;
110 } // otherwise skip already existing data
111 x += len;
112 }
113 dpos += stride;
114 }
115 Ok(false)
116 },
117 2 => {
118 for _ in 0..h {
119 let pix = &mut dst[dpos..][..w];
120 br.read_buf(pix)?;
121 dpos += stride;
122 }
123 Ok(true)
124 },
125 3 => {
126 for _ in 0..h {
127 let mut x = 0;
128 while x < w {
129 let val = br.read_byte()?;
130 let len = ((val & 0x7F) as usize) + 1;
131 validate!(x + len <= w);
132 if (val & 0x80) != 0 {
133 let pix = &mut dst[dpos + x..][..len];
134 if br.peek_byte()? == 0xFF {
135 br.read_skip(1)?;
136 rle_unpack(br, len, pix)?;
137 } else {
138 br.read_buf(pix)?;
139 }
140 } // otherwise data is already there
141 x += len;
142 }
143 dpos += stride;
144 }
145 Ok(false)
146 },
e69b1148 147 _ => Err(DecoderError::InvalidData),
9895bd7b
KS
148 }
149}
150
151struct VMDVideoDecoder {
2422d969 152 info: NACodecInfoRef,
9895bd7b
KS
153 pal: [u8; 768],
154 buf: Vec<u8>,
155 width: usize,
156 height: usize,
157 hams: HAMShuffler,
158}
159
160impl VMDVideoDecoder {
161 fn new() -> Self {
162 Self {
2422d969 163 info: NACodecInfoRef::default(),
9895bd7b
KS
164 pal: [0; 768],
165 buf: Vec::new(),
166 width: 0,
167 height: 0,
168 hams: HAMShuffler::default(),
169 }
170 }
171 fn decode_frame(&mut self, br: &mut ByteReader, buf: &mut NAVideoBuffer<u8>) -> DecoderResult<bool> {
172 let paloff = buf.get_offset(1);
173 let stride = buf.get_stride(0);
1a967e6b 174 let data = buf.get_data_mut().unwrap();
9895bd7b
KS
175 let dst = data.as_mut_slice();
176
177 let frame_x = br.read_u16le()? as usize;
178 let frame_y = br.read_u16le()? as usize;
179 let frame_l = br.read_u16le()? as usize;
180 let frame_d = br.read_u16le()? as usize;
181 br.read_skip(1)?;
182 let flags = br.read_byte()?;
183 let has_pal = (flags & 0x02) != 0;
5961ae1d
KS
184 if (frame_x == 0xFFFF) && (frame_y == 0xFFFF) && (frame_l == 0xFFFF) && (frame_d == 0xFFFF) {
185 return Ok(false);
186 }
9895bd7b
KS
187 validate!(frame_l >= frame_x && frame_d >= frame_y);
188 validate!(frame_l < self.width && frame_d < self.height);
189
190 if has_pal {
191 br.read_skip(2)?;
192 for e in self.pal.iter_mut() {
193 let val = br.read_byte()?;
194 *e = (val << 2) | (val >> 4);
195 }
196 }
197
198 let dpal = &mut dst[paloff..][..768];
199 dpal.copy_from_slice(&self.pal[0..]);
200
201 if br.left() == 0 { return Ok(false); }
202
203 let w = frame_l + 1 - frame_x;
204 let h = frame_d + 1 - frame_y;
205 let dpos = frame_x + frame_y * stride;
206
207 let method = br.read_byte()?;
208 let is_intra;
209 if (method & 0x80) != 0 {
e69b1148 210 validate!(!self.buf.is_empty());
9895bd7b
KS
211 lz_unpack(br, &mut self.buf)?;
212 let mut mr = MemoryReader::new_read(&self.buf);
213 let mut buf_br = ByteReader::new(&mut mr);
214 is_intra = decode_frame_data(&mut buf_br, dst, dpos, stride, w, h, method & 0x7F)?;
215 } else {
216 is_intra = decode_frame_data(br, dst, dpos, stride, w, h, method & 0x7F)?;
217 }
218 Ok(is_intra && frame_x == 0 && frame_y == 0 && w == self.width && h == self.height)
219 }
220}
221
222impl NADecoder for VMDVideoDecoder {
01613464 223 fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
9895bd7b
KS
224 if let NACodecTypeInfo::Video(vinfo) = info.get_properties() {
225 self.width = vinfo.get_width();
226 self.height = vinfo.get_height();
227 let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(self.width, self.height, false, PAL8_FORMAT));
2422d969 228 self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref();
9895bd7b
KS
229 validate!(info.get_extradata().is_some());
230
231 if let Some(ref edata) = info.get_extradata() {
232 validate!(edata.len() == 0x330);
233 let unp_size = read_u32le(&edata[800..])? as usize;
234 validate!(unp_size < self.width * self.height * 3 + 64); // just for sanity
235 self.buf.resize(unp_size, 0);
236 for i in 0..768 {
237 let el = edata[28 + i];
238 self.pal[i] = (el << 2) | (el >> 4);
239 }
240 }
241
242 Ok(())
243 } else {
244 Err(DecoderError::InvalidData)
245 }
246 }
01613464 247 fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
9895bd7b
KS
248 let src = pkt.get_buffer();
249 validate!(src.len() >= 10);
250
251 let mut mr = MemoryReader::new_read(&src);
252 let mut br = ByteReader::new(&mut mr);
253
254 let mut buf;
255 let bufret = self.hams.clone_ref();
256 if let Some(bbuf) = bufret {
257 buf = bbuf;
258 } else {
e69b1148 259 let bufinfo = alloc_video_buffer(self.info.get_properties().get_video_info().unwrap(), 4)?;
9895bd7b
KS
260 buf = bufinfo.get_vbuf().unwrap();
261 self.hams.add_frame(buf);
262 buf = self.hams.get_output_frame().unwrap();
263 }
264
265 let is_intra = self.decode_frame(&mut br, &mut buf)?;
266
267 let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), NABufferType::Video(buf));
268 frm.set_keyframe(is_intra);
269 frm.set_frame_type(if is_intra { FrameType::I } else { FrameType::P });
171860fc 270 Ok(frm.into_ref())
9895bd7b 271 }
f9be4e75
KS
272 fn flush(&mut self) {
273 self.hams.clear();
274 }
9895bd7b
KS
275}
276
277
08a1fab7 278pub fn get_decoder_video() -> Box<dyn NADecoder + Send> {
9895bd7b
KS
279 Box::new(VMDVideoDecoder::new())
280}
281
f45dfcf7
KS
282#[derive(Clone,Copy,PartialEq)]
283enum VMDAudioMode {
284 U8,
285 DPCM,
286 StereoDPCM,
287}
288
9895bd7b
KS
289struct VMDAudioDecoder {
290 ainfo: NAAudioInfo,
f45dfcf7 291 info: Arc<NACodecInfo>,
9895bd7b 292 chmap: NAChannelMap,
9895bd7b
KS
293 blk_align: usize,
294 blk_size: usize,
f45dfcf7
KS
295 mode: VMDAudioMode,
296 pred: [i32; 2],
297 last_byte: Option<u8>,
298 is_odd: bool,
299 ch: usize,
9895bd7b
KS
300}
301
302const SOL_AUD_STEPS16: [i16; 128] = [
303 0x00, 0x08, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60,
304 0x70, 0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0,
305 0xF0, 0x100, 0x110, 0x120, 0x130, 0x140, 0x150, 0x160,
306 0x170, 0x180, 0x190, 0x1A0, 0x1B0, 0x1C0, 0x1D0, 0x1E0,
307 0x1F0, 0x200, 0x208, 0x210, 0x218, 0x220, 0x228, 0x230,
308 0x238, 0x240, 0x248, 0x250, 0x258, 0x260, 0x268, 0x270,
309 0x278, 0x280, 0x288, 0x290, 0x298, 0x2A0, 0x2A8, 0x2B0,
310 0x2B8, 0x2C0, 0x2C8, 0x2D0, 0x2D8, 0x2E0, 0x2E8, 0x2F0,
311 0x2F8, 0x300, 0x308, 0x310, 0x318, 0x320, 0x328, 0x330,
312 0x338, 0x340, 0x348, 0x350, 0x358, 0x360, 0x368, 0x370,
313 0x378, 0x380, 0x388, 0x390, 0x398, 0x3A0, 0x3A8, 0x3B0,
314 0x3B8, 0x3C0, 0x3C8, 0x3D0, 0x3D8, 0x3E0, 0x3E8, 0x3F0,
315 0x3F8, 0x400, 0x440, 0x480, 0x4C0, 0x500, 0x540, 0x580,
316 0x5C0, 0x600, 0x640, 0x680, 0x6C0, 0x700, 0x740, 0x780,
317 0x7C0, 0x800, 0x900, 0xA00, 0xB00, 0xC00, 0xD00, 0xE00,
318 0xF00, 0x1000, 0x1400, 0x1800, 0x1C00, 0x2000, 0x3000, 0x4000
319];
320
321impl VMDAudioDecoder {
322 fn new() -> Self {
323 Self {
324 ainfo: NAAudioInfo::new(0, 1, SND_S16P_FORMAT, 0),
f45dfcf7 325 info: NACodecInfo::new_dummy(),
9895bd7b 326 chmap: NAChannelMap::new(),
9895bd7b
KS
327 blk_align: 0,
328 blk_size: 0,
f45dfcf7
KS
329 mode: VMDAudioMode::U8,
330 pred: [0; 2],
331 last_byte: None,
332 is_odd: false,
333 ch: 0,
9895bd7b
KS
334 }
335 }
336 fn decode_16bit(&self, dst: &mut [i16], off1: usize, br: &mut ByteReader, nblocks: usize, mut mask: u32) -> DecoderResult<()> {
337 let channels = self.chmap.num_channels();
338 let mut off = [0, off1];
339 for _ in 0..nblocks {
340 if (mask & 1) != 0 {
341 for ch in 0..channels {
342 for i in 0..self.blk_align {
343 dst[off[ch] + i] = 0;
344 }
345 off[ch] += self.blk_align;
346 }
347 } else {
348 let mut pred: [i32; 2] = [0; 2];
349 for ch in 0..channels {
e69b1148 350 pred[ch] = i32::from(br.read_u16le()?);
9895bd7b
KS
351 dst[off[ch]] = pred[ch] as i16;
352 off[ch] += 1;
353 }
354 let mut ch = 0;
355 let flip_ch = if channels == 2 { 1 } else { 0 };
aa7e65d2 356 for _ in channels..self.blk_align*channels {
f45dfcf7 357 pred[ch] = Self::pred16(pred[ch], br.read_byte()?);
9895bd7b
KS
358 //pred[ch] = pred[ch].max(-32768).min(32767);
359 dst[off[ch]] = pred[ch] as i16;
360 off[ch] += 1;
361 ch ^= flip_ch;
362 }
363 }
364 mask >>= 1;
365 }
366 validate!(br.left() == 0);
367 Ok(())
368 }
f45dfcf7
KS
369 fn pred16(pred: i32, val: u8) -> i32 {
370 if (val & 0x80) != 0 {
371 pred - i32::from(SOL_AUD_STEPS16[(val & 0x7F) as usize])
372 } else {
373 pred + i32::from(SOL_AUD_STEPS16[(val & 0x7F) as usize])
374 }
375 }
376 fn cvt_u8(val: u8) -> u8 {
377 if val < 128 {
378 127 - val
379 } else {
380 val
381 }
382 }
9895bd7b
KS
383}
384
385impl NADecoder for VMDAudioDecoder {
01613464 386 fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
9895bd7b
KS
387 if let NACodecTypeInfo::Audio(ainfo) = info.get_properties() {
388 let fmt;
f45dfcf7
KS
389 let channels = ainfo.get_channels() as usize;
390 let edata = info.get_extradata();
391 let flags = if let Some(ref buf) = edata {
392 validate!(buf.len() >= 2);
393 (buf[0] as u16) | ((buf[1] as u16) << 8)
394 } else {
395 0
396 };
397 validate!((channels == 1) ^ ((flags & 0x8200) != 0));
9895bd7b 398 if ainfo.get_format().get_bits() == 8 {
9895bd7b 399 self.blk_size = ainfo.get_block_len();
f45dfcf7
KS
400 self.blk_align = ainfo.get_block_len() / channels;
401 if (flags & 0x8000) == 0 {
402 fmt = SND_U8_FORMAT;
403 self.mode = VMDAudioMode::U8;
404 } else {
405 fmt = SND_S16_FORMAT;
406 self.mode = VMDAudioMode::StereoDPCM;
407 self.is_odd = (channels == 2) && ((self.blk_size & 1) != 0);
408 }
9895bd7b
KS
409 } else {
410 fmt = SND_S16P_FORMAT;
f45dfcf7 411 self.blk_size = (ainfo.get_block_len() + 1) * channels;
aa7e65d2 412 self.blk_align = ainfo.get_block_len();
f45dfcf7 413 self.mode = VMDAudioMode::DPCM;
9895bd7b 414 };
9895bd7b 415 self.ainfo = NAAudioInfo::new(ainfo.get_sample_rate(), ainfo.get_channels(), fmt, ainfo.get_block_len());
f45dfcf7
KS
416 self.info = info.replace_info(NACodecTypeInfo::Audio(self.ainfo.clone()));
417 self.chmap = NAChannelMap::from_str(if channels == 1 { "C" } else { "L,R" }).unwrap();
9895bd7b
KS
418 Ok(())
419 } else {
420 Err(DecoderError::InvalidData)
421 }
422 }
01613464 423 fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
9895bd7b
KS
424 let info = pkt.get_stream().get_info();
425 if let NACodecTypeInfo::Audio(_) = info.get_properties() {
426 let pktbuf = pkt.get_buffer();
427 validate!(pktbuf.len() >= 6);
428 let mut mr = MemoryReader::new_read(&pktbuf);
429 let mut br = ByteReader::new(&mut mr);
430 let blk_type = br.read_byte()?;
431 br.read_skip(9)?;
432 let mask;
433 let nblocks;
434 if blk_type == 2 { // initial
435 mask = br.read_u32le()?;
436 nblocks = (mask.count_ones() as usize) + (pktbuf.len() - 14) / self.blk_size;
437 } else if blk_type == 3 { // silence
438 mask = 1;
439 nblocks = 1;
440 } else {
441 mask = 0;
442 nblocks = 1;
443 }
f45dfcf7
KS
444 let mut samples = nblocks * self.blk_align;
445 if self.mode == VMDAudioMode::StereoDPCM && self.is_odd {
446 samples += (nblocks + if self.last_byte.is_some() { 1 } else { 0 }) / 2;
447 }
9895bd7b 448 let abuf = alloc_audio_buffer(self.ainfo, samples, self.chmap.clone())?;
f45dfcf7
KS
449 match self.mode {
450 VMDAudioMode::DPCM => {
451 let mut adata = abuf.get_abuf_i16().unwrap();
452 let off1 = adata.get_offset(1);
453 let mut dst = adata.get_data_mut().unwrap();
454 self.decode_16bit(&mut dst, off1, &mut br, nblocks, mask)?;
455 },
456 VMDAudioMode::U8 => {
457 let mut adata = abuf.get_abuf_u8().unwrap();
458 let dst = adata.get_data_mut().unwrap();
459 let mut doff = 0;
460 let mut mask = mask;
461 let channels = self.chmap.num_channels();
462 for _ in 0..nblocks {
463 if (mask & 1) != 0 {
464 for i in 0..self.blk_align * channels {
465 dst[doff + i] = 128;
466 }
467 } else if channels == 1 {
468 for i in 0..self.blk_size {
469 dst[doff + i] = br.read_byte()?;
470 }
471 } else {
472 for i in 0..self.blk_size {
473 let val = Self::cvt_u8(br.read_byte()?);
474 dst[doff + i] = val;
475 }
9895bd7b 476 }
f45dfcf7
KS
477 doff += self.blk_align * channels;
478 mask >>= 1;
479 }
480 },
481 VMDAudioMode::StereoDPCM => {
482 let mut adata = abuf.get_abuf_i16().unwrap();
483 let dst = adata.get_data_mut().unwrap();
484 let mut doff = 0;
485 let mut mask = mask;
486 let mut ch = self.ch;
487 for _ in 0..nblocks {
488 let put_sample = self.last_byte.is_some();
489 if let (true, Some(val)) = (self.is_odd, self.last_byte) {
490 self.pred[ch] = Self::pred16(self.pred[ch], val);
491 dst[doff] = self.pred[ch] as i16;
492 doff += 1;
493 ch ^= 1;
494 self.last_byte = None;
9895bd7b 495 }
f45dfcf7
KS
496 if (mask & 1) != 0 {
497 for i in 0..self.blk_align {
498 dst[doff + i * 2 + 0] = self.pred[ch] as i16;
499 dst[doff + i * 2 + 1] = self.pred[ch ^ 1] as i16;
500 }
501 if self.is_odd {
502 if put_sample {
503 dst[doff + self.blk_align * 2] = self.pred[ch] as i16;
504 doff += 1;
505 ch ^= 1;
506 } else {
507 self.last_byte = Some(0);
508 }
509 }
510 } else {
511 for i in 0..self.blk_align {
512 self.pred[ch] = Self::pred16(self.pred[ch], br.read_byte()?);
513 dst[doff + i * 2] = self.pred[ch] as i16;
514 self.pred[ch ^ 1] = Self::pred16(self.pred[ch ^ 1], br.read_byte()?);
515 dst[doff + i * 2 + 1] = self.pred[ch ^ 1] as i16;
516 }
517 if self.is_odd {
518 let val = br.read_byte()?;
519 if put_sample {
520 self.pred[ch] = Self::pred16(self.pred[ch], val);
521 dst[doff + self.blk_align * 2] = self.pred[ch] as i16;
522 doff += 1;
523 ch ^= 1;
524 } else {
525 self.last_byte = Some(val);
526 }
aa7e65d2
KS
527 }
528 }
f45dfcf7
KS
529 doff += self.blk_align * 2;
530 mask >>= 1;
9895bd7b 531 }
f45dfcf7
KS
532 self.ch = ch;
533 },
534 };
9895bd7b 535
f45dfcf7 536 let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), abuf);
9895bd7b
KS
537 frm.set_duration(Some(samples as u64));
538 frm.set_keyframe(true);
171860fc 539 Ok(frm.into_ref())
9895bd7b
KS
540 } else {
541 Err(DecoderError::InvalidData)
542 }
543 }
f9be4e75
KS
544 fn flush(&mut self) {
545 }
9895bd7b
KS
546}
547
08a1fab7 548pub fn get_decoder_audio() -> Box<dyn NADecoder + Send> {
9895bd7b
KS
549 Box::new(VMDAudioDecoder::new())
550}
551
552#[cfg(test)]
553mod test {
554 use nihav_core::codecs::RegisteredDecoders;
555 use nihav_core::demuxers::RegisteredDemuxers;
ce742854 556 use nihav_codec_support::test::dec_video::*;
e64739f8
KS
557 use crate::game_register_all_codecs;
558 use crate::game_register_all_demuxers;
9895bd7b
KS
559 #[test]
560 fn test_vmd_video() {
561 let mut dmx_reg = RegisteredDemuxers::new();
562 game_register_all_demuxers(&mut dmx_reg);
563 let mut dec_reg = RegisteredDecoders::new();
564 game_register_all_codecs(&mut dec_reg);
565
1678d59a
KS
566// let file = "assets/Game/1491.VMD";
567 let file = "assets/Game/128.vmd";
9895bd7b
KS
568 test_file_decoding("vmd", file, Some(10), true, false, None/*Some("vmd")*/, &dmx_reg, &dec_reg);
569 }
570 #[test]
571 fn test_vmd_audio() {
572 let mut dmx_reg = RegisteredDemuxers::new();
573 game_register_all_demuxers(&mut dmx_reg);
574 let mut dec_reg = RegisteredDecoders::new();
575 game_register_all_codecs(&mut dec_reg);
576
1678d59a
KS
577// let file = "assets/Game/1491.VMD";
578 let file = "assets/Game/128.vmd";
579// let file = "assets/Game/1000.VMD";
580// let file = "assets/Game/235.VMD";
5580b11b 581 test_decode_audio("vmd", file, None, None/*Some("vmd")*/, &dmx_reg, &dec_reg);
9895bd7b
KS
582 }
583}