sam12345324 commited on
Commit
34decfe
·
verified ·
1 Parent(s): 4f44126

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +100 -58
app.py CHANGED
@@ -26,7 +26,7 @@ def check_port(port):
26
  except socket.error:
27
  return False
28
 
29
- def trim_silence(audio_clip, threshold=0.01):
30
  """
31
  Trim silence from the start and end of an audio clip.
32
  Args:
@@ -35,32 +35,41 @@ def trim_silence(audio_clip, threshold=0.01):
35
  Returns:
36
  Trimmed AudioFileClip
37
  """
38
- # Get audio data as numpy array
39
- samples = audio_clip.to_soundarray(fps=44100)
40
- # Compute amplitude (RMS)
41
- if len(samples.shape) > 1: # Stereo audio
42
- amplitudes = np.sqrt(np.mean(samples**2, axis=1))
43
- else: # Mono audio
44
- amplitudes = np.sqrt(samples**2)
45
-
46
- # Find non-silent regions
47
- non_silent = amplitudes > threshold
48
- if not np.any(non_silent):
49
- logger.warning("Audio clip is completely silent")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
  return audio_clip
51
-
52
- # Find start and end indices
53
- start_idx = np.argmax(non_silent)
54
- end_idx = len(non_silent) - np.argmax(non_silent[::-1])
55
-
56
- # Convert indices to time (seconds)
57
- start_time = start_idx / 44100
58
- end_time = end_idx / 44100
59
-
60
- # Trim the audio
61
- trimmed_audio = audio_clip.subclip(start_time, end_time)
62
- logger.info(f"Trimmed audio from {start_time:.2f}s to {end_time:.2f}s (original duration: {audio_clip.duration:.2f}s)")
63
- return trimmed_audio
64
 
65
  def merge_videos_and_audios(video_files=None, audio_files=None, orig_vol=1.0, music_vol=0.5):
66
  """
@@ -101,17 +110,35 @@ def merge_videos_and_audios(video_files=None, audio_files=None, orig_vol=1.0, mu
101
  audio_clips = []
102
  for audio in audio_files:
103
  clip = AudioFileClip(audio).set_fps(44100) # Normalize sample rate
104
- logger.info(f"Original audio duration for {audio}: {clip.duration:.2f}s")
 
105
  trimmed_clip = trim_silence(clip)
106
- audio_clips.append(trimmed_clip)
 
 
 
 
 
 
 
 
 
 
 
107
 
108
  # Log durations after trimming
109
  for i, clip in enumerate(audio_clips):
110
- logger.info(f"Trimmed audio {i+1} duration: {clip.duration:.2f}s")
111
 
112
  # Concatenate audio clips
 
113
  final_audio_clip = concatenate_audioclips(audio_clips)
114
- logger.info(f"Concatenated audio duration: {final_audio_clip.duration:.2f}s")
 
 
 
 
 
115
 
116
  # Write the final audio
117
  logger.info(f"Writing output audio to {output_path}")
@@ -143,38 +170,52 @@ def merge_videos_and_audios(video_files=None, audio_files=None, orig_vol=1.0, mu
143
  audio_clips = []
144
  for audio in audio_files:
145
  clip = AudioFileClip(audio).set_fps(44100) # Normalize sample rate
146
- logger.info(f"Original audio duration for {audio}: {clip.duration:.2f}s")
 
147
  trimmed_clip = trim_silence(clip)
148
- audio_clips.append(trimmed_clip)
 
 
 
149
 
150
  # Log durations after trimming
151
  for i, clip in enumerate(audio_clips):
152
- logger.info(f"Trimmed audio {i+1} duration: {clip.duration:.2f}s")
153
-
154
- # Concatenate audio clips
155
- concatenated_audio = concatenate_audioclips(audio_clips)
156
- logger.info(f"Concatenated audio duration: {concatenated_audio.duration:.2f}s")
157
 
158
- # Adjust concatenated audio duration to match video duration (trim or loop)
159
- if concatenated_audio.duration > video_duration:
160
- concatenated_audio = concatenated_audio.subclip(0, video_duration)
161
- logger.info(f"Trimmed concatenated audio to match video duration: {concatenated_audio.duration:.2f}s")
162
- elif concatenated_audio.duration < video_duration:
163
- # Loop the audio to match video duration
164
- concatenated_audio = concatenated_audio.fx(lambda clip: clip.loop(duration=video_duration))
165
- logger.info(f"Looped concatenated audio to match video duration: {concatenated_audio.duration:.2f}s")
166
-
167
- # Apply volume to concatenated audio
168
- concatenated_audio = concatenated_audio.volumex(music_vol)
169
-
170
- # Get original video audio (if any) and apply volume
171
- original_audio = final_video_clip.audio.volumex(orig_vol) if final_video_clip.audio else None
172
-
173
- # Composite the audio tracks
174
- if original_audio:
175
- final_audio = CompositeAudioClip([original_audio, concatenated_audio])
176
  else:
177
- final_audio = concatenated_audio
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
178
  else:
179
  logger.info("No audio files provided; using original video audio if available")
180
  # If no audio files provided, retain original video audio (if any)
@@ -191,10 +232,11 @@ def merge_videos_and_audios(video_files=None, audio_files=None, orig_vol=1.0, mu
191
  final_video_clip.close()
192
  for clip in video_clips:
193
  clip.close()
194
- if audio_files:
195
  for clip in audio_clips:
196
  clip.close()
197
- concatenated_audio.close()
 
198
 
199
  logger.info("Video merge completed successfully")
200
  return output_path
 
26
  except socket.error:
27
  return False
28
 
29
+ def trim_silence(audio_clip, threshold=0.005):
30
  """
