Python 方波函数 - 这是怎么回事?

2 投票
1 回答
2843 浏览
提问于 2025-04-18 14:19

我在用Python写一个生成方波的函数,但我总是听不到声音。不过,当我把这段代码:

value = state * volume
s.append( [value, value] )

换成这段代码:

value = state * volume
s.append( [0, value] )

我能听到声音,但这个声音的频率比我想要的130.81高得多。下面是完整的代码:

def SquareWave(freq=1000, volume=10000, length=1):

    num_steps = length * SAMPLE_RATE
    s = []

    length_of_plateau = SAMPLE_RATE / (2*freq)

    counter = 0
    state = 1

    for n in range(num_steps):

        value = state * volume
        s.append( [value, value] )

        counter += 1

        if counter == length_of_plateau:
            counter = 0
            state *= -1

    return numpy.array(s)

def MakeSound(arr):
    return pygame.sndarray.make_sound(arr)

def MakeSquareWave(freq=1000):
    return MakeSound(SquareWave(freq))

调用这些函数的代码块如下:

elif current_type == SQUARE_WAVE_TYPE:

            if event.type == KEYDOWN:

                #lower notes DOWN

                if event.key == K_z:
                    print current_type, 130.81
                    #current_played['z'] = MakeSineWave(80.81)
                    current_played['z'] = MakeSquareWave(130.81)
                    current_played['z'].play(-1)

                elif event.key == K_c:
                    print current_type, 180.81
                    #current_played['c'] = MakeSineWave(80.81)
                    current_played['c'] = MakeSquareWave(180.81)
                    current_played['c'].play(-1)

有人能看出这是为什么吗?这个方波函数真的正确吗?

1 个回答

2

你遇到的问题很可能是因为你没有正确处理浮点数值。

来看这个比较:

if counter == length_of_plateau:

这里是在比较一个整数 counter 和一个浮点数 length_of_plateau

length_of_plateau 是通过这个赋值得到的:

length_of_plateau = SAMPLE_RATE / (2*freq)

假设频率是 130.81,采样率是 44100(我在这里猜测,因为你没有提供 SAMPLE_RATE 的具体值),你会得到这个:

length_of_plateau = 168.565094412

所以,一个整数永远不会等于这个值。

相反,我会这样做:

state = 1
next_plateau_end = length_of_plateau

counter = 0
for n in range(num_steps):
    value = state * volume
    s.append( [value, value] )

    if counter >= next_plateau_end:
        counter -= length_of_plateau
        state *= -1
    counter += 1

与其每次把 counter 重置为 0,不如我们减去 plateau 的长度(这是一个浮点数值)。这样,原代码中引入的四舍五入误差会随着时间的推移而被平滑掉。

撰写回答