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.

652 lines
23KB

  1. /* _______ ____ __ ___ ___
  2. * \ _ \ \ / \ / \ \ / / ' ' '
  3. * | | \ \ | | || | \/ | . .
  4. * | | | | | | || ||\ /| |
  5. * | | | | | | || || \/ | | ' ' '
  6. * | | | | | | || || | | . .
  7. * | |_/ / \ \__// || | |
  8. * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
  9. * / \
  10. * / . \
  11. * readmod.c - Code to read a good old-fashioned / / \ \
  12. * Amiga module from an open file. | < / \_
  13. * | \/ /\ /
  14. * By entheh. \_ / > /
  15. * | \ / /
  16. * | ' /
  17. * \__/
  18. */
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <math.h>
  22. #include "dumb.h"
  23. #include "internal/dumb.h"
  24. #include "internal/it.h"
  25. static int it_mod_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, int n_channels,
  26. unsigned char *buffer) {
  27. int pos;
  28. int channel;
  29. int row;
  30. IT_ENTRY *entry;
  31. pattern->n_rows = 64;
  32. if (n_channels == 0) {
  33. /* Read the first four channels, leaving gaps for the rest. */
  34. for (pos = 0; pos < 64 * 8 * 4; pos += 8 * 4)
  35. dumbfile_getnc((char *)buffer + pos, 4 * 4, f);
  36. /* Read the other channels into the gaps we left. */
  37. for (pos = 4 * 4; pos < 64 * 8 * 4; pos += 8 * 4)
  38. dumbfile_getnc((char *)buffer + pos, 4 * 4, f);
  39. n_channels = 8;
  40. } else
  41. dumbfile_getnc((char *)buffer, 64 * n_channels * 4, f);
  42. if (dumbfile_error(f))
  43. return -1;
  44. /* compute number of entries */
  45. pattern->n_entries = 64; /* Account for the row end markers */
  46. pos = 0;
  47. for (row = 0; row < 64; row++) {
  48. for (channel = 0; channel < n_channels; channel++) {
  49. if (buffer[pos + 0] | buffer[pos + 1] | buffer[pos + 2] |
  50. buffer[pos + 3])
  51. pattern->n_entries++;
  52. pos += 4;
  53. }
  54. }
  55. pattern->entry = malloc(pattern->n_entries * sizeof(*pattern->entry));
  56. if (!pattern->entry)
  57. return -1;
  58. entry = pattern->entry;
  59. pos = 0;
  60. for (row = 0; row < 64; row++) {
  61. for (channel = 0; channel < n_channels; channel++) {
  62. if (buffer[pos + 0] | buffer[pos + 1] | buffer[pos + 2] |
  63. buffer[pos + 3]) {
  64. unsigned char sample =
  65. (buffer[pos + 0] & 0xF0) | (buffer[pos + 2] >> 4);
  66. int period =
  67. ((int)(buffer[pos + 0] & 0x0F) << 8) | buffer[pos + 1];
  68. entry->channel = channel;
  69. entry->mask = 0;
  70. if (period) {
  71. int note;
  72. entry->mask |= IT_ENTRY_NOTE;
  73. /* frequency = (AMIGA_DIVISOR / 8) / (period * 2)
  74. * C-1: period = 214 -> frequency = 16726
  75. * so, set C5_speed to 16726
  76. * and period = 214 should translate to C5 aka 60
  77. * halve the period, go up an octive
  78. *
  79. * period = 214 / pow(DUMB_SEMITONE_BASE, note - 60)
  80. * pow(DUMB_SEMITONE_BASE, note - 60) = 214 / period
  81. * note - 60 = log(214/period) / log(DUMB_SEMITONE_BASE)
  82. */
  83. note = (int)floor(
  84. log(214.0 / period) / log(DUMB_SEMITONE_BASE) + 60.5);
  85. entry->note = MID(0, note, 119);
  86. // or should we preserve the period?
  87. // entry->note = buffer[pos+0] & 0x0F; /* High nibble */
  88. // entry->volpan = buffer[pos+1]; /* Low byte */
  89. // and what about finetune?
  90. }
  91. if (sample) {
  92. entry->mask |= IT_ENTRY_INSTRUMENT;
  93. entry->instrument = sample;
  94. }
  95. _dumb_it_xm_convert_effect(buffer[pos + 2] & 0x0F,
  96. buffer[pos + 3], entry, 1);
  97. entry++;
  98. }
  99. pos += 4;
  100. }
  101. IT_SET_END_ROW(entry);
  102. entry++;
  103. }
  104. return 0;
  105. }
  106. static int it_mod_read_sample_header(IT_SAMPLE *sample, DUMBFILE *f,
  107. unsigned long fft, int stk) {
  108. int finetune, loop_start, loop_length;
  109. /**
  110. 21 22 Chars Sample 1 name. If the name is not a full
  111. 22 chars in length, it will be null
  112. terminated.
  113. If
  114. the sample name begins with a '#' character (ASCII $23 (35)) then this is
  115. assumed not to be an instrument name, and is probably a message.
  116. */
  117. dumbfile_getnc((char *)sample->name, 22, f);
  118. sample->name[22] = 0;
  119. sample->filename[0] = 0;
  120. sample->length = dumbfile_mgetw(f) << 1;
  121. if (fft == DUMB_ID('F', 'E', 'S', 'T'))
  122. finetune = (signed char)((-dumbfile_getc(f) & 0x1F) << 3) >> 3;
  123. else
  124. finetune =
  125. (signed char)(dumbfile_getc(f) << 4) >> 4; /* signed nibble */
  126. /** Each finetune step changes the note 1/8th of a semitone. */
  127. sample->global_volume = 64;
  128. sample->default_volume =
  129. dumbfile_getc(f); // Should we be setting global_volume to this instead?
  130. loop_start = dumbfile_mgetw(f);
  131. if (!stk)
  132. loop_start <<= 1;
  133. loop_length = dumbfile_mgetw(f) << 1;
  134. if (loop_length > 2 && loop_start + loop_length > sample->length &&
  135. loop_start / 2 + loop_length <= sample->length)
  136. loop_start /= 2;
  137. sample->loop_start = loop_start;
  138. sample->loop_end = loop_start + loop_length;
  139. /**
  140. Once this sample has been played completely from beginning
  141. to end, if the repeat length (next field) is greater than two bytes it
  142. will loop back to this position in the sample and continue playing. Once
  143. it has played for the repeat length, it continues to loop back to the
  144. repeat start offset. This means the sample continues playing until it is
  145. told to stop.
  146. */
  147. if (sample->length <= 0) {
  148. sample->flags = 0;
  149. return 0;
  150. }
  151. sample->flags = IT_SAMPLE_EXISTS;
  152. sample->default_pan = 0;
  153. sample->C5_speed =
  154. (int)(AMIGA_CLOCK /
  155. 214.0); //(long)(16726.0*pow(DUMB_PITCH_BASE, finetune*32));
  156. sample->finetune =
  157. finetune * ((fft == DUMB_ID('F', 'E', 'S', 'T')) ? 16 : 32);
  158. // the above line might be wrong
  159. if (sample->loop_end > sample->length)
  160. sample->loop_end = sample->length;
  161. if (sample->loop_end - sample->loop_start > 2)
  162. sample->flags |= IT_SAMPLE_LOOP;
  163. sample->vibrato_speed = 0;
  164. sample->vibrato_depth = 0;
  165. sample->vibrato_rate = 0;
  166. sample->vibrato_waveform = 0; // do we have to set _all_ these?
  167. sample->max_resampling_quality = -1;
  168. return dumbfile_error(f);
  169. }
  170. static int it_mod_read_sample_data(IT_SAMPLE *sample, DUMBFILE *f,
  171. unsigned long fft) {
  172. long i;
  173. long truncated_size;
  174. /* let's get rid of the sample data coming after the end of the loop */
  175. if ((sample->flags & IT_SAMPLE_LOOP) && sample->loop_end < sample->length) {
  176. truncated_size = sample->length - sample->loop_end;
  177. sample->length = sample->loop_end;
  178. } else {
  179. truncated_size = 0;
  180. }
  181. if (sample->length) {
  182. sample->data = malloc(sample->length);
  183. if (!sample->data)
  184. return -1;
  185. /* Sample data are stored in "8-bit two's compliment format" (sic). */
  186. /*
  187. for (i = 0; i < sample->length; i++)
  188. ((signed char *)sample->left)[i] = dumbfile_getc(f);
  189. */
  190. /* F U Olivier Lapicque */
  191. if (sample->length >= 5) {
  192. i = dumbfile_getnc(sample->data, 5, f);
  193. if (i == 5) {
  194. if (!memcmp(sample->data, "ADPCM", 5)) {
  195. if (_dumb_it_read_sample_data_adpcm4(sample, f) < 0)
  196. return -1;
  197. return 0;
  198. } else {
  199. i += dumbfile_getnc(((char *)sample->data) + 5,
  200. sample->length - 5, f);
  201. }
  202. }
  203. } else {
  204. i = dumbfile_getnc(sample->data, sample->length, f);
  205. }
  206. if (i < sample->length) {
  207. if (i <= 0) {
  208. sample->flags = 0;
  209. return 0;
  210. }
  211. sample->length = i;
  212. if (sample->loop_end > i)
  213. sample->loop_end = i;
  214. // holy crap!
  215. if (sample->loop_start > i)
  216. sample->flags &= ~IT_SAMPLE_LOOP;
  217. } else {
  218. /* skip truncated data */
  219. int feh = dumbfile_error(f);
  220. if (truncated_size)
  221. dumbfile_skip(f, truncated_size);
  222. // Should we be truncating it?
  223. if (feh)
  224. return -1;
  225. }
  226. if (fft == DUMB_ID('M', 0, 0, 0) || fft == DUMB_ID('8', 0, 0, 0)) {
  227. int delta = 0;
  228. for (i = 0; i < sample->length; i++) {
  229. delta += ((signed char *)sample->data)[i];
  230. ((signed char *)sample->data)[i] = delta;
  231. }
  232. }
  233. }
  234. return 0;
  235. }
  236. #define MOD_FFT_OFFSET (20 + 31 * (22 + 2 + 1 + 1 + 2 + 2) + 1 + 1 + 128)
  237. static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int restrict_) {
  238. DUMB_IT_SIGDATA *sigdata;
  239. int n_channels;
  240. int i;
  241. unsigned long fft;
  242. if (dumbfile_seek(f, MOD_FFT_OFFSET, DFS_SEEK_SET))
  243. return NULL;
  244. fft = dumbfile_mgetl(f);
  245. if (dumbfile_error(f))
  246. return NULL;
  247. if (dumbfile_seek(f, 0, DFS_SEEK_SET))
  248. return NULL;
  249. sigdata = malloc(sizeof(*sigdata));
  250. if (!sigdata) {
  251. return NULL;
  252. }
  253. /**
  254. 1 20 Chars Title of the song. If the title is not a
  255. full 20 chars in length, it will be null-
  256. terminated.
  257. */
  258. if (dumbfile_getnc((char *)sigdata->name, 20, f) < 20) {
  259. free(sigdata);
  260. return NULL;
  261. }
  262. sigdata->name[20] = 0;
  263. sigdata->n_samples = 31;
  264. switch (fft) {
  265. case DUMB_ID('M', '.', 'K', '.'):
  266. case DUMB_ID('M', '!', 'K', '!'):
  267. case DUMB_ID('M', '&', 'K', '!'):
  268. case DUMB_ID('N', '.', 'T', '.'):
  269. case DUMB_ID('N', 'S', 'M', 'S'):
  270. case DUMB_ID('F', 'L', 'T', '4'):
  271. case DUMB_ID('M', 0, 0, 0):
  272. case DUMB_ID('8', 0, 0, 0):
  273. case DUMB_ID('F', 'E', 'S', 'T'):
  274. n_channels = 4;
  275. break;
  276. case DUMB_ID('F', 'L', 'T', '8'):
  277. n_channels = 0;
  278. /* 0 indicates a special case; two four-channel patterns must be
  279. * combined into one eight-channel pattern. Pattern indexes must
  280. * be halved. Why oh why do they obfuscate so?
  281. */
  282. /*for (i = 0; i < 128; i++)
  283. sigdata->order[i] >>= 1;*/
  284. break;
  285. case DUMB_ID('C', 'D', '8', '1'):
  286. case DUMB_ID('O', 'C', 'T', 'A'):
  287. case DUMB_ID('O', 'K', 'T', 'A'):
  288. n_channels = 8;
  289. break;
  290. case DUMB_ID('1', '6', 'C', 'N'):
  291. n_channels = 16;
  292. break;
  293. case DUMB_ID('3', '2', 'C', 'N'):
  294. n_channels = 32;
  295. break;
  296. default:
  297. /* If we get an illegal tag, assume 4 channels 15 samples. */
  298. if ((fft & 0x0000FFFFL) == DUMB_ID(0, 0, 'C', 'H')) {
  299. if (fft >= '1' << 24 && fft < '4' << 24) {
  300. n_channels = ((fft & 0x00FF0000L) >> 16) - '0';
  301. if ((unsigned int)n_channels >= 10) {
  302. /* Rightmost character wasn't a digit. */
  303. n_channels = 4;
  304. sigdata->n_samples = 15;
  305. } else {
  306. n_channels += (((fft & 0xFF000000L) >> 24) - '0') * 10;
  307. /* MODs should really only go up to 32 channels, but we're
  308. * lenient. */
  309. if ((unsigned int)(n_channels - 1) >=
  310. DUMB_IT_N_CHANNELS - 1) {
  311. /* No channels or too many? Can't be right... */
  312. n_channels = 4;
  313. sigdata->n_samples = 15;
  314. }
  315. }
  316. } else {
  317. n_channels = 4;
  318. sigdata->n_samples = 15;
  319. }
  320. } else if ((fft & 0x00FFFFFFL) == DUMB_ID(0, 'C', 'H', 'N')) {
  321. n_channels = (int)((fft >> 24) - '0');
  322. if ((unsigned int)(n_channels - 1) >= 9) {
  323. /* Character was '0' or it wasn't a digit */
  324. n_channels = 4;
  325. sigdata->n_samples = 15;
  326. }
  327. } else if ((fft & 0xFFFFFF00L) == DUMB_ID('T', 'D', 'Z', 0)) {
  328. n_channels = (fft & 0x000000FFL) - '0';
  329. if ((unsigned int)(n_channels - 1) >= 9) {
  330. /* We've been very lenient, given that it should have
  331. * been 1, 2 or 3, but this MOD has been very naughty and
  332. * must be punished.
  333. */
  334. n_channels = 4;
  335. sigdata->n_samples = 15;
  336. }
  337. } else {
  338. n_channels = 4;
  339. sigdata->n_samples = 15;
  340. fft = 0;
  341. }
  342. }
  343. // moo
  344. if ((restrict_ & 1) && sigdata->n_samples == 15) {
  345. free(sigdata);
  346. return NULL;
  347. }
  348. sigdata->n_pchannels =
  349. n_channels ? n_channels : 8; /* special case for 0, see above */
  350. sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample));
  351. if (!sigdata->sample) {
  352. free(sigdata);
  353. return NULL;
  354. }
  355. sigdata->song_message = NULL;
  356. sigdata->order = NULL;
  357. sigdata->instrument = NULL;
  358. sigdata->pattern = NULL;
  359. sigdata->midi = NULL;
  360. sigdata->checkpoint = NULL;
  361. sigdata->n_instruments = 0;
  362. for (i = 0; i < sigdata->n_samples; i++)
  363. sigdata->sample[i].data = NULL;
  364. for (i = 0; i < sigdata->n_samples; i++) {
  365. if (it_mod_read_sample_header(&sigdata->sample[i], f, fft,
  366. sigdata->n_samples == 15)) {
  367. _dumb_it_unload_sigdata(sigdata);
  368. return NULL;
  369. }
  370. }
  371. sigdata->n_orders = dumbfile_getc(f);
  372. sigdata->restart_position = dumbfile_getc(f);
  373. // what if this is >= 127? what about with Fast Tracker II?
  374. /* if (sigdata->n_orders <= 0 || sigdata->n_orders > 128) { // is this
  375. right? _dumb_it_unload_sigdata(sigdata); return NULL;
  376. }*/
  377. // if (sigdata->restart_position >= sigdata->n_orders)
  378. // sigdata->restart_position = 0;
  379. sigdata->order = malloc(128); /* We may need to scan the extra ones! */
  380. if (!sigdata->order) {
  381. _dumb_it_unload_sigdata(sigdata);
  382. return NULL;
  383. }
  384. if (dumbfile_getnc((char *)sigdata->order, 128, f) < 128) {
  385. _dumb_it_unload_sigdata(sigdata);
  386. return NULL;
  387. }
  388. if (sigdata->n_orders <= 0 || sigdata->n_orders > 128) { // is this right?
  389. sigdata->n_orders = 128;
  390. // while (sigdata->n_orders > 1 && !sigdata->order[sigdata->n_orders -
  391. // 1]) sigdata->n_orders--;
  392. }
  393. if (!n_channels)
  394. for (i = 0; i < 128; i++)
  395. sigdata->order[i] >>= 1;
  396. /* "The old NST format contains only 15 samples (instead of 31). Further
  397. * it doesn't contain a file format tag (id). So Pattern data offset is
  398. * at 20+15*30+1+1+128."
  399. * - Then I shall assume the File Format Tag never exists if there are
  400. * only 15 samples. I hope this isn't a faulty assumption...
  401. */
  402. if (sigdata->n_samples == 31)
  403. dumbfile_skip(f, 4);
  404. sigdata->n_patterns = -1;
  405. if ((restrict_ & 2)) {
  406. unsigned char buffer[5];
  407. long sample_number;
  408. long total_sample_size;
  409. long offset = dumbfile_pos(f);
  410. long remain = dumbfile_get_size(f) - offset;
  411. if (dumbfile_error(f) || dumbfile_seek(f, 0, SEEK_END)) {
  412. _dumb_it_unload_sigdata(sigdata);
  413. return NULL;
  414. }
  415. sample_number = sigdata->n_samples - 1;
  416. total_sample_size = 0;
  417. while (dumbfile_pos(f) > offset && sample_number >= 0) {
  418. if (sigdata->sample[sample_number].flags & IT_SAMPLE_EXISTS) {
  419. if (dumbfile_seek(
  420. f,
  421. -((sigdata->sample[sample_number].length + 1) / 2 + 5 +
  422. 16),
  423. DFS_SEEK_CUR) ||
  424. dumbfile_getnc((char *)buffer, 5, f) < 5) {
  425. _dumb_it_unload_sigdata(sigdata);
  426. return NULL;
  427. }
  428. if (!memcmp(buffer, "ADPCM", 5)) { /* BAH */
  429. total_sample_size +=
  430. (sigdata->sample[sample_number].length + 1) / 2 + 5 +
  431. 16;
  432. if (dumbfile_seek(f, -5, DFS_SEEK_CUR)) {
  433. _dumb_it_unload_sigdata(sigdata);
  434. return NULL;
  435. }
  436. } else {
  437. total_sample_size += sigdata->sample[sample_number].length;
  438. if (dumbfile_seek(
  439. f,
  440. -(sigdata->sample[sample_number].length -
  441. ((sigdata->sample[sample_number].length + 1) / 2 +
  442. 5 + 16) +
  443. 5),
  444. DFS_SEEK_CUR)) {
  445. _dumb_it_unload_sigdata(sigdata);
  446. return NULL;
  447. }
  448. }
  449. }
  450. --sample_number;
  451. }
  452. if (remain > total_sample_size) {
  453. sigdata->n_patterns = (int)((remain - total_sample_size + 4) /
  454. (256 * sigdata->n_pchannels));
  455. if (fft == DUMB_ID('M', 0, 0, 0) || fft == DUMB_ID('8', 0, 0, 0)) {
  456. remain -= sigdata->n_patterns * 256 * sigdata->n_pchannels;
  457. if (dumbfile_skip(f, remain - total_sample_size)) {
  458. _dumb_it_unload_sigdata(sigdata);
  459. return NULL;
  460. }
  461. }
  462. }
  463. } else {
  464. for (i = 0; i < 128; i++) {
  465. if (sigdata->order[i] > sigdata->n_patterns)
  466. sigdata->n_patterns = sigdata->order[i];
  467. }
  468. sigdata->n_patterns++;
  469. }
  470. if (sigdata->n_patterns <= 0) {
  471. _dumb_it_unload_sigdata(sigdata);
  472. return NULL;
  473. }
  474. /* May as well try to save a tiny bit of memory. */
  475. if (sigdata->n_orders < 128) {
  476. unsigned char *order = realloc(sigdata->order, sigdata->n_orders);
  477. if (order)
  478. sigdata->order = order;
  479. }
  480. sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
  481. if (!sigdata->pattern) {
  482. _dumb_it_unload_sigdata(sigdata);
  483. return NULL;
  484. }
  485. for (i = 0; i < sigdata->n_patterns; i++)
  486. sigdata->pattern[i].entry = NULL;
  487. /* Read in the patterns */
  488. {
  489. unsigned char *buffer =
  490. malloc(256 * sigdata->n_pchannels); /* 64 rows * 4 bytes */
  491. if (!buffer) {
  492. _dumb_it_unload_sigdata(sigdata);
  493. return NULL;
  494. }
  495. for (i = 0; i < sigdata->n_patterns; i++) {
  496. if (it_mod_read_pattern(&sigdata->pattern[i], f, n_channels,
  497. buffer) != 0) {
  498. free(buffer);
  499. _dumb_it_unload_sigdata(sigdata);
  500. return NULL;
  501. }
  502. }
  503. free(buffer);
  504. }
  505. /* And finally, the sample data */
  506. for (i = 0; i < sigdata->n_samples; i++) {
  507. if (it_mod_read_sample_data(&sigdata->sample[i], f, fft)) {
  508. _dumb_it_unload_sigdata(sigdata);
  509. return NULL;
  510. }
  511. }
  512. /* w00t! */
  513. /*if ( n_channels == 4 &&
  514. ( sigdata->n_samples == 15 ||
  515. ( ( fft & 240 ) != DUMB_ID( 0, 0, 'C', 0 ) &&
  516. ( fft & 240 ) != DUMB_ID( 0, 0, 'H', 0 ) &&
  517. ( fft & 240 ) != 0 ) ) ) {
  518. for ( i = 0; i < sigdata->n_samples; ++i ) {
  519. IT_SAMPLE * sample = &sigdata->sample [i];
  520. if ( sample && ( sample->flags & IT_SAMPLE_EXISTS ) ) {
  521. int n, o;
  522. o = sample->length;
  523. if ( o > 4 ) o = 4;
  524. for ( n = 0; n < o; ++n )
  525. ( ( char * ) sample->data ) [n] = 0;
  526. }
  527. }
  528. }*/
  529. /* Now let's initialise the remaining variables, and we're done! */
  530. sigdata->flags = IT_WAS_AN_XM | IT_WAS_A_MOD | IT_OLD_EFFECTS |
  531. IT_COMPATIBLE_GXX | IT_STEREO;
  532. sigdata->global_volume = 128;
  533. sigdata->mixing_volume = 48;
  534. /* We want 50 ticks per second; 50/6 row advances per second;
  535. * 50*10=500 row advances per minute; 500/4=125 beats per minute.
  536. */
  537. sigdata->speed = 6;
  538. sigdata->tempo = 125;
  539. sigdata->pan_separation = 128;
  540. memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
  541. for (i = 0; i < DUMB_IT_N_CHANNELS; i += 4) {
  542. int sep = 32 * dumb_it_default_panning_separation / 100;
  543. sigdata->channel_pan[i + 0] = 32 - sep;
  544. sigdata->channel_pan[i + 1] = 32 + sep;
  545. sigdata->channel_pan[i + 2] = 32 + sep;
  546. sigdata->channel_pan[i + 3] = 32 - sep;
  547. }
  548. if (_dumb_it_fix_invalid_orders(sigdata) < 0) {
  549. _dumb_it_unload_sigdata(sigdata);
  550. return NULL;
  551. }
  552. return sigdata;
  553. }
  554. DUH *dumb_read_mod_quick(DUMBFILE *f, int restrict_) {
  555. sigdata_t *sigdata;
  556. DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
  557. sigdata = it_mod_load_sigdata(f, restrict_);
  558. if (!sigdata)
  559. return NULL;
  560. {
  561. const char *tag[2][2];
  562. tag[0][0] = "TITLE";
  563. tag[0][1] = (const char *)(((DUMB_IT_SIGDATA *)sigdata)->name);
  564. tag[1][0] = "FORMAT";
  565. tag[1][1] = "MOD";
  566. return make_duh(-1, 2, (const char *const(*)[2])tag, 1, &descptr,
  567. &sigdata);
  568. }
  569. }