Advertisement
TorutheRedFox

setloop but more portable

Apr 23rd, 2022
972
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 8.16 KB | None | 0 0
  1. /* gcc setloop.c -o setloop */
  2. /* ./setloop sound.aiff soundout.aiff start end */
  3.  
  4. /**
  5.  * Set loop data for an AIFF file.
  6.  */
  7. #include <assert.h>
  8. #include <math.h>
  9. #include <string.h>
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <stdarg.h>
  13.  
  14. typedef signed char s8;
  15. typedef short s16;
  16. typedef int s32;
  17. typedef unsigned char u8;
  18. typedef unsigned short u16;
  19. typedef unsigned int u32;
  20. typedef unsigned long long u64;
  21. typedef float f32;
  22.  
  23. #ifdef _MSC_VER // MSVC
  24.  
  25. #define bswap16(x) _byteswap_ushort(x)
  26. #define bswap32(x) _byteswap_ulong(x)
  27. #define BSWAP16(x) x = _byteswap_ushort(x)
  28. #define BSWAP32(x) x = _byteswap_ulong(x)
  29.  
  30. #elif defined(__APPLE__)
  31.  
  32. // Mac OS X / Darwin features
  33. #include <libkern/OSByteOrder.h>
  34. #define bswap16(x) OSSwapInt16(x)
  35. #define bswap32(x) OSSwapInt32(x)
  36. #define BSWAP16(x) x = OSSwapInt16(x)
  37. #define BSWAP32(x) x = OSSwapInt32(x)
  38.  
  39. #elif defined(__sun) || defined(sun)
  40.  
  41. #include <sys/byteorder.h>
  42. #define bswap16(x) BSWAP_16(x)
  43. #define bswap32(x) BSWAP_32(x)
  44. #define BSWAP16(x) x = BSWAP_16(x)
  45. #define BSWAP32(x) x = BSWAP_32(x)
  46.  
  47. #elif defined(__FreeBSD__)
  48.  
  49. #include <sys/endian.h>
  50. #define bswap16(x) bswap16(x)
  51. #define bswap32(x) bswap32(x)
  52. #define BSWAP16(x) x = bswap16(x)
  53. #define BSWAP32(x) x = bswap32(x)
  54.  
  55. #elif defined(__OpenBSD__)
  56.  
  57. #include <sys/types.h>
  58. #define bswap16(x) swap16(x)
  59. #define bswap32(x) swap32(x)
  60. #define BSWAP16(x) x = swap16(x)
  61. #define BSWAP32(x) x = swap32(x)
  62.  
  63. #elif defined(__NetBSD__)
  64.  
  65. #include <sys/types.h>
  66. #include <machine/bswap.h>
  67. #if defined(__BSWAP_RENAME) && !defined(__bswap_32)
  68. #define bswap16(x) bswap16(x)
  69. #define bswap32(x) bswap32(x)
  70. #define BSWAP16(x) x = bswap16(x)
  71. #define BSWAP32(x) x = bswap32(x)
  72.  
  73. #endif
  74.  
  75. #else // GCC
  76.  
  77. #define bswap16(x) __builtin_bswap16(x)
  78. #define bswap32(x) __builtin_bswap32(x)
  79. #define BSWAP16(x) x = __builtin_bswap16(x)
  80. #define BSWAP32(x) x = __builtin_bswap32(x)
  81.  
  82. #endif
  83.  
  84. #define NORETURN __attribute__((noreturn))
  85. #define UNUSED __attribute__((unused))
  86.  
  87. typedef struct {
  88.     u32 ckID;
  89.     u32 ckSize;
  90. } ChunkHeader;
  91.  
  92. typedef struct {
  93.     u32 ckID;
  94.     u32 ckSize;
  95.     u32 formType;
  96. } Chunk;
  97.  
  98. typedef struct {
  99.     s16 numChannels;
  100.     u16 numFramesH;
  101.     u16 numFramesL;
  102.     s16 sampleSize;
  103.     s16 sampleRate[5]; // 80-bit float
  104.     u16 compressionTypeH;
  105.     u16 compressionTypeL;
  106. } CommonChunk;
  107.  
  108. typedef struct {
  109.     s16 MarkerID;
  110.     u16 positionH;
  111.     u16 positionL;
  112. } Marker;
  113.  
  114. typedef struct {
  115.     s16 playMode;
  116.     s16 beginLoop;
  117.     s16 endLoop;
  118. } Loop;
  119.  
  120. typedef struct {
  121.     s8 baseNote;
  122.     s8 detune;
  123.     s8 lowNote;
  124.     s8 highNote;
  125.     s8 lowVelocity;
  126.     s8 highVelocity;
  127.     s16 gain;
  128.     Loop sustainLoop;
  129.     Loop releaseLoop;
  130. } InstrumentChunk;
  131.  
  132. typedef struct
  133. {
  134.     u32 start;
  135.     u32 end;
  136.     u32 count;
  137.     s16 state[16];
  138. } ALADPCMloop;
  139.  
  140.  
  141. static char usage[] = "input.aiff output.aiff [<loopstart> <loopend> | none]";
  142. static const char* progname, * infilename;
  143.  
  144. #define checked_fread(a, b, c, d) if (fread(a, b, c, d) != c) fail_parse("error parsing file")
  145.  
  146. /*NORETURN*/ void fail_parse(const char* fmt, ...)
  147. {
  148.     char* formatted = NULL;
  149.     va_list ap;
  150.     va_start(ap, fmt);
  151.     int size = vsnprintf(NULL, 0, fmt, ap);
  152.     va_end(ap);
  153.     if (size >= 0) {
  154.         size++;
  155.         formatted = malloc(size);
  156.         if (formatted != NULL) {
  157.             va_start(ap, fmt);
  158.             size = vsnprintf(formatted, size, fmt, ap);
  159.             va_end(ap);
  160.             if (size < 0) {
  161.                 free(formatted);
  162.                 formatted = NULL;
  163.             }
  164.         }
  165.     }
  166.  
  167.     if (formatted != NULL) {
  168.         fprintf(stderr, "%s: %s [%s]\n", progname, formatted, infilename);
  169.         free(formatted);
  170.     }
  171.     exit(1);
  172. }
  173.  
  174. int read_int(const char* in, int* out)
  175. {
  176.     if (in[0] == '0' && (in[1] == 'x' || in[1] == 'X'))
  177.         return sscanf(in + 2, "%x", out);
  178.     return sscanf(in, "%d", out);
  179. }
  180.  
  181. void write_header(FILE* ofile, const char* id, s32 size)
  182. {
  183.     fwrite(id, 4, 1, ofile);
  184.     BSWAP32(size);
  185.     fwrite(&size, sizeof(s32), 1, ofile);
  186. }
  187.  
  188. int main(int argc, char** argv)
  189. {
  190.     u8* soundData = NULL;
  191.     s32 soundDataSize = -1;
  192.     u8* commData = NULL;
  193.     s32 commDataSize = -1;
  194.     s32 hasLoop = 0;
  195.     s32 loopStart = -1;
  196.     s32 loopEnd = -1;
  197.     Chunk FormChunk;
  198.     ChunkHeader Header;
  199.     InstrumentChunk InstChunk;
  200.     FILE* ifile;
  201.     FILE* ofile;
  202.     progname = argv[0];
  203.  
  204.     if (argc < 4) {
  205.         fprintf(stderr, "%s %s\n", progname, usage);
  206.         exit(1);
  207.     }
  208.  
  209.     if (strcmp(argv[3], "none") == 0) {
  210.         hasLoop = 0;
  211.     }
  212.     else {
  213.         if (argc < 5) {
  214.             fprintf(stderr, "%s %s\n", progname, usage);
  215.             exit(1);
  216.         }
  217.         hasLoop = 1;
  218.         if (!read_int(argv[3], &loopStart) ||
  219.             !read_int(argv[4], &loopEnd)) {
  220.             fprintf(stderr, "failed to parse loop arguments: expected integers\n");
  221.         }
  222.     }
  223.  
  224.     infilename = argv[1];
  225.  
  226.     if ((ifile = fopen(infilename, "rb")) == NULL) {
  227.         fail_parse("AIFF file could not be opened");
  228.         exit(1);
  229.     }
  230.  
  231.     memset(&InstChunk, 0, sizeof(InstChunk));
  232.  
  233.     checked_fread(&FormChunk, sizeof(FormChunk), 1, ifile);
  234.     BSWAP32(FormChunk.ckID);
  235.     BSWAP32(FormChunk.formType);
  236.     if ((FormChunk.ckID != 0x464f524d) || // FORM
  237.         (FormChunk.formType != 0x41494643 && FormChunk.formType != 0x41494646)) { // AIFC, AIFF
  238.         fail_parse("not an AIFF file");
  239.     }
  240.  
  241.     for (;;) {
  242.         s32 num = fread(&Header, sizeof(Header), 1, ifile);
  243.         if (num <= 0) break;
  244.         BSWAP32(Header.ckID);
  245.         BSWAP32(Header.ckSize);
  246.  
  247.         s32 origCkSize = Header.ckSize;
  248.         Header.ckSize++;
  249.         Header.ckSize &= ~1;
  250.         s32 offset = ftell(ifile);
  251.  
  252.         switch (Header.ckID) {
  253.         case 0x434f4d4d: // COMM
  254.             commData = malloc(Header.ckSize);
  255.             commDataSize = origCkSize;
  256.             checked_fread(commData, Header.ckSize, 1, ifile);
  257.             break;
  258.  
  259.         case 0x53534e44: // SSND
  260.             soundData = malloc(Header.ckSize);
  261.             soundDataSize = origCkSize;
  262.             checked_fread(soundData, Header.ckSize, 1, ifile);
  263.             break;
  264.         }
  265.  
  266.         fseek(ifile, offset + Header.ckSize, SEEK_SET);
  267.     }
  268.     fclose(ifile);
  269.  
  270.     if ((ofile = fopen(argv[2], "wb")) == NULL) {
  271.         fprintf(stderr, "%s: output file could not be opened [%s]\n", progname, argv[2]);
  272.         exit(1);
  273.     }
  274.  
  275.     // Write an incomplete file header. We'll fill in the size later.
  276.     fwrite("FORM\0\0\0\0AIFF", 12, 1, ofile);
  277.  
  278.     write_header(ofile, "COMM", commDataSize);
  279.     fwrite(commData, (commDataSize + 1) & ~1, 1, ofile);
  280.  
  281.     // Loops
  282.     if (hasLoop) {
  283.         const char* markerNames[2] = { "start", "end" };
  284.         Marker markers[2] = {
  285.             {1, loopStart >> 16, loopStart & 0xffff},
  286.             {2, loopEnd >> 16, loopEnd & 0xffff}
  287.         };
  288.         write_header(ofile, "MARK", 2 + 2 * sizeof(Marker) + 1 + 5 + 1 + 3);
  289.         s16 numMarkers = bswap16(2);
  290.         fwrite(&numMarkers, sizeof(s16), 1, ofile);
  291.         for (s32 i = 0; i < 2; i++) {
  292.             u8 len = (u8)strlen(markerNames[i]);
  293.             BSWAP16(markers[i].MarkerID);
  294.             BSWAP16(markers[i].positionH);
  295.             BSWAP16(markers[i].positionL);
  296.             fwrite(&markers[i], sizeof(Marker), 1, ofile);
  297.             fwrite(&len, 1, 1, ofile);
  298.             fwrite(markerNames[i], len, 1, ofile);
  299.         }
  300.  
  301.         write_header(ofile, "INST", sizeof(InstrumentChunk));
  302.         InstChunk.sustainLoop.playMode = bswap16(1);
  303.         InstChunk.sustainLoop.beginLoop = bswap16(1);
  304.         InstChunk.sustainLoop.endLoop = bswap16(2);
  305.         InstChunk.releaseLoop.playMode = 0;
  306.         InstChunk.releaseLoop.beginLoop = 0;
  307.         InstChunk.releaseLoop.endLoop = 0;
  308.         fwrite(&InstChunk, sizeof(InstrumentChunk), 1, ofile);
  309.     }
  310.  
  311.     write_header(ofile, "SSND", soundDataSize);
  312.     fwrite(soundData, (soundDataSize + 1) & ~1, 1, ofile);
  313.  
  314.     // Fix the size in the header
  315.     s32 fileSize = bswap32(ftell(ofile) - 8);
  316.     fseek(ofile, 4, SEEK_SET);
  317.     fwrite(&fileSize, 4, 1, ofile);
  318.  
  319.     fclose(ofile);
  320.     return 0;
  321. }
  322.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement