OneLoopDrumMachine: Difference between revisions

From XPUB & Lens-Based wiki
No edit summary
 
Line 1: Line 1:
= One Loop Drum Machine =
using [[PyGame]]
using [[PyGame]]


Line 18: Line 17:


So playing the sound with [[PyGame]]:
So playing the sound with [[PyGame]]:
<pre>
<source lang="python">
#!python
import pygame
import pygame
pygame.init()
pygame.init()
Line 29: Line 27:
while True:
while True:
pass
pass
</pre>
</source>


Now with a clock to control the rhythm:
Now with a clock to control the rhythm:
<pre>
<source lang="python">
#!python
import pygame
import pygame
pygame.init()
pygame.init()
Line 48: Line 45:
cow.play() ## plays in background (like &amp; )
cow.play() ## plays in background (like &amp; )
clock.tick(fps)
clock.tick(fps)
</pre>
</source>


Exercise:
Exercise:
Line 61: Line 58:




attachment:beatpattern_wb.png
[[Image:Beatpattern_wb.png]]


<pre>
<source lang="python">
#!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)
</pre>
</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:
<pre>
<source lang="python">
#!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)
</pre>
</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).


<pre>
<source lang="python">
#!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)
</pre>
</source>

Latest revision as of 13: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/

Hydrogen

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 &amp; )
	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


File:Beatpattern wb.png

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)