Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
b83f917
Rudimentary listener
Mar 3, 2016
4b34e20
added gitignore
Mar 3, 2016
156f5a8
first pass at pygame audio generation, class not impemented yet
jaredbriskman Mar 3, 2016
e1b6e7c
Merge branch 'master' of https://github.com/jaredbriskman/Interactive…
jaredbriskman Mar 3, 2016
52c40d3
Broken MVC implementation, but progress
jaredbriskman Mar 5, 2016
bb170d3
tried to fix MVC, still having update problems
Mar 7, 2016
6bf4685
working keylistener
Mar 7, 2016
bde48ed
added bass and lead WAV samples
jaredbriskman Mar 9, 2016
fd580db
Added lead and bass WAV samples
jaredbriskman Mar 9, 2016
51252c5
Merge branch 'master' of https://github.com/jaredbriskman/Interactive…
jaredbriskman Mar 9, 2016
6195d44
Merge branch 'master' of github.com:jaredbriskman/InteractiveProgramm…
Mar 9, 2016
5a199b5
resolved merge conflicts
Mar 9, 2016
e864773
working test
Mar 9, 2016
765581d
made list generation work
Mar 9, 2016
ac520fb
making a sample board. loops through and should have player that impo…
Mar 10, 2016
bdf027f
Merge branch 'dev' of https://github.com/jaredbriskman/InteractivePro…
jaredbriskman Mar 10, 2016
5fb5a15
samples and samplelist
jaredbriskman Mar 10, 2016
8edc605
imported and refactored some things, moved threading out of classes
Mar 10, 2016
537e39f
Added beep and piano scale samples
jaredbriskman Mar 10, 2016
70aa303
Merge branch 'dev' of github.com:jaredbriskman/InteractiveProgramming…
Mar 10, 2016
ec43e73
Getting audio files and info
Mar 10, 2016
d06716c
dialog box object code with tkinter
jaredbriskman Mar 10, 2016
50c3847
almost a working MVC
Mar 10, 2016
4354484
getting Tkinter gui
Mar 10, 2016
b1e2217
got it to not crash on exit
Mar 10, 2016
f9061f8
made it work with arrhythmic impressionist sound sampling. +1 prime z…
Mar 10, 2016
240272a
Added more samples, fixed samplelist
jaredbriskman Mar 10, 2016
c9978d9
Merge branch 'dev' of https://github.com/jaredbriskman/InteractivePro…
jaredbriskman Mar 10, 2016
f886b32
Added documentation
Mar 10, 2016
aea2b09
Merge branch 'dev' of github.com:jaredbriskman/InteractiveProgramming…
Mar 10, 2016
8fe4ab9
fixed tuple exit issue
Mar 10, 2016
5938af7
speaker.bmp
jaredbriskman Mar 10, 2016
595cb17
added image support
Mar 10, 2016
92c41bb
Merge branch 'dev' of https://github.com/jaredbriskman/InteractivePro…
jaredbriskman Mar 10, 2016
6bc5ddb
added image support
Mar 10, 2016
385e0bd
Readme updated
jaredbriskman Mar 10, 2016
6851adc
added report
Mar 10, 2016
0b176fb
Merge branch 'master' of github.com:jaredbriskman/InteractiveProgramming
Mar 10, 2016
063acf6
added time.clock based looping
Mar 10, 2016
bdda8e8
worked out threaded timing, corrects drift
Mar 10, 2016
fc22a02
additional timing tweak
Mar 10, 2016
d03a469
Implemented time-based drift correction
Mar 10, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg
Binary file added InteractiveProgramming.pdf
Binary file not shown.
47 changes: 47 additions & 0 deletions KeyListener.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
"""A listener class that turns on and off keys in the Synthesis class"""
from pygame.key import *
import pygame
import time
import sys

#holds onto keys we're looking for
keys = [pygame.K_0, pygame.K_1, pygame.K_2, pygame.K_3, pygame.K_4, pygame.K_5, pygame.K_6, pygame.K_7, pygame.K_8, pygame.K_9, pygame.K_PLUS, pygame.K_MINUS,
pygame.K_a, pygame.K_b, pygame.K_c, pygame.K_d, pygame.K_e, pygame.K_f, pygame.K_g, pygame.K_h, pygame.K_i, pygame.K_j, pygame.K_k, pygame.K_l, pygame.K_m,
pygame.K_n, pygame.K_o, pygame.K_p, pygame.K_q, pygame.K_r, pygame.K_s, pygame.K_t, pygame.K_u, pygame.K_v, pygame.K_w, pygame.K_x, pygame.K_y, pygame.K_z]

class KeyListener(object):
"""
This class implements the Controller in our MVC. It uses a separate thread to
loop through the event queue, looking for keyboard events and passing the
corresponding sounds into the Model.
"""

def __init__(self, synth=None, filename='samplelist.txt'):
"""This method initializes the KeyListener and reads in the sound sample
names from a text file.
"""
self.synth = synth
f = open(filename)
samplenames = f.readlines()
self.soundmap = {keys[i]:samplenames[i][:-5] for i in range(len(keys))}

