As it happens I have a bit of experience with something like that, although 
I tend to use the OpenAL bindings in Pyglet over the convience functions 
like pyglet.media. I've modified one of my examples (you'll find it 
attached) from Peter Meijers <http://www.seeingwithsound.com/im2sound.htm> 
image to sound rendering to just output a numpy waveform array. 
Alternatively you could also have a look at pylet.media.Procedural for 
generating sound, although that may not meet your numpy requirements.

-- 
You received this message because you are subscribed to the Google Groups 
"pyglet-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to pyglet-users+unsubscr...@googlegroups.com.
To post to this group, send email to pyglet-users@googlegroups.com.
Visit this group at https://groups.google.com/group/pyglet-users.
For more options, visit https://groups.google.com/d/optout.
import math
import struct
import ctypes
import numpy as np

#using pyglet
import pyglet
from pyglet.media.drivers.openal import lib_openal as al
from pyglet.media.drivers.openal import lib_alc as alc

#using PyAL
##from openal import al, alc


class Example(object):
    def __init__(self):
        self.listener = Listener()
        self.sbuffer = buffer_sound()
        self.generator = generator()
        self.player = Player()

        self.sbuffer.load(self.generator.output)
        self.player.add(self.sbuffer)
        self.player.play()

        while self.player.playing():
            pass

        self.player.remove()
        self.player.delete()
        self.sbuffer.delete()
        self.listener.delete()



class generator(object):
#pre-calculate waveform values
    def __init__(self):
        self.speed = 1.0

        self.byte = int(20000 * self.speed)

        self.size = 64

        self.ns = self.byte
        self.TwoPi = 6.283185307179586476925287 #double Pi
        self.rnd = 0.211321159122
        self.phi0 = self.TwoPi * self.rnd

    #Generate sine wave
        self.w = np.asarray(range(self.size)) 
        self.w = self.TwoPi * 500 * np.power(1.0*5000/500, 1.0*self.w/(self.size-1))
        self.w = np.tile(self.w,(self.ns,1))

        self.core = np.asarray(range(self.ns)) #312.5 * data(4096), repeat
        self.core = np.reshape(self.core,(self.byte,1))
        self.core = np.repeat(self.core,(self.size),axis=1)

        self.w = np.sin(self.w * (self.core * (1.0 / self.byte)) + self.phi0)

    #create ctypes array
        self.output = (ctypes.c_short * self.ns)()
    #flatten wave array
        self.w = np.ravel(self.w)

    #multiply wave to make it audiable
        self.w = self.w * 32767.0
    #load wave into ctypes array to into OpenAL buffer
        for a in xrange(0,len(self.output),1):
            self.output[a] = self.output[a]+int(self.w[a])




class buffer_sound(object):
    def __init__(self):
        self.channels = 1
        self.bitrate = 16
        self.samplerate = 21000
        self.wavbuf = None
        self.alformat = al.AL_FORMAT_MONO16
        self.length = None
##        formatmap = {
##            (1, 8) : al.AL_FORMAT_MONO8,
##            (2, 8) : al.AL_FORMAT_STEREO8,
##            (1, 16): al.AL_FORMAT_MONO16,
##            (2, 16) : al.AL_FORMAT_STEREO16,
##        }
##        alformat = formatmap[(channels, bitrate)]


        self.buf = al.ALuint(0)
        al.alGenBuffers(1, self.buf)

    def load(self,data):
        self.wavbuf = data
        self.length = len(data)
    #allocate buffer space to: buffer, format, data, len(data), and samplerate
        al.alBufferData(self.buf, self.alformat, self.wavbuf, len(self.wavbuf)*2, self.samplerate)

    def delete(self):
        al.alDeleteBuffers(1, self.buf)



#load a listener to load and play sounds.
class Listener(object):
    def __init__(self):
    #load device/context/listener
        self.device = alc.alcOpenDevice(None)
        self.context = alc.alcCreateContext(self.device, None)
        alc.alcMakeContextCurrent(self.context)

#set player position
    def _set_position(self,pos):
        self._position = pos
        x,y,z = map(int, pos)
        al.alListener3f(al.AL_POSITION, x, y, z)

    def _get_position(self):
        return self._position

