1 #include <stdio.h> 2 #include <stdint.h> 3 #include <stdlib.h> 4 #include <fcntl.h> 5 #include <errno.h> 6 #include <unistd.h> 7 #include <string.h> 8 #include <sys/types.h> 9 #include <sys/stat.h> 10 11 struct wav_header { 12 char riff[4]; 13 uint32_t chunk_size; 14 char format[4]; 15 16 char subchunk1_id[4]; 17 uint32_t subchunk1_size; 18 uint16_t audio_format; 19 uint16_t num_channels; 20 uint32_t sample_rate; 21 uint32_t byte_rate; 22 uint16_t block_align; 23 uint16_t bits_per_sample; 24 25 char subchunk2_id[4]; 26 uint32_t subchunk2_size; 27 } __attribute__((packed)); 28 29 static void init_wav_header(struct wav_header *hdr, 30 uint32_t num_samples, 31 uint16_t bits_per_sample, 32 int channels, 33 uint32_t sample_rate) 34 { 35 hdr->riff[0] = 'R'; 36 hdr->riff[1] = 'I'; 37 hdr->riff[2] = 'F'; 38 hdr->riff[3] = 'F'; 39 40 hdr->subchunk2_size = num_samples * channels * bits_per_sample / 8; 41 42 hdr->chunk_size = 36 + hdr->subchunk2_size; 43 hdr->format[0] = 'W'; 44 hdr->format[1] = 'A'; 45 hdr->format[2] = 'V'; 46 hdr->format[3] = 'E'; 47 48 hdr->subchunk1_id[0] = 'f'; 49 hdr->subchunk1_id[1] = 'm'; 50 hdr->subchunk1_id[2] = 't'; 51 hdr->subchunk1_id[3] = ' '; 52 53 hdr->subchunk1_size = 16; 54 hdr->audio_format = 1; /* PCM */ 55 hdr->num_channels = channels; 56 hdr->sample_rate = sample_rate; 57 hdr->byte_rate = sample_rate * channels * bits_per_sample / 8; 58 hdr->block_align = channels * bits_per_sample / 8; 59 hdr->bits_per_sample = bits_per_sample; 60 61 hdr->subchunk2_id[0] = 'd'; 62 hdr->subchunk2_id[1] = 'a'; 63 hdr->subchunk2_id[2] = 't'; 64 hdr->subchunk2_id[3] = 'a'; 65 } 66 67 static const int divs_8000[] = { 5, 6, 6, 5 }; 68 static const int divs_11025[] = { 4 }; 69 static const int divs_22050[] = { 2 }; 70 static const int divs_44100[] = { 1 }; 71 72 int downsample(const int16_t *in, int16_t *out, int len, int *consumed, 73 const int *divs, int divs_len, 74 int out_stereo) 75 { 76 int i, j, lsum, rsum; 77 int di, div; 78 int oi; 79 80 i = 0; 81 oi = 0; 82 di = 0; 83 div = divs[0]; 84 while (i + div * 2 <= len) { 85 // printf("div %d, i %d, oi %d\n", div, i, oi); 86 for (j = 0, lsum = 0, rsum = 0; j < div; j++) { 87 lsum += in[i + j * 2]; 88 rsum += in[i + j * 2 + 1]; 89 } 90 if (!out_stereo) 91 out[oi] = (lsum + rsum) / (div * 2); 92 else { 93 out[oi] = lsum / div; 94 out[oi + 1] = rsum / div; 95 } 96 97 oi += out_stereo + 1; 98 i += div * 2; 99 div = divs[++di % divs_len]; 100 } 101 102 // printf("done: i %d, len %d, oi %d\n", i, len, oi); 103 *consumed = i; 104 return oi; 105 } 106 107 #define FAILIF(x, ...) do if (x) { \ 108 fprintf(stderr, __VA_ARGS__); \ 109 exit(EXIT_FAILURE); \ 110 } while (0) 111 112 int main(int argc, char **argv) 113 { 114 int opt, ifd, ofd; 115 int new_rate = -1; 116 const int *divs; 117 int divs_len; 118 int consumed; 119 int channels = -1; 120 char *input = NULL; 121 char *output = NULL; 122 int nr, nr_out, nw; 123 int put_header = 0; 124 int total = 0; 125 const int bits_per_sample = 16; 126 127 struct wav_header src_hdr, dst_hdr; 128 129 int16_t buf[2048]; 130 131 while ((opt = getopt(argc, argv, "o:s:c:w")) != -1) { 132 switch (opt) { 133 case 'o': 134 FAILIF(output != NULL, "Multiple output files not supported\n"); 135 output = strdup(optarg); 136 break; 137 case 's': 138 new_rate = atoi(optarg); 139 break; 140 case 'c': 141 channels = atoi(optarg); 142 break; 143 case 'w': 144 put_header = 1; 145 break; 146 default: /* '?' */ 147 fprintf(stderr, "usage: %s -o<outfile> -s<sampling> -c<channels>\n", 148 *argv); 149 fprintf(stderr, "usage: %s -o<outfile> -s<sampling> -c<channels>\n", 150 *argv); 151 exit(EXIT_FAILURE); 152 } 153 } 154 155 FAILIF(channels != 1 && channels != 2, "-c value must be 1 or 2\n"); 156 157 switch(new_rate) { 158 case 8000: 159 divs = divs_8000; 160 divs_len = 4; 161 break; 162 case 11025: 163 divs = divs_11025; 164 divs_len = 1; 165 break; 166 case 22050: 167 divs = divs_22050; 168 divs_len = 1; 169 break; 170 case 44100: 171 divs = divs_44100; 172 divs_len = 1; 173 break; 174 default: 175 FAILIF(1, "rate %d is not supported\n", new_rate); 176 } 177 178 FAILIF(!output, "Expecting an output file name\n"); 179 FAILIF(optind >= argc, "Expecting an input file name\n"); 180 181 input = argv[optind]; 182 183 printf("input file [%s]\n", input); 184 printf("output file [%s]\n", output); 185 printf("new rate: [%d]\n", new_rate); 186 187 ifd = open(input, O_RDONLY); 188 FAILIF(ifd < 0, "Could not open %s: %s\n", input, strerror(errno)); 189 ofd = open(output, O_WRONLY | O_CREAT | O_TRUNC, 0666); 190 FAILIF(ofd < 0, "Could not open %s: %s\n", output, strerror(errno)); 191 192 if (strstr(input, ".wav")) { 193 FAILIF(read(ifd, &src_hdr, sizeof(src_hdr)) != sizeof(src_hdr), 194 "Failed to read input WAV header: %s\n", 195 strerror(errno)); 196 FAILIF(src_hdr.audio_format != 1, 197 "Expecting PCM encoding\n"); 198 FAILIF(src_hdr.sample_rate != 44100, 199 "Expecting 44.kHz files\n"); 200 FAILIF(src_hdr.num_channels != 2, 201 "Expecting 2-channel files\n"); 202 FAILIF(src_hdr.bits_per_sample != bits_per_sample, 203 "Expecting 16-bit PCM files\n"); 204 } 205 206 if (put_header) 207 FAILIF(lseek(ofd, sizeof(struct wav_header), SEEK_SET) < 0, 208 "seek error in %s: %s\n", output, strerror(errno)); 209 210 consumed = 0; 211 while (1) { 212 nr = read(ifd, buf + consumed, sizeof(buf) - consumed); 213 FAILIF(nr < 0, "could not read from %s: %s\n", input, strerror(errno)); 214 if (!nr) { 215 printf("done\n"); 216 break; 217 } 218 nr += consumed; 219 220 // printf("resampling %d samples\n", nr / 2); 221 nr_out = downsample(buf, buf, nr / 2, &consumed, divs, divs_len, channels == 2); 222 consumed *= 2; 223 // printf("done: %d samples were generated (consumed %d out of %d bytes)\n", nr_out, consumed, nr); 224 225 if (consumed < nr) { 226 memcpy(buf, buf + consumed, nr - consumed); 227 consumed = nr - consumed; 228 // printf("copied %d bytes to front\n", consumed); 229 } 230 else consumed = 0; 231 232 nr_out *= 2; 233 nw = write(ofd, buf, nr_out); 234 FAILIF(nw < 0, "could not write to %s: %s\n", output, strerror(errno)); 235 FAILIF(nw != nr_out, "mismatch, generated %d, wrote %d bytes\n", nr_out, nw); 236 total += nw; 237 } 238 239 if (put_header) { 240 printf("writing WAV header\n"); 241 lseek(ofd, 0, SEEK_SET); 242 init_wav_header(&dst_hdr, 243 total * 8 / (channels * bits_per_sample), 244 bits_per_sample, 245 channels, 246 new_rate); 247 FAILIF(write(ofd, &dst_hdr, sizeof(dst_hdr)) != sizeof(dst_hdr), 248 "Could not write WAV header: %s\n", strerror(errno)); 249 } 250 251 close(ifd); 252 close(ofd); 253 254 return 0; 255 } 256