from os import listdir
from os.path import join

from pygame.mixer import Channel, Sound, music, find_channel

from GameChild import *
from Input import *

class Audio(GameChild):

    current_channel = None
    paused = False
    muted = False

    def __init__(self, game):
        GameChild.__init__(self, game)
        self.delegate = self.get_delegate()
        self.load_fx()
        self.subscribe(self.respond)

    def load_fx(self):
        fx = {}
        if self.get_configuration().has_option("audio", "sfx-path"):
            root = self.get_resource("audio", "sfx-path")
            if root:
                for name in listdir(root):
                    fx[name.split(".")[0]] = Sound(join(root, name))
        self.fx = fx

    def respond(self, event):
        if self.delegate.compare(event, "mute"):
            self.mute()

    def mute(self):
        self.muted = True
        self.set_volume()

    def unmute(self):
        self.muted = False
        self.set_volume()

    def set_volume(self):
        volume = int(not self.muted)
        music.set_volume(volume)
        if self.current_channel:
            self.current_channel.set_volume(volume)

    def play_bgm(self, path, stream=False):
        self.stop_current_channel()
        if stream:
            music.load(path)
            music.play(-1)
        else:
            self.current_channel = Sound(path).play(-1)
        self.set_volume()

    def stop_current_channel(self):
        music.stop()
        if self.current_channel:
            self.current_channel.stop()
        self.current_channel = None
        self.paused = False

    def play_fx(self, name, panning=.5):
        if not self.muted:
            channel = find_channel(True)
            if panning != .5:
                offset = 1 - abs(panning - .5) * 2
                if panning < .5:
                    channel.set_volume(1, offset)
                else:
                    channel.set_volume(offset, 1)
            channel.play(self.fx[name])

    def pause(self):
        channel = self.current_channel
        paused = self.paused
        if paused:
            music.unpause()
            if channel:
                channel.unpause()
        else:
            music.pause()
            if channel:
                channel.pause()
        self.paused = not paused

    def is_bgm_playing(self):
        current = self.current_channel
        if current and current.get_sound():
            return True
        return music.get_busy()
import os
delattr(os, "link")

from dark_stew.pgfw.Setup import Setup

if __name__ == "__main__":
    Setup().setup()
from dark_stew.pgfw.SetupWin import SetupWin

if __name__ == "__main__":
    SetupWin().setup()
from math import sqrt
from random import choice

from pygame import Rect

from dark_stew.pgfw.GameChild import GameChild
from dark_stew.floor.Floor import Floor
from dark_stew.pool.Pools import Pools
from dark_stew.aphids.Aphids import Aphids

class World(GameChild, Rect):

    def __init__(self, parent):
        GameChild.__init__(self, parent)
        self.input = self.get_input()
        self.display_surface = self.get_display_surface()
        self.directions = 0, 1, 2, 3
        self.direction = self.directions[2]
        self.load_configuration()
        self.reset_active_directions()
        self.init_rect()
        self.pools = Pools(self)
        self.floor = Floor(self)
        self.aphids = Aphids(self)
        self.get_audio().play_bgm(self.get_resource("world", "audio-path"),
                                  True)
        self.scroll_to_random_intersection()

    def load_configuration(self):
        config = self.get_configuration("world")
        self.dimensions = config["dimensions"]
        self.walk_step = config["walk-step"]
        self.run_step = config["run-step"]

    def reset_active_directions(self):
        self.active_directions = [False, False, False, False]
        self.scroll_active = False

    def init_rect(self):
        Rect.__init__(self, (0, 0), self.dimensions)

    def scroll_to_random_intersection(self):
        pools = self.pools
        cx, cy = choice(pools).center
        step = pools.step / 2
        dx, dy = self.display_surface.get_rect().center
        self.shift(cx + dx + step, cy + dy + step)

    def get_corners(self):
        x, y = self.topleft
        w, h = self.size
        return (x, y), (x, y - h), (x + w, y - h), (x + w, y), (x + w, y + h), \
               (x, y + h), (x - w, y + h), (x - w, y), (x - w, y - h)

    def update(self):
        self.scroll()
        self.floor.draw()
        self.pools.update()
        self.aphids.update()

    def scroll(self):
        if not self.aphids.sitting and not self.parent.monsters.current:
            keys = self.input
            axes = keys.get_axes()
            self.scroll_active = True in axes.values()
            shift = self.shift
            step = self.walk_step
            if keys.is_command_active("run"):
                step = self.run_step
            active = self.active_directions
            up, right, down, left = self.directions
            if axes["up"]:
                shift(y=step)
                active[up] = True
                if not active[left] and not active[right]:
                    self.direction = up
            else:
                active[up] = False
            if axes["right"]:
                shift(x=-step)
                active[right] = True
                if not active[up] and not active[down]:
                    self.direction = right
            else:
                active[right] = False
            if axes["down"]:
                shift(y=-step)
                active[down] = True
                if not active[left] and not active[right]:
                    self.direction = down
            else:
                active[down] = False
            if axes["left"]:
                shift(x=step)
                active[left] = True
                if not active[up] and not active[down]:
                    self.direction = left
            else:
                active[left] = False

    def shift(self, x=0, y=0, collide=True):
        self.move_ip(x, y)
        if collide:
            self.collide_aphids(-x, -y)
        viewport = self.display_surface.get_rect()
        if self.left > viewport.w:
            self.right = self.left
        if self.top > viewport.h:
            self.bottom = self.top
        if self.right < 0:
            self.left = self.right
        if self.bottom < 0:
            self.top = self.bottom

    def collide_aphids(self, x, y):
        for dx, dy in self.get_corners():
            aphids = self.aphids.collision_rect.move(x - dx, y - dy)
            for pool in self.pools:
                if aphids.colliderect(pool.water.rect):
                    water = pool.water.rect
                    radius = water.w / 2.0
                    distance = sqrt((aphids.centerx - water.centerx) ** 2 + \
                                    (aphids.centery - water.centery) ** 2)
                    if distance < radius:
                        self.shift(x, y)
                        return
216.73.216.157
216.73.216.157
216.73.216.157
 
September 13, 2013

from array import array
from time import sleep

import pygame
from pygame.mixer import Sound, get_init, pre_init

class Note(Sound):

    def __init__(self, frequency, volume=.1):
        self.frequency = frequency
        Sound.__init__(self, self.build_samples())
        self.set_volume(volume)

    def build_samples(self):
        period = int(round(get_init()[0] / self.frequency))
        samples = array("h", [0] * period)
        amplitude = 2 ** (abs(get_init()[1]) - 1) - 1
        for time in xrange(period):
            if time < period / 2:
                samples[time] = amplitude
            else:
                samples[time] = -amplitude
        return samples

if __name__ == "__main__":
    pre_init(44100, -16, 1, 1024)
    pygame.init()
    Note(440).play(-1)
    sleep(5)

This program generates and plays a 440 Hz tone for 5 seconds. It can be extended to generate the spectrum of notes with a frequency table or the frequency formula. Because the rewards in Send are idealized ocean waves, they can also be represented as tones. Each level has a tone in its goal and a tone based on where the player's disc lands. Both play at the end of a level, sounding harmonic for a close shot and discordant for a near miss. The game can dynamically create these tones using the program as a basis.

I'm also building an algorithmically generated song: Silk Routes (Scissored). Here is an example of how it sounds so far.