#delete current listener
    def delete(self):
        alc.alcDestroyContext(self.context)
        alc.alcCloseDevice(self.device)

    position = property(_get_position, _set_position,doc="""get/set position""")




#load sound buffers into an openal source player to play them
class Player(object):
#load default settings
    def __init__(self):
    #load source player
        self.source = al.ALuint(0)
        al.alGenSources(1, self.source)
    #disable rolloff factor by default
        al.alSourcef(self.source, al.AL_ROLLOFF_FACTOR, 0)
    #disable source relative by default
        al.alSourcei(self.source, al.AL_SOURCE_RELATIVE,0)
    #capture player state buffer
        self.state = al.ALint(0)
    #set internal variable tracking
        self._volume = 1.0
        self._pitch = 1.0
        self._position = [0,0,0]
        self._rolloff = 1.0
        self._loop = False
        self.queue = []


#set rolloff factor, determines volume based on distance from listener
    def _set_rolloff(self,value):
        self._rolloff = value
        al.alSourcef(self.source, al.AL_ROLLOFF_FACTOR, value)

    def _get_rolloff(self):
        return self._rolloff


#set whether looping or not - true/false 1/0
    def _set_loop(self,lo):
        self._loop = lo
        al.alSourcei(self.source, al.AL_LOOPING, lo)

    def _get_loop(self):
        return self._loop
      

#set player position
    def _set_position(self,pos):
        self._position = pos
        x,y,z = map(int, pos)
        al.alSource3f(self.source, al.AL_POSITION, x, y, z)

    def _get_position(self):
        return self._position
        

#set pitch - 1.5-0.5 float range only
    def _set_pitch(self,pit):
        self._pitch = pit
        al.alSourcef(self.source, al.AL_PITCH, pit)

    def _get_pitch(self):
        return self._pitch

#set volume - 1.0 float range only
    def _set_volume(self,vol):
        self._volume = vol
        al.alSourcef(self.source, al.AL_GAIN, vol)

    def _get_volume(self):
        return self._volume

#queue a sound buffer
    def add(self,sound):
        al.alSourceQueueBuffers(self.source, 1, sound.buf) #self.buf
        self.queue.append(sound)

#remove a sound from the queue (detach & unqueue to properly remove)
    def remove(self):
        if len(self.queue) > 0:
            al.alSourceUnqueueBuffers(self.source, 1, self.queue[0].buf) #self.buf
            al.alSourcei(self.source, al.AL_BUFFER, 0)
            self.queue.pop(0)

#play sound source
    def play(self):
        al.alSourcePlay(self.source)

#get current playing state
    def playing(self):
        al.alGetSourcei(self.source, al.AL_SOURCE_STATE, self.state)
        if self.state.value == al.AL_PLAYING:
            return True
        else:
            return False

#stop playing sound
    def stop(self):
        al.alSourceStop(self.source)

#rewind player
    def rewind(self):
        al.alSourceRewind(self.source)

#pause player
    def pause(self):
        al.alSourcePause(self.source)

#delete sound source
    def delete(self):
        al.alDeleteSources(1, self.source)

#Go straight to a set point in the sound file
    def _set_seek(self,offset):#float 0.0-1.0
        al.alSourcei(self.source,al.AL_BYTE_OFFSET,int(self.queue[0].length * offset))

#returns current buffer length position (IE: 21000), so divide by the buffers self.length
    def _get_seek(self):#returns float 0.0-1.0
        al.alGetSourcei(self.source, al.AL_BYTE_OFFSET, self.state)
        return float(self.state.value)/float(self.queue[0].length)

    rolloff = property(_get_rolloff, _set_rolloff,doc="""get/set rolloff factor""")
    volume = property(_get_volume, _set_volume,doc="""get/set volume""")
    pitch = property(_get_pitch, _set_pitch, doc="""get/set pitch""")
    loop = property(_get_loop, _set_loop, doc="""get/set loop state""")
    position = property(_get_position, _set_position,doc="""get/set position""")
    seek = property(_get_seek, _set_seek, doc="""get/set the current play position""")

Example()

Reply via email to