我正在尝试使用Python进行一些声音实验,我需要一个体面的play_tone(freq, dur)
函数实现。我已经看了很长一段时间,到目前为止已经发现了三种实现方式,其中只有一种实现了播放快速音符序列时所需的基本声音平滑度。
我还没有研究过声音生成的数学/物理,所以我在信任上花了很多代码 - 一旦我知道为什么这些方法中最好的一种效果最好,我会用它作为进一步研究的起点。
所以,我正在寻找解释为什么这两个"最差"版本有如此多的剪切和点击,而最好的版本(使用struct
)是如此平滑。我希望this answer与它有关,但我不确定如何。
另外,我很想找到一种方法来制作最流畅版本的最后一个音符而不是点击最后一个音符 - 即我希望它能够顺利结束。
# This is the smoothest version I can find
import math
import struct
import pyaudio
def play_tone(frequency, duration, stream, amplitude=0.5, fs=44100):
N = int(fs / frequency)
T = int(frequency * duration) # repeat for T cycles
dt = 1.0 / fs
# 1 cycle
tone = (amplitude * math.sin(2 * math.pi * frequency * n * dt)
for n in range(N))
# Notice the b to transform the operation in a bytes operation
data = b''.join(struct.pack('f', samp) for samp in tone)
for n in range(T):
stream.write(data)
#Usage
fs = 48000
p = pyaudio.PyAudio()
stream = p.open(
format=pyaudio.paFloat32,
channels=1,
rate=fs,
output=True)
a = 2 ** (1 / 24)
f0 = 110
qts = [f0 * a ** p for p in range(96)]
for i in range(0, len(qts) - 24, 3):
for j in range(i, i + 24, 4):
play_tone(qts[j], 0.1, stream)
stream.close()
p.terminate()
# This is the second smoothest version I can find
import math
import numpy
import pyaudio
def sine(frequency, length, rate):
length = int(length * rate)
factor = float(frequency) * (math.pi * 2) / rate
return numpy.sin(numpy.arange(length) * factor)
def play_tone(stream, frequency=440, length=1, rate=44100):
chunks = []
chunks.append(sine(frequency, length, rate))
chunk = numpy.concatenate(chunks) * 0.25
stream.write(chunk.astype(numpy.float32).tostring())
#Usage
fs = 48000
p = pyaudio.PyAudio()
stream = p.open(
format=pyaudio.paFloat32,
channels=1,
rate=fs,
output=True)
a = 2 ** (1 / 24)
f0 = 110
qts = [f0 * a ** p for p in range(96)]
for i in range(0, len(qts) - 24, 3):
for j in range(i, i + 24, 4):
play_tone(stream, qts[j], 0.1)
stream.close()
p.terminate()
# This is the least smooth version I can find
import numpy as np
import pyaudio
def play_tone(freq, dur, stream, fs=44100):
volume = 0.5 # range [0.0, 1.0]
duration = dur # in seconds, may be float
f = freq # sine frequency, Hz, may be float
# generate samples, note conversion to float32 array
samples = (np.sin(2*np.pi*np.arange(fs*duration)*f/fs)).astype(np.float32)
# play. May repeat with different volume values (if done interactively)
stream.write(volume*samples)
#Usage
fs = 48000
p = pyaudio.PyAudio()
stream = p.open(
format=pyaudio.paFloat32,
channels=1,
rate=fs,
output=True)
a = 2 ** (1 / 24)
f0 = 110
qts = [f0 * a ** p for p in range(96)]
for i in range(0, len(qts) - 24, 3):
for j in range(i, i + 24, 4):
play_tone(qts[j], 0.5, stream)
stream.close()
p.terminate()
答案 0 :(得分:1)
修改波形发生器,使振幅从零开始,在一定时间内(例如总持续时间的1/10)斜坡上升到所需值,并在结束时的同一时间段内斜坡下降到零。
这样,无论频率或相位,信号在每个音调的结束和开始时总是为零。这应该会产生平稳的过渡。
答案 1 :(得分:0)
我不是经验丰富的程序员(也更习惯于javascript)。另外,这是一个古老的问题,但是我在任何地方都找不到很好的答案。所以我对此有所了解。
child("closeFriends")
我正在用javascript进行类似的编程,并且在Webaudio中存在几乎相同的问题(摆脱点击;发出悦耳的声音)的问题very good article。我试图做的是将笔记开头的点击删除从webaudio / javascript转换为python。