main.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. /*
  2. * main.c
  3. *
  4. * Copyright (C) 2023 bzt
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19. *
  20. * @brief Main file for "cassette" audio-binary converter
  21. *
  22. */
  23. #include <stdint.h>
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <string.h>
  27. uint8_t *decode(uint8_t *data, size_t size, int fmt, int en, int nb, int sy, int fm, int ng, int length, int hdr, int skip, size_t *outlen);
  28. uint8_t *encode(uint8_t *data, size_t size, int fmt, int en, int nb, int sy, int fm, int ng, int length, int hdr, int rate, int ol, int zl, int bitrate, int quality, size_t *outlen);
  29. int verbose = 0;
  30. /**
  31. * Usage instructions
  32. */
  33. void usage(char *cmd)
  34. {
  35. printf("Cassette by bzt GPLv3+\r\nhttps://gitlab.com/bztsrc/cassette\r\n\r\n");
  36. printf("%s [opts|-s] <in.wav|in.mp3> <out.bin>\r\n", cmd);
  37. printf("%s [opts] <in.bin> <out.wav>\r\n", cmd);
  38. printf("%s [opts|-b|-q] <in.bin> <out.mp3>\r\n\r\n", cmd);
  39. printf(" -v | -vv be verbose\r\n");
  40. printf("Data encoding options\r\n");
  41. printf(" -e endianess, least significant bit comes first\r\n");
  42. printf(" -7 assume 7 bits per byte on the tape\r\n");
  43. printf(" -0 no sync bit (default, 0 = 0, 1 = 1)\r\n");
  44. printf(" -1 two bits, first is sync bit (10 = 0, 11 = 1)\r\n");
  45. printf(" -2 two bits, second is sync bit (01 = 0, 11 = 1)\r\n");
  46. printf(" -3 three bits, two sync bits (101 = 0, 111 = 1)\r\n");
  47. printf(" -d FM, frequency modulated, down-edge (defaults to AM)\r\n");
  48. printf(" -u FM, frequency modulated, up-edge\r\n");
  49. printf(" -du FM, frequency modulated, both edges\r\n");
  50. printf("Sample encoding options\r\n");
  51. printf(" -h do not detect but generate Homelab header\r\n");
  52. printf(" -s input is signed 8-bit PCM\r\n");
  53. printf(" -S <n> skip N samples at the beginning\r\n");
  54. printf(" -l <usec> one bit's length in microsec (eg. 770)\r\n");
  55. printf(" -g <usec> gap between bytes (AM) or diff in zero and one lengths (FM)\r\n");
  56. printf(" -r <rate> sample rate (eg. 44100 or 48000)\r\n");
  57. printf(" -o <num> bit set level (eg. 127)\r\n");
  58. printf(" -z <num> bit clear level (eg. -32)\r\n");
  59. printf("MP3 encoding options\r\n");
  60. printf(" -b <bitrate> bit rate (eg. 96, 128 or 192)\r\n");
  61. printf(" -q <quality> quality (0 best, 9 worst)\r\n\r\n");
  62. printf("You should have received a copy of the GNU General Public License\r\n");
  63. printf("along with this program. If not, see <http://www.gnu.org/licenses/>.\r\n\r\n");
  64. exit(1);
  65. }
  66. /**
  67. * Main function
  68. */
  69. int main(int argc, char **argv)
  70. {
  71. FILE *f;
  72. int i, j;
  73. int length = 0, en = 0, nb = 8, sy = 0, fm = 0, ng = 0, hdr = 0, skip = 0, rate = 44100, ol = 127, zl = -65536;
  74. int bitrate = 96, quality = 0, fmt = 0;
  75. char *infile = NULL, *outfile = NULL, *ext;
  76. uint8_t *data = NULL, *out = NULL;
  77. size_t size;
  78. /* parse command line */
  79. for(i = 1; i < argc; i++)
  80. if(argv[i][0] == '-')
  81. switch(argv[i][1]) {
  82. case 'l': length = atoi(argv[++i]); break;
  83. case 'g': ng = atoi(argv[++i]); break;
  84. case 'r': rate = atoi(argv[++i]); break;
  85. case 'o': ol = atoi(argv[++i]); break;
  86. case 'z': zl = atoi(argv[++i]); break;
  87. case 'b': bitrate = atoi(argv[++i]); break;
  88. case 'q': quality = atoi(argv[++i]); break;
  89. case 'S': skip = atoi(argv[++i]); break;
  90. default:
  91. for(j = 1; argv[i][j]; j++)
  92. switch(argv[i][j]) {
  93. case 's': fmt = 1; break;
  94. case 'd': fm |= 1; break;
  95. case 'u': fm |= 2; break;
  96. case 'e': en = 1; break;
  97. case '7': nb = 7; break;
  98. case '0': sy = 0; break;
  99. case '1': sy = 1; break;
  100. case '2': sy = 2; break;
  101. case '3': sy = 3; break;
  102. case 'h': hdr = 1; break;
  103. case 'v': verbose++; break;
  104. default: usage(argv[0]); break;
  105. }
  106. break;
  107. }
  108. else
  109. if(!infile) infile = argv[i]; else
  110. if(!outfile) outfile = argv[i]; else usage(argv[0]);
  111. if(!infile || !outfile) usage(argv[0]);
  112. if(zl == -65536) zl = fm ? -127 : -64;
  113. /* read input file */
  114. f = fopen(infile, "rb");
  115. if(f) {
  116. fseek(f, 0, SEEK_END);
  117. size = (size_t)ftell(f);
  118. fseek(f, 0, SEEK_SET);
  119. data = (uint8_t*)malloc(size);
  120. if(!data) { fprintf(stderr, "cassette: unable to allocate memory\r\n"); exit(2); }
  121. (void)fread(data, 1, size, f);
  122. fclose(f);
  123. } else {
  124. fprintf(stderr, "cassette: unable to open '%s'\r\n", infile);
  125. exit(1);
  126. }
  127. /* do the thing */
  128. ext = strrchr(outfile, '.');
  129. if(ext && (!strcmp(ext, ".wav") || !strcmp(ext, ".mp3")))
  130. out = encode(data, size, ext && !strcmp(ext, ".mp3"), en, nb, sy, fm, ng, length, hdr, rate, ol, zl, bitrate, quality, &size);
  131. else
  132. out = decode(data, size, fmt, en, nb, sy, fm, ng, length, !hdr, skip, &size);
  133. /* write output file */
  134. if(size > 0 && out) {
  135. f = fopen(outfile, "wb");
  136. if(f) {
  137. (void)fwrite(out, 1, size, f);
  138. fclose(f);
  139. } else {
  140. fprintf(stderr, "cassette: unable to write '%s'\r\n", outfile);
  141. }
  142. }
  143. /* free resources */
  144. if(out) free(out);
  145. if(data) free(data);
  146. return 0;
  147. }