• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
init_wav_header(struct wav_header * hdr,uint32_t num_samples,uint16_t bits_per_sample,int channels,uint32_t sample_rate)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
main(int argc,char * argv[])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