Conversion to WEM format requires Audiokinetic Wwise:
# audio_converter.py:196-233def wav_to_wem(wav_file, output_file=None, wwise_dir=None): if not wwise_console.is_installed(): raise RuntimeError( "Wwise is not installed. " "Please install Wwise from the Settings page." ) # Uses WwiseConsole.exe with pre-configured project result_wem = wwise.convert_to_wem(wav_file, output_dir) return result_wem
# wwise_wrapper.py:250-323def batch_convert_to_wem(wav_files, output_dir): # Group files by parent directory for efficient processing wav_dir = wav_files[0].parent if all(f.parent == wav_dir for f in wav_files): # Single .wsources file with all WAVs wsources = create_wsources_file(wav_files, wav_dir, output_dir) convert_batch(wsources, output_dir) else: # Fall back to individual conversion for wav in wav_files: convert_to_wem(wav, output_dir)
Batch conversion is 10-50x faster than individual conversions due to reduced Wwise startup overhead.
# pck_packer.py:226-237wem_files = list(Path(bnk_wems_dir).glob('*.wem'))for wem_file in wem_files: wem_id = int(wem_file.stem) # Get ID from filename bnk.replace_wem(wem_id, wem_path=wem_file)
3
Recalculate BNK Structure
# bnk_handler.py:219-236def _correct_offsets(self): # Calculate DATA section start position self.data['DATA'].start_pos = ( 8 + len(self.data['BKHD']) + # BKHD chunk 8 + len(self.data['DIDX']) + # DIDX chunk 8 # DATA header ) # Rebuild DATA with alignment new_wem_offsets = self.data['DATA'].setdata() # Update DIDX with new offsets self.data['DIDX'].setdata(new_wem_offsets)
4
Insert Modified BNK into PCK
# pck_packer.py:243-252modified_bnk_bytes = bnk.get_bytes()# Store in memory for packingtemp_bnk = BytesIO(modified_bnk_bytes)file_index = len(self.file_list)self.file_list.append(temp_bnk)# Update PCK file tableself.soundbank_titles[lang_id][bnk_id] = [ (file_index, len(modified_bnk_bytes), 0)]
Example:
packer = PCKPacker('SoundBank_SFX_1.pck', 'SoundBank_SFX_1_mod.pck')packer.load_original_pck()# Replace multiple WEMs in a BNKpacker.replace_bnk_wems( bnk_id=2882561007, bnk_wems_dir='./2882561007_bnk/', # Directory with WEM files lang_id=1 # English)packer.pack()
# pck_packer.py:292-383def pack_with_patching(self): # Copy original PCK shutil.copy2(original_pck, output_pck) # Open in read-write mode with open(output_pck, 'r+b') as f: for patch in patches: # Look up original file offset original_offset = index[patch['file_id']]['offset'] original_size = index[patch['file_id']]['size'] new_size = patch['new_size'] # Seek and write f.seek(original_offset) if new_size <= original_size: f.write(new_data) if new_size < original_size: # Pad with zeros f.write(b'\x00' * (original_size - new_size)) else: # Truncate if larger f.write(new_data[:original_size])
Patching limitations:
Cannot handle files larger than originals (will truncate)
ZZAR uses file handles instead of loading entire files:
# pck_packer.py:42, 516-522self.file_list = [] # Store file handles, not contents# When writing:for file_index, size, offset in write_info: file_obj = self.file_list[file_index] file_obj.seek(offset) data = file_obj.read(size) # Read only what we need f.write(data)
Benefits:
Can process multi-GB PCK files
Constant memory usage
Faster for large files
Batch Processing
Batch conversion reduces Wwise startup overhead:
# Single conversion: ~3 seconds per filefor wav in wav_files: convert_to_wem(wav) # 100 files = 300 seconds# Batch conversion: ~5 seconds for all filesconvert_batch(wav_files) # 100 files = 5 seconds
Speedup: 60x faster for 100 files
Patching vs Rebuild
Operation
Patching
Rebuild
Replace 1 file
0.1s
5s
Replace 10 files
0.5s
5s
Replace 100 files
2s
8s
Handles size changes
❌
✅
Use patching for simple replacements, rebuild for BNK modifications.
Warning:ID 134133939 is larger than originalCause: Replacement audio is longer or higher quality than originalSolution:
# Option 1: Use rebuild modepacker.pack(use_patching=False)# Option 2: Trim audio to match original lengthffmpeg -i input.mp3 -t 5.2 -c:a copy output.mp3 # Trim to 5.2 seconds
BNK WEM Not Found
Error:KeyError: WEM ID 134133939 not found in BNKCause: Wrong WEM ID or wrong BNK fileSolution:
# List all WEMs in BNKfrom bnk_handler import BNKFilebnk = BNKFile('original.bnk')print("Available WEM IDs:", bnk.list_wems())# Extract BNK from PCK firstfrom pck_extractor import PCKExtractorextractor = PCKExtractor('SoundBank_SFX_1.pck')extractor.extract_all('./extracted/', extract_bnk=True)