I have a microphone and speaker connect to a RPI inside an art sculpture, my objective is to record new audio clips of people talking into the mic while playing back 3 random recorded audio clips. It does work but the mic keeps picking up the feedback and echo from the speaker itself, how can I fix this? I cannot order new hardware since I need this by Monday.
import pygameimport randomimport osimport sounddevice as sdimport numpy as npimport waveimport timefrom threading import Thread, Lockimport pyaudioimport webrtcvad# Function to record audio for a specified durationdef record_audio(filename, sample_rate=16000, chunk_duration_ms=30): vad = webrtcvad.Vad(3) # Set aggressiveness from 0 to 3 format = pyaudio.paInt16 channels = 1 chunk_size = int(sample_rate * chunk_duration_ms / 1000) audio = pyaudio.PyAudio() stream = audio.open(format=format, channels=channels, rate=sample_rate, input=True, frames_per_buffer=chunk_size) print("Listening for speech...") frames = [] recording = False silence_counter = 0 while True: frame = stream.read(chunk_size) is_speech = vad.is_speech(frame, sample_rate) if recording: frames.append(frame) if len(frames) >= int(10 * 1000 / chunk_duration_ms): # 10 seconds of audio # Save the recording wf = wave.open(filename, 'wb') wf.setnchannels(channels) wf.setsampwidth(audio.get_sample_size(format)) wf.setframerate(sample_rate) wf.writeframes(b''.join(frames)) wf.close() print(f"Recording saved: {filename}") return # Stop after saving one 10-second clip if is_speech: recording = True silence_counter = 0 elif recording: # Increment silence counter if no speech detected silence_counter += 1 if silence_counter > int(3 * 1000 / chunk_duration_ms): # 3 seconds of silence recording = False frames.clear() stream.stop_stream() stream.close() audio.terminate()# Function to play a random 3-5 second interval from an available file on a given channel with random volumedef play_random_interval_on_channel(channel, current_files, playback_lock): with playback_lock: # Filter out files that are currently being played on any channel available_files = [file for file in audio_files if file not in current_files.values()] if not available_files: return file_path = random.choice(available_files) sound = pygame.mixer.Sound(os.path.join(audio_files_dir, file_path)) sound_length = sound.get_length() # Set start time to a random point within the audio clip's length start_time = random.uniform(0, max(sound_length - 5, 0)) # Ensure there's enough time for a 3-5 second clip duration = random.uniform(3, 5) # Duration between 3 and 5 seconds volume = random.uniform(0.7, 1.0) # Random volume adjustment between 70% and 100% # Adjust duration if it exceeds the available duration if start_time + duration > sound_length: duration = sound_length - start_time sound.set_volume(volume) # Set the adjusted volume # Ensure that the end time does not exceed the audio clip's length end_time = min(start_time + duration, sound_length) # Play the specified interval sound.play() # Delay to allow playing only the specified interval pygame.time.delay(int(start_time * 1000)) # Stop the playback after the interval duration pygame.time.delay(int((end_time - start_time) * 1000)) sound.stop() with playback_lock: # Update the current file being played on this channel current_files[channel] = file_path return file_path # Return the file being played# Function to play tracks and record once simultaneouslydef play_and_record(channel, recording_lock, current_files, playback_lock): while True: file = play_random_interval_on_channel(channel, current_files, playback_lock) if file: current_files[channel] = file # Try to acquire the lock to ensure only one thread records at a time if recording_lock.acquire(blocking=False): try: new_file_name = os.path.join(audio_files_dir, f"recording_{int(time.time())}.wav") record_audio(new_file_name) audio_files.append(new_file_name) # Add new recording to the playlist finally: recording_lock.release()# Initialize pygame and the mixerpygame.mixer.init()# Directory containing the audio filesaudio_files_dir = "/home/pi/Desktop/art_proj/mp3clips"# List all files in the directoryaudio_files = os.listdir(audio_files_dir)# Initialize three channelschannels = [pygame.mixer.Channel(i) for i in range(4)]# Create a lock to control recording accessrecording_lock = Lock()# Create a new lock for playbackplayback_lock = Lock()# Dictionary to track which file is playing on each channelcurrent_files = {}# Start threads as daemon threads to play tracks and record on each channelthreads = [Thread(target=play_and_record, args=(channel, recording_lock, current_files, playback_lock), daemon=True) for channel in channels]for thread in threads: thread.start()try: while True: pygame.time.Clock().tick(10)except KeyboardInterrupt: print("Stopping...") pygame.quit()