使用 numpy 和 scipy 生成波形文件后波形之间的间隙

Gaps in between waveforms after generating wave file using numpy and scipy

我使用 python 3.7、numpy 和 scipy 编写了一个程序,该程序使用 pi 的数字生成波形,并将它们拼接在一起形成 "song"。我唯一的问题是每个音符之间有空隙。

我尝试过使用数学函数让每个音符的波浪淡出,我尝试让音符重叠一点(运气不太好),还有一些更疯狂的事情没有做任何事...

import numpy as np
from scipy.io.wavfile import write

pi = "3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651328230664709384460955058223172535940812848"
piarray = list(pi)
piarray.remove(".")

print(piarray)

# Samples per second
sps = 44100

# Frequency / pitch of the sine wave
freq_hz = 440.0

# Duration
duration_s = 0.2

each_sample_number = np.arange(duration_s * sps)

for i in range(len(piarray)):
    if(piarray[i] == "0"):
        freq_hz = 277.18
    elif(piarray[i] == "1"):
        freq_hz = 311.13
    elif(piarray[i] == "2"):
        freq_hz = 369.99
    elif(piarray[i] == "3"):
        freq_hz = 415.30
    elif(piarray[i] == "4"):
        freq_hz = 466.16
    elif(piarray[i] == "5"):
        freq_hz = 554.37
    elif(piarray[i] == "6"):
        freq_hz = 622.25
    elif(piarray[i] == "7"):
        freq_hz = 739.99
    elif(piarray[i] == "8"):
        freq_hz = 830.61
    else:
        freq_hz = 932.33

    waveform = np.sin(2 * np.pi * each_sample_number * freq_hz / sps)*0.3
    #The line above and below this one make an individual note.
    waveform_integers = np.int16(waveform * 32767)

    if(i == 0):
        waveformc = waveform_integers
        print(waveformc)
    else:
        waveformc = np.append(waveformc, waveform_integers, axis=None)

write('song.wav', sps, waveformc)
print("DONE")


我已经尝试寻找解决这个特定问题的方法,但我没有在任何地方找到任何相关的东西。我只是希望波形文件在每个音符之间没有间隙,但是有。感谢您能给我的任何帮助!

您的波形之间没有任何间隙。您可以从 Reaper 的结果视图中看到您有连续的声音:

每次开始一个新音符时,您的波形都会出现不连续性。每次音符更改时,都会听到咔哒声或爆裂声。由于每个音符的波形都是根据底层数据结构计算的,因此它们都将在 0 处有一个零交叉点,然后从那里快速相互脱离一个相位。

要解决此问题,您可以尝试对每个声音进行适当的渐变 in/out,或者确保跟踪波形的相位并在音符变化时保持一致。

对于衰减函数,您需要类似于 (frames - each_sample_number) / frames)**n 的东西,以便它在最后达到零。您可以试用此功能,看看它如何影响声音的持续时间和音符之间的感知削波。

import numpy as np
from scipy.io.wavfile import write

pi = "3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651328230664709384460955058223172535940812848"
piarray = list(pi)
piarray.remove(".")

print(piarray)

# Samples per second
sps = 44100

# Frequency / pitch of the sine wave
freq_hz = 440.0

# Duration
duration_s = 0.2
frames = duration_s * sps # counting how many frames for a note
each_sample_number = np.arange(duration_s * sps)



for i in range(len(piarray)):
    if(piarray[i] == "0"):
        freq_hz = 277.18
    elif(piarray[i] == "1"):
        freq_hz = 311.13
    elif(piarray[i] == "2"):
        freq_hz = 369.99
    elif(piarray[i] == "3"):
        freq_hz = 415.30
    elif(piarray[i] == "4"):
        freq_hz = 466.16
    elif(piarray[i] == "5"):
        freq_hz = 554.37
    elif(piarray[i] == "6"):
        freq_hz = 622.25
    elif(piarray[i] == "7"):
        freq_hz = 739.99
    elif(piarray[i] == "8"):
        freq_hz = 830.61
    else:
        freq_hz = 932.33

    # added fall off feature
    waveform = (((frames - each_sample_number) / frames)**0.5) * np.sin(
                        np.pi+ 2 * np.pi * each_sample_number * freq_hz / sps)*0.3

    #The line above and below this one make an individual note.
    waveform_integers = np.int16(waveform * 32767)

    if(i == 0):
        waveformc = waveform_integers
        print(waveformc)
    else:
        waveformc = np.append(waveformc, waveform_integers, axis=None)

write('song.wav', sps, waveformc)
print("DONE")

可以在波形上看到当前设置的结果:

我在频率中添加了一个 "correction factor" 以确保每个波都以零振幅结束,并且不会有间断。它会稍微改变频率,但不会超过 1%。我就是这样做的:

cor_fac = round(each_sample_number[-1] * freq_hz / sps)/(each_sample_number[-1] * freq_hz / sps)
cor_factors.append(cor_fac)
waveform = np.sin(2 * np.pi * each_sample_number * freq_hz / sps * cor_fac)*0.3

我认为它解决了问题。

如果频率上的变化不可接受,您可以尝试更改样本阵列的开始,使其以与最后一个波形完成时相同的幅度开始。

我会尽力做到,post 在这里。

让我知道它对你有用。

编辑: 不改变声音频率的代码:

import numpy as np
from scipy.io.wavfile import write
import matplotlib.pyplot as plt
import wave
import sys


pi = "3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651328230664709384460955058223172535940812848"
piarray = list(pi)
piarray.remove(".")

print(piarray)

# Samples per second
sps = 44100

# Frequency / pitch of the sine wave
freq_hz = 440.0

# Duration
duration_s = 0.2

last_amp = 0
cor_factors = []
direction_down = False

for i in range(len(piarray)):
    if(piarray[i] == "0"):
        freq_hz = 277.18
    elif(piarray[i] == "1"):
        freq_hz = 311.13
    elif(piarray[i] == "2"):
        freq_hz = 369.99
    elif(piarray[i] == "3"):
        freq_hz = 415.30
    elif(piarray[i] == "4"):
        freq_hz = 466.16
    elif(piarray[i] == "5"):
        freq_hz = 554.37
    elif(piarray[i] == "6"):
        freq_hz = 622.25
    elif(piarray[i] == "7"):
        freq_hz = 739.99
    elif(piarray[i] == "8"):
        freq_hz = 830.61
    else:
        freq_hz = 932.33

    # cor_fac = round(each_sample_number[-1] * freq_hz / sps)/(each_sample_number[-1] * freq_hz / sps)
    # cor_factors.append(cor_fac)

    start = np.arcsin(last_amp/0.3)    
    if direction_down:
        start = np.pi - start   
    start = start/(2 * np.pi * freq_hz / sps)

    each_sample_number = np.arange(start, start + duration_s * sps)
    waveform = np.sin(2 * np.pi * each_sample_number * freq_hz / sps)*0.3
    print(waveform[0]-last_amp)
    last_amp = waveform[-1]
    direction_down = waveform[-1]<waveform[-2]
    #The line above and below this one make an individual note.
    waveform_integers = np.int16(waveform * 32767)

    if(i == 0):
        waveformc = waveform_integers
        print(waveformc)
    else:
        waveformc = np.append(waveformc, waveform_integers, axis=None)

write('song_2.wav', sps, waveformc)
print("DONE")