wav.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. /* Geez, why are WAV RIFF headers are so secret? I got something together,
  2. but wow... anyway, I hope someone will find this useful.
  3. - Samuel Audet <guardia@cam.org> */
  4. /* minor simplifications and ugly AU/CDR format stuff by MH */
  5. /* It's not a very clean code ... Fix this! */
  6. #include "mpg123.h"
  7. struct
  8. {
  9. byte riffheader[4];
  10. byte WAVElen[4];
  11. struct
  12. {
  13. byte fmtheader[8];
  14. byte fmtlen[4];
  15. struct
  16. {
  17. byte FormatTag[2];
  18. byte Channels[2];
  19. byte SamplesPerSec[4];
  20. byte AvgBytesPerSec[4];
  21. byte BlockAlign[2];
  22. byte BitsPerSample[2]; /* format specific for PCM */
  23. } fmt;
  24. struct
  25. {
  26. byte dataheader[4];
  27. byte datalen[4];
  28. /* from here you insert your PCM data */
  29. } data;
  30. } WAVE;
  31. } RIFF =
  32. { { 'R','I','F','F' } , { sizeof(RIFF.WAVE),0,0,0 } ,
  33. { { 'W','A','V','E','f','m','t',' ' } , { sizeof(RIFF.WAVE.fmt),0,0,0} ,
  34. { {1,0} , {0,0},{0,0,0,0},{0,0,0,0},{0,0},{0,0} } ,
  35. { { 'd','a','t','a' } , {0,0,0,0} }
  36. }
  37. };
  38. struct auhead {
  39. byte magic[4];
  40. byte headlen[4];
  41. byte datalen[4];
  42. byte encoding[4];
  43. byte rate[4];
  44. byte channels[4];
  45. byte dummy[8];
  46. } auhead = {
  47. { 0x2e,0x73,0x6e,0x64 } , { 0x00,0x00,0x00,0x20 } ,
  48. { 0xff,0xff,0xff,0xff } , { 0,0,0,0 } , { 0,0,0,0 } , { 0,0,0,0 } ,
  49. { 0,0,0,0,0,0,0,0 }};
  50. static FILE *wavfp;
  51. static long datalen = 0;
  52. static int flipendian=0;
  53. /* Convertfunctions: */
  54. /* always little endian */
  55. static void long2littleendian(long inval,byte *outval,int b)
  56. {
  57. int i;
  58. for(i=0;i<b;i++) {
  59. outval[i] = (inval>>(i*8)) & 0xff;
  60. }
  61. }
  62. /* always big endian */
  63. static void long2bigendian(long inval,byte *outval,int b)
  64. {
  65. int i;
  66. for(i=0;i<b;i++) {
  67. outval[i] = (inval>>((b-i-1)*8)) & 0xff;
  68. }
  69. }
  70. static int testEndian(void)
  71. {
  72. long i,a=0,b=0,c=0;
  73. int ret = 0;
  74. for(i=0;i<sizeof(long);i++) {
  75. ((byte *)&a)[i] = i;
  76. b<<=8;
  77. b |= i;
  78. c |= i << (i*8);
  79. }
  80. if(a == b)
  81. ret = 1;
  82. else if(a != c) {
  83. fprintf(stderr,"Strange endianess?? %08lx %08lx %08lx\n",a,b,c);
  84. exit(1);
  85. }
  86. return ret;
  87. }
  88. static int open_file(char *filename)
  89. {
  90. #ifndef GENERIC
  91. setuid(getuid()); /* dunno whether this helps. I'm not a security expert */
  92. #endif
  93. if(!strcmp("-",filename)) {
  94. wavfp = stdout;
  95. }
  96. else {
  97. wavfp = fopen(filename,"w");
  98. if(!wavfp)
  99. return -1;
  100. }
  101. return 0;
  102. }
  103. int au_open(struct audio_info_struct *ai, char *aufilename)
  104. {
  105. flipendian = 0;
  106. switch(ai->format) {
  107. case AUDIO_FORMAT_SIGNED_16:
  108. flipendian = !testEndian(); /* big end */
  109. long2bigendian(3,auhead.encoding,sizeof(auhead.encoding));
  110. break;
  111. case AUDIO_FORMAT_UNSIGNED_8:
  112. ai->format = AUDIO_FORMAT_ULAW_8;
  113. case AUDIO_FORMAT_ULAW_8:
  114. long2bigendian(1,auhead.encoding,sizeof(auhead.encoding));
  115. break;
  116. default:
  117. fprintf(stderr,"AU output is only a hack. This audio mode isn't supported yet.\n");
  118. exit(1);
  119. }
  120. long2bigendian(0xffffffff,auhead.datalen,sizeof(auhead.datalen));
  121. long2bigendian(ai->rate,auhead.rate,sizeof(auhead.rate));
  122. long2bigendian(ai->channels,auhead.channels,sizeof(auhead.channels));
  123. if(open_file(aufilename) < 0)
  124. return -1;
  125. fwrite(&auhead, sizeof(auhead),1,wavfp);
  126. datalen = 0;
  127. return 0;
  128. }
  129. int cdr_open(struct audio_info_struct *ai, char *cdrfilename)
  130. {
  131. param.force_stereo = 0;
  132. ai->format = AUDIO_FORMAT_SIGNED_16;
  133. ai->rate = 44100;
  134. ai->channels = 2;
  135. /*
  136. if(ai->format != AUDIO_FORMAT_SIGNED_16 || ai->rate != 44100 || ai->channels != 2) {
  137. fprintf(stderr,"Oops .. not forced to 16 bit, 44kHz?, stereo\n");
  138. exit(1);
  139. }
  140. */
  141. flipendian = !testEndian(); /* big end */
  142. if(open_file(cdrfilename) < 0)
  143. return -1;
  144. return 0;
  145. }
  146. int wav_open(struct audio_info_struct *ai, char *wavfilename)
  147. {
  148. int bps;
  149. flipendian = 0;
  150. /* standard MS PCM, and its format specific is BitsPerSample */
  151. long2littleendian(1,RIFF.WAVE.fmt.FormatTag,sizeof(RIFF.WAVE.fmt.FormatTag));
  152. if(ai->format == AUDIO_FORMAT_SIGNED_16) {
  153. long2littleendian(bps=16,RIFF.WAVE.fmt.BitsPerSample,sizeof(RIFF.WAVE.fmt.BitsPerSample));
  154. flipendian = testEndian();
  155. }
  156. else if(ai->format == AUDIO_FORMAT_UNSIGNED_8)
  157. long2littleendian(bps=8,RIFF.WAVE.fmt.BitsPerSample,sizeof(RIFF.WAVE.fmt.BitsPerSample));
  158. else
  159. {
  160. fprintf(stderr,"Format not supported.");
  161. return -1;
  162. }
  163. if(ai->rate < 0) ai->rate = 44100;
  164. long2littleendian(ai->channels,RIFF.WAVE.fmt.Channels,sizeof(RIFF.WAVE.fmt.Channels));
  165. long2littleendian(ai->rate,RIFF.WAVE.fmt.SamplesPerSec,sizeof(RIFF.WAVE.fmt.SamplesPerSec));
  166. long2littleendian((int)(ai->channels * ai->rate * bps)>>3,
  167. RIFF.WAVE.fmt.AvgBytesPerSec,sizeof(RIFF.WAVE.fmt.AvgBytesPerSec));
  168. long2littleendian((int)(ai->channels * bps)>>3,
  169. RIFF.WAVE.fmt.BlockAlign,sizeof(RIFF.WAVE.fmt.BlockAlign));
  170. if(open_file(wavfilename) < 0)
  171. return -1;
  172. long2littleendian(datalen,RIFF.WAVE.data.datalen,sizeof(RIFF.WAVE.data.datalen));
  173. long2littleendian(datalen+sizeof(RIFF.WAVE),RIFF.WAVElen,sizeof(RIFF.WAVElen));
  174. fwrite(&RIFF, sizeof(RIFF),1,wavfp);
  175. datalen = 0;
  176. return 0;
  177. }
  178. int wav_write(unsigned char *buf,int len)
  179. {
  180. int temp;
  181. int i;
  182. if(!wavfp)
  183. return 0;
  184. if(flipendian) {
  185. if(len & 1) {
  186. fprintf(stderr,"Odd number of bytes!\n");
  187. exit(1);
  188. }
  189. for(i=0;i<len;i+=2) {
  190. unsigned char tmp;
  191. tmp = buf[i+0];
  192. buf[i+0] = buf[i+1];
  193. buf[i+1] = tmp;
  194. }
  195. }
  196. temp = fwrite(buf, 1, len, wavfp);
  197. if(temp <= 0)
  198. return 0;
  199. datalen += temp;
  200. return temp;
  201. }
  202. int wav_close(void)
  203. {
  204. if(!wavfp)
  205. return 0;
  206. if(fseek(wavfp, 0L, SEEK_SET) >= 0) {
  207. long2littleendian(datalen,RIFF.WAVE.data.datalen,sizeof(RIFF.WAVE.data.datalen));
  208. long2littleendian(datalen+sizeof(RIFF.WAVE),RIFF.WAVElen,sizeof(RIFF.WAVElen));
  209. fwrite(&RIFF, sizeof(RIFF),1,wavfp);
  210. }
  211. else {
  212. fprintf(stderr,"Warning can't rewind WAV file. File-format isn't fully conform now.\n");
  213. }
  214. return 0;
  215. }
  216. int au_close(void)
  217. {
  218. if(!wavfp)
  219. return 0;
  220. if(fseek(wavfp, 0L, SEEK_SET) >= 0) {
  221. long2bigendian(datalen,auhead.datalen,sizeof(auhead.datalen));
  222. fwrite(&auhead, sizeof(auhead),1,wavfp);
  223. }
  224. return 0;
  225. }
  226. int cdr_close(void)
  227. {
  228. return 0;
  229. }