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.

640 lines
22KB

  1. #include "meta.h"
  2. #include "../coding/coding.h"
  3. static void load_name(char *name, size_t name_size, STREAMFILE *sf, int big_endian, int total_subsongs, int target_subsong);
  4. static STREAMFILE* setup_nub_streamfile(STREAMFILE *sf, off_t header_offset, size_t header_size, off_t stream_offset, size_t stream_size, const char *fake_ext);
  5. /* .nub - Namco's nuSound2 audio container */
  6. VGMSTREAM * init_vgmstream_nub(STREAMFILE *streamFile) {
  7. VGMSTREAM *vgmstream = NULL;
  8. STREAMFILE *temp_sf = NULL;
  9. int big_endian;
  10. int total_subsongs, target_subsong = streamFile->stream_index;
  11. uint32_t version, codec;
  12. const char* fake_ext;
  13. VGMSTREAM*(*init_vgmstream_function)(STREAMFILE *) = NULL;
  14. char name[STREAM_NAME_SIZE] = {0};
  15. int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
  16. /* checks */
  17. /* .nub: standard
  18. * .nub2: rare [iDOLM@STER - Gravure For You (PS3)] */
  19. if (!check_extensions(streamFile, "nub,nub2"))
  20. goto fail;
  21. version = read_32bitBE(0x00,streamFile);
  22. if (version != 0x00020000 && /* v2.0 (rare, ex. Ridge Race 6 (X360)) */
  23. version != 0x00020100 && /* v2.1 (common) */
  24. version != 0x01020100) /* same but LE (seen in PSP/PC games, except PS4) */
  25. goto fail;
  26. if (read_32bitBE(0x04,streamFile) != 0x00000000) /* null */
  27. goto fail;
  28. /* sometimes LE [Soul Calibur: Broken Destiny (PSP), Tales of Vesperia (PS4) */
  29. big_endian = guess_endianness32bit(0x10, streamFile);
  30. if (big_endian) {
  31. read_32bit = read_32bitBE;
  32. } else{
  33. read_32bit = read_32bitLE;
  34. }
  35. /* parse TOC */
  36. {
  37. off_t offset, data_start, header_start;
  38. off_t header_offset, subheader_start, stream_offset;
  39. size_t header_size, subheader_size, stream_size;
  40. /* - base header */
  41. /* 0x08: file id (0 = first) */
  42. total_subsongs = read_32bit(0x0c, streamFile); /* .nub with 0 files do exist, and with 1 song only too */
  43. data_start = read_32bit(0x10, streamFile); /* exists even with 0 files */
  44. /* 0x14: data end (may have padding) */
  45. header_start = read_32bit(0x18, streamFile);
  46. /* 0x1c: header end */
  47. /* probably means "header end" in v2.0 */
  48. if (version == 0x00020000) {
  49. data_start = align_size_to_block(data_start, 0x800);
  50. }
  51. if (target_subsong == 0) target_subsong = 1;
  52. if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
  53. offset = read_32bit(header_start + (target_subsong-1)*0x04, streamFile);
  54. /* .nus have all headers first then all data, but extractors often just paste them together,
  55. * so we'll combine header+data on the fly to make them playable with existing parsers.
  56. * Formats inside .nub normally don't exist as external files, so they could be extracted in various
  57. * ways that we'll try to match (though IDSP/BNSF can be found as header+data in some bigfiles).
  58. * Headers seem to be called "tones" and data "streams" in debug strings. */
  59. header_offset = offset;
  60. /* - extension (as referenced in companion files with internal filenames, ex. "BGM_MovingDemo1.is14" > "is14") */
  61. if (version != 0x00020000)
  62. offset += 0x04; /* skip, not found in v2.0 */
  63. /* - tone header */
  64. /* 0x00: config? */
  65. /* 0x04: header id/number */
  66. codec = (uint32_t)read_32bit(offset + 0x08, streamFile);
  67. /* 0x0c: null */
  68. stream_size = read_32bit(offset + 0x10, streamFile); /* 0x10 aligned */
  69. stream_offset = read_32bit(offset + 0x14, streamFile) + data_start;
  70. subheader_size = read_32bit(offset + 0x18, streamFile);
  71. /* 0x1c: extra info, size 0x10 (meaning varies but usually loop points) */
  72. /* rest until sub-header start looks like config/volumes/pan/etc in various floats */
  73. if (version == 0x00020000)
  74. subheader_start = 0xAC;
  75. else
  76. subheader_start = 0xBC;
  77. header_size = align_size_to_block(subheader_start + subheader_size, 0x10);
  78. switch(codec) {
  79. case 0x00: /* (none) (xma1) */
  80. fake_ext = "xma";
  81. init_vgmstream_function = init_vgmstream_nub_xma;
  82. break;
  83. case 0x01: /* "wav\0" */
  84. fake_ext = "wav";
  85. init_vgmstream_function = init_vgmstream_nub_wav;
  86. break;
  87. case 0x02: /* "vag\0" */
  88. fake_ext = "vag";
  89. init_vgmstream_function = init_vgmstream_nub_vag;
  90. break;
  91. case 0x03: /* "at3\0" */
  92. fake_ext = "at3";
  93. init_vgmstream_function = init_vgmstream_nub_at3;
  94. break;
  95. case 0x04: /* "xma\0" (xma2 old) */
  96. case 0x08: /* "xma\0" (xma2 new) */
  97. fake_ext = "xma";
  98. init_vgmstream_function = init_vgmstream_nub_xma;
  99. break;
  100. case 0x05: /* "dsp\0" */
  101. fake_ext = "dsp";
  102. init_vgmstream_function = init_vgmstream_nub_dsp;
  103. break;
  104. case 0x06: /* "idsp" */
  105. fake_ext = "idsp";
  106. init_vgmstream_function = init_vgmstream_nub_idsp;
  107. break;
  108. case 0x07: /* "is14" */
  109. fake_ext = "is14";
  110. init_vgmstream_function = init_vgmstream_nub_is14;
  111. break;
  112. default:
  113. VGM_LOG("NUB: unknown codec %x\n", codec);
  114. goto fail;
  115. }
  116. //;VGM_LOG("NUB: subfile header=%lx + %x, offset=%lx + %x\n", header_offset, header_size, stream_offset, stream_size);
  117. temp_sf = setup_nub_streamfile(streamFile, header_offset, header_size, stream_offset, stream_size, fake_ext);
  118. if (!temp_sf) goto fail;
  119. }
  120. /* get names from companion file, rarely [Noby Noby Boy (PS3), Wangan Midnight Maximum Tune (AC)] */
  121. load_name(name, sizeof(name), streamFile, big_endian, total_subsongs, target_subsong);
  122. /* init the VGMSTREAM */
  123. vgmstream = init_vgmstream_function(temp_sf);
  124. if (!vgmstream) goto fail;
  125. vgmstream->stream_size = get_streamfile_size(temp_sf);
  126. vgmstream->num_streams = total_subsongs;
  127. if (name[0] != '\0')
  128. strcpy(vgmstream->stream_name, name);
  129. close_streamfile(temp_sf);
  130. return vgmstream;
  131. fail:
  132. close_streamfile(temp_sf);
  133. close_vgmstream(vgmstream);
  134. return NULL;
  135. }
  136. /* *********************************************************** */
  137. static void load_name(char *name, size_t name_size, STREAMFILE *sf, int big_endian, int total_subsongs, int target_subsong) {
  138. STREAMFILE *sf_names = NULL;
  139. char filename[PATH_LIMIT];
  140. char basename[255];
  141. char name1[0x40+1] = {0};
  142. char name2[0x40+1] = {0};
  143. int count;
  144. off_t offset;
  145. size_t name1_size, name2_size;
  146. uint32_t (*read_u32)(off_t,STREAMFILE*) = big_endian ? read_u32be : read_u32le;
  147. get_streamfile_basename(sf, basename, sizeof(basename));
  148. snprintf(filename, sizeof(filename), "nuSound2ToneStr%s.bin", basename);
  149. sf_names = open_streamfile_by_filename(sf, filename);
  150. if (!sf_names) goto done;
  151. /* 0x00: version/endianness? (0=NNB, 1=WMMT5) */
  152. /* 0x04: version/endianness? (1=NNB, 0=WMMT5) */
  153. count = read_u32(0x08, sf_names);
  154. /* 0x0c: file size */
  155. name1_size = read_u32(0x10, sf_names);
  156. name2_size = read_u32(0x14, sf_names);
  157. /* 0x18/1c: null */
  158. /* 0x20: bank name (size 0x20) */
  159. if (count != total_subsongs)
  160. goto done;
  161. if (name1_size >= sizeof(name1) || name2_size >= sizeof(name2))
  162. goto done;
  163. offset = 0x40 + (target_subsong - 1) * (name1_size + name2_size);
  164. read_string(name1, name1_size, offset + 0x00, sf_names); /* internal name */
  165. read_string(name2, name2_size, offset + name1_size, sf_names); /* file name */
  166. //todo some filenames use shift-jis, not sure what to do
  167. snprintf(name, name_size, "%s/%s", name1, name2);
  168. done:
  169. close_streamfile(sf_names);
  170. }
  171. static STREAMFILE* setup_nub_streamfile(STREAMFILE *sf, off_t header_offset, size_t header_size, off_t stream_offset, size_t stream_size, const char *fake_ext) {
  172. STREAMFILE *new_sf = NULL;
  173. STREAMFILE *multi_sf[2] = {0};
  174. multi_sf[0] = open_wrap_streamfile(sf);
  175. multi_sf[0] = open_clamp_streamfile_f(multi_sf[0], header_offset, header_size);
  176. multi_sf[1] = open_wrap_streamfile(sf);
  177. multi_sf[1] = open_clamp_streamfile_f(multi_sf[1], stream_offset, stream_size);
  178. new_sf = open_multifile_streamfile_f(multi_sf, 2);
  179. new_sf = open_fakename_streamfile_f(new_sf, NULL, fake_ext);
  180. return new_sf;
  181. }
  182. /* *********************************************************** */
  183. //todo could be simplified
  184. /* .nub wav - from Namco NUB archives [Ridge Racer 7 (PS3)] */
  185. VGMSTREAM * init_vgmstream_nub_wav(STREAMFILE *streamFile) {
  186. VGMSTREAM * vgmstream = NULL;
  187. off_t start_offset;
  188. int loop_flag, channel_count, sample_rate;
  189. size_t data_size, loop_start, loop_length;
  190. int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
  191. int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL;
  192. /* checks */
  193. if (!check_extensions(streamFile, "wav,lwav"))
  194. goto fail;
  195. if (read_32bitBE(0x00,streamFile) != 0x77617600) /* "wav\0" "*/
  196. goto fail;
  197. if (guess_endianness32bit(0x1c, streamFile)) {
  198. read_32bit = read_32bitBE;
  199. read_16bit = read_16bitBE;
  200. } else {
  201. read_32bit = read_32bitLE;
  202. read_16bit = read_16bitLE;
  203. }
  204. data_size = read_32bit(0x14,streamFile);
  205. /* info header */
  206. loop_start = read_32bit(0x20,streamFile);
  207. loop_length = read_32bit(0x24,streamFile);
  208. loop_flag = read_32bit(0x28,streamFile);
  209. /* 0x2c: null */
  210. /* format header: mini "fmt" chunk */
  211. if (read_16bit(0xBC + 0x00, streamFile) != 0x0001)
  212. goto fail;
  213. channel_count = read_16bit(0xBC + 0x02,streamFile);
  214. sample_rate = read_32bit(0xBC + 0x04,streamFile);
  215. /* 0x08: bitrate */
  216. /* 0x0c: block align/bps */
  217. start_offset = 0xD0;
  218. /* build the VGMSTREAM */
  219. vgmstream = allocate_vgmstream(channel_count,loop_flag);
  220. if (!vgmstream) goto fail;
  221. vgmstream->meta_type = meta_NUB;
  222. vgmstream->sample_rate = sample_rate;
  223. vgmstream->num_samples = pcm_bytes_to_samples(data_size, channel_count, 16);
  224. vgmstream->loop_start_sample = pcm_bytes_to_samples(loop_start, channel_count, 16);
  225. vgmstream->loop_end_sample = pcm_bytes_to_samples(loop_start + loop_length, channel_count, 16);
  226. vgmstream->coding_type = coding_PCM16BE; /* always BE */
  227. vgmstream->layout_type = layout_interleave;
  228. vgmstream->interleave_block_size = 0x02;
  229. if (!vgmstream_open_stream(vgmstream, streamFile, start_offset))
  230. goto fail;
  231. return vgmstream;
  232. fail:
  233. close_vgmstream(vgmstream);
  234. return NULL;
  235. }
  236. /* .nub vag - from Namco NUB archives [Ridge Racer 7 (PS3), Noby Noby Boy (PS3)] */
  237. VGMSTREAM * init_vgmstream_nub_vag(STREAMFILE *streamFile) {
  238. VGMSTREAM * vgmstream = NULL;
  239. off_t start_offset;
  240. int loop_flag, channel_count, sample_rate;
  241. size_t data_size, loop_start, loop_length;
  242. int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
  243. /* checks */
  244. if ( !check_extensions(streamFile, "vag"))
  245. goto fail;
  246. if (read_32bitBE(0x00,streamFile) != 0x76616700) /* "vag\0" */
  247. goto fail;
  248. if (guess_endianness32bit(0x1c, streamFile)) {
  249. read_32bit = read_32bitBE;
  250. } else {
  251. read_32bit = read_32bitLE;
  252. }
  253. data_size = read_32bit(0x14,streamFile);
  254. /* info header */
  255. loop_start = read_32bit(0x20,streamFile);
  256. loop_length = read_32bit(0x24,streamFile);
  257. loop_flag = read_32bit(0x28,streamFile);
  258. /* 0x2c: null */
  259. /* format header */
  260. sample_rate = read_32bit(0xBC + 0x00,streamFile);
  261. channel_count = 1;
  262. start_offset = 0xC0;
  263. /* build the VGMSTREAM */
  264. vgmstream = allocate_vgmstream(channel_count,loop_flag);
  265. if (!vgmstream) goto fail;
  266. vgmstream->meta_type = meta_NUB;
  267. vgmstream->sample_rate = sample_rate;
  268. vgmstream->num_samples = ps_bytes_to_samples(data_size, channel_count);
  269. vgmstream->loop_start_sample = ps_bytes_to_samples(loop_start, channel_count);
  270. vgmstream->loop_end_sample = ps_bytes_to_samples(loop_start + loop_length, channel_count);
  271. vgmstream->coding_type = coding_PSX;
  272. vgmstream->layout_type = layout_none;
  273. vgmstream->allow_dual_stereo = 1;
  274. if (!vgmstream_open_stream(vgmstream, streamFile, start_offset))
  275. goto fail;
  276. return vgmstream;
  277. fail:
  278. close_vgmstream(vgmstream);
  279. return NULL;
  280. }
  281. /* .nub at3 - from Namco NUB archives [Ridge Racer 7 (PS3), Katamari Forever (PS3)] */
  282. VGMSTREAM * init_vgmstream_nub_at3(STREAMFILE *streamFile) {
  283. VGMSTREAM * vgmstream = NULL;
  284. STREAMFILE *temp_sf = NULL;
  285. off_t subfile_offset = 0;
  286. size_t subfile_size = 0;
  287. /* checks */
  288. if (!check_extensions(streamFile,"at3"))
  289. goto fail;
  290. if (read_32bitBE(0x00,streamFile) != 0x61743300) /* "at3\0" */
  291. goto fail;
  292. /* info header */
  293. /* 0x20: loop start (in samples) */
  294. /* 0x24: loop length (in samples) */
  295. /* 0x28: loop flag */
  296. /* 0x2c: null */
  297. /* format header: mini fmt (WAVEFORMATEX) + fact chunks LE (clone of RIFF's) */
  298. /* we can just ignore and use RIFF at data start since it has the same info */
  299. subfile_offset = 0x100;
  300. subfile_size = read_32bitLE(subfile_offset + 0x04, streamFile) + 0x08; /* RIFF size */
  301. temp_sf = setup_subfile_streamfile(streamFile, subfile_offset,subfile_size, NULL);
  302. if (!temp_sf) goto fail;
  303. vgmstream = init_vgmstream_riff(temp_sf);
  304. if (!vgmstream) goto fail;
  305. close_streamfile(temp_sf);
  306. return vgmstream;
  307. fail:
  308. close_streamfile(temp_sf);
  309. close_vgmstream(vgmstream);
  310. return NULL;
  311. }
  312. /* .nub xma - from Namco NUB archives [Ridge Racer 6 (X360), Tekken 6 (X360), Galaga Legions DX (X360)] */
  313. VGMSTREAM * init_vgmstream_nub_xma(STREAMFILE *streamFile) {
  314. VGMSTREAM * vgmstream = NULL;
  315. off_t start_offset, chunk_offset;
  316. size_t data_size, chunk_size, header_size;
  317. int loop_flag, channel_count, sample_rate, nus_codec;
  318. int num_samples, loop_start_sample, loop_end_sample;
  319. /* checks */
  320. if (!check_extensions(streamFile,"xma"))
  321. goto fail;
  322. if (read_32bitBE(0x00,streamFile) == 0x786D6100) { /* "xma\0" */
  323. /* nub v2.1 */
  324. nus_codec = read_32bitBE(0x0C,streamFile);
  325. data_size = read_32bitBE(0x14,streamFile);
  326. header_size = read_32bitBE(0x1c,streamFile);
  327. chunk_offset = 0xBC;
  328. /* info header */
  329. /* 0x20: null */
  330. chunk_size = read_32bitBE(0x24,streamFile);
  331. /* 0x24: loop flag */
  332. /* 0x20: null */
  333. }
  334. else if (read_32bitBE(0x08,streamFile) == 0 && read_32bitBE(0x0c,streamFile) == 0) {
  335. /* nub v2.0 from Ridge Racer 6 */
  336. nus_codec = read_32bitBE(0x08,streamFile);
  337. data_size = read_32bitBE(0x10,streamFile);
  338. header_size = read_32bitBE(0x18,streamFile);
  339. chunk_offset = 0xAC;
  340. chunk_size = header_size;
  341. }
  342. else {
  343. goto fail;
  344. }
  345. start_offset = align_size_to_block(chunk_offset + header_size, 0x10);
  346. if (nus_codec == 0x00) { /* XMA1 "fmt " */
  347. int loop_start_b, loop_end_b, loop_subframe;
  348. xma1_parse_fmt_chunk(streamFile, chunk_offset, &channel_count,&sample_rate, &loop_flag, &loop_start_b, &loop_end_b, &loop_subframe, 1);
  349. {
  350. ms_sample_data msd = {0};
  351. msd.xma_version = 1;
  352. msd.channels = channel_count;
  353. msd.data_offset = start_offset;
  354. msd.data_size = data_size;
  355. msd.loop_flag = loop_flag;
  356. msd.loop_start_b= loop_start_b;
  357. msd.loop_end_b = loop_end_b;
  358. msd.loop_start_subframe = loop_subframe & 0xF; /* lower 4b: subframe where the loop starts, 0..4 */
  359. msd.loop_end_subframe = loop_subframe >> 4; /* upper 4b: subframe where the loop ends, 0..3 */
  360. msd.chunk_offset= chunk_offset;
  361. xma_get_samples(&msd, streamFile);
  362. num_samples = msd.num_samples;
  363. loop_start_sample = msd.loop_start_sample;
  364. loop_end_sample = msd.loop_end_sample;
  365. }
  366. }
  367. else if (nus_codec == 0x04) { /* "XMA2" */
  368. xma2_parse_xma2_chunk(streamFile, chunk_offset, &channel_count,&sample_rate, &loop_flag, &num_samples, &loop_start_sample, &loop_end_sample);
  369. }
  370. else if (nus_codec == 0x08) { /* XMA2 "fmt " */
  371. channel_count = read_16bitBE(chunk_offset+0x02,streamFile);
  372. sample_rate = read_32bitBE(chunk_offset+0x04,streamFile);
  373. xma2_parse_fmt_chunk_extra(streamFile, chunk_offset, &loop_flag, &num_samples, &loop_start_sample, &loop_end_sample, 1);
  374. }
  375. else {
  376. goto fail;
  377. }
  378. /* build the VGMSTREAM */
  379. vgmstream = allocate_vgmstream(channel_count,loop_flag);
  380. if (!vgmstream) goto fail;
  381. vgmstream->meta_type = meta_NUB;
  382. vgmstream->sample_rate = sample_rate;
  383. vgmstream->num_samples = num_samples;
  384. vgmstream->loop_start_sample = loop_start_sample;
  385. vgmstream->loop_end_sample = loop_end_sample;
  386. #ifdef VGM_USE_FFMPEG
  387. {
  388. uint8_t buf[0x100];
  389. size_t bytes;
  390. if (nus_codec == 0x04) {
  391. bytes = ffmpeg_make_riff_xma2_from_xma2_chunk(buf,0x100, chunk_offset,chunk_size, data_size, streamFile);
  392. } else {
  393. bytes = ffmpeg_make_riff_xma_from_fmt_chunk(buf,0x100, chunk_offset,chunk_size, data_size, streamFile, 1);
  394. }
  395. vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, start_offset,data_size);
  396. if ( !vgmstream->codec_data ) goto fail;
  397. vgmstream->coding_type = coding_FFmpeg;
  398. vgmstream->layout_type = layout_none;
  399. xma_fix_raw_samples(vgmstream, streamFile, start_offset, data_size, chunk_offset, 1,1); /* samples needs adjustment */
  400. }
  401. #else
  402. goto fail;
  403. #endif
  404. if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
  405. goto fail;
  406. return vgmstream;
  407. fail:
  408. close_vgmstream(vgmstream);
  409. return NULL;
  410. }
  411. /* .nub dsp - from Namco NUB archives [Taiko no Tatsujin Wii Chou Goukanban (Wii)] */
  412. VGMSTREAM * init_vgmstream_nub_dsp(STREAMFILE *streamFile) {
  413. VGMSTREAM *vgmstream = NULL;
  414. STREAMFILE *temp_sf = NULL;
  415. off_t header_offset, stream_offset;
  416. size_t header_size, stream_size;
  417. /* checks */
  418. if (!check_extensions(streamFile,"dsp"))
  419. goto fail;
  420. if (read_32bitBE(0x00,streamFile) != 0x64737000) /* "dsp\0" */
  421. goto fail;
  422. /* paste header+data together and pass to meta, which has loop info too */
  423. header_offset = 0xBC;
  424. stream_size = read_32bitBE(0x14, streamFile);
  425. header_size = read_32bitBE(0x1c, streamFile);
  426. stream_offset = align_size_to_block(header_offset + header_size, 0x10);
  427. temp_sf = setup_nub_streamfile(streamFile, header_offset, header_size, stream_offset, stream_size, "dsp");
  428. if (!temp_sf) goto fail;
  429. vgmstream = init_vgmstream_ngc_dsp_std(temp_sf);
  430. if (!vgmstream) goto fail;
  431. close_streamfile(temp_sf);
  432. return vgmstream;
  433. fail:
  434. close_streamfile(temp_sf);
  435. close_vgmstream(vgmstream);
  436. return NULL;
  437. }
  438. /* .nub idsp - from Namco NUB archives [Soul Calibur Legends (Wii), Sky Crawlers: Innocent Aces (Wii)] */
  439. VGMSTREAM * init_vgmstream_nub_idsp(STREAMFILE *streamFile) {
  440. VGMSTREAM *vgmstream = NULL;
  441. STREAMFILE *temp_sf = NULL;
  442. off_t header_offset, stream_offset;
  443. size_t header_size, stream_size;
  444. /* checks */
  445. if (!check_extensions(streamFile,"idsp"))
  446. goto fail;
  447. if (read_32bitBE(0x00,streamFile) != 0x69647370) /* "idsp" */
  448. goto fail;
  449. /* info header */
  450. /* 0x20: loop start (in samples) */
  451. /* 0x24: loop length (in samples) */
  452. /* 0x28: loop flag */
  453. /* 0x2c: null */
  454. /* paste header+data together and pass to meta, which has loop info too */
  455. header_offset = 0xBC;
  456. stream_size = read_32bitBE(0x14, streamFile);
  457. header_size = read_32bitBE(0x1c, streamFile);
  458. stream_offset = align_size_to_block(header_offset + header_size, 0x10);
  459. temp_sf = setup_nub_streamfile(streamFile, header_offset, header_size, stream_offset, stream_size, "idsp");
  460. if (!temp_sf) goto fail;
  461. vgmstream = init_vgmstream_idsp_namco(temp_sf);
  462. if (!vgmstream) goto fail;
  463. close_streamfile(temp_sf);
  464. return vgmstream;
  465. fail:
  466. close_streamfile(temp_sf);
  467. close_vgmstream(vgmstream);
  468. return NULL;
  469. }
  470. /* .nub is14 - from Namco NUB archives [Tales of Vesperia (PS3), Mojipittan (Wii)] */
  471. VGMSTREAM * init_vgmstream_nub_is14(STREAMFILE *streamFile) {
  472. VGMSTREAM *vgmstream = NULL;
  473. STREAMFILE *temp_sf = NULL;
  474. off_t header_offset, stream_offset;
  475. size_t header_size, stream_size, sdat_size;
  476. int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
  477. /* checks */
  478. if (!check_extensions(streamFile,"is14"))
  479. goto fail;
  480. if (read_32bitBE(0x00,streamFile) != 0x69733134) /* "is14" */
  481. goto fail;
  482. if (guess_endianness32bit(0x1c, streamFile)) {
  483. read_32bit = read_32bitBE;
  484. } else{
  485. read_32bit = read_32bitLE;
  486. }
  487. /* info header: null (even when BSNF loops) */
  488. /* paste header+data together and pass to meta */
  489. header_offset = 0xBC;
  490. header_size = read_32bit(0x1c, streamFile);
  491. /* size at 0x14 is padded, find "sdat" size BE (may move around) */
  492. if (!find_chunk_riff_be(streamFile, 0x73646174, 0xbc+0x0c, header_size - 0x0c, NULL, &sdat_size))
  493. goto fail;
  494. stream_offset = align_size_to_block(header_offset + header_size, 0x10);
  495. stream_size = sdat_size;
  496. temp_sf = setup_nub_streamfile(streamFile, header_offset, header_size, stream_offset, stream_size, "bnsf");
  497. if (!temp_sf) goto fail;
  498. vgmstream = init_vgmstream_bnsf(temp_sf);
  499. if (!vgmstream) goto fail;
  500. close_streamfile(temp_sf);
  501. return vgmstream;
  502. fail:
  503. close_streamfile(temp_sf);
  504. close_vgmstream(vgmstream);
  505. return NULL;
  506. }