def to_pcm(self): #if mpg123 is available, use that for decoding if (BIN.can_execute(BIN["mpg123"])): sub = subprocess.Popen([BIN["mpg123"],"-qs",self.filename], stdout=subprocess.PIPE, stderr=file(os.devnull,"a")) return PCMReader(sub.stdout, sample_rate=self.sample_rate(), channels=self.channels(), bits_per_sample=16, channel_mask=int(ChannelMask.from_channels(self.channels())), process=sub, big_endian=BIG_ENDIAN) else: #if not, use LAME for decoding if (self.filename.endswith("." + self.SUFFIX)): if (BIG_ENDIAN): endian = ['-x'] else: endian = [] sub = subprocess.Popen([BIN['lame']] + endian + \ ["--decode","-t","--quiet", self.filename,"-"], stdout=subprocess.PIPE) return PCMReader(sub.stdout, sample_rate=self.sample_rate(), channels=self.channels(), bits_per_sample=16, channel_mask=int(ChannelMask.from_channels(self.channels())), process=sub) else: import tempfile from audiotools import TempWaveReader #copy our file to one that ends with .mp3 tempmp3 = tempfile.NamedTemporaryFile(suffix='.' + self.SUFFIX) f = open(self.filename,'rb') transfer_data(f.read,tempmp3.write) f.close() tempmp3.flush() #decode the mp3 file to a WAVE file wave = tempfile.NamedTemporaryFile(suffix='.wav') returnval = subprocess.call([BIN['lame'],"--decode","--quiet", tempmp3.name,wave.name]) tempmp3.close() if (returnval == 0): #return WAVE file as a stream wave.seek(0,0) return TempWaveReader(wave) else: return PCMReaderError(None, sample_rate=self.sample_rate(), channels=self.channels(), bits_per_sample=16)
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 MP2Audio object""" from audiotools import (PCMConverter, BufferedPCMReader, ChannelMask, __default_quality__, EncodingError) from audiotools.encoders import encode_mp2 import bisect if (((compression is None) or (compression not in cls.COMPRESSION_MODES))): compression = __default_quality__(cls.NAME) if pcmreader.sample_rate in (32000, 48000, 44100): sample_rate = pcmreader.sample_rate else: sample_rate = [32000, 32000, 44100, 48000][bisect.bisect([32000, 44100, 48000], pcmreader.sample_rate)] if total_pcm_frames is not None: from audiotools import CounterPCMReader pcmreader = CounterPCMReader(pcmreader) try: encode_mp2(filename, PCMConverter(pcmreader, sample_rate=sample_rate, channels=min(pcmreader.channels, 2), channel_mask=ChannelMask.from_channels( min(pcmreader.channels, 2)), bits_per_sample=16), int(compression)) if ((total_pcm_frames is not None) and (total_pcm_frames != pcmreader.frames_written)): from audiotools.text import ERR_TOTAL_PCM_FRAMES_MISMATCH cls.__unlink__(filename) raise EncodingError(ERR_TOTAL_PCM_FRAMES_MISMATCH) return MP2Audio(filename) except (ValueError, IOError) as err: cls.__unlink__(filename) raise EncodingError(str(err)) finally: pcmreader.close()
def channel_mask(self): """Returns a ChannelMask object of this track's channel layout.""" if (self.channels() <= 2): return ChannelMask.from_channels(self.channels()) else: return ChannelMask(0)
def from_pcm(cls, filename, pcmreader, compression="2"): import decimal,bisect if (compression not in cls.COMPRESSION_MODES): compression = cls.DEFAULT_COMPRESSION if ((pcmreader.channels > 2) or (pcmreader.sample_rate not in (32000,48000,44100))): pcmreader = PCMConverter( pcmreader, sample_rate=[32000,32000,44100,48000][bisect.bisect( [32000,44100,48000],pcmreader.sample_rate)], channels=min(pcmreader.channels,2), channel_mask=ChannelMask.from_channels(min(pcmreader.channels,2)), bits_per_sample=16) if (pcmreader.channels > 1): mode = "j" else: mode = "m" #FIXME - not sure if all LAME versions support "--little-endian" # #LAME 3.98 (and up, presumably) handle the byteswap correctly # #LAME 3.97 always uses -x # if (BIG_ENDIAN or (cls.__lame_version__() < (3,98))): # endian = ['-x'] # else: # endian = [] devnull = file(os.devnull,'ab') sub = subprocess.Popen([BIN['lame'],"--quiet", "-r", "-s",str(decimal.Decimal(pcmreader.sample_rate) / 1000), "--bitwidth",str(pcmreader.bits_per_sample), "--signed","--little-endian", "-m",mode, "-V" + str(compression), "-", filename], stdin=subprocess.PIPE, stdout=devnull, stderr=devnull, preexec_fn=ignore_sigint) transfer_framelist_data(pcmreader,sub.stdin.write) try: pcmreader.close() except DecodingError: raise EncodingError() sub.stdin.close() devnull.close() if (sub.wait() == 0): return MP3Audio(filename) else: raise EncodingError(BIN['lame'])
def channel_mask(self): """Returns a ChannelMask object of this track's channel layout.""" if (self.channels() <= 2): return ChannelMask.from_channels(self.channels()) else: return ChannelMask(0)
def channel_mask(self): from audiotools import ChannelMask """returns a ChannelMask object of this track's channel layout""" if (self.channels() <= 2): return ChannelMask.from_channels(self.channels()) else: return ChannelMask(0)
def channel_mask(self): from audiotools import ChannelMask """returns a ChannelMask object of this track's channel layout""" if self.channels() <= 2: return ChannelMask.from_channels(self.channels()) else: return ChannelMask(0)
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 __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): """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 SpeexAudio object.""" import bisect if ((compression is None) or (compression not in cls.COMPRESSION_MODES)): compression = __default_quality__(cls.NAME) if ((pcmreader.bits_per_sample not in (8, 16)) or (pcmreader.channels > 2) or (pcmreader.sample_rate not in (8000, 16000, 32000, 44100))): pcmreader = PCMConverter( pcmreader, sample_rate=[8000, 8000, 16000, 32000, 44100][bisect.bisect([8000, 16000, 32000, 44100], pcmreader.sample_rate)], channels=min(pcmreader.channels, 2), channel_mask=ChannelMask.from_channels( min(pcmreader.channels, 2)), bits_per_sample=min(pcmreader.bits_per_sample, 16)) BITS_PER_SAMPLE = { 8: ['--8bit'], 16: ['--16bit'] }[pcmreader.bits_per_sample] CHANNELS = {1: [], 2: ['--stereo']}[pcmreader.channels] devnull = file(os.devnull, "ab") sub = subprocess.Popen([BIN['speexenc'], '--quality', str(compression), '--rate', str(pcmreader.sample_rate), '--le'] + \ BITS_PER_SAMPLE + \ CHANNELS + \ ['-', filename], stdin=subprocess.PIPE, stderr=devnull, preexec_fn=ignore_sigint) try: transfer_framelist_data(pcmreader, sub.stdin.write) except (IOError, ValueError), err: sub.stdin.close() sub.wait() cls.__unlink__(filename) raise EncodingError(str(err))
def to_pcm(self): devnull = file(os.devnull,'ab') sub = subprocess.Popen([BIN['speexdec'],self.filename,'-'], stdout=subprocess.PIPE, stderr=devnull) return PCMReader( sub.stdout, sample_rate=self.sample_rate(), channels=self.channels(), channel_mask=int(ChannelMask.from_channels(self.channels())), bits_per_sample=self.bits_per_sample(), process=sub)
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 SpeexAudio object.""" import bisect if ((compression is None) or (compression not in cls.COMPRESSION_MODES)): compression = __default_quality__(cls.NAME) if ((pcmreader.bits_per_sample not in (8, 16)) or (pcmreader.channels > 2) or (pcmreader.sample_rate not in (8000, 16000, 32000, 44100))): pcmreader = PCMConverter( pcmreader, sample_rate=[8000, 8000, 16000, 32000, 44100][bisect.bisect( [8000, 16000, 32000, 44100], pcmreader.sample_rate)], channels=min(pcmreader.channels, 2), channel_mask=ChannelMask.from_channels( min(pcmreader.channels, 2)), bits_per_sample=min(pcmreader.bits_per_sample, 16)) BITS_PER_SAMPLE = {8: ['--8bit'], 16: ['--16bit']}[pcmreader.bits_per_sample] CHANNELS = {1: [], 2: ['--stereo']}[pcmreader.channels] devnull = file(os.devnull, "ab") sub = subprocess.Popen([BIN['speexenc'], '--quality', str(compression), '--rate', str(pcmreader.sample_rate), '--le'] + \ BITS_PER_SAMPLE + \ CHANNELS + \ ['-', filename], stdin=subprocess.PIPE, stderr=devnull, preexec_fn=ignore_sigint) try: transfer_framelist_data(pcmreader, sub.stdin.write) except (IOError, ValueError), err: sub.stdin.close() sub.wait() cls.__unlink__(filename) raise EncodingError(str(err))
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 channel_mask(self): """Returns a ChannelMask object of this track's channel layout.""" if ((self.__channels__ == 1) or (self.__channels__ == 2)): return ChannelMask.from_channels(self.__channels__) else: for (block_id, nondecoder, data) in self.sub_frames(): if ((block_id == 0xD) and not nondecoder): mask = 0 for byte in reversed(map(ord, data[1:])): mask = (mask << 8) | byte return ChannelMask(mask) else: return ChannelMask(0)
def to_pcm(self): """Returns a PCMReader object containing the track's PCM data.""" devnull = file(os.devnull, 'ab') sub = subprocess.Popen([BIN['speexdec'], self.filename, '-'], stdout=subprocess.PIPE, stderr=devnull) return PCMReader( sub.stdout, sample_rate=self.sample_rate(), channels=self.channels(), channel_mask=int(ChannelMask.from_channels(self.channels())), bits_per_sample=self.bits_per_sample(), process=sub)
def channel_mask(self): """Returns a ChannelMask object of this track's channel layout.""" if ((self.__channels__ == 1) or (self.__channels__ == 2)): return ChannelMask.from_channels(self.__channels__) else: for (block_id, nondecoder, data) in self.sub_frames(): if ((block_id == 0xD) and not nondecoder): mask = 0 for byte in reversed(map(ord, data[1:])): mask = (mask << 8) | byte return ChannelMask(mask) else: return ChannelMask(0)
def from_pcm(cls, filename, pcmreader, compression=None): import bisect if (compression not in cls.COMPRESSION_MODES): compression = cls.DEFAULT_COMPRESSION if ((pcmreader.bits_per_sample not in (8,16)) or (pcmreader.channels > 2) or (pcmreader.sample_rate not in (8000,16000,32000,44100))): pcmreader = PCMConverter( pcmreader, sample_rate=[8000,8000,16000,32000,44100][bisect.bisect( [8000,16000,32000,44100],pcmreader.sample_rate)], channels=min(pcmreader.channels,2), channel_mask=ChannelMask.from_channels(min(pcmreader.channels,2)), bits_per_sample=min(pcmreader.bits_per_sample,16)) BITS_PER_SAMPLE = {8:['--8bit'], 16:['--16bit']}[pcmreader.bits_per_sample] CHANNELS = {1:[],2:['--stereo']}[pcmreader.channels] devnull = file(os.devnull,"ab") sub = subprocess.Popen([BIN['speexenc'], '--quality',str(compression), '--rate',str(pcmreader.sample_rate), '--le'] + \ BITS_PER_SAMPLE + \ CHANNELS + \ ['-',filename], stdin=subprocess.PIPE, stderr=devnull, preexec_fn=ignore_sigint) transfer_framelist_data(pcmreader,sub.stdin.write) try: pcmreader.close() except DecodingError: raise EncodingError() sub.stdin.close() result = sub.wait() devnull.close() if (result == 0): return SpeexAudio(filename) else: raise EncodingError(BIN['speexenc'])
def to_pcm(self): """returns a PCMReader object containing the track's PCM data""" BIG_ENDIAN = sys.byteorder == 'big' sub = subprocess.Popen([BIN["mpg123"], "-qs", self.filename], stdout=subprocess.PIPE, stderr=file(os.devnull, "a")) return PCMReader(sub.stdout, sample_rate=self.sample_rate(), channels=self.channels(), bits_per_sample=16, channel_mask=int(ChannelMask.from_channels( self.channels())), process=sub, big_endian=BIG_ENDIAN)
def parse_comm(comm): """given a COMM chunk (without the 8 byte name/size header) returns (channels, total_sample_frames, bits_per_sample, sample_rate, channel_mask) where channel_mask is a ChannelMask object and the rest are ints may raise IOError if an error occurs reading the chunk""" (channels, total_sample_frames, bits_per_sample) = comm.parse("16u 32u 16u") sample_rate = int(parse_ieee_extended(comm)) if (channels <= 2): channel_mask = ChannelMask.from_channels(channels) else: channel_mask = ChannelMask(0) return (channels, total_sample_frames, bits_per_sample, sample_rate, channel_mask)
def parse_comm(comm): """given a COMM chunk (without the 8 byte name/size header) returns (channels, total_sample_frames, bits_per_sample, sample_rate, channel_mask) where channel_mask is a ChannelMask object and the rest are ints may raise IOError if an error occurs reading the chunk""" from audiotools import ChannelMask (channels, total_sample_frames, bits_per_sample) = comm.parse("16u 32u 16u") sample_rate = int(parse_ieee_extended(comm)) if channels <= 2: channel_mask = ChannelMask.from_channels(channels) else: channel_mask = ChannelMask(0) return (channels, total_sample_frames, bits_per_sample, sample_rate, channel_mask)
def channel_mask(self): """Returns a ChannelMask object of this track's channel layout.""" #this unusual arrangement is taken from the AIFF specification if (self.channels() <= 2): return ChannelMask.from_channels(self.channels()) elif (self.channels() == 3): return ChannelMask.from_fields( front_left=True, front_right=True, front_center=True) elif (self.channels() == 4): return ChannelMask.from_fields( front_left=True, front_right=True, back_left=True, back_right=True) elif (self.channels() == 6): return ChannelMask.from_fields( front_left=True, side_left=True, front_center=True, front_right=True, side_right=True, back_center=True) else: return ChannelMask(0)
def channel_mask(self): #this unusual arrangement is taken from the AIFF specification if (self.channels() <= 2): return ChannelMask.from_channels(self.channels()) elif (self.channels() == 3): return ChannelMask.from_fields(front_left=True, front_right=True, front_center=True) elif (self.channels() == 4): return ChannelMask.from_fields(front_left=True, front_right=True, back_left=True, back_right=True) elif (self.channels() == 6): return ChannelMask.from_fields(front_left=True, side_left=True, front_center=True, front_right=True, side_right=True, back_center=True) else: return ChannelMask(0)
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 MP3Audio object""" from audiotools import (PCMConverter, BufferedPCMReader, ChannelMask, __default_quality__, EncodingError) from audiotools.encoders import encode_mp3 if (((compression is None) or (compression not in cls.COMPRESSION_MODES))): compression = __default_quality__(cls.NAME) try: encode_mp3( filename, BufferedPCMReader( PCMConverter(pcmreader, sample_rate=pcmreader.sample_rate, channels=min(pcmreader.channels, 2), channel_mask=ChannelMask.from_channels( min(pcmreader.channels, 2)), bits_per_sample=16)), compression) return MP3Audio(filename) except (ValueError, 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 MP3Audio object""" from audiotools import (PCMConverter, BufferedPCMReader, ChannelMask, __default_quality__, EncodingError) from audiotools.encoders import encode_mp3 if (((compression is None) or (compression not in cls.COMPRESSION_MODES))): compression = __default_quality__(cls.NAME) try: encode_mp3(filename, BufferedPCMReader( PCMConverter(pcmreader, sample_rate=pcmreader.sample_rate, channels=min(pcmreader.channels, 2), channel_mask=ChannelMask.from_channels( min(pcmreader.channels, 2)), bits_per_sample=16)), compression) return MP3Audio(filename) except (ValueError, IOError), err: cls.__unlink__(filename) raise EncodingError(str(err))
def from_pcm(cls, filename, pcmreader, compression=None, total_pcm_frames=None): from audiotools import __default_quality__ from audiotools import PCMConverter from audiotools import ChannelMask from audiotools.encoders import encode_mpc if (compression is None) or (compression not in cls.COMPRESSION_MODES): compression = __default_quality__(cls.NAME) if pcmreader.bits_per_sample not in {8, 16, 24}: from audiotools import UnsupportedBitsPerSample pcmreader.close() raise UnsupportedBitsPerSample(filename, pcmreader.bits_per_sample) if pcmreader.sample_rate in (32000, 37800, 44100, 48000): sample_rate = pcmreader.sample_rate if total_pcm_frames is not None: from audiotools import CounterPCMReader pcmreader = CounterPCMReader(pcmreader) else: from bisect import bisect sample_rate = [32000, 32000, 37800, 44100, 48000][bisect([32000, 37800, 44100, 4800], pcmreader.sample_rate)] total_pcm_frames = None try: encode_mpc( filename, PCMConverter(pcmreader, sample_rate=sample_rate, channels=min(pcmreader.channels, 2), channel_mask=int(ChannelMask.from_channels( min(pcmreader.channels, 2))), bits_per_sample=16), float(compression), total_pcm_frames if (total_pcm_frames is not None) else 0) # ensure PCM frames match, if indicated if ((total_pcm_frames is not None) and (total_pcm_frames != pcmreader.frames_written)): from audiotools.text import ERR_TOTAL_PCM_FRAMES_MISMATCH from audiotools import EncodingError raise EncodingError(ERR_TOTAL_PCM_FRAMES_MISMATCH) return MPCAudio(filename) except (IOError, ValueError) as err: from audiotools import EncodingError cls.__unlink__(filename) raise EncodingError(str(err)) except Exception: cls.__unlink__(filename) raise finally: pcmreader.close()
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) if pcmreader.channels > 2: pcmreader = PCMConverter( pcmreader, sample_rate=pcmreader.sample_rate, channels=2, channel_mask=ChannelMask.from_channels(2), bits_per_sample=pcmreader.bits_per_sample, ) # faac requires files to end with .m4a for some reason if not filename.endswith(".m4a"): import tempfile actual_filename = filename tempfile = tempfile.NamedTemporaryFile(suffix=".m4a") filename = tempfile.name else: actual_filename = tempfile = None devnull = file(os.devnull, "ab") sub = subprocess.Popen( [ BIN["faac"], "-q", compression, "-P", "-R", str(pcmreader.sample_rate), "-B", str(pcmreader.bits_per_sample), "-C", str(pcmreader.channels), "-X", "-o", filename, "-", ], stdin=subprocess.PIPE, stderr=devnull, stdout=devnull, preexec_fn=ignore_sigint, ) # Note: faac handles SIGINT on its own, # so trying to ignore it doesn't work like on most other encoders. try: transfer_framelist_data(pcmreader, sub.stdin.write) except (ValueError, IOError), err: sub.stdin.close() sub.wait() 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 subprocess import os from audiotools import PCMConverter from audiotools import transfer_data from audiotools import transfer_framelist_data from audiotools import ignore_sigint from audiotools import EncodingError from audiotools import DecodingError from audiotools import ChannelMask from audiotools import __default_quality__ if ((compression is None) or (compression not in cls.COMPRESSION_MODES)): compression = __default_quality__(cls.NAME) if pcmreader.channels > 2: pcmreader = PCMConverter(pcmreader, sample_rate=pcmreader.sample_rate, channels=2, channel_mask=ChannelMask.from_channels(2), bits_per_sample=pcmreader.bits_per_sample) # faac requires files to end with .m4a for some reason if not filename.endswith(".m4a"): import tempfile actual_filename = filename tempfile = tempfile.NamedTemporaryFile(suffix=".m4a") filename = tempfile.name else: actual_filename = tempfile = None sub = subprocess.Popen( [ BIN['faac'], "-q", compression, "-P", "-R", str(pcmreader.sample_rate), "-B", str(pcmreader.bits_per_sample), "-C", str(pcmreader.channels), "-X", "-o", filename, "-" ], stdin=subprocess.PIPE, stderr=subprocess.DEVNULL if hasattr(subprocess, "DEVNULL") else open(os.devnull, "wb"), stdout=subprocess.DEVNULL if hasattr(subprocess, "DEVNULL") else open(os.devnull, "wb"), preexec_fn=ignore_sigint) # Note: faac handles SIGINT on its own, # so trying to ignore it doesn't work like on most other encoders. try: if total_pcm_frames is not None: from audiotools import CounterPCMReader pcmreader = CounterPCMReader(pcmreader) transfer_framelist_data(pcmreader, sub.stdin.write) if ((total_pcm_frames is not None) and (total_pcm_frames != pcmreader.frames_written)): from audiotools.text import ERR_TOTAL_PCM_FRAMES_MISMATCH raise EncodingError(ERR_TOTAL_PCM_FRAMES_MISMATCH) except (ValueError, IOError) as err: sub.stdin.close() sub.wait() cls.__unlink__(filename) raise EncodingError(str(err)) except Exception: sub.stdin.close() sub.wait() cls.__unlink__(filename) raise sub.stdin.close() if sub.wait() == 0: if tempfile is not None: filename = actual_filename f = open(filename, 'wb') tempfile.seek(0, 0) transfer_data(tempfile.read, f.write) f.close() tempfile.close() return M4AAudio(filename) else: if tempfile is not None: tempfile.close() raise EncodingError(u"unable to write file with faac")
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 AudioFile-compatible object specifying total_pcm_frames, when the number is known in advance, may allow the encoder to work more efficiently but is never required """ import bisect import os import subprocess from audiotools import __default_quality__ from audiotools import transfer_framelist_data from audiotools import EncodingError from audiotools import PCMConverter from audiotools import ChannelMask if ((compression is None) or (compression not in cls.COMPRESSION_MODES)): compression = __default_quality__(cls.NAME) if pcmreader.bits_per_sample not in (8, 16, 24): from audiotools import UnsupportedBitsPerSample raise UnsupportedBitsPerSample( filename, pcmreader.bits_per_sample) if total_pcm_frames is not None: from audiotools import CounterPCMReader counter_reader = CounterPCMReader(pcmreader) else: counter_reader = pcmreader pcmreader = PCMConverter( counter_reader, sample_rate=[8000, 8000, 16000, 32000][bisect.bisect( [8000, 16000, 32000], pcmreader.sample_rate)], channels=min(pcmreader.channels, 2), channel_mask=ChannelMask.from_channels( min(pcmreader.channels, 2)), bits_per_sample=min(pcmreader.bits_per_sample, 16)) BITS_PER_SAMPLE = {8: ['--8bit'], 16: ['--16bit']}[pcmreader.bits_per_sample] CHANNELS = {1: [], 2: ['--stereo']}[pcmreader.channels] sub = subprocess.Popen( [BIN['speexenc'], '--quality', str(compression), '--rate', str(pcmreader.sample_rate), '--le'] + \ BITS_PER_SAMPLE + \ CHANNELS + \ ['-', filename], stdin=subprocess.PIPE, stderr=subprocess.DEVNULL if hasattr(subprocess, "DEVNULL") else open(os.devnull, "wb")) try: transfer_framelist_data(pcmreader, sub.stdin.write) except (IOError, ValueError) as err: sub.stdin.close() sub.wait() cls.__unlink__(filename) raise EncodingError(str(err)) except Exception as err: sub.stdin.close() sub.wait() cls.__unlink__(filename) raise err sub.stdin.close() if sub.wait() == 0: if ((total_pcm_frames is None) or (total_pcm_frames == counter_reader.frames_written)): return SpeexAudio(filename) else: from audiotools.text import ERR_TOTAL_PCM_FRAMES_MISMATCH cls.__unlink__(filename) raise EncodingError(ERR_TOTAL_PCM_FRAMES_MISMATCH) else: raise EncodingError(u"unable to encode file with speexenc")
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 AudioFile-compatible object specifying total_pcm_frames, when the number is known in advance, may allow the encoder to work more efficiently but is never required """ import bisect import os import subprocess from audiotools import __default_quality__ from audiotools import transfer_framelist_data from audiotools import EncodingError from audiotools import PCMConverter from audiotools import ChannelMask if ((compression is None) or (compression not in cls.COMPRESSION_MODES)): compression = __default_quality__(cls.NAME) if pcmreader.bits_per_sample not in (8, 16, 24): from audiotools import UnsupportedBitsPerSample raise UnsupportedBitsPerSample(filename, pcmreader.bits_per_sample) if total_pcm_frames is not None: from audiotools import CounterPCMReader counter_reader = CounterPCMReader(pcmreader) else: counter_reader = pcmreader pcmreader = PCMConverter( counter_reader, sample_rate=[8000, 8000, 16000, 32000][bisect.bisect([8000, 16000, 32000], pcmreader.sample_rate)], channels=min(pcmreader.channels, 2), channel_mask=ChannelMask.from_channels(min(pcmreader.channels, 2)), bits_per_sample=min(pcmreader.bits_per_sample, 16)) BITS_PER_SAMPLE = { 8: ['--8bit'], 16: ['--16bit'] }[pcmreader.bits_per_sample] CHANNELS = {1: [], 2: ['--stereo']}[pcmreader.channels] sub = subprocess.Popen( [BIN['speexenc'], '--quality', str(compression), '--rate', str(pcmreader.sample_rate), '--le'] + \ BITS_PER_SAMPLE + \ CHANNELS + \ ['-', filename], stdin=subprocess.PIPE, stderr=subprocess.DEVNULL if hasattr(subprocess, "DEVNULL") else open(os.devnull, "wb")) try: transfer_framelist_data(pcmreader, sub.stdin.write) except (IOError, ValueError) as err: sub.stdin.close() sub.wait() cls.__unlink__(filename) raise EncodingError(str(err)) except Exception as err: sub.stdin.close() sub.wait() cls.__unlink__(filename) raise err sub.stdin.close() if sub.wait() == 0: if ((total_pcm_frames is None) or (total_pcm_frames == counter_reader.frames_written)): return SpeexAudio(filename) else: from audiotools.text import ERR_TOTAL_PCM_FRAMES_MISMATCH cls.__unlink__(filename) raise EncodingError(ERR_TOTAL_PCM_FRAMES_MISMATCH) else: raise EncodingError(u"unable to encode file with speexenc")
def from_pcm(cls, filename, pcmreader, compression=None, total_pcm_frames=None): from audiotools import __default_quality__ from audiotools import PCMConverter from audiotools import ChannelMask from audiotools.encoders import encode_mpc if (compression is None) or (compression not in cls.COMPRESSION_MODES): compression = __default_quality__(cls.NAME) if pcmreader.bits_per_sample not in {8, 16, 24}: from audiotools import UnsupportedBitsPerSample pcmreader.close() raise UnsupportedBitsPerSample(filename, pcmreader.bits_per_sample) if pcmreader.sample_rate in (32000, 37800, 44100, 48000): sample_rate = pcmreader.sample_rate if total_pcm_frames is not None: from audiotools import CounterPCMReader pcmreader = CounterPCMReader(pcmreader) else: from bisect import bisect sample_rate = [32000, 32000, 37800, 44100, 48000][bisect([32000, 37800, 44100, 4800], pcmreader.sample_rate)] total_pcm_frames = None try: encode_mpc( filename, PCMConverter(pcmreader, sample_rate=sample_rate, channels=min(pcmreader.channels, 2), channel_mask=int( ChannelMask.from_channels( min(pcmreader.channels, 2))), bits_per_sample=16), float(compression), total_pcm_frames if (total_pcm_frames is not None) else 0) # ensure PCM frames match, if indicated if ((total_pcm_frames is not None) and (total_pcm_frames != pcmreader.frames_written)): from audiotools.text import ERR_TOTAL_PCM_FRAMES_MISMATCH from audiotools import EncodingError raise EncodingError(ERR_TOTAL_PCM_FRAMES_MISMATCH) return MPCAudio(filename) except (IOError, ValueError) as err: from audiotools import EncodingError cls.__unlink__(filename) raise EncodingError(str(err)) except Exception: cls.__unlink__(filename) raise finally: pcmreader.close()
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 MP3Audio object.""" import decimal import bisect if ((compression is None) or (compression not in cls.COMPRESSION_MODES)): compression = __default_quality__(cls.NAME) if ((pcmreader.channels > 2) or (pcmreader.sample_rate not in (32000, 48000, 44100))): pcmreader = PCMConverter( pcmreader, sample_rate=[32000, 32000, 44100, 48000][bisect.bisect( [32000, 44100, 48000], pcmreader.sample_rate)], channels=min(pcmreader.channels, 2), channel_mask=ChannelMask.from_channels( min(pcmreader.channels, 2)), bits_per_sample=16) if (pcmreader.channels > 1): mode = "j" else: mode = "m" #FIXME - not sure if all LAME versions support "--little-endian" # #LAME 3.98 (and up, presumably) handle the byteswap correctly # #LAME 3.97 always uses -x # if (BIG_ENDIAN or (cls.__lame_version__() < (3,98))): # endian = ['-x'] # else: # endian = [] devnull = file(os.devnull, 'ab') if (str(compression) in map(str, range(0, 10))): compression = ["-V" + str(compression)] else: compression = ["--preset", str(compression)] sub = subprocess.Popen([ BIN['lame'], "--quiet", "-r", "-s", str(decimal.Decimal(pcmreader.sample_rate) / 1000), "--bitwidth", str(pcmreader.bits_per_sample), "--signed", "--little-endian", "-m", mode] + compression + ["-", filename], stdin=subprocess.PIPE, stdout=devnull, stderr=devnull, preexec_fn=ignore_sigint) try: transfer_framelist_data(pcmreader, sub.stdin.write) except (IOError, ValueError), err: sub.stdin.close() sub.wait() cls.__unlink__(filename) raise EncodingError(str(err))
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 MP3Audio object.""" import decimal import bisect if ((compression is None) or (compression not in cls.COMPRESSION_MODES)): compression = __default_quality__(cls.NAME) if ((pcmreader.channels > 2) or (pcmreader.sample_rate not in (32000, 48000, 44100))): pcmreader = PCMConverter( pcmreader, sample_rate=[32000, 32000, 44100, 48000][bisect.bisect( [32000, 44100, 48000], pcmreader.sample_rate)], channels=min(pcmreader.channels, 2), channel_mask=ChannelMask.from_channels( min(pcmreader.channels, 2)), bits_per_sample=16) if (pcmreader.channels > 1): mode = "j" else: mode = "m" #FIXME - not sure if all LAME versions support "--little-endian" # #LAME 3.98 (and up, presumably) handle the byteswap correctly # #LAME 3.97 always uses -x # if (BIG_ENDIAN or (cls.__lame_version__() < (3,98))): # endian = ['-x'] # else: # endian = [] devnull = file(os.devnull, 'ab') sub = subprocess.Popen([ BIN['lame'], "--quiet", "-r", "-s", str(decimal.Decimal(pcmreader.sample_rate) / 1000), "--bitwidth", str(pcmreader.bits_per_sample), "--signed", "--little-endian", "-m", mode, "-V" + str(compression), "-", filename], stdin=subprocess.PIPE, stdout=devnull, stderr=devnull, preexec_fn=ignore_sigint) try: transfer_framelist_data(pcmreader, sub.stdin.write) except (IOError, ValueError), err: sub.stdin.close() sub.wait() cls.__unlink__(filename) raise EncodingError(str(err))
def channel_mask(self): if (self.channels() <= 2): return ChannelMask.from_channels(self.channels()) else: return ChannelMask(0)
def to_pcm(self): """Returns a PCMReader object containing the track's PCM data.""" #if mpg123 is available, use that for decoding if (BIN.can_execute(BIN["mpg123"])): sub = subprocess.Popen([BIN["mpg123"], "-qs", self.filename], stdout=subprocess.PIPE, stderr=file(os.devnull, "a")) return PCMReader(sub.stdout, sample_rate=self.sample_rate(), channels=self.channels(), bits_per_sample=16, channel_mask=int(ChannelMask.from_channels( self.channels())), process=sub, big_endian=BIG_ENDIAN) else: #if not, use LAME for decoding if (self.filename.endswith("." + self.SUFFIX)): if (BIG_ENDIAN): endian = ['-x'] else: endian = [] sub = subprocess.Popen([BIN['lame']] + endian + \ ["--decode", "-t", "--quiet", self.filename, "-"], stdout=subprocess.PIPE) return PCMReader( sub.stdout, sample_rate=self.sample_rate(), channels=self.channels(), bits_per_sample=16, channel_mask=int(self.channel_mask()), process=sub) else: import tempfile from audiotools import TempWaveReader #copy our file to one that ends with .mp3 tempmp3 = tempfile.NamedTemporaryFile(suffix='.' + self.SUFFIX) f = open(self.filename, 'rb') transfer_data(f.read, tempmp3.write) f.close() tempmp3.flush() #decode the mp3 file to a WAVE file wave = tempfile.NamedTemporaryFile(suffix='.wav') returnval = subprocess.call([BIN['lame'], "--decode", "--quiet", tempmp3.name, wave.name]) tempmp3.close() if (returnval == 0): #return WAVE file as a stream wave.seek(0, 0) return TempWaveReader(wave) else: return PCMReaderError( error_message=u"lame exited with error", sample_rate=self.sample_rate(), channels=self.channels(), channel_mask=int(self.channel_mask()), bits_per_sample=16)
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 subprocess import os from audiotools import PCMConverter from audiotools import transfer_data from audiotools import transfer_framelist_data from audiotools import ignore_sigint from audiotools import EncodingError from audiotools import DecodingError from audiotools import ChannelMask from audiotools import __default_quality__ if ((compression is None) or (compression not in cls.COMPRESSION_MODES)): compression = __default_quality__(cls.NAME) if pcmreader.bits_per_sample not in {8, 16, 24}: from audiotools import UnsupportedBitsPerSample pcmreader.close() raise UnsupportedBitsPerSample(filename, pcmreader.bits_per_sample) if pcmreader.channels > 2: pcmreader = PCMConverter(pcmreader, sample_rate=pcmreader.sample_rate, channels=2, channel_mask=ChannelMask.from_channels(2), bits_per_sample=pcmreader.bits_per_sample) # faac requires files to end with .m4a for some reason if not filename.endswith(".m4a"): import tempfile actual_filename = filename tempfile = tempfile.NamedTemporaryFile(suffix=".m4a") filename = tempfile.name else: actual_filename = tempfile = None sub = subprocess.Popen( [BIN['faac'], "-q", compression, "-P", "-R", str(pcmreader.sample_rate), "-B", str(pcmreader.bits_per_sample), "-C", str(pcmreader.channels), "-X", "-o", filename, "-"], stdin=subprocess.PIPE, stderr=subprocess.DEVNULL if hasattr(subprocess, "DEVNULL") else open(os.devnull, "wb"), stdout=subprocess.DEVNULL if hasattr(subprocess, "DEVNULL") else open(os.devnull, "wb"), preexec_fn=ignore_sigint) # Note: faac handles SIGINT on its own, # so trying to ignore it doesn't work like on most other encoders. try: if total_pcm_frames is not None: from audiotools import CounterPCMReader pcmreader = CounterPCMReader(pcmreader) transfer_framelist_data(pcmreader, sub.stdin.write) if ((total_pcm_frames is not None) and (total_pcm_frames != pcmreader.frames_written)): from audiotools.text import ERR_TOTAL_PCM_FRAMES_MISMATCH raise EncodingError(ERR_TOTAL_PCM_FRAMES_MISMATCH) except (ValueError, IOError) as err: sub.stdin.close() sub.wait() cls.__unlink__(filename) raise EncodingError(str(err)) except Exception: sub.stdin.close() sub.wait() cls.__unlink__(filename) raise sub.stdin.close() if sub.wait() == 0: if tempfile is not None: filename = actual_filename f = open(filename, 'wb') tempfile.seek(0, 0) transfer_data(tempfile.read, f.write) f.close() tempfile.close() return M4AAudio(filename) else: if tempfile is not None: tempfile.close() raise EncodingError(u"unable to write file with faac")