OneLoopDrumMachine: Difference between revisions
No edit summary |
|||
Line 7: | Line 7: | ||
http://www.hydrogen-music.org/ | http://www.hydrogen-music.org/ | ||
[[Image: | [[Image:Hydrogen.png|Hydrogen]] | ||
In a simple single-loop program, there is no explicit timeline. So you have to simulate it using variables as state. | In a simple single-loop program, there is no explicit timeline. So you have to simulate it using variables as state. |
Revision as of 12:06, 21 May 2008
One Loop Drum Machine
using PyGame
Drum machines (and software simulating them), typically work with spreadsheet-like timeline views that allow you to trigger playback of different percussive sounds as a pattern in time.
Example drum machine software: http://www.hydrogen-music.org/
In a simple single-loop program, there is no explicit timeline. So you have to simulate it using variables as state.
For instance, you might create a variable called beat to represent what portion (column) of the timeline / pattern you are currently in.
Programming a simple drum machine in PyGame
First, you need some sound samples. You could pull them from a program like Hydrogen (just make sure they're either OGG or raw wav format for PyGame to load. Or you can use ["sox"] to generate some retro 8bit sounds.
So playing the sound with PyGame:
#!python import pygame pygame.init() pygame.mixer.init() sweep = pygame.mixer.Sound("sweep_up.wav") sweep.play() while True: pass
Now with a clock to control the rhythm:
#!python import pygame pygame.init() pygame.mixer.init() sweep = pygame.mixer.Sound("sweep.wav") cow = pygame.mixer.Sound("sweep_up_long.wav") clock = pygame.time.Clock() bpm = 180 fps = float(bpm) / 60 while True: cow.play() ## plays in background (like & ) clock.tick(fps)
Exercise: How, with this single loop, might you implement a simple drum pattern such as:
bell | x | x | |||
beep | x | x | x | x |
attachment:beatpattern_wb.png
#!python import pygame pygame.init() pygame.mixer.init() beep = pygame.mixer.Sound("08.wav") noise = pygame.mixer.Sound("noise.wav") clock = pygame.time.Clock() bpm = 120 fps = float(bpm) / 60 beat = 0 while True: print beat beep.play() # lbeat = beat % 4 if beat == 0 or beat==2: noise.play() beat += 1 if beat==4: beat=0 clock.tick(fps)
This is a buggy version of an attempt to make the rhythm loop more responsive to the keyboard:
#!python import sys, pygame from pygame.locals import * pygame.init() pygame.mixer.init() beep = pygame.mixer.Sound("08.wav") noise = pygame.mixer.Sound("noise.wav") cowbell = pygame.mixer.Sound("hi.wav") clock = pygame.time.Clock() bpm = 120 fps = float(bpm) / 60 beat = 0 screen = pygame.display.set_mode((320, 240)) frame = 0 playCow = False while True: print frame, beat # HANDLE EVENTS for event in pygame.event.get(): if event.type == QUIT: sys.exit() if event.type == KEYDOWN and event.key == K_SPACE: cowbell.play() # print beat beep.play() # lbeat = beat % 4 if beat == 0 or beat==2: noise.play() if frame == 15: # UPDATE BEAT beat += 1 if beat==4: beat=0 frame = 0 # add frame counter frame += 1 clock.tick(30)
The solution is to move the "drum machine" code (the two play commands) inside the if block (so only when the beat changes, are new sounds triggered).
#!python import sys, pygame from pygame.locals import * pygame.init() pygame.mixer.init() beep = pygame.mixer.Sound("08.wav") noise = pygame.mixer.Sound("noise.wav") cowbell = pygame.mixer.Sound("hi.wav") clock = pygame.time.Clock() bpm = 120 fps = float(bpm) / 60 beat = 0 screen = pygame.display.set_mode((320, 240)) frame = 0 playCow = False while True: print frame, beat # HANDLE EVENTS for event in pygame.event.get(): if event.type == QUIT: sys.exit() if event.type == KEYDOWN and event.key == K_SPACE: cowbell.play() if frame == 15: # UPDATE BEAT beat += 1 if beat==4: beat=0 frame = 0 # print beat beep.play() # lbeat = beat % 4 if beat == 0 or beat==2: noise.play() # add frame counter frame += 1 clock.tick(30)