Pygame e OSS [RESOLVIDO]

1. Pygame e OSS [RESOLVIDO]

Perfil removido
removido

(usa Nenhuma)

Enviado em 03/07/2011 - 15:45h

Eu tenho um aplicativo aqui que reproduz fluxos de audio usando o pygame.mixer.music. Funciona... o problema é que só funciona com alsa/pulseaudio , com OSS ele da o seguinte erro:

error: mixer system not initialized

Na linha:

pygame.mixer.music.load(fileName)

Já que que pelo jeito não posso usar isso para reproduzir no OSS, pois não tem compatibilidade... procurei na net e não encontrei nenhuma biblioteca referente que pudesse usar para substituir no lugar.

Segue abaixo o Audio.py

# -*- coding: iso-8859-1 -*-

import pygame
import Log
import time
import struct
from Task import Task
import Config

#stump: check for pitch bending support
try:
import pygame.pitchbend
pitchBendSupported = True
if not hasattr(pygame.pitchbend, 'ALL'):
Log.warn("Your pitchbend module is too old; upgrade it to r7 or higher for pitch bending to work.")
pitchBendSupported = False
except ImportError:
Log.warn("Pitch bending is not supported; install john.stumpo's pitchbend module (r7 or higher) if you want it.")
pitchBendSupported = False

#stump: get around some strangeness in pygame when py2exe'd...
if not hasattr(pygame.mixer, 'music'):
import sys
__import__('pygame.mixer_music')
pygame.mixer.music = sys.modules['pygame.mixer_music']

try:
import ogg.vorbis
except ImportError:
Log.warn("PyOGG not found. OGG files will be fully decoded prior to playing; expect absurd memory usage.")
ogg = None

class Audio:
def pre_open(self, frequency = 22050, bits = 16, stereo = True, bufferSize = 1024):
pygame.mixer.pre_init(frequency, -bits, stereo and 2 or 1, bufferSize)
return True

def open(self, frequency = 22050, bits = 16, stereo = True, bufferSize = 1024):
try:
pygame.mixer.quit()
except:
pass

try:
pygame.mixer.init(frequency, -bits, stereo and 2 or 1, bufferSize)
except:
Log.warn("Audio setup failed. Trying with default configuration.")
pygame.mixer.init()

Log.debug("Audio configuration: %s" % str(pygame.mixer.get_init()))

#myfingershurt: ensuring we have enough audio channels!
pygame.mixer.set_num_channels(10)

return True

#myfingershurt:
def findChannel(self):
return pygame.mixer.find_channel()


def getChannelCount(self):
return pygame.mixer.get_num_channels()

def getChannel(self, n):
return Channel(n)

def close(self):
try:
pygame.mixer.quit()
except:
pass
#pygame.mixer.quit()

def pause(self):
pygame.mixer.pause()

def unpause(self):
pygame.mixer.unpause()

class Music(object):
def __init__(self, fileName):
pygame.mixer.music.load(fileName)
self.pausePos = 0.0
self.isPause = False
self.toUnpause = False
self.buffersize = Config.get("audio","buffersize")

@staticmethod
def setEndEvent(event = None):
if event:
pygame.mixer.music.set_endevent(event)
else:
pygame.mixer.music.set_endevent() #MFH - to set NO event.

def play(self, loops = -1, pos = 0.0):
pygame.mixer.music.play(loops, pos)

def stop(self):
pygame.mixer.music.stop()

def rewind(self):
pygame.mixer.music.rewind()

def pause(self):
pygame.mixer.music.pause()
self.pausePos = pygame.mixer.music.get_pos()
self.isPause = True

def unpause(self):
self.isPause = False
pygame.mixer.music.unpause()

def setVolume(self, volume):
pygame.mixer.music.set_volume(volume)

#stump: pitch bending
# SDL_mixer doesn't support callback processing of the music stream.
# Thus, as a workaround, we must bend the whole output.
def setPitchBend(self, factor):
pygame.pitchbend.start(pygame.pitchbend.ALL)
pygame.pitchbend.setFactor(pygame.pitchbend.ALL, factor)

def stopPitchBend(self):
pygame.pitchbend.stop(pygame.pitchbend.ALL)

def fadeout(self, time):
pygame.mixer.music.fadeout(time)

def isPlaying(self):
#MFH - gotta catch case when mixer not initialized yet...
try:
busy = pygame.mixer.music.get_busy()
except Exception, e:
busy = True
#return pygame.mixer.music.get_busy()
return busy

def getPosition(self):
if self.isPause:
self.toUnpause = True
return self.pausePos
elif self.toUnpause:
if pygame.mixer.music.get_pos() < (self.pausePos + 60 + (self.buffersize/32)): #this should technically be buffersize*1000/samplerate; 32 keeps it integer, 60 allows for processing time
self.toUnpause = False
return pygame.mixer.music.get_pos()
else:
return self.pausePos
else:
return pygame.mixer.music.get_pos()

class Channel(object):
def __init__(self, id):
self.channel = pygame.mixer.Channel(id)
self.id = id

