# ---------------------------------------------------------------------------- # pyglet # Copyright (c) 2006-2008 Alex Holkner # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # * Neither the name of pyglet nor the names of its # contributors may be used to endorse or promote products # derived from this software without specific prior written # permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # ---------------------------------------------------------------------------- '''Simple Python-only RIFF reader, supports uncompressed WAV files. ''' __docformat__ = 'restructuredtext' __version__ = '$Id: riff.py 2005 2008-04-13 01:03:03Z Alex.Holkner $' # RIFF reference: # http://www.saettler.com/RIFFMCI/riffmci.html # # More readable WAVE summaries: # # http://www.borg.com/~jglatt/tech/wave.htm # http://www.sonicspot.com/guide/wavefiles.html from pyglet.media import StreamingSource, AudioData, AudioFormat from pyglet.media import MediaFormatException import ctypes import struct import StringIO WAVE_FORMAT_PCM = 0x0001 IBM_FORMAT_MULAW = 0x0101 IBM_FORMAT_ALAW = 0x0102 IBM_FORMAT_ADPCM = 0x0103 class RIFFFormatException(MediaFormatException): pass class WAVEFormatException(RIFFFormatException): pass class RIFFChunk(object): header_fmt = '<4sL' header_length = struct.calcsize(header_fmt) def __init__(self, file, name, length, offset): self.file = file self.name = name self.length = length self.offset = offset def get_data(self): self.file.seek(self.offset) return self.file.read(self.length) def __repr__(self): return '%s(%r, offset=%r, length=%r)' % ( self.__class__.__name__, self.name, self.offset, self.length) class RIFFForm(object): _chunks = None def __init__(self, file, offset): self.file = file self.offset = offset def get_chunks(self): if self._chunks: return self._chunks self._chunks = [] self.file.seek(self.offset) offset = self.offset while True: header = self.file.read(RIFFChunk.header_length) if not header: break name, length = struct.unpack(RIFFChunk.header_fmt, header) offset += RIFFChunk.header_length cls = self._chunk_types.get(name, RIFFChunk) chunk = cls(self.file, name, length, offset) self._chunks.append(chunk) offset += length if offset & 0x3 != 0: offset = (offset | 0x3) + 1 self.file.seek(offset) return self._chunks def __repr__(self): return '%s(offset=%r)' % (self.__class__.__name__, self.offset) class RIFFType(RIFFChunk): def __init__(self, *args, **kwargs): super(RIFFType, self).__init__(*args, **kwargs) self.file.seek(self.offset) form = self.file.read(4) if form != 'WAVE': raise RIFFFormatException('Unsupported RIFF form "%s"' % form) self.form = WaveForm(self.file, self.offset + 4) class RIFFFile(RIFFForm): _chunk_types = { 'RIFF': RIFFType, } def __init__(self, file): if not hasattr(file, 'seek'): file = StringIO.StringIO(file.read()) super(RIFFFile, self).__init__(file, 0) def get_wave_form(self): chunks = self.get_chunks() if len(chunks) == 1 and isinstance(chunks[0], RIFFType): return chunks[0].form class WaveFormatChunk(RIFFChunk): def __init__(self, *args, **kwargs): super(WaveFormatChunk, self).__init__(*args, **kwargs) fmt = '