31
  Trim silence from the start and end of an audio clip.
32
  Args:
 
35
  Returns:
36
  Trimmed AudioFileClip
37
  """
38
+ try:
39
+ # Get audio data as numpy array
40
+ samples = audio_clip.to_soundarray(fps=44100)
41
+ # Compute amplitude (RMS)
42
+ if len(samples.shape) > 1: # Stereo audio
43
+ amplitudes = np.sqrt(np.mean(samples**2, axis=1))
44
+ else: # Mono audio
45
+ amplitudes = np.sqrt(samples**2)
46
+
47
+ # Find non-silent regions
48
+ non_silent = amplitudes > threshold
49
+ if not np.any(non_silent):
50
+ logger.warning("Audio clip is completely silent; returning original clip")
51
+ return audio_clip
52
+
53
+ # Find start and end indices
54
+ start_idx = np.argmax(non_silent)
55
+ end_idx = len(non_silent) - np.argmax(non_silent[::-1])
56
+
57
+ # Convert indices to time (seconds)
58
+ start_time = start_idx / 44100
59
+ end_time = end_idx / 44100
60
+
61
+ # Ensure the trimmed duration is reasonable
62
+ if end_time <= start_time:
63
+ logger.warning("Trimmed duration is zero or negative; returning original clip")
64
+ return audio_clip
65
+
66
+ # Trim the audio
67
+ trimmed_audio = audio_clip.subclip(start_time, end_time)
68
+ logger.info(f"Trimmed audio from {start_time:.2f}s to {end_time:.2f}s (original duration: {audio_clip.duration:.2f}s)")
69
+ return trimmed_audio
70
+ except Exception as e:
71
+ logger.error(f"Error trimming silence: {str(e)}")
72
  return audio_clip
 
 
 
 
 
 
 
 
 
 
 
 
 
73
 
74
  def merge_videos_and_audios(video_files=None, audio_files=None, orig_vol=1.0, music_vol=0.5):
75
  """
 
110
  audio_clips = []
111
  for audio in audio_files:
112
  clip = AudioFileClip(audio).set_fps(44100) # Normalize sample rate
113
+ clip = clip.to_stereo() if clip.nchannels == 1 else clip # Convert mono to stereo
114
+ logger.info(f"Original audio duration for {audio}: {clip.duration:.2f}s, channels: {clip.nchannels}")
115
  trimmed_clip = trim_silence(clip)
116
+ if trimmed_clip.duration > 0:
117
+ audio_clips.append(trimmed_clip)
118
+ else:
119
+ logger.warning(f"Skipping audio file {audio} as it has zero duration after trimming")
120
+
121
+ # Check if we have enough clips to concatenate
122
+ if len(audio_clips) < 2:
123
+ error_msg = "Error: Fewer than 2 audio clips available after trimming (clips may be silent or too short)."
124
+ logger.error(error_msg)
125
+ for clip in audio_clips:
126
+ clip.close()
127
+ return error_msg
128
 
129
  # Log durations after trimming
130
  for i, clip in enumerate(audio_clips):
