LyndonCatan/audio-forensic-app
1
1# ================================2# Audio Forensic Analysis Script3# ================================4 5import librosa6import librosa.display7import matplotlib8import matplotlib.pyplot as plt9import numpy as np10from scipy.signal import find_peaks11import json12import sys13import base6414import io15from scipy.io import wavfile16import tempfile17import os18 19# Set matplotlib to use Agg backend for server environments20matplotlib.use('Agg')21 22def analyze_audio(audio_data_base64, filename="uploaded_audio"):23 """24 Analyze audio data and return comprehensive forensic analysis results25 """26 try:27 # Decode base64 audio data28 audio_bytes = base64.b64decode(audio_data_base64)29 30 # Create temporary file31 with tempfile.NamedTemporaryFile(delete=False, suffix='.wav') as temp_file:32 temp_file.write(audio_bytes)33 temp_path = temp_file.name34 35 # Load audio with librosa36 y, sr = librosa.load(temp_path, sr=None)37 38 print(f"โ
Audio loaded: {filename}")39 print(f"Sample Rate: {sr} Hz")40 print(f"Duration: {librosa.get_duration(y=y, sr=sr):.2f} seconds")41 42 # ================================43 # STFT - Short-Time Fourier Transform44 # ================================45 stft_result = librosa.stft(y)46 stft_db = librosa.amplitude_to_db(np.abs(stft_result), ref=np.max)47 48 # ================================49 # FFT - Fast Fourier Transform50 # ================================51 fft_result = np.fft.fft(y)52 magnitude = np.abs(fft_result)53 frequency = np.linspace(0, sr, len(magnitude))54 55 # ================================56 # Detect Sound Events57 # ================================58 frame_length = 102459 hop_length = 51260 energy = np.array([61 sum(abs(y[i:i+frame_length]**2))62 for i in range(0, len(y), hop_length)63 ])64 65 # Normalize energy66 energy = energy / np.max(energy) if np.max(energy) > 0 else energy67 68 # Find peaks (sound events)69 peaks, properties = find_peaks(energy, height=0.2, distance=5)70 num_sounds = len(peaks)71 72 # ================================73 # Advanced Analysis74 # ================================75 duration = librosa.get_duration(y=y, sr=sr)76 rms = np.mean(librosa.feature.rms(y=y))77 78 # Spectral features79 spectral_centroids = librosa.feature.spectral_centroid(y=y, sr=sr)[0]80 dominant_frequency = np.mean(spectral_centroids)81 82 # Convert to decibels83 max_decibels = 20 * np.log10(np.max(np.abs(y))) if np.max(np.abs(y)) > 0 else -np.inf84 85 # Detect different types of sounds based on frequency characteristics86 sound_events = []87 for i, peak in enumerate(peaks):88 time_pos = (peak * hop_length) / sr89 freq_at_peak = spectral_centroids[min(peak, len(spectral_centroids)-1)]90 amplitude = energy[peak]91 92 # Classify sound type based on frequency93 if freq_at_peak < 300:94 sound_type = "Low Frequency/Bass"95 elif freq_at_peak < 1000:96 sound_type = "Voice/Mid Range"97 elif freq_at_peak < 4000:98 sound_type = "High Voice/Instruments"99 else:100 sound_type = "High Frequency/Noise"101 102 sound_events.append({103 "time": round(time_pos, 2),104 "frequency": round(freq_at_peak, 1),105 "amplitude": round(amplitude, 3),106 "type": sound_type,107 "decibels": round(20 * np.log10(amplitude) if amplitude > 0 else -np.inf, 1)108 })109 110 # Sort by amplitude (loudest first)111 sound_events.sort(key=lambda x: x["amplitude"], reverse=True)112 113 # Create frequency spectrum data114 freq_spectrum = []115 freq_step = len(frequency) // 100 # Sample 100 points116 for i in range(0, len(frequency)//2, freq_step):117 if i < len(magnitude):118 freq_spectrum.append({119 "frequency": round(frequency[i], 1),120 "magnitude": round(magnitude[i] / np.max(magnitude), 3) if np.max(magnitude) > 0 else 0121 })122 123 # ================================124 # Generate Analysis Report125 # ================================126 analysis_results = {127 "filename": filename,128 "duration": round(duration, 2),129 "sampleRate": int(sr),130 "averageRMS": round(float(rms), 6),131 "detectedSounds": num_sounds,132 "dominantFrequency": round(float(dominant_frequency), 1),133 "maxDecibels": round(float(max_decibels), 1),134 "soundEvents": sound_events[:10], # Top 10 events135 "frequencySpectrum": freq_spectrum,136 "analysisComplete": True,137 "timestamp": "2024-01-01T00:00:00Z"138 }139 140 print("\n๐ Audio Analysis Report")141 print(f"๐ File Name: {filename}")142 print(f"โฑ Duration: {duration:.2f} seconds")143 print(f"๐ Sample Rate: {sr} Hz")144 print(f"๐ Average RMS Energy: {rms:.6f}")145 print(f"๐ Detected Sound Events: {num_sounds}")146 print(f"๐ต Dominant Frequency: {dominant_frequency:.1f} Hz")147 print(f"๐ข Max Decibels: {max_decibels:.1f} dB")148 149 print("\n๐ฏ Top Sound Events:")150 for i, event in enumerate(sound_events[:5]):151 print(f"{i+1}. {event['type']} at {event['time']}s - {event['frequency']:.1f}Hz ({event['decibels']:.1f}dB)")152 153 # Clean up temporary file154 os.unlink(temp_path)155 156 return json.dumps(analysis_results, indent=2)157 158 except Exception as e:159 error_result = {160 "error": str(e),161 "analysisComplete": False,162 "message": "Audio analysis failed"163 }164 print(f"โ Analysis Error: {str(e)}")165 return json.dumps(error_result, indent=2)166 167if __name__ == "__main__":168 # Example usage - in real implementation, this would receive base64 data169 print("๐ต Audio Forensic Analysis System Ready")170 print("Waiting for audio data...")171 172 # This script can be called with audio data as argument173 if len(sys.argv) > 1:174 audio_data = sys.argv[1]175 filename = sys.argv[2] if len(sys.argv) > 2 else "uploaded_audio"176 result = analyze_audio(audio_data, filename)177 print(result)178 else:179 print("No audio data provided. Script ready for integration.")180 