import numpy as np
from scipy.io import wavfile
import matplotlib.pyplot as plt
# --- 1. GENERACIÓN DE AUDIO CON ARMÓNICOS Y ENVOLVENTE ---
sample_rate = 44100 # Frecuencia de muestreo (Hz)
note_duration = 0.5 # Duración de cada nota (segundos)
notes = [
("Do4", 261.63),
("Mi4", 329.63),
("Sol4", 392.00),
("Do5", 523.25)
]
harmonics = [(1, 1.00), (2, 0.50), (3, 0.25), (4, 0.125)]
audio_signal = np.array([], dtype=np.float32)
note_signals = [] # Para guardar cada nota de forma individual
time_single_note = np.linspace(0, note_duration, int(sample_rate * note_duration), endpoint=False)
for name, freq in notes:
envelope = np.exp(-3 * time_single_note)
note_wave = np.zeros_like(time_single_note)
for mult, weight in harmonics:
note_wave += weight * np.sin(2 * np.pi * (freq * mult) * time_single_note)
note_wave *= envelope
note_signals.append((name, note_wave))
audio_signal = np.concatenate((audio_signal, note_wave))
# Normalizar señal completa y las notas individuales con la misma escala
max_amp = np.max(np.abs(audio_signal))
audio_signal /= max_amp
note_signals = [(name, wave / max_amp) for name, wave in note_signals]
# Guardar archivo .wav
wavfile.write("melodia_armonicos.wav", sample_rate, (audio_signal * 32767).astype(np.int16))
total_duration = len(audio_signal) / sample_rate
time_vector = np.linspace(0, total_duration, len(audio_signal), endpoint=False)
# ==========================================
# IMAGEN 1: SEÑALES TEMPORALES (COMPLETA + NOTAS INDIVIDUALES)
# ==========================================
fig1, axes = plt.subplots(5, 1, figsize=(10, 10), sharex=False)
# Signal Completa
axes[0].plot(time_vector, audio_signal, color='#2ca02c', linewidth=0.6)
axes[0].set_title("Señal Completa en el Dominio del Tiempo", fontsize=11, fontweight='bold')
axes[0].set_ylabel("Amplitud")
axes[0].set_xlim(0, total_duration)
axes[0].set_ylim(-1.1, 1.1)
axes[0].grid(True, alpha=0.3)
# Notas Individuales
colors = ['#1f77b4', '#ff7f0e', '#d62728', '#9467bd']
for i, (name, wave) in enumerate(note_signals):
ax = axes[i + 1]
ax.plot(time_single_note, wave, color=colors[i], linewidth=0.7)
ax.set_title(f"Nota Individual: {name}", fontsize=10)
ax.set_ylabel("Amplitud")
ax.set_xlim(0, note_duration)
ax.set_ylim(-1.1, 1.1)
ax.grid(True, alpha=0.3)
if i == 3:
ax.set_xlabel("Tiempo por Nota (segundos)")
plt.tight_layout()
plt.savefig("1_senial_temporal.png")
plt.close(fig1)
# ==========================================
# IMAGEN 2: TRANSFORMADA DE FOURIER (FFT LINEAL)
# ==========================================
N = len(audio_signal)
fft_spectrum = np.fft.rfft(audio_signal)
freqs = np.fft.rfftfreq(N, 1 / sample_rate)
magnitude = np.abs(fft_spectrum) / N
fig2, ax = plt.subplots(figsize=(10, 5))
ax.plot(freqs, magnitude, color='#1f77b4', linewidth=0.9)
ax.set_title("Transformada Rápida de Fourier (FFT Lineal) - Señal Completa", fontsize=11, fontweight='bold')
ax.set_xlabel("Frecuencia (Hz)")
ax.set_ylabel("Amplitud Lineal")
ax.set_xlim(0, 2500)
ax.set_ylim(0, np.max(magnitude) * 1.1)
ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig("2_fft_lineal.png")
plt.close(fig2)
# ==========================================
# IMAGEN 3: ESPECTROGRAMA
# ==========================================
fig3, ax = plt.subplots(figsize=(10, 5))
Pxx, freqs_spec, bins, im = ax.specgram(
audio_signal,
Fs=sample_rate,
NFFT=1024,
noverlap=512,
cmap='magma'
)
ax.set_title("Espectrograma de la Melodía (Frecuencia vs Tiempo)", fontsize=11, fontweight='bold')
ax.set_xlabel("Tiempo (segundos)")
ax.set_ylabel("Frecuencia (Hz)")
ax.set_ylim(0, 2500)
ax.grid(True, alpha=0.3)
cbar = fig3.colorbar(im, ax=ax)
cbar.set_label("Intensidad (dB)")
plt.tight_layout()
plt.savefig("3_espectrograma.png")
plt.close(fig3)
print("Generated 3 separate images successfully")