2 * Bruteforcing decoder for converting ADPCM-encoded AIFC into AIFF, in a way
3 * that roundtrips with vadpcm_enc.
13 typedef signed char s8
;
16 typedef unsigned char u8
;
17 typedef unsigned short u16
;
18 typedef unsigned int u32
;
19 typedef unsigned long long u64
;
22 #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
23 # define bswap16(x) (x)
24 # define bswap32(x) (x)
27 # define BSWAP16_MANY(x, n)
29 # define bswap16(x) __builtin_bswap16(x)
30 # define bswap32(x) __builtin_bswap32(x)
31 # define BSWAP16(x) x = __builtin_bswap16(x)
32 # define BSWAP32(x) x = __builtin_bswap32(x)
33 # define BSWAP16_MANY(x, n) for (s32 _i = 0; _i < n; _i++) BSWAP16((x)[_i])
36 #define NORETURN __attribute__((noreturn))
37 #define UNUSED __attribute__((unused))
55 s16 sampleRate
[5]; // 80-bit float
104 static char usage
[] = "input.aifc output.aiff";
105 static const char *progname
, *infilename
;
107 #define checked_fread(a, b, c, d) if (fread(a, b, c, d) != c) fail_parse("error parsing file")
110 void fail_parse(const char *fmt
, ...)
112 char *formatted
= NULL
;
115 int size
= vsnprintf(NULL
, 0, fmt
, ap
);
119 formatted
= malloc(size
);
120 if (formatted
!= NULL
) {
122 size
= vsnprintf(formatted
, size
, fmt
, ap
);
131 if (formatted
!= NULL
) {
132 fprintf(stderr
, "%s: %s [%s]\n", progname
, formatted
, infilename
);
140 static u64 state
= 1619236481962341ULL;
141 state
*= 3123692312231ULL;
146 s16
qsample(s32 x
, s32 scale
)
148 // Compute x / 2^scale rounded to the nearest integer, breaking ties towards zero.
149 if (scale
== 0) return x
;
150 return (x
+ (1 << (scale
- 1)) - (x
> 0)) >> scale
;
153 s16
clamp_to_s16(s32 x
)
155 if (x
< -0x8000) return -0x8000;
156 if (x
> 0x7fff) return 0x7fff;
162 if (x
>= 8) return x
- 16;
166 s32
readaifccodebook(FILE *fhandle
, s32
****table
, s16
*order
, s16
*npredictors
)
168 checked_fread(order
, sizeof(s16
), 1, fhandle
);
170 checked_fread(npredictors
, sizeof(s16
), 1, fhandle
);
171 BSWAP16(*npredictors
);
172 *table
= malloc(*npredictors
* sizeof(s32
**));
173 for (s32 i
= 0; i
< *npredictors
; i
++) {
174 (*table
)[i
] = malloc(8 * sizeof(s32
*));
175 for (s32 j
= 0; j
< 8; j
++) {
176 (*table
)[i
][j
] = malloc((*order
+ 8) * sizeof(s32
));
180 for (s32 i
= 0; i
< *npredictors
; i
++) {
181 s32
**table_entry
= (*table
)[i
];
182 for (s32 j
= 0; j
< *order
; j
++) {
183 for (s32 k
= 0; k
< 8; k
++) {
185 checked_fread(&ts
, sizeof(s16
), 1, fhandle
);
187 table_entry
[k
][j
] = ts
;
191 for (s32 k
= 1; k
< 8; k
++) {
192 table_entry
[k
][*order
] = table_entry
[k
- 1][*order
- 1];
195 table_entry
[0][*order
] = 1 << 11;
197 for (s32 k
= 1; k
< 8; k
++) {
200 table_entry
[j
][k
+ *order
] = 0;
204 table_entry
[j
][k
+ *order
] = table_entry
[j
- k
][*order
];
211 ALADPCMloop
*readlooppoints(FILE *ifile
, s16
*nloops
)
213 checked_fread(nloops
, sizeof(s16
), 1, ifile
);
215 ALADPCMloop
*al
= malloc(*nloops
* sizeof(ALADPCMloop
));
216 for (s32 i
= 0; i
< *nloops
; i
++) {
217 checked_fread(&al
[i
], sizeof(ALADPCMloop
), 1, ifile
);
218 BSWAP32(al
[i
].start
);
220 BSWAP32(al
[i
].count
);
221 BSWAP16_MANY(al
[i
].state
, 16);
226 s32
inner_product(s32 length
, s32
*v1
, s32
*v2
)
229 for (s32 i
= 0; i
< length
; i
++) {
230 out
+= v1
[i
] * v2
[i
];
233 // Compute "out / 2^11", rounded down.
234 s32 dout
= out
/ (1 << 11);
235 s32 fiout
= dout
* (1 << 11);
236 return dout
- (out
- fiout
< 0);
239 void my_decodeframe(u8
*frame
, s32
*state
, s32 order
, s32
***coefTable
)
243 u8 header
= frame
[0];
244 s32 scale
= 1 << (header
>> 4);
245 s32 optimalp
= header
& 0xf;
247 for (s32 i
= 0; i
< 16; i
+= 2) {
248 u8 c
= frame
[1 + i
/2];
253 for (s32 i
= 0; i
< 16; i
++) {
254 if (ix
[i
] >= 8) ix
[i
] -= 16;
258 for (s32 j
= 0; j
< 2; j
++) {
261 for (s32 i
= 0; i
< order
; i
++) {
262 in_vec
[i
] = state
[16 - order
+ i
];
265 for (s32 i
= 0; i
< order
; i
++) {
266 in_vec
[i
] = state
[8 - order
+ i
];
270 for (s32 i
= 0; i
< 8; i
++) {
272 in_vec
[order
+ i
] = ix
[ind
];
273 state
[ind
] = inner_product(order
+ i
, coefTable
[optimalp
][i
], in_vec
) + ix
[ind
];
278 void my_encodeframe(u8
*out
, s16
*inBuffer
, s32
*state
, s32
***coefTable
, s32 order
, s32 npredictors
)
290 for (s32 k
= 0; k
< npredictors
; k
++) {
291 for (s32 j
= 0; j
< 2; j
++) {
292 for (s32 i
= 0; i
< order
; i
++) {
293 inVector
[i
] = (j
== 0 ? state
[16 - order
+ i
] : inBuffer
[8 - order
+ i
]);
296 for (s32 i
= 0; i
< 8; i
++) {
297 prediction
[j
* 8 + i
] = inner_product(order
+ i
, coefTable
[k
][i
], inVector
);
298 e
[j
* 8 + i
] = inVector
[i
+ order
] = inBuffer
[j
* 8 + i
] - prediction
[j
* 8 + i
];
303 for (s32 j
= 0; j
< 16; j
++) {
304 se
+= (f32
) e
[j
] * (f32
) e
[j
];
313 for (s32 j
= 0; j
< 2; j
++) {
314 for (s32 i
= 0; i
< order
; i
++) {
315 inVector
[i
] = (j
== 0 ? state
[16 - order
+ i
] : inBuffer
[8 - order
+ i
]);
318 for (s32 i
= 0; i
< 8; i
++) {
319 prediction
[j
* 8 + i
] = inner_product(order
+ i
, coefTable
[optimalp
][i
], inVector
);
320 e
[j
* 8 + i
] = inVector
[i
+ order
] = inBuffer
[j
* 8 + i
] - prediction
[j
* 8 + i
];
324 for (s32 i
= 0; i
< 16; i
++) {
325 ie
[i
] = clamp_to_s16(e
[i
]);
329 for (s32 i
= 0; i
< 16; i
++) {
330 if (abs(ie
[i
]) > abs(max
)) {
335 for (scale
= 0; scale
<= 12; scale
++) {
336 if (max
<= 7 && max
>= -8) break;
340 for (s32 i
= 0; i
< 16; i
++) {
341 saveState
[i
] = state
[i
];
344 for (s32 nIter
= 0, again
= 1; nIter
< 2 && again
; nIter
++) {
346 if (nIter
== 1) scale
++;
351 for (s32 j
= 0; j
< 2; j
++) {
353 for (s32 i
= 0; i
< order
; i
++) {
354 inVector
[i
] = (j
== 0 ?
355 saveState
[16 - order
+ i
] : state
[8 - order
+ i
]);
358 for (s32 i
= 0; i
< 8; i
++) {
359 prediction
[base
+ i
] = inner_product(order
+ i
, coefTable
[optimalp
][i
], inVector
);
360 s32 se
= inBuffer
[base
+ i
] - prediction
[base
+ i
];
361 ix
[base
+ i
] = qsample(se
, scale
);
362 s32 cV
= clamp_to_s16(ix
[base
+ i
]) - ix
[base
+ i
];
363 if (cV
> 1 || cV
< -1) again
= 1;
365 inVector
[i
+ order
] = ix
[base
+ i
] * (1 << scale
);
366 state
[base
+ i
] = prediction
[base
+ i
] + inVector
[i
+ order
];
371 u8 header
= (scale
<< 4) | (optimalp
& 0xf);
373 for (s32 i
= 0; i
< 16; i
+= 2) {
374 u8 c
= ((ix
[i
] & 0xf) << 4) | (ix
[i
+ 1] & 0xf);
379 void permute(s16
*out
, s32
*in
, s32 scale
)
381 for (s32 i
= 0; i
< 16; i
++) {
382 out
[i
] = clamp_to_s16(in
[i
] - scale
/ 2 + myrand() % (scale
+ 1));
386 void write_header(FILE *ofile
, const char *id
, s32 size
)
388 fwrite(id
, 4, 1, ofile
);
390 fwrite(&size
, sizeof(s32
), 1, ofile
);
393 int main(int argc
, char **argv
)
397 ALADPCMloop
*aloops
= NULL
;
398 s16 npredictors
= -1;
399 s32
***coefTable
= NULL
;
401 s32 soundPointer
= -1;
406 CommonChunk CommChunk
;
407 InstrumentChunk InstChunk
;
408 SoundDataChunk SndDChunk
;
414 fprintf(stderr
, "%s %s\n", progname
, usage
);
418 infilename
= argv
[1];
420 if ((ifile
= fopen(infilename
, "rb")) == NULL
) {
421 fail_parse("AIFF-C file could not be opened");
425 if ((ofile
= fopen(argv
[2], "wb")) == NULL
) {
426 fprintf(stderr
, "%s: output file could not be opened [%s]\n", progname
, argv
[2]);
430 memset(&InstChunk
, 0, sizeof(InstChunk
));
432 checked_fread(&FormChunk
, sizeof(FormChunk
), 1, ifile
);
433 BSWAP32(FormChunk
.ckID
);
434 BSWAP32(FormChunk
.formType
);
435 if ((FormChunk
.ckID
!= 0x464f524d) || (FormChunk
.formType
!= 0x41494643)) { // FORM, AIFC
436 fail_parse("not an AIFF-C file");
440 s32 num
= fread(&Header
, sizeof(Header
), 1, ifile
);
443 BSWAP32(Header
.ckID
);
444 BSWAP32(Header
.ckSize
);
448 s32 offset
= ftell(ifile
);
450 switch (Header
.ckID
) {
451 case 0x434f4d4d: // COMM
452 checked_fread(&CommChunk
, sizeof(CommChunk
), 1, ifile
);
453 BSWAP16(CommChunk
.numChannels
);
454 BSWAP16(CommChunk
.numFramesH
);
455 BSWAP16(CommChunk
.numFramesL
);
456 BSWAP16(CommChunk
.sampleSize
);
457 BSWAP16(CommChunk
.compressionTypeH
);
458 BSWAP16(CommChunk
.compressionTypeL
);
459 s32 cType
= (CommChunk
.compressionTypeH
<< 16) + CommChunk
.compressionTypeL
;
460 if (cType
!= 0x56415043) { // VAPC
461 fail_parse("file is of the wrong compression type");
463 if (CommChunk
.numChannels
!= 1) {
464 fail_parse("file contains %d channels, only 1 channel supported", CommChunk
.numChannels
);
466 if (CommChunk
.sampleSize
!= 16) {
467 fail_parse("file contains %d bit samples, only 16 bit samples supported", CommChunk
.sampleSize
);
470 nSamples
= (CommChunk
.numFramesH
<< 16) + CommChunk
.numFramesL
;
472 // Allow broken input lengths
477 if (nSamples
% 16 != 0) {
478 fail_parse("number of chunks must be a multiple of 16, found %d", nSamples
);
482 case 0x53534e44: // SSND
483 checked_fread(&SndDChunk
, sizeof(SndDChunk
), 1, ifile
);
484 BSWAP32(SndDChunk
.offset
);
485 BSWAP32(SndDChunk
.blockSize
);
486 assert(SndDChunk
.offset
== 0);
487 assert(SndDChunk
.blockSize
== 0);
488 soundPointer
= ftell(ifile
);
491 case 0x4150504c: // APPL
492 checked_fread(&ts
, sizeof(u32
), 1, ifile
);
494 if (ts
== 0x73746f63) { // stoc
496 checked_fread(&len
, 1, 1, ifile
);
500 checked_fread(ChunkName
, 11, 1, ifile
);
501 ChunkName
[11] = '\0';
502 if (strcmp("VADPCMCODES", ChunkName
) == 0) {
503 checked_fread(&version
, sizeof(s16
), 1, ifile
);
506 fail_parse("Unknown codebook chunk version");
508 readaifccodebook(ifile
, &coefTable
, &order
, &npredictors
);
510 else if (strcmp("VADPCMLOOPS", ChunkName
) == 0) {
511 checked_fread(&version
, sizeof(s16
), 1, ifile
);
514 fail_parse("Unknown loop chunk version");
516 aloops
= readlooppoints(ifile
, &nloops
);
518 fail_parse("Only a single loop supported");
526 fseek(ifile
, offset
+ Header
.ckSize
, SEEK_SET
);
529 if (coefTable
== NULL
) {
530 fail_parse("Codebook missing from bitstream");
533 for (s32 i
= 0; i
< order
; i
++) {
537 u32 outputBytes
= nSamples
* sizeof(s16
);
538 u8
*outputBuf
= malloc(outputBytes
);
540 fseek(ifile
, soundPointer
, SEEK_SET
);
541 while (currPos
< nSamples
) {
549 memcpy(lastState
, state
, sizeof(lastState
));
550 checked_fread(input
, 9, 1, ifile
);
553 my_decodeframe(input
, state
, order
, coefTable
);
554 memcpy(decoded
, state
, sizeof(lastState
));
556 // Create a guess from that, by clamping to 16 bits
557 for (s32 i
= 0; i
< 16; i
++) {
558 origGuess
[i
] = clamp_to_s16(state
[i
]);
562 memcpy(state
, lastState
, sizeof(lastState
));
563 memcpy(guess
, origGuess
, sizeof(guess
));
564 my_encodeframe(encoded
, guess
, state
, coefTable
, order
, npredictors
);
566 // If it doesn't match, randomly round numbers until it does.
567 if (memcmp(input
, encoded
, 9) != 0) {
568 s32 scale
= 1 << (input
[0] >> 4);
570 permute(guess
, decoded
, scale
);
571 memcpy(state
, lastState
, sizeof(lastState
));
572 my_encodeframe(encoded
, guess
, state
, coefTable
, order
, npredictors
);
573 } while (memcmp(input
, encoded
, 9) != 0);
575 // Bring the matching closer to the original decode (not strictly
576 // necessary, but it will move us closer to the target on average).
577 for (s32 failures
= 0; failures
< 50; failures
++) {
578 s32 ind
= myrand() % 16;
579 s32 old
= guess
[ind
];
580 if (old
== origGuess
[ind
]) continue;
581 guess
[ind
] = origGuess
[ind
];
582 if (myrand() % 2) guess
[ind
] += (old
- origGuess
[ind
]) / 2;
583 memcpy(state
, lastState
, sizeof(lastState
));
584 my_encodeframe(encoded
, guess
, state
, coefTable
, order
, npredictors
);
585 if (memcmp(input
, encoded
, 9) == 0) {
594 memcpy(state
, decoded
, sizeof(lastState
));
595 BSWAP16_MANY(guess
, 16);
596 memcpy(outputBuf
+ currPos
* 2, guess
, sizeof(guess
));
600 // Write an incomplete file header. We'll fill in the size later.
601 fwrite("FORM\0\0\0\0AIFF", 12, 1, ofile
);
603 // Subtract 4 from the COMM size to skip the compression field.
604 write_header(ofile
, "COMM", sizeof(CommonChunk
) - 4);
605 CommChunk
.numFramesH
= nSamples
>> 16;
606 CommChunk
.numFramesL
= nSamples
& 0xffff;
607 BSWAP16(CommChunk
.numChannels
);
608 BSWAP16(CommChunk
.numFramesH
);
609 BSWAP16(CommChunk
.numFramesL
);
610 BSWAP16(CommChunk
.sampleSize
);
611 fwrite(&CommChunk
, sizeof(CommonChunk
) - 4, 1, ofile
);
614 s32 startPos
= aloops
[0].start
, endPos
= aloops
[0].end
;
615 const char *markerNames
[2] = {"start", "end"};
616 Marker markers
[2] = {
617 {1, startPos
>> 16, startPos
& 0xffff},
618 {2, endPos
>> 16, endPos
& 0xffff}
620 write_header(ofile
, "MARK", 2 + 2 * sizeof(Marker
) + 1 + 5 + 1 + 3);
621 s16 numMarkers
= bswap16(2);
622 fwrite(&numMarkers
, sizeof(s16
), 1, ofile
);
623 for (s32 i
= 0; i
< 2; i
++) {
624 u8 len
= (u8
) strlen(markerNames
[i
]);
625 BSWAP16(markers
[i
].MarkerID
);
626 BSWAP16(markers
[i
].positionH
);
627 BSWAP16(markers
[i
].positionL
);
628 fwrite(&markers
[i
], sizeof(Marker
), 1, ofile
);
629 fwrite(&len
, 1, 1, ofile
);
630 fwrite(markerNames
[i
], len
, 1, ofile
);
633 write_header(ofile
, "INST", sizeof(InstrumentChunk
));
634 InstChunk
.sustainLoop
.playMode
= bswap16(1);
635 InstChunk
.sustainLoop
.beginLoop
= bswap16(1);
636 InstChunk
.sustainLoop
.endLoop
= bswap16(2);
637 InstChunk
.releaseLoop
.playMode
= 0;
638 InstChunk
.releaseLoop
.beginLoop
= 0;
639 InstChunk
.releaseLoop
.endLoop
= 0;
640 fwrite(&InstChunk
, sizeof(InstrumentChunk
), 1, ofile
);
643 // Save the coefficient table for use when encoding. Ideally this wouldn't
644 // be needed and "tabledesign -s 1" would generate the right table, but in
645 // practice it's difficult to adjust samples to make that happen.
646 write_header(ofile
, "APPL", 4 + 12 + sizeof(CodeChunk
) + npredictors
* order
* 8 * 2);
647 fwrite("stoc", 4, 1, ofile
);
649 cChunk
.version
= bswap16(1);
650 cChunk
.order
= bswap16(order
);
651 cChunk
.nEntries
= bswap16(npredictors
);
652 fwrite("\x0bVADPCMCODES", 12, 1, ofile
);
653 fwrite(&cChunk
, sizeof(CodeChunk
), 1, ofile
);
654 for (s32 i
= 0; i
< npredictors
; i
++) {
655 for (s32 j
= 0; j
< order
; j
++) {
656 for (s32 k
= 0; k
< 8; k
++) {
657 s16 ts
= bswap16(coefTable
[i
][k
][j
]);
658 fwrite(&ts
, sizeof(s16
), 1, ofile
);
663 write_header(ofile
, "SSND", outputBytes
+ 8);
664 SndDChunk
.offset
= 0;
665 SndDChunk
.blockSize
= 0;
666 fwrite(&SndDChunk
, sizeof(SoundDataChunk
), 1, ofile
);
667 fwrite(outputBuf
, outputBytes
, 1, ofile
);
669 // Fix the size in the header
670 s32 fileSize
= bswap32(ftell(ofile
) - 8);
671 fseek(ofile
, 4, SEEK_SET
);
672 fwrite(&fileSize
, 4, 1, ofile
);