def from_wave(cls, filename, wave_filename, compression=None, block_size=256): """Encodes a new AudioFile from an existing .wav file. Takes a filename string, wave_filename string of an existing WaveAudio file and an optional compression level string. Encodes a new audio file from the wave's data at the given filename with the specified compression level and returns a new ShortenAudio object.""" wave = WaveAudio(wave_filename) if (wave.bits_per_sample() not in (8, 16)): raise UnsupportedBitsPerSample() (head, tail) = wave.pcm_split() if (len(tail) > 0): blocks = [head, None, tail] else: blocks = [head, None] import audiotools.encoders try: audiotools.encoders.encode_shn(filename=filename, pcmreader=wave.to_pcm(), block_size=block_size, verbatim_chunks=blocks) return cls(filename) except IOError, err: cls.__unlink__(filename) raise EncodingError(str(err))
def from_pcm(cls, filename, pcmreader, compression=None, total_pcm_frames=None): """encodes a new file from PCM data takes a filename string, PCMReader object, optional compression level string and optional total_pcm_frames integer encodes a new audio file from pcmreader's data at the given filename with the specified compression level and returns a new M4AAudio object""" import tempfile import os import os.path from audiotools import PCMConverter from audiotools import WaveAudio from audiotools import __default_quality__ if ((compression is None) or (compression not in cls.COMPRESSION_MODES)): compression = __default_quality__(cls.NAME) tempwavefile = tempfile.NamedTemporaryFile(suffix=".wav", delete=False) tempwave_name = tempwavefile.name try: if pcmreader.sample_rate > 96000: tempwave = WaveAudio.from_pcm( tempwave_name, PCMConverter(pcmreader, sample_rate=96000, channels=pcmreader.channels, channel_mask=pcmreader.channel_mask, bits_per_sample=pcmreader.bits_per_sample), total_pcm_frames=total_pcm_frames) else: tempwave = WaveAudio.from_pcm( tempwave_name, pcmreader, total_pcm_frames=total_pcm_frames) cls.__from_wave__(filename, tempwave.filename, compression) return cls(filename) finally: tempwavefile.close() if os.path.isfile(tempwave_name): os.unlink(tempwave_name)
def to_wave(self, wave_filename): if (not hasattr(self,"__format__")): self.__populate_metadata__() if (self.__format__ is WaveAudio): try: f = open(wave_filename,'wb') except IOError: raise EncodingError() for block in self.__blocks__: if (block is not None): f.write(block) else: transfer_framelist_data( audiotools.decoders.SHNDecoder(self.filename), f.write) else: WaveAudio.from_pcm(wave_filename,self.to_pcm())
def __populate_metadata__(self): #set up some default values self.__bits_per_sample__ = 16 self.__channels__ = 2 self.__channel_mask__ = 0x3 self.__sample_rate__ = 44100 self.__total_frames__ = 0 self.__blocks__ = [] self.__format__ = None #grab a few pieces of technical metadata from the Shorten file itself #which requires a dry-run through the decoder try: decoder = audiotools.decoders.SHNDecoder(self.filename) try: self.__bits_per_sample__ = decoder.bits_per_sample self.__channels__ = decoder.channels (self.__total_frames__, self.__blocks__) = decoder.metadata() finally: decoder.close() try: self.__channel_mask__ = ChannelMask.from_channels( self.__channels__) except ValueError: self.__channel_mask__ = 0 except (ValueError, IOError): #if we hit an error in SHNDecoder while reading #technical metadata, the default values will have to do return #the remainder requires parsing the file's VERBATIM blocks #which may contain Wave, AIFF or Sun AU info if (self.__blocks__[0] is not None): header = cStringIO.StringIO(self.__blocks__[0]) for format in WaveAudio, AiffAudio: header.seek(0, 0) if (format.is_type(header)): self.__format__ = format break if (self.__format__ is WaveAudio): for (chunk_id, chunk_data) in self.__wave_chunks__(): if (chunk_id == 'fmt '): fmt_chunk = WaveAudio.FMT_CHUNK.parse(chunk_data) self.__sample_rate__ = fmt_chunk.sample_rate if (fmt_chunk.compression == 0xFFFE): self.__channel_mask__ = \ WaveAudio.fmt_chunk_to_channel_mask( fmt_chunk.channel_mask) elif (self.__format__ is AiffAudio): for (chunk_id, chunk_data) in self.__aiff_chunks__(): if (chunk_id == 'COMM'): comm_chunk = AiffAudio.COMM_CHUNK.parse(chunk_data) self.__sample_rate__ = comm_chunk.sample_rate
def from_pcm(cls, filename, pcmreader, compression=None, total_pcm_frames=None, block_size=256, encoding_function=None): """encodes a new file from PCM data takes a filename string, PCMReader object, optional compression level string and optional total_pcm_frames integer encodes a new audio file from pcmreader's data at the given filename with the specified compression level and returns a new ShortenAudio object""" # can't build artificial header because we don't know # how long the PCMReader will be and there's no way # to go back and write one later because all the byte values # are stored variable-sized # so we have to build a temporary Wave file instead from audiotools import UnsupportedBitsPerSample if (pcmreader.bits_per_sample not in (8, 16)): raise UnsupportedBitsPerSample(filename, pcmreader.bits_per_sample) if (total_pcm_frames is not None): from audiotools.wav import wave_header return cls.from_wave( filename, wave_header(pcmreader.sample_rate, pcmreader.channels, pcmreader.channel_mask, pcmreader.bits_per_sample, total_pcm_frames), pcmreader, chr(0) * (((pcmreader.bits_per_sample // 8) * pcmreader.channels * total_pcm_frames) % 2), compression, block_size, encoding_function) else: from audiotools import WaveAudio import tempfile f = tempfile.NamedTemporaryFile(suffix=".wav") try: w = WaveAudio.from_pcm(f.name, pcmreader) (header, footer) = w.wave_header_footer() return cls.from_wave(filename, header, w.to_pcm(), footer, compression, block_size, encoding_function) finally: if (os.path.isfile(f.name)): f.close() else: f.close_called = True
def from_pcm(cls, filename, pcmreader, compression=None): if (pcmreader.bits_per_sample not in (8,16)): raise UnsupportedBitsPerSample() import tempfile f = tempfile.NamedTemporaryFile(suffix=".wav") w = WaveAudio.from_pcm(f.name, pcmreader) try: return cls.from_wave(filename,f.name,compression) finally: f.close()
def __populate_metadata__(self): # Alteration for BootTunes: # Since the vast majority of files will match the defaults, and because this method crashes # Windows 7 and locks up Mac, just go with the defaults. self.__bits_per_sample__ = 16 self.__channels__ = 2 self.__channel_mask__ = 0x3 self.__sample_rate__ = 44100 self.__total_frames__ = 0 self.__blocks__ = [] self.__format__ = None return #grab a few pieces of technical metadata from the Shorten file itself #which requires a dry-run through the decoder decoder = audiotools.decoders.SHNDecoder(self.filename) self.__bits_per_sample__ = decoder.bits_per_sample self.__channels__ = decoder.channels (self.__total_frames__, self.__blocks__) = decoder.metadata() decoder.close() #set up some default values self.__sample_rate__ = 44100 try: self.__channel_mask__ = ChannelMask.from_channels(self.__channels__) except ValueError: self.__channel_mask__ = 0 self.__format__ = None #the remainder requires parsing the file's VERBATIM blocks #which may contain Wave, AIFF or Sun AU info if (self.__blocks__[0] is not None): header = cStringIO.StringIO(self.__blocks__[0]) for format in WaveAudio,AiffAudio: header.seek(0,0) if (format.is_type(header)): self.__format__ = format break if (self.__format__ is WaveAudio): for (chunk_id,chunk_data) in self.__wave_chunks__(): if (chunk_id == 'fmt '): fmt_chunk = WaveAudio.FMT_CHUNK.parse(chunk_data) self.__sample_rate__ = fmt_chunk.sample_rate if (fmt_chunk.compression == 0xFFFE): self.__channel_mask__ = WaveAudio.fmt_chunk_to_channel_mask(fmt_chunk.channel_mask) elif (self.__format__ is AiffAudio): for (chunk_id,chunk_data) in self.__aiff_chunks__(): if (chunk_id == 'COMM'): comm_chunk = AiffAudio.COMM_CHUNK.parse(chunk_data) self.__sample_rate__ = comm_chunk.sample_rate
def from_wave(cls, filename, wave_filename, compression=None): wave = WaveAudio(wave_filename) if (wave.bits_per_sample() not in (8,16)): raise UnsupportedBitsPerSample() (head,tail) = wave.pcm_split() if (len(tail) > 0): blocks = [head,None,tail] else: blocks = [head,None] import audiotools.encoders try: audiotools.encoders.encode_shn(filename=filename, pcmreader=wave.to_pcm(), block_size=256, verbatim_chunks=blocks) return cls(filename) except IOError: raise EncodingError("shn")
def from_pcm(cls, filename, pcmreader, compression=None): """Encodes a new file from PCM data. Takes a filename string, PCMReader object and optional compression level string. Encodes a new audio file from pcmreader's data at the given filename with the specified compression level and returns a new M4AAudio object.""" if (compression is None) or (compression not in cls.COMPRESSION_MODES): compression = __default_quality__(cls.NAME) import tempfile tempwavefile = tempfile.NamedTemporaryFile(suffix=".wav") try: if pcmreader.sample_rate > 96000: tempwave = WaveAudio.from_pcm( tempwavefile.name, PCMConverter( pcmreader, sample_rate=96000, channels=pcmreader.channels, channel_mask=pcmreader.channel_mask, bits_per_sample=pcmreader.bits_per_sample, ), ) else: tempwave = WaveAudio.from_pcm(tempwavefile.name, pcmreader) cls.__from_wave__(filename, tempwave.filename, compression) return cls(filename) finally: if os.path.isfile(tempwavefile.name): tempwavefile.close() else: tempwavefile.close_called = True
def from_wave(cls, filename, wave_filename, compression=None, block_size=256, progress=None): """Encodes a new AudioFile from an existing .wav file. Takes a filename string, wave_filename string of an existing WaveAudio file and an optional compression level string. Encodes a new audio file from the wave's data at the given filename with the specified compression level and returns a new ShortenAudio object.""" wave = WaveAudio(wave_filename) if (wave.bits_per_sample() not in (8, 16)): raise UnsupportedBitsPerSample(filename, wave.bits_per_sample()) (head, tail) = wave.pcm_split() if (len(tail) > 0): blocks = [head, None, tail] else: blocks = [head, None] import audiotools.encoders try: audiotools.encoders.encode_shn( filename=filename, pcmreader=to_pcm_progress(wave, progress), block_size=block_size, file_type={8: 2, 16: 5}[wave.bits_per_sample()], verbatim_chunks=blocks) return cls(filename) except IOError, err: cls.__unlink__(filename) raise EncodingError(str(err))
def from_wave(cls, filename, wave_filename, compression=None, progress=None): """Encodes a new AudioFile from an existing .wav file. Takes a filename string, wave_filename string of an existing WaveAudio file and an optional compression level string. Encodes a new audio file from the wave's data at the given filename with the specified compression level and returns a new M4AAudio object.""" if (compression is None) or (compression not in cls.COMPRESSION_MODES): compression = __default_quality__(cls.NAME) try: wave = WaveAudio(wave_filename) wave.verify() except InvalidFile: raise EncodingError(u"invalid wave file") if wave.sample_rate > 96000: # convert through PCMConverter if sample rate is too high import tempfile tempwavefile = tempfile.NamedTemporaryFile(suffix=".wav") try: tempwave = WaveAudio.from_pcm( tempwavefile.name, PCMConverter( to_pcm_progress(wave, progress), sample_rate=96000, channels=wave.channels(), channel_mask=wave.channel_mask(), bits_per_sample=wave.bits_per_sample(), ), ) return cls.__from_wave__(filename, tempwave.filename, compression) finally: if os.path.isfile(tempwavefile.name): tempwavefile.close() else: tempwavefile.close_called = True else: return cls.__from_wave__(filename, wave_filename, compression)
def from_pcm(cls, filename, pcmreader, compression=None, block_size=256): """encodes a new file from PCM data takes a filename string, PCMReader object and optional compression level string encodes a new audio file from pcmreader's data at the given filename with the specified compression level and returns a new ShortenAudio object""" if pcmreader.bits_per_sample not in (8, 16): raise UnsupportedBitsPerSample(filename, pcmreader.bits_per_sample) import tempfile f = tempfile.NamedTemporaryFile(suffix=".wav") try: w = WaveAudio.from_pcm(f.name, pcmreader) return cls.from_wave(filename, f.name, compression, block_size) finally: if os.path.isfile(f.name): f.close() else: f.close_called = True
def from_wave(cls, filename, wave_filename, compression=None, block_size=256, progress=None): """encodes a new AudioFile from an existing .wav file takes a filename string, wave_filename string of an existing WaveAudio file and an optional compression level string encodes a new audio file from the wave's data at the given filename with the specified compression level and returns a new ShortenAudio object""" wave = WaveAudio(wave_filename) if wave.bits_per_sample() not in (8, 16): raise UnsupportedBitsPerSample(filename, wave.bits_per_sample()) (head, tail) = wave.pcm_split() from .encoders import encode_shn try: if len(tail) == 0: encode_shn( filename=filename, pcmreader=to_pcm_progress(wave, progress), is_big_endian=False, signed_samples=wave.bits_per_sample() == 16, header_data=head, block_size=block_size, ) else: encode_shn( filename=filename, pcmreader=to_pcm_progress(wave, progress), is_big_endian=False, signed_samples=wave.bits_per_sample() == 16, header_data=head, footer_data=tail, block_size=block_size, ) return cls(filename) except IOError, err: cls.__unlink__(filename) raise EncodingError(str(err))
def from_pcm(cls, filename, pcmreader, compression=None, block_size=256): """Encodes a new file from PCM data. Takes a filename string, PCMReader object and optional compression level string. Encodes a new audio file from pcmreader's data at the given filename with the specified compression level and returns a new ShortenAudio object.""" if (pcmreader.bits_per_sample not in (8, 16)): raise UnsupportedBitsPerSample() import tempfile f = tempfile.NamedTemporaryFile(suffix=".wav") try: w = WaveAudio.from_pcm(f.name, pcmreader) return cls.from_wave(filename, f.name, compression, block_size) finally: if (os.path.isfile(f.name)): f.close() else: f.close_called = True
def play_wave(self, stream): """ @param stream: A pyaudio.Stream object """ pcm = self.to_pcm() WaveAudio.from_pcm_to_stream(pcm, stream)
current_frames = 0 decoder = decoders.SHNDecoder(self.filename) frame = decoder.read(4096) while (len(frame) > 0): f.write(frame.to_bytes(False, self.bits_per_sample() > 8)) current_frames += frame.frames if (progress is not None): progress(current_frames, total_frames) frame = decoder.read(4096) f.write(tail) f.close() except IOError, msg: self.__unlink__(wave_filename) raise EncodingError(str(msg)) else: WaveAudio.from_pcm(wave_filename, to_pcm_progress(self, progress)) def to_aiff(self, aiff_filename, progress=None): """writes the contents of this file to the given .aiff filename string raises EncodingError if some error occurs during decoding""" from . import decoders try: (head, tail) = decoders.SHNDecoder(self.filename).pcm_split() except IOError: raise EncodingError(str(msg)) if ((head[0:4] == 'FORM') and (head[8:12] == 'AIFF')): try:
def from_pcm(cls, filename, pcmreader, compression=None, total_pcm_frames=None, block_size=256, encoding_function=None): """encodes a new file from PCM data takes a filename string, PCMReader object, optional compression level string and optional total_pcm_frames integer encodes a new audio file from pcmreader's data at the given filename with the specified compression level and returns a new ShortenAudio object""" # can't build artificial header because we don't know # how long the PCMReader will be and there's no way # to go back and write one later because all the byte values # are stored variable-sized # so we have to build a temporary Wave file instead from audiotools import UnsupportedBitsPerSample if (pcmreader.bits_per_sample not in (8, 16)): raise UnsupportedBitsPerSample(filename, pcmreader.bits_per_sample) if (total_pcm_frames is not None): from audiotools.wav import wave_header return cls.from_wave(filename, wave_header(pcmreader.sample_rate, pcmreader.channels, pcmreader.channel_mask, pcmreader.bits_per_sample, total_pcm_frames), pcmreader, chr(0) * (((pcmreader.bits_per_sample // 8) * pcmreader.channels * total_pcm_frames) % 2), compression, block_size, encoding_function) else: from audiotools import WaveAudio import tempfile f = tempfile.NamedTemporaryFile(suffix=".wav") try: w = WaveAudio.from_pcm(f.name, pcmreader) (header, footer) = w.wave_header_footer() return cls.from_wave(filename, header, w.to_pcm(), footer, compression, block_size, encoding_function) finally: if (os.path.isfile(f.name)): f.close() else: f.close_called = True
try: f = open(wave_filename, 'wb') except IOError, msg: raise EncodingError(str(msg)) for block in self.__blocks__: if (block is not None): f.write(block) else: try: transfer_framelist_data( audiotools.decoders.SHNDecoder(self.filename), f.write) except IOError, msg: raise EncodingError(str(msg)) else: WaveAudio.from_pcm(wave_filename, self.to_pcm()) @classmethod def from_wave(cls, filename, wave_filename, compression=None, block_size=256): """Encodes a new AudioFile from an existing .wav file. Takes a filename string, wave_filename string of an existing WaveAudio file and an optional compression level string. Encodes a new audio file from the wave's data at the given filename with the specified compression level and returns a new ShortenAudio object.""" wave = WaveAudio(wave_filename)