Closed GoogleCodeExporter closed 9 years ago
There is still an issue with the buffer creation code for the source. If I try
and play the same SoundData on two different sources I get this error:
Traceback (most recent call last):
File "C:\Users\demolishun\Documents\Programming\python\vlc\custom_vlc.pyw", line 714, in <module>
player = Player("Simple PyVLC Player")
File "C:\Users\demolishun\Documents\Programming\python\vlc\custom_vlc.pyw", line 253, in __init__
self.playFeedbackAudio("breath1m.wav", 1, 1.0, 0.0, 1.0)
File "C:\Users\demolishun\Documents\Programming\python\vlc\custom_vlc.pyw", line 414, in playFeedbackAudio
self.asink.process_source(self.asources[source])
File "C:\Python27\lib\site-packages\pygame2\audio\__init__.py", line 219, in process_source
self._create_buffers(source) # modified to fix buffer error
File "C:\Python27\lib\site-packages\pygame2\audio\__init__.py", line 166, in _create_buffers
snddata.frequency)
File "C:\Python27\lib\site-packages\pygame2\openal\al.py", line 712, in buffer_data
_raise_error_or_continue()
File "C:\Python27\lib\site-packages\pygame2\openal\al.py", line 138, in _raise_error_or_continue
raise OpenALError(_ERRMAP[errcode])
OpenALError: 'Invalid operation'
I read on a website that OpenAL can play the same buffer on more than one
source. So this should be solvable. Here is the link:
http://opensource.creative.com/pipermail/openal/2007-August/010624.html
Original comment by demolish...@gmail.com
on 8 Nov 2012 at 4:44
I found a way around this and I hope this does not cause a memory leak:
tsnd = pygame2.audio.SoundData(snd.format,snd.data[:],snd.size,snd.frequency)
Basically I take the snd which is a SoundData object and make a duplicate
called tsnd. Then I queue the tsnd into the source and I can play the sound at
the same time on different sources.
Original comment by demolish...@gmail.com
on 8 Nov 2012 at 4:56
This is a bigger issue than I thought. In order to solve this you must modify
_create_buffers in the SoundSource object like so:
def _create_buffers(self, source):
"""Creates a new set of OpenAL buffers from the passed
SoundSource."""
queue = []
for snddata in source._buffers:
if snddata._bufid is None:
bufid = None
for kbufid, kdata in self._buffers.items():
if kdata is None:
# free buffer found
bufid = kbufid
break
if bufid is not None:
snddata._bufid = bufid
self._buffers[bufid] = snddata
else:
# No free buffer id, create a new one
bufid = al.gen_buffers(1)[0]
self._buffers[bufid] = snddata
snddata._bufid = bufid
# Buffer id assigned, now buffer the data.
# fhc indented
al.buffer_data(snddata._bufid, snddata.format, snddata.data,
snddata.frequency)
queue.append(snddata._bufid)
# fhc added clearing of buffers
al.source_i(source._ssid, al.AL_BUFFER, al.AL_NONE)
al.source_queue_buffers(source._ssid, queue)
This does a couple of things. It prevents an existing buffer from attempting
to create a new buffer. It also wipes out the already queued buffers on the
source. So when it rebuilds the queue there is not extra sounds attached.
This change alleviates the need to copy sounds in order to play them.
Also, when you queue buffers using the SoundSource.queue() call you need to
wipe out the existing internal _buffers if you don't want to play an existing
sound anymore. So doing this is sufficient if you made the changes above:
SoundSource._buffers = [].
Original comment by demolish...@gmail.com
on 8 Nov 2012 at 11:25
Alright, that was not a good fix. Instead I have moved the create buffers into
the SoundSource where they belong. This way the SoundSource can manage their
own buffers. The SoundSink now does nothing with buffers. So remove the call
in SoundSink and use this SoundSource instead:
class SoundSource(Component):
"""A sound source.
The SoundSource is an object within the application world, that can emit
sounds.
"""
def __init__(self, gain=1.0, pitch=1.0, position=(0, 0, 0),
velocity=(0, 0, 0)):
"""Creates a new SoundSource."""
super(SoundSource, self).__init__()
self._ssid = None
self._buffers = []
self._buffids = {}
self.gain = gain
self.pitch = pitch
self.position = position
self.velocity = velocity
self.request = SOURCE_NONE
@property
def ssid(self):
"""The OpenAL source id, if any."""
return self._ssid
def _create_buffers(self):
"""Creates a new set of OpenAL buffers from the passed
SoundSource."""
queue = []
for snddata in self._buffers:
if snddata._bufid is None:
bufid = None
for kbufid, kdata in self._buffids.items():
if kdata is None:
# free buffer found
bufid = kbufid
break
if bufid is not None:
snddata._bufid = bufid
self._buffids[bufid] = snddata
else:
# No free buffer id, create a new one
bufid = al.gen_buffers(1)[0]
self._buffids[bufid] = snddata
snddata._bufid = bufid
# Buffer id assigned, now buffer the data.
# fhc indented
al.buffer_data(snddata._bufid, snddata.format, snddata.data,
snddata.frequency)
queue.append(snddata._bufid)
# fhc added clearing of buffers
al.source_i(self._ssid, al.AL_BUFFER, al.AL_NONE)
al.source_queue_buffers(self._ssid, queue)
def dequeue(self, snd=None):
"""Removes SoundData from the playback queue for the source."""
# dequeu all
if snd is None:
self._buffers = []
# or attempt to remove a specific sound
else:
if snd in self._buffers:
self._buffers.remove(snd)
self._create_buffers()
def queue(self, sounddata):
"""Appends a SoundData to the playback queue for the source."""
if not isinstance(sounddata, SoundData):
raise TypeError("sounddata must be a SoundData")
self._buffers.append(sounddata)
self._create_buffers()
This has fixed all the issues I had with playing sound and buffer management.
Original comment by demolish...@gmail.com
on 9 Nov 2012 at 12:03
As discussed off-list, the OpenAL/Audio wrappers are to be replaced in the
foreseeable future with the implementation of http://code.google.com/p/py-al
I will close the issue for now.
Original comment by marcusvonappen@googlemail.com
on 17 Nov 2012 at 8:23
Original issue reported on code.google.com by
demolish...@gmail.com
on 6 Nov 2012 at 9:43