An audio player for macOS 10.8 and newer. https://kode54.net/cog
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

76 lines
3.4KB

  1. #include "layout.h"
  2. #include "../coding/coding.h"
  3. #include "../layout/layout.h"
  4. #include "../vgmstream.h"
  5. static size_t get_channel_header_size(STREAMFILE* sf, off_t offset, int channels, int big_endian);
  6. static size_t get_block_header_size(STREAMFILE* sf, off_t offset, size_t channel_header_size, int channels, int big_endian);
  7. /* AWC music chunks */
  8. void block_update_awc(off_t block_offset, VGMSTREAM * vgmstream) {
  9. STREAMFILE* sf = vgmstream->ch[0].streamfile;
  10. int32_t (*read_32bit)(off_t,STREAMFILE*) = vgmstream->codec_endian ? read_32bitBE : read_32bitLE;
  11. size_t header_size, entries, block_size, block_samples;
  12. size_t channel_header_size;
  13. int i;
  14. /* assumed only AWC_IMA enters here, MPEG/XMA2 need special parsing as blocked layout is too limited */
  15. entries = read_32bit(block_offset + 0x04, sf); /* se first channel, assume all are the same */
  16. //block_samples = entries * (0x800-4)*2; //todo use
  17. block_samples = read_32bit(block_offset + 0x0c, sf);
  18. block_size = vgmstream->full_block_size;
  19. vgmstream->current_block_offset = block_offset;
  20. vgmstream->next_block_offset = block_offset + block_size;
  21. vgmstream->current_block_samples = block_samples;
  22. /* starts with a header block */
  23. /* for each channel
  24. * 0x00: start entry within channel (ie. entries * ch) but may be off by +1/+2
  25. * 0x04: entries
  26. * 0x08: samples to discard in the beginning of this block (MPEG only?)
  27. * 0x0c: samples in channel (for MPEG/XMA2 can vary between channels)
  28. * (next fields don't exist in later versions for IMA)
  29. * 0x10: (MPEG only, empty otherwise) close to number of frames but varies a bit?
  30. * 0x14: (MPEG only, empty otherwise) channel usable data size (not counting padding)
  31. * for each channel
  32. * 32b * entries = global samples per frame in each block (for MPEG probably per full frame)
  33. */
  34. channel_header_size = get_channel_header_size(sf, block_offset, vgmstream->channels, vgmstream->codec_endian);
  35. header_size = get_block_header_size(sf, block_offset, channel_header_size, vgmstream->channels, vgmstream->codec_endian);
  36. for (i = 0; i < vgmstream->channels; i++) {
  37. vgmstream->ch[i].offset = block_offset + header_size + 0x800*entries*i;
  38. VGM_ASSERT(entries != read_32bit(block_offset + channel_header_size*i + 0x04, sf), "AWC: variable number of entries found at %lx\n", block_offset);
  39. }
  40. }
  41. static size_t get_channel_header_size(STREAMFILE* sf, off_t offset, int channels, int big_endian) {
  42. int32_t (*read_32bit)(off_t,STREAMFILE*) = big_endian ? read_32bitBE : read_32bitLE;
  43. /* later games have an smaller channel header, try to detect using
  44. * an empty field not in IMA */
  45. if (read_32bit(offset + 0x14, sf) == 0x00)
  46. return 0x18;
  47. return 0x10;
  48. }
  49. static size_t get_block_header_size(STREAMFILE* sf, off_t offset, size_t channel_header_size, int channels, int big_endian) {
  50. size_t header_size = 0;
  51. int i;
  52. int entries = channels;
  53. int32_t (*read_32bit)(off_t,STREAMFILE*) = big_endian ? read_32bitBE : read_32bitLE;
  54. for (i = 0; i < entries; i++) {
  55. header_size += channel_header_size;
  56. header_size += read_32bit(offset + channel_header_size*i + 0x04, sf) * 0x04; /* entries in the table */
  57. }
  58. if (header_size % 0x800) /* padded */
  59. header_size += 0x800 - (header_size % 0x800);
  60. return header_size;
  61. }