def main(self):
"""This method loops through the pygame event queue checking for key
presses or for a quit event.
"""
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
self.synth.loop[self.synth.count].append(self.soundmap.get(event.key, 'Zoom'))
# print self.soundmap.get(event.key, 'Zoom')
if event.type == pygame.QUIT:
self.synth.playq.put(('exit',))
sys.exit()

if __name__ == '__main__':
pygame.init()
_display_surf = pygame.display.set_mode((300, 300), pygame.HWSURFACE | pygame.DOUBLEBUF)
_running = True
k = KeyListener()
while True:
k.main()
time.sleep(.01)
16 changes: 15 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,16 @@
# InteractiveProgramming
This is the base repo for the interactive programming project for Software Design, Spring 2016 at Olin College.
SampleScape2k17 is an Interactive Programming project for Olin College Spring 2016 SoftDes.

To run, simply download the repository, and run synthesis.py

```
$ python synthesis.py
```

SampleScape2k17 requires PyGame and TKinter.

To install these packages:

```
$ sudo apt-get install python-pygame python-tk
```
Binary file added Samples/2012.wav
Binary file not shown.
Binary file added Samples/808.wav
Binary file not shown.
Binary file added Samples/BANG.wav
Binary file not shown.
Binary file added Samples/BassSaw.wav
Binary file not shown.
Binary file added Samples/Beep.wav
Binary file not shown.
Binary file added Samples/Boats.wav
Binary file not shown.
Binary file added Samples/Cats.wav
Binary file not shown.
Binary file added Samples/Chord.wav
Binary file not shown.
Binary file added Samples/Clank.wav
Binary file not shown.
Binary file added Samples/Clap.wav
Binary file not shown.
Binary file added Samples/Crash.wav
Binary file not shown.
Binary file added Samples/Done.wav
Binary file not shown.
Binary file added Samples/Kick.wav
Binary file not shown.
Binary file added Samples/MVC.wav
Binary file not shown.
Binary file added Samples/Meow1.wav
Binary file not shown.
Binary file added Samples/Meow2.wav
Binary file not shown.
Binary file added Samples/Pruves.wav
Binary file not shown.
Binary file added Samples/RealClap.wav
Binary file not shown.
Binary file added Samples/Ring.wav
Binary file not shown.
Empty file added Samples/SampleNames.txt~
Empty file.
Binary file added Samples/Shake.wav
Binary file not shown.
Binary file added Samples/Tap.wav
Binary file not shown.
Binary file added Samples/Tss.wav
Binary file not shown.
Binary file added Samples/YEAHYEAHYEAH.wav
Binary file not shown.
Binary file added Samples/Yeah.wav
Binary file not shown.
Binary file added Samples/Zoom.wav
Binary file not shown.
Binary file added Samples/a1.wav
Binary file not shown.
Binary file added Samples/a1s.wav
Binary file not shown.
Binary file added Samples/b1.wav
Binary file not shown.
Binary file added Samples/c1.wav
Binary file not shown.
Binary file added Samples/c1s.wav
Binary file not shown.
Binary file added Samples/c2.wav
Binary file not shown.
Binary file added Samples/d1.wav
Binary file not shown.
Binary file added Samples/d1s.wav
Binary file not shown.
Binary file added Samples/e1.wav
Binary file not shown.
Binary file added Samples/f1.wav
Binary file not shown.
Binary file added Samples/f1s.wav
Binary file not shown.
Binary file added Samples/g1.wav
Binary file not shown.
Binary file added Samples/g1s.wav
Binary file not shown.
Binary file added bass1.wav
Binary file not shown.
26 changes: 26 additions & 0 deletions entrytest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import tkSimpleDialog
from Tkinter import *

import tkSimpleDialog

class MyDialog(tkSimpleDialog.Dialog):

def body(self, other):
Label(other, text="BPM:").grid(row=0)
Label(other, text="Bars:").grid(row=1)
self.e1 = Entry(other)
self.e2 = Entry(other)
self.e1.grid(row=0, column=1)
self.e2.grid(row=1, column=1)
return self.e1 # initial focus

def apply(self):
try:
first = int(self.e1.get())
second = int(self.e2.get())
except:
first, second = 120, 8
self.result = first, second

def values(self):
return self.result
Binary file added lead1.wav
Binary file not shown.
23 changes: 23 additions & 0 deletions pygame_play_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import pygame
import sys

pygame.mixer.init()

bass1 = pygame.mixer.Sound('bass1.wav')
lead1 = pygame.mixer.Sound('lead1.wav')

bass1.play()

pygame.init()
_display_surf = pygame.display.set_mode((300, 300), pygame.HWSURFACE | pygame.DOUBLEBUF)
_running = True