131
+ logger.info(f"Trimmed audio {i+1} duration: {clip.duration:.2f}s, channels: {clip.nchannels}")
132
 
133
  # Concatenate audio clips
134
+ logger.info(f"Attempting to concatenate {len(audio_clips)} audio clips")
135
  final_audio_clip = concatenate_audioclips(audio_clips)
136
+ logger.info(f"Concatenated audio duration: {final_audio_clip.duration:.2f}s, channels: {final_audio_clip.nchannels}")
137
+
138
+ # Verify concatenated duration
139
+ expected_duration = sum(clip.duration for clip in audio_clips)
140
+ if abs(final_audio_clip.duration - expected_duration) > 0.1:
141
+ logger.warning(f"Concatenated duration ({final_audio_clip.duration:.2f}s) does not match expected duration ({expected_duration:.2f}s)")
142
 
143
  # Write the final audio
144
  logger.info(f"Writing output audio to {output_path}")
 
170
  audio_clips = []
171
  for audio in audio_files:
172
  clip = AudioFileClip(audio).set_fps(44100) # Normalize sample rate
173
+ clip = clip.to_stereo() if clip.nchannels == 1 else clip # Convert mono to stereo
174
+ logger.info(f"Original audio duration for {audio}: {clip.duration:.2f}s, channels: {clip.nchannels}")
175
  trimmed_clip = trim_silence(clip)
176
+ if trimmed_clip.duration > 0:
177
+ audio_clips.append(trimmed_clip)
178
+ else:
179
+ logger.warning(f"Skipping audio file {audio} as it has zero duration after trimming")
180
 
181
  # Log durations after trimming
182
  for i, clip in enumerate(audio_clips):
183
+ logger.info(f"Trimmed audio {i+1} duration: {clip.duration:.2f}s, channels: {clip.nchannels}")
 
 
 
 
184
 
185
+ if not audio_clips:
186
+ logger.warning("No valid audio clips after trimming; using original video audio only")
187
+ final_audio = final_video_clip.audio.volumex(orig_vol) if final_video_clip.audio else None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
188
  else:
189
+ # Concatenate audio clips
190
+ logger.info(f"Attempting to concatenate {len(audio_clips)} audio clips")
191
+ concatenated_audio = concatenate_audioclips(audio_clips)
192
+ logger.info(f"Concatenated audio duration: {concatenated_audio.duration:.2f}s, channels: {concatenated_audio.nchannels}")
193
+
194
+ # Verify concatenated duration
195
+ expected_duration = sum(clip.duration for clip in audio_clips)
196
+ if abs(concatenated_audio.duration - expected_duration) > 0.1:
197
+ logger.warning(f"Concatenated duration ({concatenated_audio.duration:.2f}s) does not match expected duration ({expected_duration:.2f}s)")
198
+
199
+ # Adjust concatenated audio duration to match video duration (trim or loop)
200
+ if concatenated_audio.duration > video_duration:
201
+ concatenated_audio = concatenated_audio.subclip(0, video_duration)
202
+ logger.info(f"Trimmed concatenated audio to match video duration: {concatenated_audio.duration:.2f}s")
203
+ elif concatenated_audio.duration < video_duration:
204
+ # Loop the audio to match video duration
205
+ concatenated_audio = concatenated_audio.fx(lambda clip: clip.loop(duration=video_duration))
206
+ logger.info(f"Looped concatenated audio to match video duration: {concatenated_audio.duration:.2f}s")
207
+
208
+ # Apply volume to concatenated audio
209
+ concatenated_audio = concatenated_audio.volumex(music_vol)
210
+
211
+ # Get original video audio (if any) and apply volume
212
+ original_audio = final_video_clip.audio.volumex(orig_vol) if final_video_clip.audio else None
213
+
214
+ # Composite the audio tracks
215
+ if original_audio:
216
+ final_audio = CompositeAudioClip([original_audio, concatenated_audio])
217
+ else:
218
+ final_audio = concatenated_audio
219
  else:
220
  logger.info("No audio files provided; using original video audio if available")
221
  # If no audio files provided, retain original video audio (if any)
 
232
  final_video_clip.close()
233
  for clip in video_clips:
234
  clip.close()
235
+ if audio_files and audio_clips:
236
  for clip in audio_clips:
237
  clip.close()
238
+ if 'concatenated_audio' in locals():
239
+ concatenated_audio.close()
240
 
241
  logger.info("Video merge completed successfully")
242
  return output_path