def __del__(self):
if pitchBendSupported:
pygame.pitchbend.stop(self.id)

def play(self, sound):
self.channel.play(sound.sound)

def stop(self):
self.channel.stop()
if pitchBendSupported:
pygame.pitchbend.stop(self.id)

def setVolume(self, volume):
self.channel.set_volume(volume)

def fadeout(self, time):
self.channel.fadeout(time)

#stump: pitch bending
def setPitchBend(self, factor):
pygame.pitchbend.start(self.id)
pygame.pitchbend.setFactor(self.id, factor)

def stopPitchBend(self):
pygame.pitchbend.stop(self.id)

class Sound(object):
def __init__(self, fileName):
self.sound = pygame.mixer.Sound(fileName)

def isPlaying(self): #MFH - adding function to check if sound is playing
return self.sound.get_num_channels()

def play(self, loops = 0):
self.sound.play(loops)

def stop(self):
self.sound.stop()

def setVolume(self, volume):
self.sound.set_volume(volume)

def fadeout(self, time):
self.sound.fadeout(time)

if tuple(int(i) for i in pygame.__version__[:5].split('.')) < (1, 9, 0):
# Must use Numeric instead of numpy, since PyGame 1.7.1 is
# not compatible with the latter, and 1.8.x isn't either (though it claims to be).
import Numeric
def zeros(size):
return Numeric.zeros(size, typecode='s') #myfingershurt: typecode s = short = int16
else:
import numpy
def zeros(size):
return numpy.zeros(size, dtype='h')

#stump: mic passthrough
class MicrophonePassthroughStream(Sound, Task):
def __init__(self, engine, mic):
Task.__init__(self)
self.engine = engine
self.channel = None
self.mic = mic
self.playing = False
self.volume = 1.0
def __del__(self):
self.stop()
def play(self):
if not self.playing:
self.engine.addTask(self, synchronized=False)
self.playing = True
def stop(self):
if self.playing:
self.channel.stop()
self.engine.removeTask(self)
self.playing = False
def setVolume(self, vol):
self.volume = vol
def run(self, ticks):
chunk = ''.join(self.mic.passthroughQueue)
self.mic.passthroughQueue = []
if chunk == '':
return
samples = len(chunk)/4
data = tuple(int(s * 32767) for s in struct.unpack('%df' % samples, chunk))
playbuf = zeros((samples, 2))
playbuf[:, 0] = data
playbuf[:, 1] = data
snd = pygame.sndarray.make_sound(playbuf)
if self.channel is None or not self.channel.get_busy():
self.channel = snd.play()
else:
self.channel.queue(snd)
self.channel.set_volume(self.volume)

if ogg:
class OggStream(object):
def __init__(self, inputFileName):
self.file = ogg.vorbis.VorbisFile(inputFileName)

def read(self, bytes = 4096):
(data, bytes, bit) = self.file.read(bytes)
return data[:bytes]

class StreamingOggSound(Sound, Task):
def __init__(self, engine, channel, fileName):
Task.__init__(self)
self.engine = engine
self.fileName = fileName
self.channel = channel
self.playing = False
self.bufferSize = 1024 * 64
self.bufferCount = 8
self.volume = 1.0

#myfingershurt: buffer is 2D array (one D for each channel) of 16-bit UNSIGNED integers / samples
# 2*1024*64 = 131072 samples per channel
self.buffer = zeros((2 * self.bufferSize, 2))

self.decodingRate = 4
self._reset()

def _reset(self):
self.stream = OggStream(self.fileName)

#myfingershurt: 2D buffer (L,R) of 16-bit unsigned integer samples, each channel 65536 samples long
#.... buffersIn = a list of 9 of these.
self.buffersIn = [pygame.sndarray.make_sound(zeros((self.bufferSize, 2))) for i in range(self.bufferCount + 1)]

self.buffersOut = []
self.buffersBusy = []
self.bufferPos = 0
self.done = False
self.lastQueueTime = time.time()

while len(self.buffersOut) < self.bufferCount and not self.done:
#myfingershurt: while there are less than 8 sets of 65k sample 2 channel buffers in the buffersOut list,
# continue to decode and fill them.
self._produceSoundBuffers()

def __del__(self):
self.engine.removeTask(self)

def streamIsPlaying(self): #MFH - adding function to check if sound is playing
return self.playing


def play(self):
if self.playing:
return

self.engine.addTask(self, synchronized = False)
self.playing = True

while len(self.buffersOut) < self.bufferCount and not self.done:
#myfingershurt: while there are less than 8 sets of 65k sample 2 channel buffers in the buffersOut list,
# continue to decode and fill them.
self._produceSoundBuffers()


#once all 8 output buffers are filled, play the first one.
self.channel.channel.play(self.buffersOut.pop())

def stop(self):
self.playing = False
self.channel.stop()
self.engine.removeTask(self)
self._reset()

def setVolume(self, volume):
self.volume = volume
#myfingershurt: apply volume changes IMMEDIATELY:
self.channel.setVolume(self.volume)

