22
33import concurrent .futures
44import logging
5- from typing import Any , Optional , Tuple , List
5+ from typing import Any , Optional
66
77import numpy as np
88
99from binaural_generator .core .data_types import AudioStep , NoiseConfig
1010from binaural_generator .core .exceptions import AudioGenerationError , ConfigurationError
1111from binaural_generator .core .noise import NoiseFactory , NoiseStrategy
1212from binaural_generator .core .tone_generator import (
13- mix_beats_and_noise , # Import the public mixer
1413 _process_beat_step ,
1514 config_step_to_audio_step ,
1615 generate_tone ,
16+ mix_beats_and_noise ,
1717)
1818
1919logger = logging .getLogger (__name__ )
@@ -27,7 +27,7 @@ def generate_step_in_parallel(
2727 previous_freq : Optional [float ],
2828 * ,
2929 title : str = "Binaural Beat" ,
30- ) -> Tuple [int , np .ndarray , np .ndarray , float , float ]:
30+ ) -> tuple [int , np .ndarray , np .ndarray , float , float ]:
3131 """Generate audio for a single step, to be used in parallel processing.
3232
3333 This function adapts _process_beat_step for concurrent execution.
@@ -97,7 +97,7 @@ def _submit_tone_generation_tasks(
9797 base_freq : float ,
9898 * ,
9999 title : str = "Binaural Beat" ,
100- ) -> list [Tuple [int , concurrent .futures .Future , float , float ]]:
100+ ) -> list [tuple [int , concurrent .futures .Future , float , float ]]:
101101 """Submit tone generation tasks to the thread pool."""
102102 futures_context = []
103103 for idx , audio_step in enumerate (audio_steps , start = 1 ):
@@ -111,7 +111,7 @@ def _submit_noise_task(
111111 executor : concurrent .futures .ThreadPoolExecutor ,
112112 noise_config : NoiseConfig ,
113113 total_num_samples : int ,
114- ) -> Optional [Tuple [concurrent .futures .Future , NoiseStrategy ]]:
114+ ) -> Optional [tuple [concurrent .futures .Future , NoiseStrategy ]]:
115115 """Submits the noise generation task if needed."""
116116 if (
117117 noise_config .type == "none"
@@ -137,9 +137,9 @@ def _submit_noise_task(
137137
138138def _collect_beat_results (
139139 beat_futures_with_context : list [
140- Tuple [int , concurrent .futures .Future , float , float ]
140+ tuple [int , concurrent .futures .Future , float , float ]
141141 ],
142- ) -> list [Tuple [int , np .ndarray , np .ndarray , float , float ]]:
142+ ) -> list [tuple [int , np .ndarray , np .ndarray , float , float ]]:
143143 """Collect results from beat futures, wait for completion, sort by index."""
144144 results = []
145145 future_to_context = {
@@ -162,7 +162,7 @@ def _collect_beat_results(
162162
163163
164164def _collect_noise_result (
165- noise_task : Optional [Tuple [concurrent .futures .Future , NoiseStrategy ]],
165+ noise_task : Optional [tuple [concurrent .futures .Future , NoiseStrategy ]],
166166 noise_config : NoiseConfig ,
167167) -> Optional [np .ndarray ]:
168168 """Waits for and collects the noise generation result if the task was submitted."""
@@ -184,7 +184,7 @@ def _collect_noise_result(
184184
185185
186186def _combine_audio_segments (
187- step_results : list [Tuple [int , np .ndarray , np .ndarray , float , float ]],
187+ step_results : list [tuple [int , np .ndarray , np .ndarray , float , float ]],
188188) -> tuple [np .ndarray , np .ndarray , float ]:
189189 """Combine audio segments into continuous channels."""
190190 if not step_results :
@@ -207,18 +207,17 @@ def _combine_audio_segments(
207207 return left_channel , right_channel , total_duration
208208
209209
210- # Removed _mix_noise_if_present as mix_beats_and_noise is now imported and used directly
211-
212210def _execute_parallel_tasks (
213211 audio_steps : list [AudioStep ],
214212 noise_config : NoiseConfig ,
215213 sample_rate : int ,
216214 base_freq : float ,
217215 total_num_samples : int ,
218- title : str ,
219- max_workers : Optional [int ],
220- ) -> Tuple [
221- List [Tuple [int , np .ndarray , np .ndarray , float , float ]], Optional [np .ndarray ]
216+ * ,
217+ title : str = "Binaural Beat" ,
218+ max_workers : Optional [int ] = None ,
219+ ) -> tuple [
220+ list [tuple [int , np .ndarray , np .ndarray , float , float ]], Optional [np .ndarray ]
222221]:
223222 """Executes beat and noise generation tasks in parallel using a thread pool."""
224223 logger .info ("Starting parallel generation of beats and noise..." )
@@ -243,16 +242,11 @@ def generate_audio_sequence_parallel(
243242 * ,
244243 title : str = "Binaural Beat" ,
245244 max_workers : Optional [int ] = None ,
246- ) -> Tuple [np .ndarray , np .ndarray , float ]:
245+ ) -> tuple [np .ndarray , np .ndarray , float ]:
247246 """Generates the complete stereo audio sequence in parallel, including noise."""
248- logger .info ("Preparing audio steps for parallel generation..." )
249- audio_steps = prepare_audio_steps (steps )
250-
251- total_duration = sum (step .duration for step in audio_steps )
252- total_num_samples = int (sample_rate * total_duration )
253- logger .debug (
254- "Total duration: %.2f s, Total samples: %d" , total_duration , total_num_samples
255- )
247+ # Prepare audio steps and calculate duration
248+ duration_info = _prepare_and_calculate_duration (steps , sample_rate )
249+ audio_steps , total_duration , total_num_samples = duration_info
256250
257251 # Execute tasks in parallel
258252 step_results , noise_signal = _execute_parallel_tasks (
@@ -261,11 +255,63 @@ def generate_audio_sequence_parallel(
261255 sample_rate ,
262256 base_freq ,
263257 total_num_samples ,
264- title ,
265- max_workers ,
258+ title = title ,
259+ max_workers = max_workers ,
260+ )
261+
262+ # Process audio segments
263+ left_final , right_final = _process_audio_segments (
264+ step_results , noise_signal , noise_config , total_duration
266265 )
267266
268- # Combine and Mix Sequentially
267+ return left_final , right_final , total_duration
268+
269+
270+ def _prepare_and_calculate_duration (
271+ steps : list [dict [str , Any ]], sample_rate : int
272+ ) -> tuple [list [AudioStep ], float , int ]:
273+ """Prepare audio steps and calculate total duration.
274+
275+ Args:
276+ steps: List of step configuration dictionaries
277+ sample_rate: Audio sample rate in Hz
278+
279+ Returns:
280+ tuple containing:
281+ - List of prepared AudioStep objects
282+ - Total duration in seconds
283+ - Total number of samples
284+ """
285+ logger .info ("Preparing audio steps for parallel generation..." )
286+ audio_steps = prepare_audio_steps (steps )
287+
288+ total_duration = sum (step .duration for step in audio_steps )
289+ total_num_samples = int (sample_rate * total_duration )
290+ logger .debug (
291+ "Total duration: %.2f s, Total samples: %d" , total_duration , total_num_samples
292+ )
293+
294+ return audio_steps , total_duration , total_num_samples
295+
296+
297+ def _process_audio_segments (
298+ step_results : list [tuple [int , np .ndarray , np .ndarray , float , float ]],
299+ noise_signal : Optional [np .ndarray ],
300+ noise_config : NoiseConfig ,
301+ total_duration : float ,
302+ ) -> tuple [np .ndarray , np .ndarray ]:
303+ """Process audio segments by combining and mixing with noise if needed.
304+
305+ Args:
306+ step_results: List of step result tuples
307+ noise_signal: Optional noise signal to mix
308+ noise_config: Noise configuration parameters
309+ total_duration: Total duration in seconds (for validation)
310+
311+ Returns:
312+ tuple of left and right channel arrays
313+ """
314+ # Combine beat segments
269315 left_beats , right_beats , combined_duration = _combine_audio_segments (step_results )
270316
271317 # Verify combined duration (logging only)
@@ -276,6 +322,27 @@ def generate_audio_sequence_parallel(
276322 combined_duration ,
277323 )
278324
325+ # Apply final processing
326+ return _apply_final_processing (left_beats , right_beats , noise_signal , noise_config )
327+
328+
329+ def _apply_final_processing (
330+ left_beats : np .ndarray ,
331+ right_beats : np .ndarray ,
332+ noise_signal : Optional [np .ndarray ],
333+ noise_config : NoiseConfig ,
334+ ) -> tuple [np .ndarray , np .ndarray ]:
335+ """Apply final processing steps to the audio channels.
336+
337+ Args:
338+ left_beats: Left channel beat data
339+ right_beats: Right channel beat data
340+ noise_signal: Optional noise signal to mix
341+ noise_config: Noise configuration
342+
343+ Returns:
344+ tuple of final left and right channels
345+ """
279346 # Mix noise if applicable
280347 if noise_signal is not None and noise_config .amplitude > 0 :
281348 logger .info ("Mixing '%s' noise with beat segments..." , noise_config .type )
@@ -293,4 +360,4 @@ def generate_audio_sequence_parallel(
293360 left_final = left_final .astype (np .float64 )
294361 right_final = right_final .astype (np .float64 )
295362
296- return left_final , right_final , total_duration # Use initial total_duration
363+ return left_final , right_final
0 commit comments