周波数の異なる sine curve を滑らかにつなぐ

サインカーブつなぐテスト。

Pygame での波形作成のテストが目的なのでこの範囲では不要な array なんて使っちゃってますが気にしないように。
(Python 2.5 + Pygame 1.8)

from __future__ import division
import math
import array
import random
import pygame
from pygame.locals import *

FULLSCREEN = False # True にするとフルスクリーン表示
WIDTH, HEIGHT = 50 * 13, 200  # 表示する画面のサイズ
BG_COLOR = 0, 0, 50  # 背景色
BASE_FREQUENCY = 1  # 基本周波数(Hz)
PYGAME_FREQUENCY = 100  # 1Hz の長さ

def sins(frequency, start, length):
##    volume = BASE_FREQUENCY / frequency
    volume = 1
    datalen =int(PYGAME_FREQUENCY * length)
    data = array.array('h', [0] * 2 * datalen)
    a = math.pi * 2 * frequency / PYGAME_FREQUENCY
    start_a = start
    vol = min(32767, 32767 * volume)
    for i in range(datalen):
        data[i * 2] = data[i * 2 + 1] = int(math.sin(a * i + start_a) * vol)
    return data, (a * datalen + start_a) % (math.pi * 2)

def main():
    screen = pygame.display.set_mode(
        (WIDTH, HEIGHT),
        (pygame.FULLSCREEN |
         pygame.HWSURFACE |
         pygame.DOUBLEBUF) if FULLSCREEN else 0)
    log_base = math.log(BASE_FREQUENCY, 2)
    while True:
        screen.fill(BG_COLOR)
        for x in range(0, WIDTH, 50):
            pygame.draw.line(
                screen, (0, 0, 255),
                (x, 0), (x, HEIGHT - 1), 1)
        xp = 0
        alpha = 0
        for note in range(13):
##            frequency = 2 ** (log_base + note / 12)
            frequency = 2 ** (log_base + random.random())
            data, alpha = sins(frequency, alpha, .5)
            h = HEIGHT // 2
            pygame.draw.lines(
                screen, ((1 - note % 2) * 255, (note % 2) * 255, 200), False,
                [(x + xp, data[x * 2] * h // 32767 + h)
                 for x in range(0, len(data) // 2)], 1)
            xp += 50
        pygame.display.flip()
        break_while = False
        while not break_while:
            pygame.time.wait(100)
            for event in pygame.event.get():
                if event.type in (KEYDOWN, QUIT):
                    return
                elif event.type == MOUSEBUTTONDOWN:
                    break_while = True
                    break

if __name__=='__main__':
    pygame.init()
    try:
        main()
    finally:
        pygame.quit()
# 好きに流用してください。

マウスクリックで別パターン描画、何かのキーを押すと終了です。

##    volume = BASE_FREQUENCY / frequency
    volume = 1

ここんところ生かすと波形は合ってもボリュームの差で上手くつながらないのが悩みどころ。