#stump: pitch bending
def setPitchBend(self, factor):
self.channel.setPitchBend(factor)

def stopPitchBend(self):
self.channel.stopPitchBend()

def fadeout(self, time):
self.stop()

def _decodeStream(self):
# No available buffers to fill?
if not self.buffersIn or self.done:
return

data = self.stream.read()

if not data:
self.done = True
else:
data = struct.unpack("%dh" % (len(data) / 2), data)
samples = len(data) / 2
self.buffer[self.bufferPos:self.bufferPos + samples, 0] = data[0::2]
self.buffer[self.bufferPos:self.bufferPos + samples, 1] = data[1::2]
self.bufferPos += samples

# If we have at least one full buffer decode, claim a buffer and copy the
# data over to it.
if self.bufferPos >= self.bufferSize or (self.done and self.bufferPos):
# Claim the sound buffer and copy the data
if self.bufferPos < self.bufferSize:
self.buffer[self.bufferPos:] = 0
soundBuffer = self.buffersIn.pop()
pygame.sndarray.samples(soundBuffer)[:] = self.buffer[0:self.bufferSize]

# Discard the copied sound data
n = max(0, self.bufferPos - self.bufferSize)
self.buffer[0:n] = self.buffer[self.bufferSize:self.bufferSize+n]
self.bufferPos = n

return soundBuffer

def _produceSoundBuffers(self):
# Decode enough that we have at least one full sound buffer
# ready in the queue if possible
while not self.done:
for i in xrange(self.decodingRate):
soundBuffer = self._decodeStream()
if soundBuffer:
self.buffersOut.insert(0, soundBuffer)
if self.buffersOut:
break

def run(self, ticks):
if not self.playing:
return

#myfingershurt: this is now done directly when called.
#self.channel.setVolume(self.volume)

if len(self.buffersOut) < self.bufferCount:
self._produceSoundBuffers()

if not self.channel.channel.get_queue() and self.buffersOut:
# Queue one decoded sound buffer and mark the previously played buffer as free
soundBuffer = self.buffersOut.pop()
self.buffersBusy.insert(0, soundBuffer)
self.lastQueueTime = time.time()
self.channel.channel.queue(soundBuffer)
if len(self.buffersBusy) > 2:
self.buffersIn.insert(0, self.buffersBusy.pop())

if not self.buffersOut and self.done and time.time() - self.lastQueueTime > 4:
self.stop()

class StreamingSound(Sound, Task):
def __init__(self, engine, channel, fileName):
Task.__init__(self)
Sound.__init__(self, fileName)
self.channel = channel

def __new__(cls, engine, channel, fileName):
frequency, format, stereo = pygame.mixer.get_init()
if fileName.lower().endswith(".ogg"):

return StreamingOggSound(engine, channel, fileName) #MFH - forced allow of non-matching sample rates

#- if frequency == 44100 and format == -16 and stereo:
#- return StreamingOggSound(engine, channel, fileName)
#- else:
#- Log.warn("Audio settings must match stereo 16 bits at 44100 Hz in order to stream OGG files.")
#- return super(StreamingSound, cls).__new__(cls, engine, channel, fileName)

def play(self):
self.channel.play(self)

def stop(self):
Sound.stop(self)
self.channel.stop()

def setVolume(self, volume):
Sound.setVolume(self, volume)
self.channel.setVolume(volume)

def streamIsPlaying(self): #MFH - adding function to check if sound is playing
return Sound.get_num_channels()


def fadeout(self, time):
Sound.fadeout(self, time)
self.channel.fadeout(time)

#stump: pitch bending
def setPitchBend(self, factor):
self.channel.setPitchBend(factor)

def stopPitchBend(self):
self.channel.stopPitchBend()

Alguém conhece alguma referencia na net que funcione com OSS e que eu possa usar no lugar?

Agradeço


  


2. MELHOR RESPOSTA

Samuel Leonardo
SamL

(usa XUbuntu)

Enviado em 03/07/2011 - 18:00h

Deve ser porque falta o pacote da lib SDL que manipula Oss. Talvez seja isso, porque o Pygame usa audio via SDL.
Instale o pacote para SDL e Oss:

sudo apt-get install libsdl1.2debian-oss


3. Re: Pygame e OSS [RESOLVIDO]

Perfil removido
removido

(usa Nenhuma)

Enviado em 03/07/2011 - 23:38h

Cara, resolveu! No lugar do libsdl1.2debian-oss estava instalado o libsdl1.2debian-pulseaudio, foi desinstalar o pulse e instalar o oss que tudo funcionou.

Mas eu li em algum lugar na própria documentação do pygame dizendo que não tinha suporte a oss, fiquei sem entender agora...

Acho que o manual estava se referindo a suporte nativo, certo?




4. Re: Pygame e OSS [RESOLVIDO]

Perfil removido
removido

(usa Nenhuma)

Enviado em 04/07/2011 - 15:25h

Vlw cara, exatamente como pensei. Vou da uma estudada nessa lib.

Join ;)






Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts