2

I have two pieces of audio: (1) 15 heartbeat clips and (2) 15 frequency noises. The frequency noises are only 1 second and shorter in duration than the heartbeat clips (generated on-the-fly, variable length).

I'm able to successfully play both pieces through different speakers but only in series (one at a time), not in parallel (together). I'm doing this through sounddevice as follows:

import sounddevice as sd
import sound file as sf

for i, clip in enumerate(user_heartbeats):
      clip.export("temp.wav", format="wav")
      audio_data, sample_rate = sf.read("temp.wav", dtype='float32')
      sd.play(audio_data, sample_rate, device=heartbeat_speaker_id)
      sd.wait()

      t = np.linspace(0.0, freq_duration_sec, int(freq_duration_sec * sampling_freq), endpoint=False)
      waveform = (volume) * np.sin(2.0 * np.pi * frequencies_to_play[i] * t)
      sd.play(waveform, sampling_freq, device=frequency_speaker_id)
      sd.wait()

I looked into the threading library to play both simultaneously but I'm not able to get the intended result:

def play_audio_pairing(audio, delay, device):
    # load heartbeat sound
    audio_data, sample_rate = sf.read(audio, dtype='float32')
    
    if delay > 0:
        padding = np.zeros((int(delay * sample_rate), audio_data.shape[1]))
        audio_data = np.concatenate((padding, audio_data), axis=0)
    
    # Play audio file on the specified sound device
    sd.play(audio_data, sample_rate, device=device)
    sd.wait()

max_audio_duration = max([sf.info(file).duration for file in heartbeat_sounds + frequencies_to_play])

threads = []
for i in range(len(heartbeat_sounds)):
      heartbeat_sound = heartbeat_sounds[i]
      frequency_noise = frequencies_to_play[i % len(frequencies_to_play)]
      heartbeat_delay = max_audio_duration - sf.info(heartbeat_sound).duration
      frequency_delay = max_audio_duration - sf.info(frequency_noise).duration
      thread = threading.Thread(target=play_audio_pairing, args=(heartbeat_sound, heartbeat_delay - frequency_delay, heartbeat_speaker_id))
      threads.append(thread)
      thread.start()
      thread = threading.Thread(target=play_audio_pairing, args=(frequency_noise, 0, frequency_speaker_id))
      threads.append(thread)
      thread.start()

for thread in threads:
      thread.join()

Any help on how to merge these so that each frequency noise starts and plays with its corresponding heartbeat sound, in different speakers, would be really helpful.

Ricardo Francois
  • 752
  • 7
  • 24

0 Answers0