@@ -98,105 +98,6 @@ def align_audio_to_frame_boundary(audio_data: bytes, pcm_format: AudioFormat) ->
9898 return audio_data
9999
100100
101- async def crossfade_pcm_parts (
102- fade_in_part : bytes ,
103- fade_out_part : bytes ,
104- pcm_format : AudioFormat ,
105- fade_out_pcm_format : AudioFormat | None = None ,
106- ) -> bytes :
107- """Crossfade two chunks of pcm/raw audio using ffmpeg."""
108- if fade_out_pcm_format is None :
109- fade_out_pcm_format = pcm_format
110-
111- # calculate the fade_length from the smallest chunk
112- fade_length = min (
113- len (fade_in_part ) / pcm_format .pcm_sample_size ,
114- len (fade_out_part ) / fade_out_pcm_format .pcm_sample_size ,
115- )
116- # write the fade_out_part to a temporary file
117- fadeout_filename = f"/tmp/{ shortuuid .random (20 )} .pcm" # noqa: S108
118- async with aiofiles .open (fadeout_filename , "wb" ) as outfile :
119- await outfile .write (fade_out_part )
120-
121- args = [
122- # generic args
123- "ffmpeg" ,
124- "-hide_banner" ,
125- "-loglevel" ,
126- "quiet" ,
127- # fadeout part (as file)
128- "-acodec" ,
129- fade_out_pcm_format .content_type .name .lower (),
130- "-ac" ,
131- str (fade_out_pcm_format .channels ),
132- "-ar" ,
133- str (fade_out_pcm_format .sample_rate ),
134- "-channel_layout" ,
135- "mono" if fade_out_pcm_format .channels == 1 else "stereo" ,
136- "-f" ,
137- fade_out_pcm_format .content_type .value ,
138- "-i" ,
139- fadeout_filename ,
140- # fade_in part (stdin)
141- "-acodec" ,
142- pcm_format .content_type .name .lower (),
143- "-ac" ,
144- str (pcm_format .channels ),
145- "-channel_layout" ,
146- "mono" if pcm_format .channels == 1 else "stereo" ,
147- "-ar" ,
148- str (pcm_format .sample_rate ),
149- "-f" ,
150- pcm_format .content_type .value ,
151- "-i" ,
152- "-" ,
153- # filter args
154- "-filter_complex" ,
155- f"[0][1]acrossfade=d={ fade_length } " ,
156- # output args
157- "-acodec" ,
158- pcm_format .content_type .name .lower (),
159- "-ac" ,
160- str (pcm_format .channels ),
161- "-channel_layout" ,
162- "mono" if pcm_format .channels == 1 else "stereo" ,
163- "-ar" ,
164- str (pcm_format .sample_rate ),
165- "-f" ,
166- pcm_format .content_type .value ,
167- "-" ,
168- ]
169- _ , crossfaded_audio , _ = await communicate (args , fade_in_part )
170- await remove_file (fadeout_filename )
171- if crossfaded_audio :
172- LOGGER .log (
173- VERBOSE_LOG_LEVEL ,
174- "crossfaded 2 pcm chunks. fade_in_part: %s - "
175- "fade_out_part: %s - fade_length: %s seconds" ,
176- len (fade_in_part ),
177- len (fade_out_part ),
178- fade_length ,
179- )
180- return crossfaded_audio
181- # no crossfade_data, return original data instead
182- LOGGER .debug (
183- "crossfade of pcm chunks failed: not enough data? - fade_in_part: %s - fade_out_part: %s" ,
184- len (fade_in_part ),
185- len (fade_out_part ),
186- )
187- if fade_out_pcm_format .sample_rate != pcm_format .sample_rate :
188- # Edge case: the sample rates are different,
189- # we need to resample the fade_out part to the same sample rate as the fade_in part
190- async with FFMpeg (
191- audio_input = "-" ,
192- input_format = fade_out_pcm_format ,
193- output_format = pcm_format ,
194- ) as ffmpeg :
195- res = await ffmpeg .communicate (fade_out_part )
196- return res [0 ] + fade_in_part
197- return fade_out_part + fade_in_part
198-
199-
200101async def strip_silence (
201102 mass : MusicAssistant , # noqa: ARG001
202103 audio_data : bytes ,
0 commit comments