File size: 8,480 Bytes
1bb6efc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
"""
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()
        
        # Audio parameters
        self.chunk_size = 1024
        self.sample_rate = 22050
        self.channels = 1
        self.format = pyaudio.paFloat32
        
        # Audio buffer for analysis
        self.audio_buffer = deque(maxlen=int(self.sample_rate * 3))  # 3 seconds buffer
        
        # Control flags
        self.is_recording = False
        self.is_processing = False
        
        # Audio stream
        self.audio = None
        self.stream = None
        
        # Processing queue
        self.audio_queue = queue.Queue()
        
        # Callbacks
        self.on_prediction = None
        self.on_error = None
        
        # Load model
        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:
            # Convert bytes to float32 numpy array
            audio_data = np.frombuffer(in_data, dtype=np.float32)
            
            # Add to buffer
            self.audio_buffer.extend(audio_data)
            
            # Add to processing queue
            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:
            # Initialize PyAudio
            self.audio = pyaudio.PyAudio()
            
            # Create audio stream
            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
            )
            
            # Start recording
            self.is_recording = True
            self.stream.start_stream()
            
            # Start processing thread
            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
        
        # Stop recording
        self.is_recording = False
        self.is_processing = False
        
        # Stop and close stream
        if self.stream:
            self.stream.stop_stream()
            self.stream.close()
        
        # Terminate PyAudio
        if self.audio:
            self.audio.terminate()
        
        # Clear buffer
        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  # Analyze every 2 seconds
        
        while self.is_processing:
            try:
                current_time = time.time()
                
                # Check if it's time for analysis
                if current_time - last_analysis_time >= analysis_interval:
                    if len(self.audio_buffer) >= self.sample_rate * 2:  # At least 2 seconds of audio
                        # Get recent audio data
                        recent_audio = np.array(list(self.audio_buffer)[-int(self.sample_rate * 3):])
                        
                        # Analyze
                        prediction, confidence = self._analyze_audio_chunk(recent_audio)
                        
                        if prediction and confidence > 0.6:  # Only report high-confidence predictions
                            if self.on_prediction:
                                self.on_prediction(prediction, confidence)
                        
                        last_analysis_time = current_time
                
                # Small sleep to prevent excessive CPU usage
                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
            
            # Extract features
            features = self.audio_processor.extract_features_from_array(audio_data, self.sample_rate)
            
            if features is None:
                return None, None
            
            # Make prediction
            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
        
        # Get RMS of recent audio
        recent_audio = np.array(list(self.audio_buffer)[-1024:])  # Last 1024 samples
        rms = np.sqrt(np.mean(recent_audio**2))
        
        return min(rms * 100, 100.0)  # Scale to 0-100
    
    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)
        }

# Example usage and testing
if __name__ == "__main__":
    print("🎤 Real-time Cry Detector Test")
    print("=" * 40)
    
    # Initialize detector
    detector = RealTimeCryDetector()
    
    if not detector.is_ready():
        print("❌ Model not ready. Please train the model first.")
        exit(1)
    
    # Set up callbacks
    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:
        # Start recording
        if detector.start_recording():
            print("🎤 Recording started. Speak into your microphone...")
            print("Press Ctrl+C to stop")
            
            # Keep running
            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()