Weird, giving me errors when trying to post...

Thanks for taking the time to respond Neon22. My question was more about 
what buffer type to pass to alcCaptureSamples, the given C/C++ examples all 
used ALubyte or similar ctypes arrays but that didn't seem to be working, 
and I wasn't sure what the python equivalent was for Pyglets bindings. 
Turns out alBufferData uses a similar void buffer pointer as 
alcCaptureSamples which i'm already familiar with, which is a generic 
python string, so problem solved. After a bit of refining I've put together 
an example for anyone whos interested in recording any audio with Pyglets 
OpenAL bindings.

-- 
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 [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/pyglet-users.
For more options, visit https://groups.google.com/d/optout.
#using 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

#imports for sound loading and wait during example
import wave
import time
import sys
import os

class Example(object):
    def __init__(self):
    #load listener
        self.listener = listener()
    #initialize sound
        self.sound = load_sound('tone5.wav')
    #load sound player
        self.player = Player()

    #set listener position
        self.listener.position = (320,240,0)
    #set player position
        self.player.position = (0,240,0)

    #load sound into player
        self.player.add(self.sound)
    #enable loop sound so it plays forever
        self.player.loop = True
    #set rolloff factor
        self.player.rolloff = 0.01
    #play sound
        self.player.play()

    #start recording
        self.listener.rec_start()

    #capture recorded samples (and number of samples to capture)
        while len(self.listener.samplescaptured) <= 16000:
            self.listener.rec()

    #stop player
        self.player.stop()

    #stop recording
        self.listener.rec_stop()

    #load captured audio sample into a audio buffer for playback
        self.buffer = buffer_sound()
        self.buffer.load(self.listener.samplescaptured)
        self.player.remove()
        self.player.add(self.buffer)

    #play captured audio
        self.player.play()
        time.sleep(1)

    #clean up resources
        self.player.delete()
        self.sound.delete()
        self.buffer.delete()
        self.listener.delete()



#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)
        alc.alcProcessContext(self.context)
    #get list of capture devices
        self.cap_devices = self.parse(alc.alcGetString(None, alc.ALC_CAPTURE_DEVICE_SPECIFIER))
    #capture device container
        self.captureDev = None
    #main buffer
        self.samplescaptured = ''

#list available capture devices
    def get_devices(self):
        return self.parse(alc.alcGetString(None, alc.ALC_CAPTURE_DEVICE_SPECIFIER))

#set capture device
    def _set_cap(self,data=0):
        if self.captureDev != None:
            alc.alcCaptureStop(self.captureDev)
            alc.alcCaptureCloseDevice(self.captureDev)
        self.captureDev = alc.alcCaptureOpenDevice(self.cap_devices[data], 8000, al.AL_FORMAT_MONO16, 800)

#get current capture device
    def _get_cap(self):
        if self.captureDev != None:
            return self.parse(alc.alcGetString(self.captureDev, alc.ALC_CAPTURE_DEVICE_SPECIFIER))
        else:
            return None

#get default capture device
    def get_default(self):
        return self.parse(alc.alcGetString(None, alc.ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER))

#start recording
    def rec_start(self):
    #load default capture device if none loaded
        if self.captureDev == None: #capture device, sample rate, format, buffer size
            self.captureDev = alc.alcCaptureOpenDevice(None, 8000, al.AL_FORMAT_MONO16, 800)
    #start capturing audio
        alc.alcCaptureStart(self.captureDev)
    #set main buffer
        self.samplescaptured = ''

#transfer recorded audio to main buffer
    def rec(self):
        if self.captureDev != None:
            s_available = al.ALint(0)
        #capture audio
            alc.alcGetIntegerv(self.captureDev, alc.ALC_CAPTURE_SAMPLES, 1, s_available)
        #transfer captured audio data into tmp buffer, add to main buffer
            box = ' '*(s_available.value*2)
            alc.alcCaptureSamples(self.captureDev, box, s_available)
            self.samplescaptured += box

#stop recording
    def rec_stop(self):
        if self.captureDev != None:
            s_available = al.ALint(0)
        #capture audio
            alc.alcGetIntegerv(self.captureDev, alc.ALC_CAPTURE_SAMPLES, 1, s_available)
        #transfer captured audio data into tmp buffer, add to main buffer
            self.box = ' '*(s_available.value*2)
            alc.alcCaptureSamples(self.captureDev, self.box, s_available)
            self.samplescaptured += self.box
        #if sample size isn't divisible by our sample rate, clip it
            if len(self.samplescaptured) > 16000:
                self.samplescaptured = self.samplescaptured[:16000]
        #stop capturing audio
            alc.alcCaptureStop(self.captureDev)

#parse openal data strings
    def parse(self,data):
    #parse available devices
        stri = ['']
        dev = 0
        for a in xrange(0,100,1):
            if data[a].isalnum() or data[a].isspace():
                stri[dev] += data[a]
            else:
                if len(stri[dev]) == 0:
                    stri.pop(dev)
                    break
                else:
                    stri.append('')
                    dev += 1
        return stri

#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.alcCaptureCloseDevice(self.captureDev)
        alc.alcDestroyContext(self.context)
        alc.alcCloseDevice(self.device)

    position = property(_get_position, _set_position,doc="""get/set position""")
    cap = property(_get_cap, _set_cap,doc="""get/set caputure device""")



#load and store a wav file into an openal buffer
class load_sound(object):
    def __init__(self,filename):
        self.name = filename
    #load/set wav file
        if len (sys.argv) < 2:
            print ("Usage: %s wavefile" % os.path.basename(sys.argv[0]))
            print ("    Using an example wav file...")
            dirname = os.path.dirname(os.path.realpath(__file__))
            fname = os.path.join(dirname, filename)
        else:
            fname = sys.argv[1]

        wavefp = wave.open(fname)
        channels = wavefp.getnchannels()
        bitrate = wavefp.getsampwidth() * 8
        samplerate = wavefp.getframerate()
        wavbuf = wavefp.readframes(wavefp.getnframes())
        self.duration = (len(wavbuf) / float(samplerate))/2
        self.length = len(wavbuf)
        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)
    #allocate buffer space to: buffer, format, data, len(data), and samplerate
        al.alBufferData(self.buf, alformat, wavbuf, len(wavbuf), samplerate)

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



#OpenAL Sound Buffer
class buffer_sound(object):
    def __init__(self):
        self.channels = 1
        self.bitrate = 16
        self.samplerate = 8000
        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 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