while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_1:
bass1.play()
if event.key == pygame.K_2:
lead1.play()
38 changes: 38 additions & 0 deletions samplelist.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
c1.wav
c1s.wav
d1.wav
d1s.wav
e1.wav
f1.wav
f1s.wav
g1.wav
g1s.wav
a1.wav
a1s.wav
b1.wav
c2.wav
Clank.wav
Clap.wav
Kick.wav
Ring.wav
Zoom.wav
Beep.wav
BassSaw.wav
Crash.wav
Chord.wav
Pruves.wav
BANG.wav
Yeah.wav
YEAHYEAHYEAH.wav
Shake.wav
MVC.wav
Boats.wav
2012.wav
808.wav
Tss.wav
Meow1.wav
Meow2.wav
Cats.wav
RealClap.wav
Tap.wav
Done.wav
Binary file added speaker.bmp
Binary file not shown.
162 changes: 162 additions & 0 deletions synthesis.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
import pygame
from pygame.mixer import *
from pygame.locals import *
import math
import numpy as np
from Queue import Queue
import threading
from threading import Thread
import time
from KeyListener import KeyListener
import sys
from Tkinter import Tk
import entrytest

SUBDIVISIONS = 8

class Synth(object):
"""This class holds onto the state of our synthesizer. It is the M in our MVC.
This class has a list of "16th notes", which are lists of sounds to be played.
As it loops through the list, it adds any key presses to the list and places
any sounds already in the list onto the playing queue.

attributes: bpm, bars, click, sleep_time
"""

def __init__(self, bpm=120, bars=8, click=True):
"""This method initializes the synthesizer's bpm, the length of the loop,
its sleep time, and sets up the empty sample loop.
"""
self.bpm = bpm
self.bars = bars
self.click = click
self.sleep_time = 60.0/(bpm/4) / SUBDIVISIONS
self.count = 0
self.loop = [[] for sub in range(bars * SUBDIVISIONS)]
self.loop = [self.loop[beat] + ['Beep'] if beat % 4 == 0 and click else self.loop[beat] for beat in range(len(self.loop))]
self.playq = Queue()

# def frequencyMap(self, index):
# return 2**(index/12.0) * 440


def main(self):
"""This method keeps track of our position in the sample loop and puts
any samples it finds in the current subdivision into the sound playing
queue.
"""
for e in self.loop[self.count]:
# Note that queues will take tuples, but will break up strings.
self.playq.put((e,))
self.count += 1
self.count = self.count % (self.bars * SUBDIVISIONS)


class Viewer(object):
"""This class is the View part of our MVC model. It runs in its own separate
thread, waiting for sounds to appear in its queue. It then maps those sounds
to pygame Sound objects and plays them.
"""
def __init__(self, synth=None, filename='samplelist.txt'):
"""This method handles initializing this class's synth, and also prepares
the name-sound mapping for playing sounds.
"""
if synth == None:
synth = Synth()
self.synth = synth

pygame.mixer.init()

f = open(filename)

#preparing the sound map
self.soundmap = {line.strip('\n')[:-4]:Sound('Samples/' + line.strip('\n')) for line in f.readlines()}
print self.soundmap

def main(self):
"""This method interprets the play queue, and plays sounds unless it
receives a special exit tag.
"""
for sound in self.synth.playq.get():
if sound == ('exit'):
break
self.soundmap[sound].play()

if __name__ == '__main__':
"""This main function is where a lot of learning happened. We went through
many iterations to get the threading to work properly. First, everything is
initialized, and then three threads are started, one on each of the classes'
main methods. Conditionals in these loops serve to clean up when the
controller receives an exit event.
"""

#pygame initialization
pygame.init()
_display_surf = pygame.display.set_mode((46,45), pygame.HWSURFACE | pygame.DOUBLEBUF)
_running = True
img = pygame.image.load('speaker.bmp')
_display_surf.blit(img, pygame.Surface.get_rect(img))

#synthesizer initialization
d = entrytest.MyDialog(Tk())
a = Synth(*d.values())
b = KeyListener(a)
c = Viewer(a, 'samplelist.txt')

#thread target functions
def _synthstart():
print 'running SYNTH'
global _running
next_loop = time.time()
print a.sleep_time
while _running:
#handles processing time and drift
next_loop += a.sleep_time
a.main()
try:
time.sleep(next_loop - time.time())
except:
pass

print 'finished SYNTH'

def _keylistenerstart():
'running KEYLISTENER'
try:
global _running
while _running:
b.main()
except SystemExit:
_running = False
pygame.quit()
print 'finished KEYLISTENER'

def _viewerstart():
print 'running VIEWER'
global _running
while _running:
c.main()
print 'finished VIEWER'

# def _exit():
# print 'running EXIT'
# while True:
# for event in pygame.event.get():
# if event.type == pygame.QUIT:
# _running = False
# pygame.quit()
# sys.exit()
k = Thread(target=_keylistenerstart, name='KEYLISTENER')
v = Thread(target=_viewerstart, name='VIEWER')
s = Thread(target=_synthstart, name='SYNTH')
# exit = Thread(target=_exit, name='EXIT')

# exit.start()
s.start()
k.start()
v.start()

s.join()
v.join()
k.join()
# exit.join()
8 changes: 8 additions & 0 deletions timingtest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import time

next_loop = time.time()

while True:
next_loop += 1
print 'hi'
time.sleep(next_loop - time.time())
Loading