Python 輸出聲音


常見的波形圖

波長為1的鋸齒波 \(f(x)=x-\lfloor x \rfloor\)

波長為1的三角波 \(f(x)=2 |2*(x - \lfloor x+ \frac 1 2 \rfloor)|-1\)

圖片生成網址:https://www.desmos.com/

以三角波為例,不同的頻率產生不同聲音
網上可以查到C4調,D4調,E4調的頻率

C4 D4 E4 F4 G4 A4 B4
261.63 293.66 329.63 349.23 392.00 440.00 493.88

常用的音頻采樣頻率有8kHz、11.025kHz、22.05kHz、16kHz、37.8kHz、44.1kHz、48kHz等

from wave import open
from struct import Struct
from math import floor

sampler_rate=11025
"""對連續三角波函數進行離散取樣"""
def tri(frequency, amplitude=0.3):
    """a continuous triangle wave"""
    wave_length = sampler_rate // frequency
    # range from -0.3 to 0.3
    def sampler(t):
        saw_wave = t / wave_length - floor(t / wave_length + 0.5)
        tri_wave = 2 * abs(2 * saw_wave) - 1
        return amplitude * tri_wave 

    return sampler

def encode(x):
    """Encode float x between -1 and 1 as two bytes.
    (See https://docs.python.org/3/library/struct.html)
    """
    i = int(16384 * x)
    return Struct('h').pack(i)

def play(sampler, name="song.wav", seconds=2):
    """
    當輸出持續2s的聲音文件時,需要采樣 2*sampler_rate=22250次
    """
    out = open(name, "wb")
    out.setnchannels(1)
    out.setsampwidth(2)
    out.setframerate(sample_rate)
    t = 0
    while t < seconds * sample_rate:
        sample = sampler(t)
        out.writeframes(encode(sample))
        t = t + 1
    out.close()

play(tri(e_freq))

這樣輸出的音頻很難聽,還需要對波形做一些調整。

def note(f, start, end, fade=.01):
    """Play f for a fixed duration."""

    def sampler(t):
        seconds = t / sampler_rate
        if seconds < start:
            return 0
        elif seconds > end:
            return 0
        elif seconds < start + fade:
            return (seconds - start) / fade * f(t)
        elif seconds > end - fade:
            return (end - seconds) / fade * f(t)
        else:
            return f(t)

    return sampler

play(note(tri(e_freq), 1, 1.5)) #在(1,1.5)之間播放E4調

輸出一段馬里奧前奏

def both(f, g):
    return lambda t: f(t) + g(t)

def mario(c, e, g, low_g):
    z = 0
    song = note(e, z, z + 1 / 8)
    z += 1 / 8
    song = both(song, note(e, z, z + 1 / 8))
    z += 1 / 4
    song = both(song, note(e, z, z + 1 / 8))
    z += 1 / 4
    song = both(song, note(c, z, z + 1 / 8))
    z += 1 / 8
    song = both(song, note(e, z, z + 1 / 8))
    z += 1 / 4
    song = both(song, note(g, z, z + 1 / 4))
    z += 1 / 2
    song = both(song, note(low_g, z, z + 1 / 4))
    return song


def mario_at(octave):
    c = tri(octave * c_freq)
    e = tri(octave * e_freq)
    g = tri(octave * g_freq)
    low_g = tri(octave * g_freq / 2)
    return mario(c, e, g, low_g)

play(both(mario_at(1), mario_at(1 / 2)))


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM