2 player.py (play various sound/music files)
4 based on ogg123.py By Andrew Chatham Based on ogg123.c by Keneth Arnold.
5 also based on mpg123.py from the pymad module (no attribution in those sources)
7 Copyright 2005 Kenneth Hayber <ken@hayber.us>, All rights reserved.
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License.
13 This program is distributed in the hope that it will be useful
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 import os
, time
, string
, sys
, Queue
30 print 'No ALSA support'
37 print 'No OSS support!!'
46 if not HAVE_AO
and not HAVE_OSS
:
47 print 'No OSS and no AO support Falling back to linuxaudiodev which sucks!!'
53 """A class to playback sound files to an audio device."""
61 def __init__(self
, id='esd', buffersize
=4096, device
='/dev/dsp',):
62 """Initialize the Player instance"""
64 self
.buffersize
= buffersize
67 self
.queue
= Queue
.Queue(5)
69 def open(self
, rate
=44100, channels
=2):
70 """Open and configure the audio device driver"""
73 #try 3 times to open the device, then give up.
77 self
.dev
= ao
.AudioDevice(self
.id, bits
, rate
, channels
)
79 elif HAVE_ALSA
and self
.id in ('alsa09',):
80 self
.dev
= alsaaudio
.PCM(cardname
=self
.device
)
81 self
.dev
.setchannels(channels
)
82 self
.dev
.setrate(rate
)
83 if sys
.byteorder
== 'big':
84 format
= alsaaudio
.PCM_FORMAT_S16_BE
86 format
= alsaaudio
.PCM_FORMAT_S16_LE
87 self
.dev
.setformat(format
)
90 self
.dev
= ossaudiodev
.open(self
.device
, 'w')
91 if sys
.byteorder
== 'big':
92 format
= ossaudiodev
.AFMT_S16_BE
94 format
= ossaudiodev
.AFMT_S16_LE
95 self
.dev
.setparameters(format
, channels
, rate
)
98 self
.dev
= linuxaudiodev
.open('w')
99 if sys
.byteorder
== 'big':
100 format
= linuxaudiodev
.AFMT_S16_BE
102 format
= linuxaudiodev
.AFMT_S16_LE
103 self
.dev
.setparameters(rate
, bits
, channels
, format
)
111 """Close the current device if open and delete it"""
113 if USING_DEV
in ('ao', 'alsa', 'other'):
115 elif USING_DEV
in ('oss',):
119 def write(self
, buff
, bytes
):
120 """Write data to the audio device"""
121 if USING_DEV
in ('ao',):
122 self
.dev
.play(buff
, bytes
)
123 elif USING_DEV
in ('oss', 'alsa'):
126 while self
.dev
.obuffree() < bytes
:
128 self
.dev
.write(buff
[:bytes
])
130 def play(self
, name
, type):
131 """Push the song info on the queue"""
132 if not os
.path
.isfile(name
):
133 raise SyntaxError, "File not found or not accessible (%s)." % name
134 self
.queue
.put((name
, type))
137 """Check the filename and type, create a decoder and start playing"""
139 (name
, type) = self
.queue
.get()
140 if os
.path
.isfile(name
):
141 self
.decoder
= plugins
.get_decoder(name
, type, self
.buffersize
)
143 raise SyntaxError, 'play takes a filename.'
147 """Start playing a file calling the current decoder to get file info and data"""
151 self
.total_time
= self
.decoder
.length()
152 self
.remain
= self
.total_time
157 self
.open(self
.decoder
.samplerate(), self
.decoder
.channels())
159 while self
.state
== 'play' or self
.state
== 'pause':
160 if self
.state
== 'pause':
163 self
.decoder
.seek(self
.seek_val
)
166 (buff
, bytes
) = self
.decoder
.read()
169 self
.elapse
= self
.total_time
173 self
.elapse
= self
.decoder
.tell()
174 self
.remain
= max(0, self
.total_time
- self
.elapse
)
175 self
.write(buff
, bytes
)
176 if self
.elapse
!= last_elapse
or self
.state
== 'pause':
177 last_elapse
= self
.elapse
184 """Set a flag telling the current play-loop to exit and close the device"""
187 try: self
.queue
.get_nowait()
188 except Queue
.Empty
: break
191 """Pause playback (works as a toggle between play and pause)"""
192 if self
.state
== 'play':
194 elif self
.state
== 'pause':
197 def seek(self
, percent
):
198 """Jump to a specific point in the song by percent"""
199 self
.seek_val
= percent
201 def set_volume(self
, volume
, device
=None):
202 """Set the PCM volume to a new value"""
206 mixer
= alsaaudio
.Mixer('PCM', 0, device
)
209 print >>sys
.stderr
, "Failed to open mixer device %s" % device
213 mixer
= ossaudiodev
.openmixer(device
)
214 mixer
.set(ossaudiodev
.SOUND_MIXER_PCM
, (vol
, vol
))
216 print >>sys
.stderr
, "Failed to open mixer device %s" % device
220 def get_volume(self
, device
=None):
221 """Return the current volume setting"""
224 mixer
= alsaaudio
.Mixer('PCM', 0, device
)
225 vol
= mixer
.getvolume()
226 return float(max(vol
[0], vol
[1]))
228 print >>sys
.stderr
, "Failed to open mixer device %s" % device
233 mixer
= ossaudiodev
.openmixer(device
)
234 vol
= mixer
.get(ossaudiodev
.SOUND_MIXER_PCM
)
235 return float(max(vol
[0], vol
[1]))
237 print >>sys
.stderr
, "Failed to open mixer device %s" % device