波形を生成し音色を聞き比べる (1)

波形を生成し音色を聞き比べる (1)#

C1S3_Timbre

import numpy as np
import matplotlib.pyplot as plt
import libfmp.b
import libfmp.c1
import librosa
import IPython.display as ipd
def plot_spectrogram(x, Fs=11025, N=4096, H=2048, figsize=(4, 2)):
    """Computation and subsequent plotting of the spectrogram of a signal

    Notebook: C1/C1S3_Timbre.ipynb

    Args:
        x: Signal (waveform) to be analyzed
        Fs: Sampling rate (Default value = 11025)
        N: FFT length (Default value = 4096)
        H: Hopsize (Default value = 2048)
        figsize: Size of the figure (Default value = (4, 2))

    """
    # N, H = 2048, 1024
    X = librosa.stft(x, n_fft=N, hop_length=H, win_length=N, window=np.hanning)  # not 'hamming'
    Y = np.abs(X)
    plt.figure(figsize=figsize)
    librosa.display.specshow(librosa.amplitude_to_db(Y, ref=np.max),
                             y_axis='linear', x_axis='time', sr=Fs, hop_length=H) # cmap='gray_r'
    plt.ylim([0, 3000])
    # plt.colorbar(format='%+2.0f dB')
    plt.xlabel('Time (seconds)')
    plt.ylabel('Frequency (Hz)')
    plt.tight_layout()
    plt.show()
Fs = 11025
dur = 4
freq = 261.626
amp = 0.5
figsize = (8, 2)

正弦波 (sinusoid) を生成する#

num_samples = int(Fs * dur)
t = np.arange(num_samples) / Fs
x = amp * np.sin(2*np.pi*(freq*t))

# x, t = libfmp.c1.generate_sinusoid(dur=dur, Fs=Fs, amp=amp, freq=freq)
libfmp.b.plot_signal(x, Fs=Fs, figsize=figsize, ylabel='Amplitude', title='Sinusoid')
plt.ylim([-0.9, 0.9])
plt.show()
../../_images/8f0ec486c3921d52b2ceb4f79f0d66460c320588617d2bc243fa36a4e468c4aa.png
libfmp.b.plot_signal(x, Fs=Fs, figsize=figsize, ylabel='Amplitude', title='Sinusoid')
plt.ylim([-0.9, 0.9])
plt.xlim([0, 1])
plt.show()
../../_images/437d9fd493e49ed8eaf8b54c18f5cac07ec357367d2900ca68aa666cb5e4c611.png
libfmp.b.plot_signal(x, Fs=Fs, figsize=figsize, ylabel='Amplitude', title='Sinusoid')
plt.ylim([-0.9, 0.9])
plt.xlim([0, .1])
plt.show()
../../_images/bc4e4651f55e48a1830be1ca9b24ed7c0a4a49d8a3b43eebd492e6515009dce4.png
ipd.display(ipd.Audio(data=x, rate=Fs))

Note

スペクトログラムは、時間 (横軸)、周波数(縦軸)、信号成分の強さ(色)の三次元グラフです

plot_spectrogram(x, Fs=Fs, N=1024, H=256, figsize=(4, 3))
../../_images/3c435eb2581087d8dbc8e0a7db793dbfdcb76873769e78bf13bfc19e3105ce62.png

ADSRを加える#

import libfmp.b
import libfmp.c1

%matplotlib inline

def compute_adsr(len_A=10, len_D=10, len_S=60, len_R=10, height_A=1.0, height_S=0.5):
    """Computation of idealized ADSR model

    Notebook: C1/C1S3_Timbre.ipynb

    Args:
        len_A (int): Length (samples) of A phase (Default value = 10)
        len_D (int): Length (samples) of D phase (Default value = 10)
        len_S (int): Length (samples) of S phase (Default value = 60)
        len_R (int): Length (samples) of R phase (Default value = 10)
        height_A (float): Height of A phase (Default value = 1.0)
        height_S (float): Height of S phase (Default value = 0.5)

    Returns:
        curve_ADSR (np.ndarray): ADSR model
    """
    curve_A = np.arange(len_A) * height_A / len_A
    curve_D = height_A - np.arange(len_D) * (height_A - height_S) / len_D
    curve_S = np.ones(len_S) * height_S
    curve_R = height_S * (1 - np.arange(1, len_R + 1) / len_R)
    curve_ADSR = np.concatenate((curve_A, curve_D, curve_S, curve_R))
    return curve_ADSR
curve_ADSR = compute_adsr(len_A=int(x.size*0.3), len_D=int(x.size*0.3), len_S=int(x.size*0.3), len_R=int(x.size*0.1), height_A=1.0, height_S=0.8)
libfmp.b.plot_signal(curve_ADSR, figsize=(4,2.5), ylabel='Amplitude', title='ADSR model', color='red')
plt.show()
../../_images/91cca2cc84f2f71993d41c1027c486d4c6561cb6e180d1b170ef9ac38f2635af.png
x, t = libfmp.c1.generate_sinusoid(dur=dur, Fs=Fs, amp=amp, freq=freq)
x.size, curve_ADSR.size
(44100, 44100)
x *= curve_ADSR
libfmp.b.plot_signal(x, Fs=Fs, figsize=figsize, ylabel='Amplitude', title='Sinusoid')
plt.ylim([-0.9, 0.9])
plt.show()
../../_images/682b3703db0901be0b574a0556e0622840cde3b2f0c4f02fd1821f16e1a618aa.png
libfmp.b.plot_signal(x, Fs=Fs, figsize=figsize, ylabel='Amplitude', title='Sinusoid')
plt.ylim([-0.9, 0.9])
plt.xlim([0, 1])
plt.show()
../../_images/1a49af7b9d12397a906330fe48dff32cccc8e7b3fbb6b4688fbabdaf6e4fabfb.png
libfmp.b.plot_signal(x, Fs=Fs, figsize=figsize, ylabel='Amplitude', title='Sinusoid')
plt.ylim([-0.9, 0.9])
plt.xlim([0, .1])
plt.show()
../../_images/7699c5dd34992e91dad413b515164279ec862dd6b14dd500fccbc35aa0cf2581.png
ipd.display(ipd.Audio(data=x, rate=Fs))
plot_spectrogram(x, Fs=Fs, N=1024, H=256, figsize=(4, 3))
../../_images/44ca02bc14edf1a1aa0a55fe8b39b758f6d0e0da174e0ba510f229f6c43bc1ec.png

倍音を持つ波形を生成する#

t = np.arange(num_samples) / Fs
x = np.arange(num_samples) / Fs
amp = 1.0
for i in range(1, 12):
    x += (amp / i) * np.sin(2*np.pi*(freq*i*t)) * curve_ADSR
plot_spectrogram(x, Fs=Fs, N=1024, H=256, figsize=(4, 3))
../../_images/c06d1534513feff88675882efeb3f0868dd1979edd561360e6ee742b99e1db0e.png
ipd.display(ipd.Audio(data=x, rate=Fs))
x_violin, Fs = librosa.load('./FMP_C1_F23_Violin.wav', sr=Fs)
plot_spectrogram(x_violin, Fs=Fs, N=1024, H=256, figsize=(4, 3))
../../_images/d4ccb5f0c0950e9b81e680ab0dc0d3014d44d184eadf4f83556751ab39fbcc61.png
ipd.display(ipd.Audio(data=x_violin, rate=Fs))