#!/usr/bin/env python3 """Dekodiert Argonaut-ASF-Musik (v2.1, 4-Bit-ADPCM) wie asfcodec.adl aus dem Spiel. Nachgebaut aus der Disassembly von asfcodec.adl (Routinen 0x26e01969 / 0x26e01ca1): Filter 0: s = s1 + (n << shift) Filter 1: s = 2*s1 - s2 + (n << shift) (+ Übertrag aus 'adc', s. u.) - kein Clipping; Ausgabe wird als 16 Bit gespeichert (Überlauf = Wrap) - s1 läuft innerhalb eines Blocks ungekürzt im Register weiter, am Blockanfang wird es aus dem 16-Bit-Puffer gelesen - s2 wird immer aus dem 16-Bit-Puffer gelesen Aufruf: asf2wav.py eingabe.asf ausgabe.wav """ import array import struct import sys import wave M32 = 0xFFFFFFFF def s32(x): x &= M32 return x - (1 << 32) if x & 0x80000000 else x def wrap16(x): return ((x + 0x8000) & 0xFFFF) - 0x8000 def decode(data): off = struct.unpack_from('> 4) + 2 prev2, prev1 = mem[c] eax = prev1 # Blockanfang: s1 aus dem Speicher k = o + c for byte in blk: for nib in (byte >> 4, byte & 15): n = nib - 16 if nib & 8 else nib edx = s32((n * 16) << cl) if ctl & 4: ebx = s32(eax << 7) a = s32(-prev2 << 6) carry = ((a & M32) + (edx & M32)) >> 32 eax = s32(a + edx + ebx + carry) >> 6 else: eax = s32((eax << 6) + edx) >> 6 w = wrap16(eax) out[k] = w k += ch prev2, prev1 = prev1, w mem[c] = [prev2, prev1] o += 32 * ch return rate, ch, out if __name__ == '__main__': rate, ch, pcm = decode(open(sys.argv[1], 'rb').read()) with wave.open(sys.argv[2], 'wb') as w: w.setnchannels(ch) w.setsampwidth(2) w.setframerate(rate) w.writeframes(pcm.tobytes())