Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/library
diff options
context:
space:
mode:
authorC. Scott Ananian <cscott@laptop.org>2007-12-11 09:24:34 (GMT)
committer C. Scott Ananian <cscott@laptop.org>2007-12-11 09:24:34 (GMT)
commit9df72c5591aee015089a4e96f9403183262dcc01 (patch)
tree4a01e662068fe7977dbb4fd14e232fc7354863d4 /library
parent90c54afd7ea81be376b078eb08b87e4f20e71dcf (diff)
Factor out a pippy library, which programs can use with 'import pippy'.
The pygame portion of the library uses 'best practices' to avoid eating up CPU, and pauses & suspends after 20 seconds of inactivity.
Diffstat (limited to 'library')
-rw-r--r--library/pippy/__init__.py9
-rw-r--r--library/pippy/console.py5
-rw-r--r--library/pippy/game.py61
-rwxr-xr-xlibrary/pippy/sound.py210
4 files changed, 285 insertions, 0 deletions
diff --git a/library/pippy/__init__.py b/library/pippy/__init__.py
new file mode 100644
index 0000000..8ddcc7e
--- /dev/null
+++ b/library/pippy/__init__.py
@@ -0,0 +1,9 @@
+"""Pippy standard library."""
+import pippy.console as console
+import pippy.game as pygame
+import pippy.sound as sound
+
+def wait(delay=0.1):
+ """Pause briefly, for animations."""
+ import time
+ time.sleep(delay)
diff --git a/library/pippy/console.py b/library/pippy/console.py
new file mode 100644
index 0000000..cdbb023
--- /dev/null
+++ b/library/pippy/console.py
@@ -0,0 +1,5 @@
+"""Console helpers for pippy."""
+def clear():
+ """Clear screen on console."""
+ # magic escape sequence
+ print '\x1B[H\x1B[J' # clear screen
diff --git a/library/pippy/game.py b/library/pippy/game.py
new file mode 100644
index 0000000..e5996fa
--- /dev/null
+++ b/library/pippy/game.py
@@ -0,0 +1,61 @@
+"""pygame support for pippy."""
+
+import pygame
+
+def pause():
+ # display a "Paused" screen and suspend.
+ caption, icon_caption = pygame.display.get_caption()
+ screen = pygame.display.get_surface()
+ old_screen = screen.copy() # save this for later.
+
+ # dim the screen and display the 'paused' message in the center.
+ BLACK = (0,0,0)
+ WHITE = (255,255,255)
+ dimmed = screen.copy()
+ dimmed.set_alpha(128)
+ screen.fill(WHITE)
+ screen.blit(dimmed, (0,0))
+ font = pygame.font.Font(None, 36) # 36px high
+ msg = " PAUSED "
+ msg_surf = font.render(msg, True, BLACK, WHITE)
+ def center(rect, screen):
+ rect.center = (screen.get_width()/2, screen.get_height()/2)
+
+ rect = pygame.Rect((0,0),msg_surf.get_size())
+ rect.inflate_ip(rect.width, rect.height)
+ center(rect, screen)
+ screen.fill(WHITE, rect)
+ rect = msg_surf.get_rect()
+ center(rect, screen)
+ screen.blit(msg_surf, rect)
+ pygame.display.flip()
+
+ # SUSPEND
+ try:
+ open('/sys/power/state','w').write('mem')
+ except: # XXX: couldn't suspend (no permissions?)
+ pygame.event.post(pygame.event.wait())
+
+ pygame.display.set_caption(caption, icon_caption)
+ screen.blit(old_screen, (0,0))
+ pygame.display.flip()
+
+_last_event_time=0
+def next_frame(max_fps=20, idle_timeout=20, clock=pygame.time.Clock()):
+ """Limit maximum frame rate of pygame. Returns True.
+
+ If idle longer than the idle_timeout (in seconds), then we'll put up a
+ "paused" message and the XO will suspend. This ensures that we don't
+ burn up all of our battery running an animation!"""
+ global _last_event_time
+ clock.tick(max_fps)
+
+ if pygame.event.peek(xrange(pygame.NOEVENT, pygame.USEREVENT)):
+ # we're not idle anymore.
+ _last_event_time = pygame.time.get_ticks()
+ elif (pygame.time.get_ticks() - _last_event_time) >= idle_timeout*1000:
+ # we've been idle for a long time. Pause & suspend.
+ pause()
+ _last_event_time = pygame.time.get_ticks()
+
+ return True
diff --git a/library/pippy/sound.py b/library/pippy/sound.py
new file mode 100755
index 0000000..b84cbe6
--- /dev/null
+++ b/library/pippy/sound.py
@@ -0,0 +1,210 @@
+#! /usr/bin/env python
+
+# added frequency modulation genertor
+# audioOut write a wave file if a string is given as argument
+import os
+from sugar import env
+from sugar.activity.activity import get_bundle_path
+
+orchlines = []
+scorelines = []
+instrlist = []
+fnum = [100]
+
+temp_path = env.get_profile_path() + '/pippy'
+if not os.path.isdir(temp_path):
+ os.mkdir(temp_path)
+
+def quit(self):
+ perf.Stop()
+ perf.Join()
+ cs.Reset()
+ cs = None
+
+def defAdsr(attack=0.01, decay=0.1, sustain=0.8, release=0.1):
+ """Define an ADSR envelope. fnum = defADSR(attack = [0.01], decay = [0.1], sustain = [0.8], release = [0.1])"""
+ att = int(2048 * attack)
+ dec = int(2048 * decay)
+ rel = int(2048 * release)
+ bal = 2048 - (att + dec + rel)
+ sus = min(1., sustain)
+
+ fnum[0] += 1
+ scorelines.append("f%ld 0 2048 7 0 %ld 1. %ld %f %ld %f %ld 0\n" % (fnum[0], att, dec, sus, bal, sus, rel))
+ return fnum[0]
+
+def defLineSegments(list=[0,10,1,10,0,10,1,10,0]):
+ """Define a breakpoints envelope. list=[0,10,1,10,0,10,1,10,0]. list begin with the start value of the function and is follow by any pair values (duration, value). The number of elements in the list should odd."""
+
+ totalLength = 0
+ newlist = []
+ for i in range(len(list)):
+ if (i % 2) == 1:
+ totalLength += list[i]
+
+ for i in range(len(list)):
+ if (i % 2) == 0: newlist.append(list[i])
+ else: newlist.append(int(2048 * (list[i] / float(totalLength))))
+
+ fnum[0] += 1
+ scorelines.append("f" + str(fnum[0]) + " 0 2048 -7 " + " ".join([str(n) for n in newlist]) + '\n')
+ return fnum[0]
+
+def defComplexWave(list=[1,0,0,.3,0,.2,0,0,.1]):
+ """Define a complex waveform to be read with 'playComplex' function. list=[1,0,0,.3,0,.2,0,0,.1]
+is a list of amplitude for succesive harmonics of a waveform"""
+ fnum[0] += 1
+ scorelines.append("f" + str(fnum[0]) + " 0 2048 10 " + " ".join([str(n) for n in list]) + '\n')
+ return fnum[0]
+
+def playSine( pitch=1000, amplitude=5000, duration=1, starttime=0, pitch_envelope='default', amplitude_envelope='default'):
+ """Play a sine wave (pitch = [1000], amplitude = [5000], duration = [1], starttime = [0], pitch_envelope=['default'], amplitude_envelope=['default'])"""
+ _play(pitch, amplitude, duration, starttime, pitch_envelope, amplitude_envelope, 1)
+
+def playSquare( pitch=1000, amplitude=5000, duration=1, starttime=0, pitch_envelope='default', amplitude_envelope='default'):
+ """Play a square wave (pitch = [1000], amplitude = [5000], duration = [1], starttime = [0], pitch_envelope=['default'], amplitude_envelope=['default'])"""
+ _play(pitch, amplitude, duration, starttime, pitch_envelope, amplitude_envelope, 2)
+
+def playSawtooth( pitch=1000, amplitude=5000, duration=1, starttime=0, pitch_envelope='default', amplitude_envelope='default'):
+ """Play a sawtooth wave (pitch = [1000], amplitude = [5000], duration = [1], starttime = [0], pitch_envelope=['default'], amplitude_envelope=['default'])"""
+ _play(pitch, amplitude, duration, starttime, pitch_envelope, amplitude_envelope, 3)
+
+def playComplex( pitch=1000, amplitude=5000, duration=1, starttime=0, pitch_envelope='default', amplitude_envelope='default', wave='default'):
+ """Play a complex wave (pitch = [1000], amplitude = [5000], duration = [1], starttime = [0], pitch_envelope = ['default'], amplitude_envelope, wave = ['default'] )"""
+ if wave == 'default': wavetable = 10
+ else: wavetable = wave
+ _play(pitch, amplitude, duration, starttime, pitch_envelope, amplitude_envelope, wavetable)
+
+def _play( pitch, amplitude, duration, starttime, pitch_envelope, amplitude_envelope, instrument):
+ if pitch_envelope == 'default': pitenv = 99
+ else: pitenv = pitch_envelope
+
+ if amplitude_envelope == 'default': ampenv = 100
+ else: ampenv = amplitude_envelope
+
+ if not 1 in instrlist:
+ orchlines.append("instr 1\n")
+ orchlines.append("kpitenv oscil 1, 1/p3, p6\n")
+ orchlines.append("aenv oscil 1, 1/p3, p7\n")
+ orchlines.append("asig oscil p5*aenv, p4*kpitenv, p8\n")
+ orchlines.append("out asig\n")
+ orchlines.append("endin\n\n")
+ instrlist.append(1)
+
+ scorelines.append("i1 %s %s %s %s %s %s %s\n" % (str(starttime), str(duration), str(pitch), str(amplitude), str(pitenv), str(ampenv), str(instrument)))
+
+def playFrequencyModulation( pitch=500, amplitude=5000, duration=2, starttime=0, carrier=1, modulator=.5, index=5, pitch_envelope='default', amplitude_envelope='default', carrier_envelope='default', modulator_envelope='default', index_envelope='default', wave='default'):
+ """Play a frequency modulation synthesis sound (pitch = [100], amplitude = [5000], duration = [2], starttime = [0], carrier = [1], modulator = [.5], index = [5], pitch_envelope = ['default'], amplitude_envelope = ['default'], carrier_envelope = ['default'], modulator_envelope = ['default'], index_envelope = ['default'], wave = ['default'] )"""
+ if pitch_envelope == 'default': pitenv = 99
+ else: pitenv = pitch_envelope
+
+ if amplitude_envelope == 'default': ampenv = 100
+ else: ampenv = amplitude_envelope
+
+ if carrier_envelope == 'default': carenv = 99
+ else: carenv = carrier_envelope
+
+ if modulator_envelope == 'default': modenv = 99
+ else: modenv = modulator_envelope
+
+ if index_envelope == 'default': indenv = 99
+ else: indenv = index_envelope
+
+ if wave == 'default': wavetable = 1
+ else: wavetable = wave
+
+ if not 7 in instrlist:
+ orchlines.append("instr 7\n")
+ orchlines.append("kpitenv oscil 1, 1/p3, p10\n")
+ orchlines.append("kenv oscil 1, 1/p3, p11\n")
+ orchlines.append("kcarenv oscil 1, 1/p3, p12\n")
+ orchlines.append("kmodenv oscil 1, 1/p3, p13\n")
+ orchlines.append("kindenv oscil 1, 1/p3, p14\n")
+ orchlines.append("asig foscil p5*kenv, p4*kpitenv, p6*kcarenv, p7*kmodenv, p8*kindenv, p9\n")
+ orchlines.append("out asig\n")
+ orchlines.append("endin\n\n")
+ instrlist.append(7)
+
+ scorelines.append("i7 %s %s %s %s %s %s %s %s %s %s %s %s %s\n" % (str(starttime), str(duration), str(pitch), str(amplitude), str(carrier), str(modulator), str(index), str(wavetable), str(pitenv), str(ampenv), str(carenv), str(modenv), str(indenv)))
+
+def playPluck( pitch=100, amplitude=5000, duration=2, starttime=0, pitch_envelope='default', amplitude_envelope='default'):
+ """Play a string physical modeling sound (pitch = [100], amplitude = [5000], duration = [2], starttime = [0], pitch_envelope = ['default'], amplitude_envelope )"""
+ if pitch_envelope == 'default': pitenv = 99
+ else: pitenv = pitch_envelope
+
+ if amplitude_envelope == 'default': ampenv = 100
+ else: ampenv = amplitude_envelope
+
+ if not 8 in instrlist:
+ orchlines.append("instr 8\n")
+ orchlines.append("kpitenv oscil 1, 1/p3, p6\n")
+ orchlines.append("kenv oscil 1, 1/p3, p7\n")
+ orchlines.append("asig pluck p5*kenv, p4*kpitenv, 40, 0, 6\n")
+ orchlines.append("asig butterlp asig, 4000\n")
+ orchlines.append("out asig\n")
+ orchlines.append("endin\n\n")
+ instrlist.append(8)
+
+ scorelines.append("i8 %s %s %s %s %s %s\n" % (str(starttime), str(duration), str(pitch), str(amplitude), str(pitenv), str(ampenv)))
+
+def playWave(sound='horse', pitch=1, amplitude=1, loop=False, duration=1, starttime=0, pitch_envelope='default', amplitude_envelope='default'):
+ """Play a wave file (sound = ['horse'], pitch = [1], amplitude = [1], loop = [False], duration = [1], starttime = [0], pitch_envelope=['default'], amplitude_envelope=['default'])"""
+ fullname = '/usr/share/activities/TamTamEdit.activity/common/Resources/Sounds/' + str(sound)
+
+ if loop == False: lp = 0
+ else: lp = 1
+
+ if pitch_envelope == 'default': pitenv = 99
+ else: pitenv = pitch_envelope
+
+ if amplitude_envelope == 'default': ampenv = 100
+ else: ampenv = amplitude_envelope
+
+ if not 9 in instrlist:
+ orchlines.append("instr 9\n")
+ orchlines.append("kpitenv oscil 1, 1/p3, p8\n")
+ orchlines.append("aenv oscil 1, 1/p3, p9\n")
+ orchlines.append("asig diskin p4, p5*kpitenv, 0, p7\n")
+ orchlines.append("out asig*p6*aenv\n")
+ orchlines.append("endin\n\n")
+ instrlist.append(9)
+
+ scorelines.append('i9 %f %f "%s" %s %s %s %s %s\n' % (float(starttime), float(duration), fullname, str(pitch), str(amplitude), str(lp), str(pitenv), str(ampenv)))
+
+def getSoundList():
+ return sorted(os.listdir('/usr/share/activities/TamTamEdit.activity/common/Resources/Sounds/'))
+
+def audioOut(file=None):
+ """Compile a .csd file and start csound to run it. If a string is given as argument, it write a wave file on disk instead of sending sound to hp. (file = [None])"""
+ path = temp_path
+ csd = open(path + "/temp.csd", "w")
+ csd.write("<CsoundSynthesizer>\n\n")
+ csd.write("<CsOptions>\n")
+ if file == None:
+ csd.write("-+rtaudio=alsa -odevaudio -m0 -d -b256 -B512\n")
+ else:
+ file = path + "/" + str(file) + ".wav"
+ csd.write("-+rtaudio=alsa -o%s -m0 -W -d -b256 -B512\n" % file)
+ csd.write("</CsOptions>\n\n")
+ csd.write("<CsInstruments>\n\n")
+ csd.write("sr=16000\n")
+ csd.write("ksmps=50\n")
+ csd.write("nchnls=1\n\n")
+ for line in orchlines:
+ csd.write(line)
+ csd.write("\n</CsInstruments>\n\n")
+ csd.write("<CsScore>\n\n")
+ csd.write("f1 0 2048 10 1\n")
+ csd.write("f2 0 2048 10 1 0 .33 0 .2 0 .143 0 .111\n")
+ csd.write("f3 0 2048 10 1 .5 .33 .25 .2 .175 .143 .125 .111 .1\n")
+ csd.write("f10 0 2048 10 1 0 0 .3 0 .2 0 0 .1\n")
+ csd.write("f99 0 2048 7 1 2048 1\n")
+ csd.write("f100 0 2048 7 0. 10 1. 1900 1. 132 0.\n")
+ for line in scorelines:
+ csd.write(line)
+ csd.write("e\n")
+ csd.write("\n</CsScore>\n")
+ csd.write("\n</CsoundSynthesizer>")
+ csd.close()
+
+ os.system('csound ' + path + '/temp.csd >/dev/null 2>/dev/null')