Home | History | Annotate | Download | only in taudio
      1 #include <unistd.h>
      2 #include <stdlib.h>
      3 #include <stdio.h>
      4 #include <sys/types.h>
      5 #include <sys/stat.h>
      6 #include <fcntl.h>
      7 #include <errno.h>
      8 #include <stdint.h>
      9 #include <assert.h>
     10 #include <string.h>
     11 
     12 #include <sys/ioctl.h>
     13 
     14 #define FAILIF(x, ...) do if (x) { \
     15     fprintf(stderr, __VA_ARGS__);  \
     16     exit(EXIT_FAILURE);            \
     17 } while (0)
     18 
     19 static char buffer[4096];
     20 
     21 struct wav_header {
     22     char  riff[4];
     23     uint32_t chunk_size;
     24     char  format[4];
     25 
     26     char  subchunk1_id[4];
     27     uint32_t subchunk1_size;
     28     uint16_t audio_format;
     29     uint16_t num_channels;
     30     uint32_t sample_rate;
     31     uint32_t byte_rate;
     32     uint16_t block_align;
     33     uint16_t bits_per_sample;
     34 
     35     char  subchunk2_id[4];
     36     uint32_t subchunk2_size;
     37 } __attribute__((packed));
     38 
     39 static void init_wav_header(struct wav_header *hdr,
     40                        uint32_t num_samples,
     41                        uint16_t bits_per_sample,
     42                        int   channels,
     43                        uint32_t sample_rate)
     44 {
     45     hdr->riff[0] = 'R';
     46     hdr->riff[1] = 'I';
     47     hdr->riff[2] = 'F';
     48     hdr->riff[3] = 'F';
     49 
     50     hdr->subchunk2_size = num_samples * channels * bits_per_sample / 8;
     51 
     52     hdr->chunk_size = 36 + hdr->subchunk2_size;
     53     hdr->format[0] = 'W';
     54     hdr->format[1] = 'A';
     55     hdr->format[2] = 'V';
     56     hdr->format[3] = 'E';
     57 
     58     hdr->subchunk1_id[0] = 'f';
     59     hdr->subchunk1_id[1] = 'm';
     60     hdr->subchunk1_id[2] = 't';
     61     hdr->subchunk1_id[3] = ' ';
     62 
     63     hdr->subchunk1_size = 16;
     64     hdr->audio_format = 1; /* PCM */
     65     hdr->num_channels = channels;
     66     hdr->sample_rate = sample_rate;
     67     hdr->byte_rate = sample_rate * channels * bits_per_sample / 8;
     68     hdr->block_align = channels * bits_per_sample / 8;
     69     hdr->bits_per_sample = bits_per_sample;
     70 
     71     hdr->subchunk2_id[0] = 'd';
     72     hdr->subchunk2_id[1] = 'a';
     73     hdr->subchunk2_id[2] = 't';
     74     hdr->subchunk2_id[3] = 'a';
     75 }
     76 
     77 int
     78 main(int argc, char *argv[])
     79 {
     80     int ifd, ofd;
     81     int nr, nw = 0, total = 0;
     82     struct wav_header hdr;
     83 
     84     int opt;
     85     char * output = NULL;
     86     char * input = NULL;
     87     int bits_per_sample = 16;
     88     int sampling_rate = -1;
     89     int num_channels = -1;
     90 
     91     while ((opt = getopt(argc, argv, "o:c:b:s:")) != -1) {
     92         switch (opt) {
     93         case 'o':
     94             output = strdup(optarg);
     95             break;
     96         case 'c':
     97             num_channels = atoi(optarg);
     98             assert(num_channels == 1 || num_channels == 2);
     99             break;
    100         case 'b':
    101             bits_per_sample = atoi(optarg);
    102             break;
    103         case 's':
    104             sampling_rate = atoi(optarg);
    105             break;
    106         default: /* '?' */
    107             fprintf(stderr, "Usage: %s [-ooutfile] -c2 -b16 -s44100 infile\n",
    108                     argv[0]);
    109             exit(EXIT_FAILURE);
    110         }
    111     }
    112 
    113     assert(sampling_rate >= 0);
    114     assert(num_channels >= 0);
    115 
    116     FAILIF(!output, "Expecting an output file name\n");
    117     FAILIF(optind >= argc, "Expecting an input file name\n");
    118 
    119     input = argv[optind];
    120 
    121     printf("> input %s\n", input);
    122     printf("> output %s\n", output);
    123     printf("> bits per sample %d\n", bits_per_sample);
    124     printf("> sampling rate %d\n", sampling_rate);
    125     printf("> channels %d\n", num_channels);
    126 
    127     ofd = open(output, O_WRONLY | O_CREAT, 0777);
    128     FAILIF(ofd < 0, "could not open %s: %s\n", output, strerror(errno));
    129 
    130     ifd = open(input, O_RDONLY);
    131     FAILIF(ifd < 0, "could not open %s: %s\n", input, strerror(errno));
    132 
    133     lseek(ofd, sizeof(struct wav_header), SEEK_SET);
    134 
    135     do {
    136         nr = read(ifd, buffer, sizeof(buffer));
    137         FAILIF(nr < 0, "Could not read from input: %s\n", strerror(errno));
    138         if (!nr) {
    139             printf("done recording\n");
    140             break;
    141         }
    142         nw = write(ofd, buffer, nr);
    143         FAILIF(nw < 0, "Could not copy to output: %s\n", strerror(errno));
    144         FAILIF(nw != nr, "Mismatch nw = %d nr = %d\n", nw, nr);
    145         total += nw;
    146     } while (1);
    147 
    148     printf("writing WAV header\n");
    149     lseek(ofd, 0, SEEK_SET);
    150     init_wav_header(&hdr,
    151 		    total * 8 / (num_channels * bits_per_sample),
    152 		    bits_per_sample,
    153 		    num_channels,
    154 		    sampling_rate);
    155 
    156     FAILIF(write(ofd, &hdr, sizeof(hdr)) != sizeof(hdr),
    157            "Could not write WAV header: %s\n", strerror(errno));
    158 
    159     printf("done\n");
    160     return 0;
    161 }
    162