【问题标题】:How does the sin function from numpy work?numpy 的 sin 函数如何工作?
【发布时间】:2019-11-25 02:16:59
【问题描述】:

几个月前,我终于想出了如何用 python 程序制作声音文件。但我有问题。该代码依赖于模块“numpy”中名为“sin”的函数。这是我制作的代码:

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

sps=44100

freq=440.0

duration=5

amp=0.02

eachSampleNumber=np.arange(duration*sps)
waveform=np.sin(2*np.pi*eachSampleNumber*freq/sps)
waveformQuiet=waveform*amp
waveformIntegers=np.int16(waveformQuiet*32767)
write('first_sine_wave.wav',sps,waveformIntegers)

问题是如果我做某些事情会发生奇怪的事情。如果我改变声音的长度,它会改变音高。此外,如果我尝试将声音连接在一起(我一直在通过简单地将生成的数组添加在一起),则生成的声音文件将使两个声音相互重叠,而不是一个接一个地出现。例如,如果我将两个长度为一秒的声音加在一起,而不是创建一个两个音符一个接一个地播放的两秒声音文件,我将得到一个两个音符为一秒的声音文件同时播放。

我不知道 sin 波实际上是如何手工制作的,也找不到向我揭示此函数使用的公式的文档。我也不明白为什么在这种情况下将两个数组连接在一起会导致一个长度相同的数组。打印出结果数组,对我来说看起来很正常。我不明白为什么任何事情都是这样工作的。

至于我是如何制作声音文件的,我只是手动更改代码本身中的变量并运行程序。由于我遇到的问题,我还没有开始制作适当的可执行文件。我希望最终能用它来制作我自己的音乐制作程序。

【问题讨论】:

  • 我投票决定将此问题作为题外话结束,因为它似乎更像是一个数学问题而不是编程问题。

标签: python numpy scipy


【解决方案1】:

您想查看数组在numpy 中的工作原理,而不是sin 函数。根据"broadcasting" rules in numpy,添加两个数组(使用+)会根据数组的形状做不同的事情。如果你想要一个新数组,其中一个值后跟另一个值,那么你想要concatenate things

我对您的代码进行了一些重新排列,以使事情更清晰:

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

# set a global sample rate as this is fixed across one wav file
sample_rate = 44100

# define a function to return a tone at a given frequency and duration
def make_sinewave(duration, freq):
    time = np.arange(0, duration, 1/sample_rate)
    return np.sin(time * (2*np.pi*freq))

# join several tones together
waveform = np.concatenate([
    make_sinewave(1.0, 440) * 0.5,
    make_sinewave(0.5, 880) * 0.1,
    make_sinewave(0.7, 660) * 0.2,
])

# convert to appropriate data type
waveformIntegers = np.int16(waveform * 32767)

# write out
write('first_sine_wave.wav', sample_rate, waveformIntegers)

【讨论】:

    【解决方案2】:

    如果我尝试将声音连接在一起(我一直在通过简单地将结果数组添加在一起来做到这一点),则结果声音文件将改为使两个声音相互重叠而不是一个一个接一个。

    使用 NumPy,添加数组与使用 Python 列表添加非常不同。前者进行元素加法,而后者进行连接。

    >>> arr = np.arange(5)
    >>> arr + arr
    array([0, 2, 4, 6, 8])
    
    >>> lst = list(range(5))
    >>> lst + lst
    [0, 1, 2, 3, 4, 0, 1, 2, 3, 4]
    

    要实现你想要的,你需要使用专门的函数。

    >>> np.concatenate([arr, arr], axis=0)
    array([0, 1, 2, 3, 4, 0, 1, 2, 3, 4])
    
    >>> np.hstack([arr, arr])
    array([0, 1, 2, 3, 4, 0, 1, 2, 3, 4])
    

    【讨论】:

    • 嗯,这解决了一个问题。但是为什么如果我改变持续时间,音高也会改变?如何在不改变音高的情况下改变声音的持续时间?我是否需要进行某种循环来连接数组 x 次?是的,我知道如何同时创建一个 while 和一个 for 循环(我有一个 Python 证书,虽然我一直在自学 pygame 和我发现游戏需要的任何其他模块)
    猜你喜欢
    • 1970-01-01
    • 2019-03-27
    • 1970-01-01
    • 2014-04-14
    • 1970-01-01
    • 2015-12-24
    • 1970-01-01
    • 2018-07-13
    相关资源
    最近更新 更多