Files
wedding-phone/resample_audio.py
grabowski 73ca1e6935 Fix file path bug in resample_audio.py
Changed from os.rename() to shutil.copy2() when creating backups.
This prevents the "No such file or directory" error that occurred
when trying to write the resampled file after the original was renamed.

Now the script:
- Copies original to .backup (instead of renaming)
- Reads from .backup file
- Writes resampled audio to original filename

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-27 13:09:09 +07:00

157 lines
5.0 KiB
Python

#!/usr/bin/env python3
"""
Audio Resampling Utility for Wedding Phone
Resamples all WAV files in sounds directory to match configured sample rate
"""
import wave
import numpy as np
import os
import json
import shutil
from scipy import signal
def load_config():
"""Load sample rate from config.json"""
config_path = 'config.json'
if not os.path.exists(config_path):
print("config.json not found, using 48000Hz as default")
return 48000
with open(config_path, 'r') as f:
config = json.load(f)
return config['audio']['sample_rate']
def resample_wav(input_file, output_file, target_rate):
"""Resample a WAV file to target sample rate"""
try:
# Open source file
with wave.open(input_file, 'rb') as wf:
n_channels = wf.getnchannels()
sampwidth = wf.getsampwidth()
source_rate = wf.getframerate()
n_frames = wf.getnframes()
# Read audio data
audio_data = wf.readframes(n_frames)
# Convert to numpy array
if sampwidth == 1:
dtype = np.uint8
elif sampwidth == 2:
dtype = np.int16
elif sampwidth == 4:
dtype = np.int32
else:
print(f"Unsupported sample width: {sampwidth}")
return False
audio_array = np.frombuffer(audio_data, dtype=dtype)
# Handle stereo
if n_channels == 2:
audio_array = audio_array.reshape(-1, 2)
# Resample
if source_rate != target_rate:
print(f" Resampling from {source_rate}Hz to {target_rate}Hz...")
num_samples = int(len(audio_array) * target_rate / source_rate)
if n_channels == 1:
resampled = signal.resample(audio_array, num_samples)
else:
# Resample each channel separately
left = signal.resample(audio_array[:, 0], num_samples)
right = signal.resample(audio_array[:, 1], num_samples)
resampled = np.column_stack((left, right))
# Convert back to original dtype
resampled = np.clip(resampled, np.iinfo(dtype).min, np.iinfo(dtype).max)
audio_array = resampled.astype(dtype)
# Write output file
with wave.open(output_file, 'wb') as wf_out:
wf_out.setnchannels(n_channels)
wf_out.setsampwidth(sampwidth)
wf_out.setframerate(target_rate)
wf_out.writeframes(audio_array.tobytes())
return True
except Exception as e:
print(f" Error: {e}")
return False
def main():
"""Main resampling function"""
print("Wedding Phone Audio Resampler")
print("=" * 50)
# Load target sample rate
target_rate = load_config()
print(f"\nTarget sample rate: {target_rate}Hz")
# Check sounds directory
sounds_dir = './rotary_phone_data/sounds'
if not os.path.exists(sounds_dir):
print(f"\nSounds directory not found: {sounds_dir}")
return
# Get all WAV files
wav_files = [f for f in os.listdir(sounds_dir) if f.endswith('.wav')]
if not wav_files:
print("\nNo WAV files found in sounds directory")
return
print(f"\nFound {len(wav_files)} WAV file(s)")
print("-" * 50)
# Process each file
for filename in wav_files:
input_path = os.path.join(sounds_dir, filename)
print(f"\nProcessing: {filename}")
# Check current sample rate
try:
with wave.open(input_path, 'rb') as wf:
current_rate = wf.getframerate()
print(f" Current rate: {current_rate}Hz")
if current_rate == target_rate:
print(f" ✓ Already at {target_rate}Hz, skipping")
continue
except Exception as e:
print(f" Error reading file: {e}")
continue
# Create backup
backup_path = input_path + '.backup'
source_path = input_path
if not os.path.exists(backup_path):
# Copy to backup instead of rename, so original still exists
shutil.copy2(input_path, backup_path)
print(f" Backup created: {filename}.backup")
source_path = backup_path
else:
print(f" Using existing backup")
source_path = backup_path
# Resample
output_path = os.path.join(sounds_dir, filename)
if resample_wav(source_path, output_path, target_rate):
print(f" ✓ Successfully resampled to {target_rate}Hz")
else:
print(f" ✗ Failed to resample, restoring backup")
if os.path.exists(backup_path):
os.rename(backup_path, output_path)
print("\n" + "=" * 50)
print("Resampling complete!")
print("\nBackup files (.backup) have been created.")
print("If everything works, you can delete them.")
if __name__ == "__main__":
main()