import sys import numpy as np import sounddevice as sd import soundfile as sf from PyQt5.QtWidgets import ( QApplication, QWidget, QVBoxLayout, QLabel, QSlider, QPushButton, QFileDialog ) from PyQt5.QtCore import Qt, QTimer samplerate = 44100 blocksize = 1024 class VoiceModifier(QWidget): def __init__(self): super().__init__() self.setWindowTitle("Modificateur de voix") self.setGeometry(300, 300, 400, 350) self.pitch = 1.0 self.recording = [] self.is_recording = False layout = QVBoxLayout() self.label = QLabel("Pitch: 0 (Normal)") layout.addWidget(self.label) self.slider = QSlider(Qt.Horizontal) self.slider.setMinimum(-12) self.slider.setMaximum(12) self.slider.setValue(0) self.slider.valueChanged.connect(self.change_pitch) layout.addWidget(self.slider) self.female_button = QPushButton("Voix féminine") self.female_button.clicked.connect(lambda: self.slider.setValue(6)) layout.addWidget(self.female_button) self.male_button = QPushButton("Voix masculine") self.male_button.clicked.connect(lambda: self.slider.setValue(-6)) layout.addWidget(self.male_button) self.record_button = QPushButton("Démarrer l'enregistrement") self.record_button.clicked.connect(self.toggle_recording) layout.addWidget(self.record_button) self.preview_button = QPushButton("Préécouter l'enregistrement") self.preview_button.clicked.connect(self.preview_recording) layout.addWidget(self.preview_button) self.save_button = QPushButton("Enregistrer dans un fichier WAV") self.save_button.clicked.connect(self.save_recording) layout.addWidget(self.save_button) self.setLayout(layout) QTimer.singleShot(500, self.start_audio_stream) def change_pitch(self, value): self.pitch = 2 ** (value / 12.0) self.label.setText(f"Pitch: {value} ({'+' if value > 0 else ''}{value} demi-tons)") def toggle_recording(self): self.is_recording = not self.is_recording if self.is_recording: self.recording.clear() self.record_button.setText("Arrêter l'enregistrement") else: self.record_button.setText("Démarrer l'enregistrement") def preview_recording(self): if not self.recording: print("Aucun enregistrement à lire.") return audio_data = np.concatenate(self.recording) sd.play(audio_data, samplerate) print("Préécoute en cours...") def save_recording(self): if not self.recording: print("Aucun enregistrement disponible.") return file_path, _ = QFileDialog.getSaveFileName(self, "Enregistrer sous", "", "Fichiers WAV (*.wav)") if file_path: audio_data = np.concatenate(self.recording) sf.write(file_path, audio_data, samplerate) print("Enregistrement sauvegardé :", file_path) def start_audio_stream(self): self.stream = sd.InputStream( samplerate=samplerate, blocksize=blocksize, channels=1, dtype='float32',callback=self.audio_callback ) self.stream.start() def audio_callback(self, indata, frames, time, status): if status: print("Status:", status) data = indata[:, 0] indices = np.arange(0, len(data), self.pitch) indices = indices[indices < len(data)].astype(int) shifted = data[indices] # Adapter à la longueur originale if len(shifted) < len(data): shifted = np.pad(shifted, (0, len(data) - len(shifted)), mode='constant') else: shifted = shifted[:len(data)] if self.is_recording: self.recording.append(np.copy(shifted)) if __name__ == "__main__": app = QApplication(sys.argv) window = VoiceModifier() window.show() sys.exit(app.exec_())