OneLoopDrumMachine: Difference between revisions
No edit summary |
No edit summary |
||
(One intermediate revision by the same user not shown) | |||
Line 1: | Line 1: | ||
using [[PyGame]] | using [[PyGame]] | ||
Line 7: | Line 6: | ||
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. | ||
Line 18: | Line 17: | ||
So playing the sound with [[PyGame]]: | So playing the sound with [[PyGame]]: | ||
< | <source lang="python"> | ||
import pygame | import pygame | ||
pygame.init() | pygame.init() | ||
Line 29: | Line 27: | ||
while True: | while True: | ||
pass | pass | ||
</ | </source> | ||
Now with a clock to control the rhythm: | Now with a clock to control the rhythm: | ||
< | <source lang="python"> | ||
import pygame | import pygame | ||
pygame.init() | pygame.init() | ||
Line 48: | Line 45: | ||
cow.play() ## plays in background (like & ) | cow.play() ## plays in background (like & ) | ||
clock.tick(fps) | clock.tick(fps) | ||
</ | </source> | ||
Exercise: | Exercise: | ||
Line 61: | Line 58: | ||
[[Image:Beatpattern_wb.png]] | |||
< | <source lang="python"> | ||
import pygame | import pygame | ||
pygame.init() | pygame.init() | ||
Line 86: | Line 82: | ||
if beat==4: beat=0 | if beat==4: beat=0 | ||
clock.tick(fps) | clock.tick(fps) | ||
</ | </source> | ||
This is a buggy version of an attempt to make the rhythm loop more responsive to the keyboard: | This is a buggy version of an attempt to make the rhythm loop more responsive to the keyboard: | ||
< | <source lang="python"> | ||
import sys, pygame | import sys, pygame | ||
from pygame.locals import * | from pygame.locals import * | ||
Line 138: | Line 133: | ||
clock.tick(30) | clock.tick(30) | ||
</ | </source> | ||
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). | 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). | ||
< | <source lang="python"> | ||
import sys, pygame | import sys, pygame | ||
from pygame.locals import * | from pygame.locals import * | ||
Line 191: | Line 185: | ||
clock.tick(30) | clock.tick(30) | ||
</ | </source> |
Latest revision as of 12:09, 21 May 2008
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:
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:
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 |
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:
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).
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)