| """ |
| Baby Cry AI - Real-time Audio Processing |
| Step 5: Implement real-time audio capture and processing |
| """ |
|
|
| import pyaudio |
| import numpy as np |
| import threading |
| import queue |
| import time |
| from collections import deque |
| import warnings |
| warnings.filterwarnings('ignore') |
|
|
| from models.baseline_model import BaselineModel |
| from audio_processor import AudioProcessor |
|
|
| class RealTimeCryDetector: |
| def __init__(self, model_path="models/baseline_model.pkl"): |
| self.model = BaselineModel(model_path) |
| self.audio_processor = AudioProcessor() |
| |
| |
| self.chunk_size = 1024 |
| self.sample_rate = 22050 |
| self.channels = 1 |
| self.format = pyaudio.paFloat32 |
| |
| |
| self.audio_buffer = deque(maxlen=int(self.sample_rate * 3)) |
| |
| |
| self.is_recording = False |
| self.is_processing = False |
| |
| |
| self.audio = None |
| self.stream = None |
| |
| |
| self.audio_queue = queue.Queue() |
| |
| |
| self.on_prediction = None |
| self.on_error = None |
| |
| |
| if not self.model.load_model(): |
| print("⚠️ Warning: No trained model found. Real-time analysis will not work.") |
| |
| def audio_callback(self, in_data, frame_count, time_info, status): |
| """Callback function for audio input""" |
| if self.is_recording: |
| |
| audio_data = np.frombuffer(in_data, dtype=np.float32) |
| |
| |
| self.audio_buffer.extend(audio_data) |
| |
| |
| self.audio_queue.put(audio_data) |
| |
| return (None, pyaudio.paContinue) |
| |
| def start_recording(self): |
| """Start real-time audio recording""" |
| if self.is_recording: |
| print("⚠️ Already recording") |
| return False |
| |
| try: |
| |
| self.audio = pyaudio.PyAudio() |
| |
| |
| self.stream = self.audio.open( |
| format=self.format, |
| channels=self.channels, |
| rate=self.sample_rate, |
| input=True, |
| frames_per_buffer=self.chunk_size, |
| stream_callback=self.audio_callback |
| ) |
| |
| |
| self.is_recording = True |
| self.stream.start_stream() |
| |
| |
| self.is_processing = True |
| self.processing_thread = threading.Thread(target=self._process_audio_continuously, daemon=True) |
| self.processing_thread.start() |
| |
| print("🎤 Real-time recording started") |
| return True |
| |
| except Exception as e: |
| print(f"❌ Error starting recording: {e}") |
| if self.on_error: |
| self.on_error(str(e)) |
| return False |
| |
| def stop_recording(self): |
| """Stop real-time audio recording""" |
| if not self.is_recording: |
| print("⚠️ Not currently recording") |
| return |
| |
| |
| self.is_recording = False |
| self.is_processing = False |
| |
| |
| if self.stream: |
| self.stream.stop_stream() |
| self.stream.close() |
| |
| |
| if self.audio: |
| self.audio.terminate() |
| |
| |
| self.audio_buffer.clear() |
| |
| print("⏹️ Real-time recording stopped") |
| |
| def _process_audio_continuously(self): |
| """Continuously process audio chunks""" |
| last_analysis_time = 0 |
| analysis_interval = 2.0 |
| |
| while self.is_processing: |
| try: |
| current_time = time.time() |
| |
| |
| if current_time - last_analysis_time >= analysis_interval: |
| if len(self.audio_buffer) >= self.sample_rate * 2: |
| |
| recent_audio = np.array(list(self.audio_buffer)[-int(self.sample_rate * 3):]) |
| |
| |
| prediction, confidence = self._analyze_audio_chunk(recent_audio) |
| |
| if prediction and confidence > 0.6: |
| if self.on_prediction: |
| self.on_prediction(prediction, confidence) |
| |
| last_analysis_time = current_time |
| |
| |
| time.sleep(0.1) |
| |
| except Exception as e: |
| print(f"❌ Error in audio processing: {e}") |
| if self.on_error: |
| self.on_error(str(e)) |
| break |
| |
| def _analyze_audio_chunk(self, audio_data): |
| """Analyze a chunk of audio data""" |
| try: |
| if not self.model.is_trained: |
| return None, None |
| |
| |
| features = self.audio_processor.extract_features_from_array(audio_data, self.sample_rate) |
| |
| if features is None: |
| return None, None |
| |
| |
| prediction, confidence = self.model.predict(features) |
| |
| return prediction, confidence |
| |
| except Exception as e: |
| print(f"❌ Error analyzing audio chunk: {e}") |
| return None, None |
| |
| def get_current_audio_level(self): |
| """Get current audio level (for visualization)""" |
| if not self.audio_buffer: |
| return 0.0 |
| |
| |
| recent_audio = np.array(list(self.audio_buffer)[-1024:]) |
| rms = np.sqrt(np.mean(recent_audio**2)) |
| |
| return min(rms * 100, 100.0) |
| |
| def set_prediction_callback(self, callback): |
| """Set callback function for predictions""" |
| self.on_prediction = callback |
| |
| def set_error_callback(self, callback): |
| """Set callback function for errors""" |
| self.on_error = callback |
| |
| def is_ready(self): |
| """Check if the detector is ready for real-time analysis""" |
| return self.model.is_trained |
| |
| def get_status(self): |
| """Get current status""" |
| return { |
| 'recording': self.is_recording, |
| 'processing': self.is_processing, |
| 'model_ready': self.model.is_trained, |
| 'audio_level': self.get_current_audio_level(), |
| 'buffer_size': len(self.audio_buffer) |
| } |
|
|
| |
| if __name__ == "__main__": |
| print("🎤 Real-time Cry Detector Test") |
| print("=" * 40) |
| |
| |
| detector = RealTimeCryDetector() |
| |
| if not detector.is_ready(): |
| print("❌ Model not ready. Please train the model first.") |
| exit(1) |
| |
| |
| def on_prediction(prediction, confidence): |
| print(f"🔍 Prediction: {prediction} (Confidence: {confidence:.2f})") |
| |
| def on_error(error): |
| print(f"❌ Error: {error}") |
| |
| detector.set_prediction_callback(on_prediction) |
| detector.set_error_callback(on_error) |
| |
| try: |
| |
| if detector.start_recording(): |
| print("🎤 Recording started. Speak into your microphone...") |
| print("Press Ctrl+C to stop") |
| |
| |
| while True: |
| status = detector.get_status() |
| print(f"\r📊 Status: Recording={status['recording']}, Level={status['audio_level']:.1f}%", end="") |
| time.sleep(0.5) |
| |
| except KeyboardInterrupt: |
| print("\n⏹️ Stopping recording...") |
| detector.stop_recording() |
| print("✅ Recording stopped") |
| |
| except Exception as e: |
| print(f"❌ Error: {e}") |
| detector.stop_recording() |
|
|