|
|
1.1 root 1: //
2: // nono
3: // Copyright (C) 2025 nono project
4: // Licensed under nono-license.txt
5: //
6:
7: // ADPCM <-> PCM Converter
8:
9: #include "header.h"
10: #include <vector>
11: #include <fcntl.h>
12: #include <unistd.h>
13: #include <sys/stat.h>
14:
15: //--- ここから adpcm.h 相当 ---
16:
17: class ADPCMDevice
18: {
19: public:
20: uint32 pcm2adpcm_step(int16 pcm);
21: int16 adpcm2pcm_step(uint32 data);
22: private:
23: inline uint32 adpcm_encode(int32 dn);
24: inline int32 adpcm_decode(uint32 data, int32 xn);
25: inline void adpcm_calcstep(uint32 data);
26:
27: int32 xprev {};
28: int stepidx {};
29: static const int adpcm_stepadj[16];
30: static const int32 adpcm_stepsize[49];
31: };
32:
33: //--- ここまで adpcm.h 相当 ---
34: //--- ここから adpcm.cpp 相当 ---
35:
36: inline uint32
37: ADPCMDevice::adpcm_encode(int32 dn)
38: {
39: uint32 Ln = 0;
40:
41: int ss = adpcm_stepsize[stepidx];
42:
43: if (dn < 0) {
44: Ln = 0x8;
45: dn = -dn;
46: }
47: if (dn >= ss) {
48: Ln |= 0x4;
49: dn -= ss;
50: }
51: ss /= 2;
52: if (dn >= ss) {
53: Ln |= 0x2;
54: dn -= ss;
55: }
56: ss /= 2;
57: if (dn >= ss) {
58: Ln |= 0x1;
59: }
60: return Ln;
61: }
62:
63: inline int32
64: ADPCMDevice::adpcm_decode(uint32 data, int32 xn)
65: {
66: int b3 = (data & 8) ? 1 : 0;
67: int b2 = (data & 4) ? 1 : 0;
68: int b1 = (data & 2) ? 1 : 0;
69: int b0 = (data & 1);
70:
71: int32 ss = adpcm_stepsize[stepidx];
72: int32 dn = (ss * b2) + (ss / 2 * b1) + (ss / 4 * b0) + ss / 8;
73: if (b3) {
74: dn = -dn;
75: }
76:
77: xn += dn;
78:
79: // Saturate in 12 bits.
80: if (__predict_false(xn > 2047)) {
81: xn = 2047;
82: } else if (__predict_false(xn < -2047)) {
83: xn = -2047;
84: }
85:
86: return xn;
87: }
88:
89: inline void
90: ADPCMDevice::adpcm_calcstep(uint32 data)
91: {
92: stepidx += adpcm_stepadj[data];
93: if (__predict_false(stepidx < 0)) {
94: stepidx = 0;
95: } else if (__predict_false(stepidx > 48)) {
96: stepidx = 48;
97: }
98: }
99:
100: uint32
101: ADPCMDevice::pcm2adpcm_step(int16 pcm)
102: {
103: // Input of this algorithm is 12 bit.
104: int32 xn = pcm / 16;
105: int32 dn = xn - xprev;
106: uint32 Ln = adpcm_encode(dn);
107:
108: // next はこの Ln をデコードして PCM にした値
109: xprev = adpcm_decode(Ln, xprev);
110: adpcm_calcstep(Ln);
111:
112: return Ln;
113: }
114:
115: int16
116: ADPCMDevice::adpcm2pcm_step(uint32 data)
117: {
118: int32 xn = adpcm_decode(data, xprev);
119:
120: // next
121: xprev = xn;
122: adpcm_calcstep(data);
123:
124: // このアルゴリズムの出力は(下詰めで) 12 bit。
125: // ただし MSM6258 の出力 DAC は 10 bit 分しかない。
126: xn /= 4;
127: // その 10 bit を 16 bit PCM にする。
128: xn *= 64;
129: return xn;
130: }
131:
132: /*static*/ const int
133: ADPCMDevice::adpcm_stepadj[16] = {
134: -1, -1, -1, -1, 2, 4, 6, 8,
135: -1, -1, -1, -1, 2, 4, 6, 8,
136: };
137:
138: /*static*/ const int32
139: ADPCMDevice::adpcm_stepsize[49] = {
140: 16, 17, 19, 21, 23, 25, 28, 31, 34, 37,
141: 41, 45, 50, 55, 60, 66, 73, 80, 88, 97,
142: 107, 118, 130, 143, 157, 173, 190, 209, 230, 253,
143: 279, 307, 337, 371, 408, 449, 494, 544, 598, 658,
144: 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552,
145: };
146:
147: //--- ここまで adpcm.cpp 相当 ---
148:
149: #define RIFF(a,b,c,d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
150: #define VERBOSE(fmt...) do { if (verbose) printf(fmt); } while (0)
151:
152: struct chunk_header {
153: uint32 chunktype;
154: uint32 chunksize;
155: };
156:
157: struct fmt_chunk {
158: uint16 fmtid;
159: uint16 nchannels;
160: uint32 frequency;
161: uint32 byterate;
162: uint16 framesize;
163: uint16 bitdepth;
164: } __packed;
165:
166: static void usage();
167: static bool is_wavfile(const char *);
168: static void encode_file(const char *, const char *);
169: static void read_fmt_chunk(int ifd, const char *infile);
170: static void read_data_chunk(int ifd, int ofd, uint32 datasize,
171: const char *infile, const char *outfile);
172: static void decode_file(const char *, const char *);
173:
174: static const char wav_magic[12] = {
175: 'R', 'I', 'F', 'F', 0, 0, 0, 0, 'W', 'A', 'V', 'E'
176: };
177:
178: static const int freqtable[] = {
179: 0,
180: 3906,
181: 5208,
182: 7812,
183: 10416,
184: 15625,
185: };
186:
187: static ADPCMDevice *dev;
188: static int freq;
189: static bool verbose;
190:
191: int
192: main(int ac, char *av[])
193: {
194: enum {
195: CMD_AUTO,
196: CMD_ENCODE,
197: CMD_DECODE,
198: } cmd {};
199: int c;
200: int f = 0;
201:
202: while ((c = getopt(ac, av, "def:v")) != -1) {
203: switch (c) {
204: case 'd':
205: cmd = CMD_DECODE;
206: break;
207: case 'e':
208: cmd = CMD_ENCODE;
209: break;
210: case 'f':
211: {
212: f = atoi(optarg);
213: if (f < 0 || f > countof(freqtable)) {
214: usage();
215: }
216: break;
217: }
218: case 'v':
219: verbose = true;
220: break;
221: default:
222: usage();
223: }
224: }
225: ac -= optind;
226: av += optind;
227:
228: if (ac < 2) {
229: usage();
230: }
231: const char *infile = av[0];
232: const char *outfile = av[1];
233:
234: if (cmd == CMD_AUTO) {
235: if (is_wavfile(infile)) {
236: cmd = CMD_ENCODE;
237: VERBOSE("Input file looks WAV\n");
238: } else {
239: cmd = CMD_DECODE;
240: VERBOSE("Input file looks ADPCM\n");
241: }
242: }
243: assert(cmd == CMD_ENCODE || cmd == CMD_DECODE);
244:
245: dev = new ADPCMDevice();
246:
247: if (cmd == CMD_DECODE) {
248: // ADPCM -> PCM
249: if (f == 0) {
250: f = 5;
251: }
252: freq = freqtable[f];
253: decode_file(infile, outfile);
254: } else {
255: // PCM -> ADPCM
256: encode_file(infile, outfile);
257: }
258:
259: return 0;
260: }
261:
262: static void
263: usage()
264: {
265: printf("%s [-e] <PCMfile> <out.adpcm>\n", getprogname());
266: printf("%s [-d] [-f<n> ] <ADPCMfile> <out.PCM>\n", getprogname());
267: printf(" -f1: 3.9 kHz, -f2: 5.2 kHz, -f3: 7.8 kHz,");
268: printf(" -f4: 10.4 kHz, -f5: 15.6 kHz\n");
269: exit(1);
270: }
271:
272: // 入力ファイルが .WAV ファイルっぽければ true を返す。
273: static bool
274: is_wavfile(const char *infile)
275: {
276: char buf[12];
277: int fd;
278:
279: fd = open(infile, O_RDONLY);
280: if (fd < 0) {
281: err(1, "%s: open %s", __func__, infile);
282: }
283:
284: auto n = read(fd, buf, sizeof(buf));
285: close(fd);
286: if (n < 0) {
287: err(1, "%s: read %s", __func__, infile);
288: }
289: if (n < sizeof(buf)) {
290: return false;
291: }
292: memset(buf + 4, 0, 4);
293: if (memcmp(buf, wav_magic, sizeof(wav_magic)) != 0) {
294: return false;
295: }
296:
297: return true;
298: }
299:
300: // PCM -> ADPCM。
301: // 入力の WAV ファイルは 16bit, 1チャンネル固定。
302: // サンプリングレートは気にせずデータを列挙するだけ。
303: static void
304: encode_file(const char *infile, const char *outfile)
305: {
306: char buf[12];
307: ssize_t n;
308:
309: int ifd = open(infile, O_RDONLY);
310: if (ifd < 0) {
311: err(1, "%s: open", infile);
312: }
313: int ofd = creat(outfile, 0644);
314: if (ofd < 0) {
315: err(1, "%s: creat", outfile);
316: }
317:
318: // RIFF ヘッダ。
319: n = read(ifd, buf, sizeof(wav_magic));
320: if (n < 0) {
321: err(1, "%s: reading header", infile);
322: }
323: if (n < sizeof(wav_magic)) {
324: errx(1, "%s: file too short", infile);
325: }
326: if (memcmp(buf + 0, wav_magic + 0, 4) != 0 ||
327: memcmp(buf + 8, wav_magic + 8, 4) != 0) {
328: errx(1, "%s: Invalid WAV magic", infile);
329: }
330:
331: // チャンクが続く。
332: for (bool done = false; done == false; ) {
333: n = read(ifd, buf, sizeof(chunk_header));
334: if (n < 0) {
335: err(1, "%s: reading chunk header", infile);
336: }
337: if (n == 0) {
338: break;
339: }
340: if (n < sizeof(chunk_header)) {
341: errx(1, "%s: file too short", infile);
342: }
343:
344: const chunk_header *ch = (const chunk_header *)&buf[0];
345: uint32 chunktype = be32toh(ch->chunktype);
346: uint32 chunksize = le32toh(ch->chunksize);
347:
348: uint32 nextpos = lseek(ifd, 0, SEEK_CUR);
349: nextpos += chunksize;
350:
351: VERBOSE("Chunk '%c%c%c%c' len=%u\n",
352: (chunktype >> 24),
353: (chunktype >> 16) & 0xff,
354: (chunktype >> 8) & 0xff,
355: (chunktype & 0xff),
356: chunksize);
357: switch (chunktype) {
358: case RIFF('f', 'm', 't', ' '):
359: read_fmt_chunk(ifd, infile);
360: break;
361: case RIFF('d', 'a', 't', 'a'):
362: read_data_chunk(ifd, ofd, chunksize, infile, outfile);
363: // data チャンク処理したら後は無視して終わる?
364: done = true;
365: break;
366: default:
367: // 知らないチャンクは読み飛ばす。
368: break;
369: }
370: lseek(ifd, nextpos, SEEK_SET);
371: }
372: close(ifd);
373: close(ofd);
374: }
375:
376: // ifd から fmt チャンクを読み込んで、パラメータをチェックするだけ。
377: static void
378: read_fmt_chunk(int ifd, const char *infile)
379: {
380: struct fmt_chunk fmt;
381:
382: auto n = read(ifd, &fmt, sizeof(fmt));
383: if (n < 0) {
384: err(1, "%s: read fmt chunk", infile);
385: }
386: if (n < sizeof(fmt)) {
387: errx(1, "%s: file too short", infile);
388: }
389:
390: // 16bit, 1channel, PCM のみサポート。
391: uint32 format = le16toh(fmt.fmtid);
392: uint32 nchannels = le16toh(fmt.nchannels);
393: uint32 bitdepth = le16toh(fmt.bitdepth);
394: if (format != 1/*PCM*/) {
395: errx(1, "%s: Unknown WAV format 0x%x", infile, format);
396: }
397: if (nchannels != 1) {
398: errx(1, "%s: Only monaural is supported", infile);
399: }
400: if (bitdepth != 16) {
401: errx(1, "%s: Only 16 bit is supported", infile);
402: }
403: }
404:
405: // ifd から data チャンクを読み込んで ADPCM にして ofd に書き出す。
406: static void
407: read_data_chunk(int ifd, int ofd, uint32 datasize,
408: const char *infile, const char *outfile)
409: {
410: uint32 srcsize;
411: uint32 dstsize;
412:
413: // 奇数バイトのはずはないけど、一応。
414: srcsize = datasize;
415: if ((srcsize & 1U) != 0) {
416: srcsize += 1;
417: VERBOSE("srcsize ODD! %u\n", srcsize);
418: }
419: VERBOSE("srcsize = %u\n", srcsize);
420: // 奇数サンプルなら dst は偶数サンプルになるよう切り上げる。
421: dstsize = srcsize;
422: if ((dstsize & 2U) != 0) {
423: dstsize += 2;
424: VERBOSE("dst sample count ODD! %u\n", dstsize);
425: }
426: dstsize /= 4;
427: VERBOSE("dstsize = %u [bytes]\n", dstsize);
428:
429: std::vector<uint8> src;
430: std::vector<uint8> dst;
431: try {
432: src.resize(srcsize);
433: dst.resize(dstsize);
434: } catch (...) {
435: errno = ENOMEM;
436: err(1, "data chunk %u", datasize);
437: }
438:
439: auto n = read(ifd, src.data(), datasize);
440: if (n < 0) {
441: err(1, "%s: read data", infile);
442: }
443: if (n < src.size()) {
444: errx(1, "%s: file too short", infile);
445: }
446:
447: // 2サンプルずつ処理できる。
448: const int16 *s = (const int16 *)src.data();
449: uint8 *d = dst.data();
450: for (const uint8 *end = d + dstsize; d < end; ) {
451: uint32 v0 = dev->pcm2adpcm_step(*s++);
452: uint32 v1 = dev->pcm2adpcm_step(*s++);
453: *d++ = v0 | (v1 << 4);
454: }
455:
456: write(ofd, dst.data(), dst.size());
457: }
458:
459: // ADPCM -> PCM
460: static void
461: decode_file(const char *infile, const char *outfile)
462: {
463: struct stat st;
464: std::vector<uint8> src;
465: std::vector<int16> dst;
466: uint8 wavhdr[12];
467: chunk_header hdr;
468: fmt_chunk fmt;
469: ssize_t n;
470:
471: int ifd = open(infile, O_RDONLY);
472: if (ifd < 0) {
473: err(1, "%s: open", infile);
474: }
475: if (fstat(ifd, &st) < 0) {
476: err(1, "%s: fstat", infile);
477: }
478: // 一気に確保。
479: try {
480: src.resize(st.st_size);
481: dst.resize(st.st_size * 2);
482: } catch (...) {
483: errno = ENOMEM;
484: err(1, "buf(%zd)", st.st_size);
485: }
486: // 出力データ部のバイト数。
487: size_t databytes = dst.size() * sizeof(int16);
488:
489: // 全体を読み込む。
490: n = read(ifd, src.data(), src.size());
491: if (n < 0) {
492: err(1, "%s: read data", infile);
493: }
494: if (n < src.size()) {
495: errx(1, "%s: file too short", infile);
496: }
497:
498: // 出力ファイル。
499: int ofd = creat(outfile, 0644);
500: if (ofd < 0) {
501: err(1, "%s: creat", outfile);
502: }
503: // WAV ヘッダ。
504: memcpy(wavhdr, wav_magic, sizeof(wav_magic));
505: *(uint32 *)(wavhdr + 4) = htole32(
506: sizeof(wavhdr) +
507: sizeof(hdr) + sizeof(fmt) +
508: sizeof(hdr) + databytes);
509: n = write(ofd, wavhdr, sizeof(wavhdr));
510: if (n < 0) {
511: err(1, "%s: write", outfile);
512: }
513:
514: // fmt チャンク。
515: hdr.chunktype = htobe32(RIFF('f', 'm', 't', ' '));
516: hdr.chunksize = htole32(16);
517: n = write(ofd, &hdr, sizeof(hdr));
518: if (n < 0) {
519: err(1, "%s: write", outfile);
520: }
521: fmt.fmtid = htole16(1); // PCM
522: fmt.nchannels = htole16(1);
523: fmt.frequency = htole32(freq);
524: fmt.byterate = htole32(freq * 1 * (16 / 8));
525: fmt.framesize = htole16(1 * (16 / 8));
526: fmt.bitdepth = htole16(16);
527: n = write(ofd, &fmt, sizeof(fmt));
528: if (n < 0) {
529: err(1, "%s: write", outfile);
530: }
531:
532: // data チャンクのヘッダ部。
533: hdr.chunktype = htobe32(RIFF('d', 'a', 't', 'a'));
534: hdr.chunksize = databytes;
535: n = write(ofd, &hdr, sizeof(hdr));
536: if (n < 0) {
537: err(1, "%s: write", outfile);
538: }
539:
540: const uint8 *s = src.data();
541: int16 *d = dst.data();
542: for (const uint8 *end = s + src.size(); s < end; ) {
543: uint8 data = *s++;
544: int16 pcm0 = dev->adpcm2pcm_step(data & 0x0f);
545: int16 pcm1 = dev->adpcm2pcm_step(data >> 4);
546: *d++ = pcm0;
547: *d++ = pcm1;
548: }
549: write(ofd, dst.data(), dst.size() * sizeof(int16));
550:
551: close(ifd);
552: close(ofd);
553: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.