CS170: Programming for the World Around Us - Graphics and Sound with Python
Activity Goals
The goals of this activity are:- To use graphics and sound capabilities in Python
The Activity
Directions
Consider the activity models and answer the questions provided. First reflect on these questions on your own briefly, before discussing and comparing your thoughts with your group. Appoint one member of your group to discuss your findings with the class, and the rest of the group should help that member prepare their response. Answer each question individually from the activity, and compare with your group to prepare for our whole-class discussion. After class, think about the questions in the reflective prompt and respond to those individually in your notebook. Report out on areas of disagreement or items for which you and your group identified alternative approaches. Write down and report out questions you encountered along the way for group discussion.Model 1: Graphics
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | from ezgraphics import GraphicsWindow win = GraphicsWindow( 640 , 480 ) win.setTitle( "My First Drawing" ) canvas = win.canvas() canvas.setFill( 255 , 0 , 0 ) canvas.drawRectangle( 40 , 40 , 100 , 200 ) canvas.setFill( 255 , 255 , 255 ) canvas.setOutline( 0 , 255 , 0 ) canvas.drawRectangle( 200 , 200 , 150 , 50 ) win.wait() |
Questions
- Run this code in your terminal:
http://www.ezgraphics.org/uploads/Software/Download/ezgraphics-2.2.tar.gz && pip install ezgraphics-2.2.tar.gz
to install the ezgraphics library, and run this program. What does it do? - Experiment with the functions and generate your own shapes. Can you draw a house or a stick figure? Make a function that does this, given the
x
andy
midpoint as parameters.
Model 2: Animation
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | from ezgraphics import GraphicsWindow import random win = GraphicsWindow( 640 , 480 ) win.setTitle( "My First Drawing" ) i = 0 j = 0 lasti = - 1 lastj = - 1 canvas = win.canvas() canvas.setFill( 0 , 0 , 0 ) canvas.drawRectangle( 0 , 0 , 640 , 480 ) while True : if i > 0 and j > 0 : canvas.setFill( 0 , 0 , 0 ) canvas.drawRectangle(i - 1 , j - 1 , 10 , 20 ) canvas.setFill( 255 , 255 , 255 ) canvas.drawRectangle(i, j, 10 , 20 ) lasti = i lastj = j i = i + random.randint( - 1 , 1 ) j = j + random.randint( - 1 , 1 ) if i > 640 : i = 639 if j > 480 : j = 479 if i < 0 : i = 1 if j < 0 : j = 1 win.pause( 1 ) win.wait() |
Questions
- Comment this program; what does it do? You will find it helpful to run the program first, and may find it helpful to set a breakpoint and use the debugger!
Model 3: Sound
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | """Play a fixed frequency sound.""" from __future__ import division import math from scipy import signal from pyaudio import PyAudio # sudo apt-get install python{,3}-pyaudio try : from itertools import izip except ImportError: # Python 3 izip = zip xrange = range def sine_tone(frequency, duration, volume = 1 , sample_rate = 22050 ): n_samples = int (sample_rate * duration) restframes = n_samples % sample_rate p = PyAudio() stream = p. open ( format = p.get_format_from_width( 1 ), # 8bit channels = 1 , # mono rate = sample_rate, output = True ) s = lambda t: volume * math.sin( 2 * math.pi * frequency * t / sample_rate) samples = ( int (s(t) * 0x7f + 0x80 ) for t in xrange (n_samples)) if duration > = 1 : sample_size = sample_rate else : sample_size = int (sample_rate * duration) for buf in izip( * [samples] * sample_size): # write several samples at a time stream.write(bytes(bytearray(buf))) # fill remainder of frameset with silence stream.write(b '\x80' * restframes) stream.stop_stream() stream.close() p.terminate() def square_tone(frequency, duration, volume = 1 , sample_rate = 22050 ): n_samples = int (sample_rate * duration) restframes = n_samples % sample_rate p = PyAudio() stream = p. open ( format = p.get_format_from_width( 1 ), # 8bit channels = 1 , # mono rate = sample_rate, output = True ) s = lambda t: volume * signal.square( 2 * math.pi * frequency * t / sample_rate) samples = ( int (s(t) * 0x7f + 0x80 ) for t in xrange (n_samples)) if duration > = 1 : sample_size = sample_rate else : sample_size = int (sample_rate * duration) for buf in izip( * [samples] * sample_size): # write several samples at a time stream.write(bytes(bytearray(buf))) # fill remainder of frameset with silence stream.write(b '\x80' * restframes) stream.stop_stream() stream.close() p.terminate() def dtmf_tone(frequency1, frequency2, duration, volume = 1 , sample_rate = 22050 ): n_samples = int (sample_rate * duration) restframes = n_samples % sample_rate p = PyAudio() stream = p. open ( format = p.get_format_from_width( 1 ), # 8bit channels = 1 , # mono rate = sample_rate, output = True ) s1 = lambda t: volume * math.sin( 2 * math.pi * frequency1 * t / sample_rate) s2 = lambda t: volume * math.sin( 2 * math.pi * frequency2 * t / sample_rate) samples = ( int (s1(t) * 0x3f + 0x40 ) + int (s2(t) * 0x3f + 0x40 ) for t in xrange (n_samples)) # scale to 0-255 if duration > = 1 : sample_size = sample_rate else : sample_size = int (sample_rate * duration) for buf in izip( * [samples] * sample_size): # write several samples at a time stream.write(bytes(bytearray(buf))) # fill remainder of frameset with silence stream.write(b '\x80' * restframes) stream.stop_stream() stream.close() p.terminate() def sine_chord(frequencies, duration, volume = 1 , sample_rate = 22050 ): if len (frequencies) > = 6 : frequencies = frequencies[: 6 ] n_samples = int (sample_rate * duration) restframes = n_samples % sample_rate p = PyAudio() stream = p. open ( format = p.get_format_from_width( 1 ), # 8bit channels = 1 , # mono rate = sample_rate, output = True ) s = [] k = len (frequencies) for i in range (k): f = frequencies[i] sf = lambda t: volume * math.sin(( 2 * math.pi * f * t / sample_rate)) s.append(sf) z = lambda t: sum ([ int (x(t) * ( 2 * * ( 8 - k) - 1 ) + 2 * * ( 8 - k)) for x in s]) samples = (z(t) for t in xrange (n_samples)) # scale to 0-255 if duration > = 1 : sample_size = sample_rate else : sample_size = int (sample_rate * duration) for buf in izip( * [samples] * sample_size): # write several samples at a time stream.write(bytes(bytearray(buf))) # fill remainder of frameset with silence stream.write(b '\x80' * restframes) stream.stop_stream() stream.close() p.terminate() |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | import sounds DTMF_TABLE = { "1" : [ 1209 , 697 ], "2" : [ 1336 , 697 ], "3" : [ 1477 , 697 ], "A" : [ 1633 , 697 ], "4" : [ 1209 , 770 ], "5" : [ 1336 , 770 ], "6" : [ 1477 , 770 ], "B" : [ 1633 , 770 ], "7" : [ 1209 , 852 ], "8" : [ 1336 , 852 ], "9" : [ 1477 , 852 ], "C" : [ 1633 , 852 ], "*" : [ 1209 , 941 ], "0" : [ 1336 , 941 ], "#" : [ 1477 , 941 ], "D" : [ 1633 , 941 ], "dial_tone" : [ 350 , 440 ] } #sounds.sine_tone(2000, 0.5, volume=0.25) #sounds.square_tone(2000, 0.25, volume=0.25) sounds.dtmf_tone( * DTMF_TABLE[ 'dial_tone' ], 2 , volume = 0.25 ) # dial tone: 350, 400 sounds.dtmf_tone( * DTMF_TABLE[ '6' ], 0.25 , volume = 0.25 ) sounds.dtmf_tone( * DTMF_TABLE[ '1' ], 0.25 , volume = 0.25 ) sounds.dtmf_tone( * DTMF_TABLE[ '0' ], 0.25 , volume = 0.25 ) sounds.dtmf_tone( * DTMF_TABLE[ '4' ], 0.25 , volume = 0.25 ) sounds.dtmf_tone( * DTMF_TABLE[ '0' ], 0.25 , volume = 0.25 ) sounds.dtmf_tone( * DTMF_TABLE[ '9' ], 0.25 , volume = 0.25 ) sounds.dtmf_tone( * DTMF_TABLE[ '3' ], 0.25 , volume = 0.25 ) sounds.dtmf_tone( * DTMF_TABLE[ '2' ], 0.25 , volume = 0.25 ) sounds.dtmf_tone( * DTMF_TABLE[ '6' ], 0.25 , volume = 0.25 ) sounds.dtmf_tone( * DTMF_TABLE[ '8' ], 0.25 , volume = 0.25 ) C = 261.63 E = 329.63 G = 392 sounds.sine_chord([C, E, G], 1 , volume = 0.25 ) |
Questions
- Save these two files into your program (call the first one
sounds.py
since weimport sounds
in the second file!) and run it. - Look up DTMF tones; what is this program doing?
- Make a song with some tones and play the program. You might try this with the microbit to see what kinds of notes it plays when you play a melody; you can copy the frequencies into this program.