ポルタメントしてみる
図形を描くのは後回し。楽器ならまず音を出せないとね。
の応用で、ドラッグ操作でリアルタイムに音を出しポルタメントできるものを作ってみました。
(Python 2.6 + Pygame 1.8)
from __future__ import division import wave import math import array import pygame from pygame.locals import * FULLSCREEN = False # True にするとフルスクリーン表示 FPS = 60 # 秒間描画枚数 WIDTH, HEIGHT = 640, 480 # 表示する画面のサイズ LINEWIDTH = 20 # 線の太さ COLOR = 0, 255, 200 # 色 BG_COLOR = 0, 0, 50 # 背景色 BASE_FREQUENCY = 220 # 左端での周波数(Hz) OCTAVE_WIDTH = 240 # 1オクターブの幅 # 作業用 wave ファイルのスペック(実際の発音は pygame の設定に依存) FILE_FREQENCY = 44100 WAVE_LENGTH = .1 DUMMY_WAVE = '__dummy__.wav' def dummy_wave(length=WAVE_LENGTH): f = wave.open(DUMMY_WAVE, 'wb') f.setparams((1, 2, FILE_FREQENCY, 0, 'NONE', 'not compressed')) f.writeframes( array.array('h', [0] * int(FILE_FREQENCY * length)).tostring()) f.close() def write_sin(buf, freqency, volume=1, length=WAVE_LENGTH): data = array.array('h', [0] * 2 * int(PYGAME_FREQUENCY * length)) a = math.pi * 2 * freqency / PYGAME_FREQUENCY vol = min(32767, 32767 * volume) for i in range(int(PYGAME_FREQUENCY * length)): data[i * 2] = data[i * 2 + 1] = int(math.sin(a * i) * vol) buf.write(data, 0) def set_wave(sound, frequency): write_sin(sound.get_buffer(), frequency, BASE_FREQUENCY / frequency) def main(): dummy_wave() sound = pygame.mixer.Sound(DUMMY_WAVE) screen = pygame.display.set_mode( (WIDTH, HEIGHT), (pygame.FULLSCREEN | pygame.HWSURFACE | pygame.DOUBLEBUF) if FULLSCREEN else 0) timer = pygame.time.Clock() sound_on = False log_base = math.log(BASE_FREQUENCY, 2) old_x = -1 while True: timer.tick(FPS) screen.fill(BG_COLOR) x, y = pygame.mouse.get_pos() button1, button2, button3 = pygame.mouse.get_pressed() focuse = pygame.mouse.get_focused() a = (x / OCTAVE_WIDTH) frequency = 2 ** (log_base + a) if focuse: if button1: pygame.draw.line( screen, COLOR, (x, 0), (x, HEIGHT - 1), LINEWIDTH) if sound_on: if old_x != x: set_wave(sound, frequency) old_x = x else: set_wave(sound, frequency) old_x = x sound.play(-1) sound_on = True else: pygame.draw.line( screen, (255, 255, 0), (x, 0), (x, HEIGHT - 1), 3) sound.stop() sound_on = False old_x = -1 else: sound.stop() sound_on = False old_x = -1 for xb in range(0, WIDTH, OCTAVE_WIDTH): for s in range(12): x = xb + s * OCTAVE_WIDTH / 12 pygame.draw.line( screen, (253 - 23 * s, 0, 23 * s,), (x, 0), (x, HEIGHT - 1), 1) pygame.display.flip() cap = '%5.2f fps, %7.2fHz' % ( timer.get_fps(), frequency) pygame.display.set_caption(cap) for event in pygame.event.get(): if event.type == QUIT: return elif event.type == KEYDOWN and event.key == K_ESCAPE: return if __name__=='__main__': pygame.mixer.pre_init(44100, -16, 2) pygame.init() PYGAME_FREQUENCY, format, PYGAME_CHANNELS = pygame.mixer.get_init() try: main() finally: pygame.quit() # 好きに流用してください。
やっぱりブチブチ言うしそれに反応も怪しい。リアルタイムに連続して音程を変えられる音源の作り方をもう少し工夫する必要がありそう。
とはいえ実用品を目指すのではなくモックアップでいいならこんなのでもかまわないか。とりあえずこれのまま続けてみるかな。