Ejemplo n.º 1
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 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()
Ejemplo n.º 2
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 VorbisAudio object"""

        from audiotools import (BufferedPCMReader,
                                __default_quality__,
                                EncodingError)
        from audiotools.encoders import encode_vorbis

        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) and (pcmreader.channels <= 8):
            channel_mask = int(pcmreader.channel_mask)
            if ((channel_mask != 0) and
                (channel_mask not in
                 (0x7,       # FR, FC, FL
                  0x33,      # FR, FL, BR, BL
                  0x37,      # FR, FC, FL, BL, BR
                  0x3f,      # FR, FC, FL, BL, BR, LFE
                  0x70f,     # FL, FC, FR, SL, SR, BC, LFE
                  0x63f))):  # FL, FC, FR, SL, SR, BL, BR, LFE
                from audiotools import UnsupportedChannelMask
                pcmreader.close()
                raise UnsupportedChannelMask(filename, channel_mask)

        if total_pcm_frames is not None:
            from audiotools import CounterPCMReader
            pcmreader = CounterPCMReader(pcmreader)
        try:

            encode_vorbis(filename,
                          pcmreader,
                          float(compression) / 10)

            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 VorbisAudio(filename)
        except (ValueError, IOError) as err:
            cls.__unlink__(filename)
            raise EncodingError(str(err))
        finally:
            pcmreader.close()
Ejemplo n.º 3
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 VorbisAudio object"""

        from audiotools import (BufferedPCMReader, __default_quality__,
                                EncodingError)
        from audiotools.encoders import encode_vorbis

        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) and (pcmreader.channels <= 8):
            channel_mask = int(pcmreader.channel_mask)
            if ((channel_mask != 0) and (channel_mask not in (
                    0x7,  # FR, FC, FL
                    0x33,  # FR, FL, BR, BL
                    0x37,  # FR, FC, FL, BL, BR
                    0x3f,  # FR, FC, FL, BL, BR, LFE
                    0x70f,  # FL, FC, FR, SL, SR, BC, LFE
                    0x63f))):  # FL, FC, FR, SL, SR, BL, BR, LFE
                from audiotools import UnsupportedChannelMask
                pcmreader.close()
                raise UnsupportedChannelMask(filename, channel_mask)

        if total_pcm_frames is not None:
            from audiotools import CounterPCMReader
            pcmreader = CounterPCMReader(pcmreader)
        try:

            encode_vorbis(filename, pcmreader, float(compression) / 10)

            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 VorbisAudio(filename)
        except (ValueError, IOError) as err:
            cls.__unlink__(filename)
            raise EncodingError(str(err))
        finally:
            pcmreader.close()
Ejemplo n.º 4
0
    def verify(self, progress=None):
        """verifies the current file for correctness

        returns True if the file is okay
        raises an InvalidFile with an error message if there is
        some problem with the file"""

        from audiotools import CounterPCMReader
        from audiotools import transfer_framelist_data
        from audiotools import to_pcm_progress

        try:
            (header, footer) = self.wave_header_footer()
        except IOError as err:
            raise InvalidWave(err)
        except ValueError as err:
            raise InvalidWave(err)

        # ensure header is valid
        try:
            (total_size, data_size) = validate_header(header)
        except ValueError as err:
            raise InvalidWave(err)

        # ensure "data" chunk has all its data
        counter = CounterPCMReader(to_pcm_progress(self, progress))
        try:
            transfer_framelist_data(counter, lambda f: f)
        except (IOError, ValueError):
            from audiotools.text import ERR_WAV_TRUNCATED_DATA_CHUNK
            raise InvalidWave(ERR_WAV_TRUNCATED_DATA_CHUNK)

        data_bytes_written = counter.bytes_written()

        # ensure output data size matches the "data" chunk's size
        if data_size != data_bytes_written:
            from audiotools.text import ERR_WAV_TRUNCATED_DATA_CHUNK
            raise InvalidWave(ERR_WAV_TRUNCATED_DATA_CHUNK)

        # ensure footer validates correctly
        try:
            validate_footer(footer, data_bytes_written)
        except ValueError as err:
            from audiotools.text import ERR_WAV_INVALID_SIZE
            raise InvalidWave(ERR_WAV_INVALID_SIZE)

        # ensure total size is correct
        if (len(header) + data_size + len(footer)) != total_size:
            from audiotools.text import ERR_WAV_INVALID_SIZE
            raise InvalidWave(ERR_WAV_INVALID_SIZE)

        return True
Ejemplo n.º 5
0
    def from_pcm(cls, filename, pcmreader,
                 compression=None,
                 total_pcm_frames=None,
                 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 WavPackAudio object"""

        from audiotools.encoders import encode_wavpack
        from audiotools import BufferedPCMReader
        from audiotools import CounterPCMReader
        from audiotools import EncodingError
        from audiotools import __default_quality__

        if pcmreader.bits_per_sample not in (8, 16, 24):
            # WavPack technically supports up to 32 bits-per-sample
            # but nothing else does
            # so I'll treat it as unsupported for now
            from audiotools import UnsupportedBitsPerSample
            pcmreader.close()
            raise UnsupportedBitsPerSample(filename, pcmreader.bits_per_sample)

        if (((compression is None) or
             (compression not in cls.COMPRESSION_MODES))):
            compression = __default_quality__(cls.NAME)

        counter = CounterPCMReader(pcmreader)

        try:
            (encode_wavpack if encoding_function is None
             else encoding_function)(
                filename=filename,
                pcmreader=counter,
                total_pcm_frames=(total_pcm_frames if
                                  total_pcm_frames is not None else 0),
                compression=compression)
            counter.close()
        except (ValueError, IOError) as msg:
            counter.close()
            cls.__unlink__(filename)
            raise EncodingError(str(msg))
        except Exception:
            counter.close()
            cls.__unlink__(filename)
            raise

        # ensure actual total PCM frames matches argument, if any
        if (((total_pcm_frames is not None) and
             (counter.frames_written != total_pcm_frames))):
            cls.__unlink__(filename)
            from audiotools.text import ERR_TOTAL_PCM_FRAMES_MISMATCH
            raise EncodingError(ERR_TOTAL_PCM_FRAMES_MISMATCH)

        return cls(filename)
Ejemplo n.º 6
0
    def from_pcm(cls, filename, pcmreader,
                 compression=None,
                 total_pcm_frames=None,
                 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 WavPackAudio object"""

        from audiotools.encoders import encode_wavpack
        from audiotools import BufferedPCMReader
        from audiotools import CounterPCMReader
        from audiotools import EncodingError
        from audiotools import __default_quality__

        if (((compression is None) or
             (compression not in cls.COMPRESSION_MODES))):
            compression = __default_quality__(cls.NAME)

        counter = CounterPCMReader(pcmreader)

        try:
            (encode_wavpack if encoding_function is None
             else encoding_function)(
                filename,
                BufferedPCMReader(counter),
                total_pcm_frames=(total_pcm_frames if
                                  total_pcm_frames is not None else 0),
                **cls.__options__[compression])
            counter.close()
        except (ValueError, IOError) as msg:
            counter.close()
            cls.__unlink__(filename)
            raise EncodingError(str(msg))
        except Exception:
            counter.close()
            cls.__unlink__(filename)
            raise

        # ensure actual total PCM frames matches argument, if any
        if (((total_pcm_frames is not None) and
             (counter.frames_written != total_pcm_frames))):
            cls.__unlink__(filename)
            from audiotools.text import ERR_TOTAL_PCM_FRAMES_MISMATCH
            raise EncodingError(ERR_TOTAL_PCM_FRAMES_MISMATCH)

        return cls(filename)
Ejemplo n.º 7
0
    def from_pcm(cls, filename, pcmreader, compression=None, total_pcm_frames=None, 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 WavPackAudio object"""

        from audiotools.encoders import encode_wavpack
        from audiotools import BufferedPCMReader
        from audiotools import CounterPCMReader
        from audiotools import EncodingError
        from audiotools import __default_quality__

        if pcmreader.bits_per_sample not in (8, 16, 24):
            # WavPack technically supports up to 32 bits-per-sample
            # but nothing else does
            # so I'll treat it as unsupported for now
            from audiotools import UnsupportedBitsPerSample

            pcmreader.close()
            raise UnsupportedBitsPerSample(filename, pcmreader.bits_per_sample)

        if (compression is None) or (compression not in cls.COMPRESSION_MODES):
            compression = __default_quality__(cls.NAME)

        counter = CounterPCMReader(pcmreader)

        try:
            (encode_wavpack if encoding_function is None else encoding_function)(
                filename=filename,
                pcmreader=counter,
                total_pcm_frames=(total_pcm_frames if total_pcm_frames is not None else 0),
                compression=compression,
            )
            counter.close()
        except (ValueError, IOError) as msg:
            counter.close()
            cls.__unlink__(filename)
            raise EncodingError(str(msg))
        except Exception:
            counter.close()
            cls.__unlink__(filename)
            raise

        # ensure actual total PCM frames matches argument, if any
        if (total_pcm_frames is not None) and (counter.frames_written != total_pcm_frames):
            cls.__unlink__(filename)
            from audiotools.text import ERR_TOTAL_PCM_FRAMES_MISMATCH

            raise EncodingError(ERR_TOTAL_PCM_FRAMES_MISMATCH)

        return cls(filename)
Ejemplo n.º 8
0
    def from_pcm(cls, filename, pcmreader,
                 compression=None,
                 total_pcm_frames=None,
                 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 WavPackAudio object"""

        from audiotools.encoders import encode_wavpack
        from audiotools import BufferedPCMReader
        from audiotools import CounterPCMReader
        from audiotools import EncodingError
        from audiotools import __default_quality__

        if (((compression is None) or
             (compression not in cls.COMPRESSION_MODES))):
            compression = __default_quality__(cls.NAME)

        counter = CounterPCMReader(pcmreader)

        try:
            (encode_wavpack if encoding_function is None
             else encoding_function)(
                filename,
                BufferedPCMReader(counter),
                total_pcm_frames=(total_pcm_frames if
                                  total_pcm_frames is not None else 0),
                **cls.__options__[compression])
            counter.close()
        except (ValueError, IOError) as msg:
            counter.close()
            cls.__unlink__(filename)
            raise EncodingError(str(msg))
        except Exception:
            counter.close()
            cls.__unlink__(filename)
            raise

        # ensure actual total PCM frames matches argument, if any
        if (((total_pcm_frames is not None) and
             (counter.frames_written != total_pcm_frames))):
            cls.__unlink__(filename)
            from audiotools.text import ERR_TOTAL_PCM_FRAMES_MISMATCH
            raise EncodingError(ERR_TOTAL_PCM_FRAMES_MISMATCH)

        return cls(filename)
Ejemplo n.º 9
0
    def from_wave(cls, filename, header, pcmreader, footer, compression=None,
                  encoding_function=None):
        """encodes a new file from wave data

        takes a filename string, header string,
        PCMReader object, footer string
        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 WaveAudio object

        header + pcm data + footer should always result
        in the original wave file being restored
        without need for any padding bytes

        may raise EncodingError if some problem occurs when
        encoding the input file"""

        from audiotools.encoders import encode_wavpack
        from audiotools import BufferedPCMReader
        from audiotools import CounterPCMReader
        from audiotools.wav import (validate_header, validate_footer)
        from audiotools import EncodingError
        from audiotools import __default_quality__

        if (((compression is None) or
             (compression not in cls.COMPRESSION_MODES))):
            compression = __default_quality__(cls.NAME)

        # ensure header is valid
        try:
            (total_size, data_size) = validate_header(header)
        except ValueError as err:
            raise EncodingError(str(err))

        counter = CounterPCMReader(pcmreader)

        try:
            (encode_wavpack if encoding_function is None
             else encoding_function)(filename,
                                     BufferedPCMReader(counter),
                                     wave_header=header,
                                     wave_footer=footer,
                                     **cls.__options__[compression])

            data_bytes_written = counter.bytes_written()

            # ensure output data size matches the "data" chunk's size
            if (data_size != data_bytes_written):
                from audiotools.text import ERR_WAV_TRUNCATED_DATA_CHUNK
                raise EncodingError(ERR_WAV_TRUNCATED_DATA_CHUNK)

            # ensure footer validates correctly
            try:
                validate_footer(footer, data_bytes_written)
            except ValueError as err:
                raise EncodingError(str(err))

            # ensure total size is correct
            if ((len(header) + data_size + len(footer)) != total_size):
                from audiotools.text import ERR_WAV_INVALID_SIZE
                raise EncodingError(ERR_WAV_INVALID_SIZE)

            return cls(filename)
        except (ValueError, IOError) as msg:
            cls.__unlink__(filename)
            raise EncodingError(str(msg))
        except Exception as err:
            cls.__unlink__(filename)
            raise err
Ejemplo n.º 10
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 WaveAudio object"""

        from audiotools import EncodingError
        from audiotools import DecodingError
        from audiotools import CounterPCMReader
        from audiotools import transfer_framelist_data

        if pcmreader.bits_per_sample not in {8, 16, 24}:
            from audiotools import UnsupportedBitsPerSample
            pcmreader.close()
            raise UnsupportedBitsPerSample(filename, pcmreader.bits_per_sample)

        try:
            header = wave_header(pcmreader.sample_rate,
                                 pcmreader.channels,
                                 pcmreader.channel_mask,
                                 pcmreader.bits_per_sample,
                                 total_pcm_frames if total_pcm_frames
                                 is not None else 0)
        except ValueError as err:
            pcmreader.close()
            raise EncodingError(str(err))

        try:
            f = open(filename, "wb")
        except IOError as err:
            pcmreader.close()
            raise EncodingError(str(err))

        counter = CounterPCMReader(pcmreader)
        f.write(header)
        try:
            transfer_framelist_data(counter,
                                    f.write,
                                    pcmreader.bits_per_sample > 8,
                                    False)
        except (IOError, ValueError) as err:
            f.close()
            cls.__unlink__(filename)
            raise EncodingError(str(err))
        except Exception as err:
            f.close()
            cls.__unlink__(filename)
            raise err

        # handle odd-sized "data" chunks
        if counter.frames_written % 2:
            f.write(b"\x00")

        if total_pcm_frames is not None:
            f.close()
            if total_pcm_frames != counter.frames_written:
                # ensure written number of PCM frames
                # matches total_pcm_frames argument
                from audiotools.text import ERR_TOTAL_PCM_FRAMES_MISMATCH
                cls.__unlink__(filename)
                raise EncodingError(ERR_TOTAL_PCM_FRAMES_MISMATCH)
        else:
            # go back and rewrite populated header
            # with counted number of PCM frames
            f.seek(0, 0)
            f.write(wave_header(pcmreader.sample_rate,
                                pcmreader.channels,
                                pcmreader.channel_mask,
                                pcmreader.bits_per_sample,
                                counter.frames_written))
            f.close()

        return WaveAudio(filename)
Ejemplo n.º 11
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 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")
Ejemplo n.º 12
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 AudioFile-compatible object

        may raise EncodingError if some problem occurs when
        encoding the input file.  This includes an error
        in the input stream, a problem writing the output file,
        or even an EncodingError subclass such as
        "UnsupportedBitsPerSample" if the input stream
        is formatted in a way this class is unable to support
        """

        from audiotools import (BufferedPCMReader,
                                PCMConverter,
                                __default_quality__,
                                EncodingError)
        from audiotools.encoders import encode_opus

        if (((compression is None) or
             (compression not in cls.COMPRESSION_MODES))):
            compression = __default_quality__(cls.NAME)

        if (pcmreader.channels > 2) and (pcmreader.channels <= 8):
            if ((pcmreader.channel_mask != 0) and
                (pcmreader.channel_mask not in
                 {0x7,      # FR, FC, FL
                  0x33,     # FR, FL, BR, BL
                  0x37,     # FR, FC, FL, BL, BR
                  0x3f,     # FR, FC, FL, BL, BR, LFE
                  0x70f,    # FL, FC, FR, SL, SR, BC, LFE
                  0x63f})):  # FL, FC, FR, SL, SR, BL, BR, LFE
                from audiotools import UnsupportedChannelMask
                pcmreader.close()
                raise UnsupportedChannelMask(filename, channel_mask)

        try:
            if total_pcm_frames is not None:
                from audiotools import CounterPCMReader
                pcmreader = CounterPCMReader(pcmreader)

            encode_opus(filename,
                        PCMConverter(pcmreader,
                                     sample_rate=48000,
                                     channels=pcmreader.channels,
                                     channel_mask=pcmreader.channel_mask,
                                     bits_per_sample=16),
                        quality=int(compression),
                        original_sample_rate=pcmreader.sample_rate)

            pcmreader.close()

            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 cls(filename)
        except (ValueError, IOError) as err:
            pcmreader.close()
            cls.__unlink__(filename)
            raise EncodingError(err)
Ejemplo n.º 13
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 AuAudio object"""

        from audiotools import EncodingError
        from audiotools import DecodingError
        from audiotools import CounterPCMReader
        from audiotools import transfer_framelist_data

        if (pcmreader.bits_per_sample not in (8, 16, 24)):
            from audiotools import Filename
            from audiotools import UnsupportedBitsPerSample
            from audiotools.text import ERR_UNSUPPORTED_BITS_PER_SAMPLE
            raise UnsupportedBitsPerSample(
                ERR_UNSUPPORTED_BITS_PER_SAMPLE % {
                    "target_filename": Filename(filename),
                    "bps": pcmreader.bits_per_sample
                })

        try:
            header = au_header(
                pcmreader.sample_rate, pcmreader.channels,
                pcmreader.bits_per_sample,
                total_pcm_frames if total_pcm_frames is not None else 0)
        except ValueError as err:
            raise EncodingError(str(err))

        try:
            f = open(filename, "wb")
        except IOError as err:
            raise EncodingError(str(err))

        counter = CounterPCMReader(pcmreader)
        f.write(header)
        try:
            transfer_framelist_data(counter, f.write, True, True)
        except (IOError, ValueError) as err:
            cls.__unlink__(filename)
            raise EncodingError(str(err))

        if (total_pcm_frames is not None):
            if (total_pcm_frames != counter.frames_written):
                # ensure written number of PCM frames
                # matches total_pcm_frames argument
                from audiotools.text import ERR_TOTAL_PCM_FRAMES_MISMATCH
                cls.__unlink__(filename)
                raise EncodingError(ERR_TOTAL_PCM_FRAMES_MISMATCH)
            else:
                f.close()
        else:
            # go back and rewrite populated header
            # with counted number of PCM frames
            f.seek(0, 0)
            f.write(
                au_header(pcmreader.sample_rate, pcmreader.channels,
                          pcmreader.bits_per_sample, counter.frames_written))
            f.close()

        return AuAudio(filename)
Ejemplo n.º 14
0
    def from_aiff(cls, filename, header, pcmreader, footer, compression=None,
                  block_size=256, encoding_function=None):
        """encodes a new file from AIFF data

        takes a filename string, header string,
        PCMReader object, footer string
        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 AiffAudio object

        header + pcm data + footer should always result
        in the original AIFF file being restored
        without need for any padding bytes

        may raise EncodingError if some problem occurs when
        encoding the input file"""

        from audiotools import (CounterPCMReader,
                                BufferedPCMReader,
                                UnsupportedBitsPerSample,
                                EncodingError)
        from audiotools.aiff import (validate_header, validate_footer)

        if (encoding_function is None):
            from audiotools.encoders import encode_shn
        else:
            encode_shn = encoding_function

        if (pcmreader.bits_per_sample not in (8, 16)):
            raise UnsupportedBitsPerSample(filename, pcmreader.bits_per_sample)

        # ensure header is valid
        try:
            (total_size, ssnd_size) = validate_header(header)
        except ValueError as err:
            raise EncodingError(str(err))

        counter = CounterPCMReader(pcmreader)

        try:
            if (len(footer) == 0):
                encode_shn(filename=filename,
                           pcmreader=BufferedPCMReader(counter),
                           is_big_endian=True,
                           signed_samples=True,
                           header_data=header,
                           block_size=block_size)
            else:
                encode_shn(filename=filename,
                           pcmreader=BufferedPCMReader(counter),
                           is_big_endian=True,
                           signed_samples=True,
                           header_data=header,
                           footer_data=footer,
                           block_size=block_size)

            ssnd_bytes_written = counter.bytes_written()

            # ensure output data size matches the "SSND" chunk's size
            if (ssnd_size != ssnd_bytes_written):
                from audiotools.text import ERR_AIFF_TRUNCATED_SSND_CHUNK
                raise EncodingError(ERR_AIFF_TRUNCATED_SSND_CHUNK)

            # ensure footer validates correctly
            try:
                validate_footer(footer, ssnd_bytes_written)
            except ValueError as err:
                raise EncodingError(str(err))

            # ensure total size is correct
            if ((len(header) + ssnd_size + len(footer)) != total_size):
                from audiotools.text import ERR_AIFF_INVALID_SIZE
                raise EncodingError(ERR_AIFF_INVALID_SIZE)

            return cls(filename)
        except IOError as err:
            cls.__unlink__(filename)
            raise EncodingError(str(err))
        except Exception as err:
            cls.__unlink__(filename)
            raise err
Ejemplo n.º 15
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 AiffAudio object"""

        from audiotools import EncodingError
        from audiotools import DecodingError
        from audiotools import CounterPCMReader
        from audiotools import transfer_framelist_data

        try:
            header = aiff_header(
                pcmreader.sample_rate, pcmreader.channels,
                pcmreader.bits_per_sample,
                total_pcm_frames if total_pcm_frames is not None else 0)
        except ValueError as err:
            raise EncodingError(str(err))

        try:
            f = open(filename, "wb")
        except IOError as msg:
            raise EncodingError(str(msg))

        counter = CounterPCMReader(pcmreader)
        f.write(header)
        try:
            transfer_framelist_data(counter, f.write, True, True)
        except (IOError, ValueError) as err:
            cls.__unlink__(filename)
            raise EncodingError(str(err))

        # handle odd-sized SSND chunks
        if (counter.frames_written % 2):
            f.write(chr(0))

        if (total_pcm_frames is not None):
            if (total_pcm_frames != counter.frames_written):
                # ensure written number of PCM frames
                # matches total_pcm_frames argument
                from audiotools.text import ERR_TOTAL_PCM_FRAMES_MISMATCH
                cls.__unlink__(filename)
                raise EncodingError(ERR_TOTAL_PCM_FRAMES_MISMATCH)
            else:
                f.close()
        else:
            # go back and rewrite populated header
            # with counted number of PCM frames
            f.seek(0, 0)
            f.write(
                aiff_header(pcmreader.sample_rate, pcmreader.channels,
                            pcmreader.bits_per_sample, counter.frames_written))
            f.close()

        return AiffAudio(filename)
Ejemplo n.º 16
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 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")
Ejemplo n.º 17
0
    def from_wave(cls, filename, header, pcmreader, footer, compression=None,
                  block_size=256, encoding_function=None):
        """encodes a new file from wave data

        takes a filename string, header string,
        PCMReader object, footer string
        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 WaveAudio object

        header + pcm data + footer should always result
        in the original wave file being restored
        without need for any padding bytes

        may raise EncodingError if some problem occurs when
        encoding the input file"""

        from audiotools import (CounterPCMReader,
                                BufferedPCMReader,
                                UnsupportedBitsPerSample,
                                EncodingError)
        from audiotools.wav import (validate_header, validate_footer)

        if encoding_function is None:
            from audiotools.encoders import encode_shn
        else:
            encode_shn = encoding_function

        if pcmreader.bits_per_sample not in {8, 16}:
            pcmreader.close()
            raise UnsupportedBitsPerSample(filename, pcmreader.bits_per_sample)

        # ensure header is valid
        try:
            (total_size, data_size) = validate_header(header)
        except ValueError as err:
            pcmreader.close()
            raise EncodingError(str(err))

        counter = CounterPCMReader(pcmreader)

        try:
            if len(footer) == 0:
                encode_shn(filename=filename,
                           pcmreader=BufferedPCMReader(counter),
                           is_big_endian=False,
                           signed_samples=pcmreader.bits_per_sample == 16,
                           header_data=header,
                           block_size=block_size)
            else:
                encode_shn(filename=filename,
                           pcmreader=BufferedPCMReader(counter),
                           is_big_endian=False,
                           signed_samples=pcmreader.bits_per_sample == 16,
                           header_data=header,
                           footer_data=footer,
                           block_size=block_size)

            counter.close()
            data_bytes_written = counter.bytes_written()

            # ensure output data size matches the "data" chunk's size
            if data_size != data_bytes_written:
                from audiotools.text import ERR_WAV_TRUNCATED_DATA_CHUNK
                raise EncodingError(ERR_WAV_TRUNCATED_DATA_CHUNK)

            # ensure footer validates correctly
            try:
                validate_footer(footer, data_bytes_written)
            except ValueError as err:
                raise EncodingError(str(err))

            # ensure total size is correct
            if (len(header) + data_size + len(footer)) != total_size:
                from audiotools.text import ERR_WAV_INVALID_SIZE
                raise EncodingError(ERR_WAV_INVALID_SIZE)

            return cls(filename)
        except (IOError, ValueError) as err:
            counter.close()
            cls.__unlink__(filename)
            raise EncodingError(str(err))
        except Exception as err:
            counter.close()
            cls.__unlink__(filename)
            raise err
Ejemplo n.º 18
0
    def from_pcm(cls,
                 filename,
                 pcmreader,
                 compression=None,
                 total_pcm_frames=None,
                 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 AudioFile-compatible object

        may raise EncodingError if some problem occurs when
        encoding the input file.  This includes an error
        in the input stream, a problem writing the output file,
        or even an EncodingError subclass such as
        "UnsupportedBitsPerSample" if the input stream
        is formatted in a way this class is unable to support
        """

        from audiotools import (BufferedPCMReader, CounterPCMReader,
                                transfer_data, EncodingError)
        # from audiotools.py_encoders import encode_tta
        from audiotools.encoders import encode_tta
        from audiotools.bitstream import BitstreamWriter

        # open output file right away
        # so we can fail as soon as possible
        try:
            file = open(filename, "wb")
        except IOError as err:
            pcmreader.close()
            raise EncodingError(str(err))

        writer = BitstreamWriter(file, True)
        counter = CounterPCMReader(pcmreader)
        try:
            if (total_pcm_frames is not None):
                # write header to disk
                write_header(writer, pcmreader.channels,
                             pcmreader.bits_per_sample, pcmreader.sample_rate,
                             total_pcm_frames)

                block_size = (pcmreader.sample_rate * 256) // 245
                total_tta_frames = div_ceil(total_pcm_frames, block_size)

                # write temporary seektable to disk
                writer.mark()
                write_seektable(writer, [0] * total_tta_frames)
                writer.flush()

                # write frames to disk
                try:
                    frame_sizes = \
                        (encode_tta if encoding_function is None
                         else encoding_function)(file,
                                                 BufferedPCMReader(counter))
                except (IOError, ValueError) as err:
                    cls.__unlink__(filename)
                    raise EncodingError(str(err))

                # ensure written number of PCM frames
                # matches total_pcm_frames
                if (counter.frames_written != total_pcm_frames):
                    from audiotools.text import ERR_TOTAL_PCM_FRAMES_MISMATCH
                    cls.__unlink__(filename)
                    raise EncodingError(ERR_TOTAL_PCM_FRAMES_MISMATCH)

                assert (len(frame_sizes) == total_tta_frames)

                # go back and rewrite seektable with completed one
                writer.rewind()
                write_seektable(writer, frame_sizes)
                writer.unmark()
            else:
                import tempfile

                frames = tempfile.TemporaryFile()

                # encode TTA frames to temporary file
                try:
                    frame_sizes = \
                        (encode_tta if encoding_function is None
                         else encoding_function)(frames,
                                                 BufferedPCMReader(counter))
                except (IOError, ValueError) as err:
                    frames.close()
                    cls.__unlink__(filename)
                    raise EncodingError(str(err))

                # write header to disk
                write_header(writer, pcmreader.channels,
                             pcmreader.bits_per_sample, pcmreader.sample_rate,
                             counter.frames_written)

                # write seektable to disk
                write_seektable(writer, frame_sizes)

                # transfer TTA frames from temporary space to disk
                frames.seek(0, 0)
                transfer_data(frames.read, writer.write_bytes)
                frames.close()
        finally:
            counter.close()
            if (writer.has_mark()):
                writer.unmark()
            writer.close()

        return cls(filename)
Ejemplo n.º 19
0
    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()
Ejemplo n.º 20
0
    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()
Ejemplo n.º 21
0
    def from_wave(cls, filename, header, pcmreader, footer, compression=None,
                  encoding_function=None):
        """encodes a new file from wave data

        takes a filename string, header string,
        PCMReader object, footer string
        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 WaveAudio object

        header + pcm data + footer should always result
        in the original wave file being restored
        without need for any padding bytes

        may raise EncodingError if some problem occurs when
        encoding the input file"""

        from audiotools.encoders import encode_wavpack
        from audiotools import BufferedPCMReader
        from audiotools import CounterPCMReader
        from audiotools.wav import (validate_header, validate_footer)
        from audiotools import EncodingError
        from audiotools import __default_quality__

        if (((compression is None) or
             (compression not in cls.COMPRESSION_MODES))):
            compression = __default_quality__(cls.NAME)

        # ensure header is valid
        try:
            (total_size, data_size) = validate_header(header)
        except ValueError as err:
            raise EncodingError(str(err))

        counter = CounterPCMReader(pcmreader)

        try:
            (encode_wavpack if encoding_function is None
             else encoding_function)(filename,
                                     BufferedPCMReader(counter),
                                     wave_header=header,
                                     wave_footer=footer,
                                     **cls.__options__[compression])

            counter.close()

            data_bytes_written = counter.bytes_written()

            # ensure output data size matches the "data" chunk's size
            if (data_size != data_bytes_written):
                from audiotools.text import ERR_WAV_TRUNCATED_DATA_CHUNK
                raise EncodingError(ERR_WAV_TRUNCATED_DATA_CHUNK)

            # ensure footer validates correctly
            try:
                validate_footer(footer, data_bytes_written)
            except ValueError as err:
                raise EncodingError(str(err))

            # ensure total size is correct
            if ((len(header) + data_size + len(footer)) != total_size):
                from audiotools.text import ERR_WAV_INVALID_SIZE
                raise EncodingError(ERR_WAV_INVALID_SIZE)

            return cls(filename)
        except (ValueError, IOError) as msg:
            counter.close()
            cls.__unlink__(filename)
            raise EncodingError(str(msg))
        except Exception as err:
            counter.close()
            cls.__unlink__(filename)
            raise err
Ejemplo n.º 22
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 AudioFile-compatible object

        may raise EncodingError if some problem occurs when
        encoding the input file.  This includes an error
        in the input stream, a problem writing the output file,
        or even an EncodingError subclass such as
        "UnsupportedBitsPerSample" if the input stream
        is formatted in a way this class is unable to support
        """

        from audiotools import (BufferedPCMReader, PCMConverter,
                                __default_quality__, EncodingError)
        from audiotools.encoders import encode_opus

        if (((compression is None)
             or (compression not in cls.COMPRESSION_MODES))):
            compression = __default_quality__(cls.NAME)

        if ((pcmreader.channels > 2) and (pcmreader.channels <= 8)):
            channel_mask = int(pcmreader.channel_mask)
            if ((channel_mask != 0) and (channel_mask not in (
                    0x7,  # FR, FC, FL
                    0x33,  # FR, FL, BR, BL
                    0x37,  # FR, FC, FL, BL, BR
                    0x3f,  # FR, FC, FL, BL, BR, LFE
                    0x70f,  # FL, FC, FR, SL, SR, BC, LFE
                    0x63f))):  # FL, FC, FR, SL, SR, BL, BR, LFE
                from audiotools import UnsupportedChannelMask
                raise UnsupportedChannelMask(filename, channel_mask)

        try:
            if (total_pcm_frames is not None):
                from audiotools import CounterPCMReader
                pcmreader = CounterPCMReader(pcmreader)

            encode_opus(filename,
                        BufferedPCMReader(
                            PCMConverter(pcmreader,
                                         sample_rate=48000,
                                         channels=pcmreader.channels,
                                         channel_mask=pcmreader.channel_mask,
                                         bits_per_sample=16)),
                        quality=int(compression),
                        original_sample_rate=pcmreader.sample_rate)

            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 cls(filename)
        except (ValueError, IOError) as err:
            cls.__unlink__(filename)
            raise EncodingError(err)
Ejemplo n.º 23
0
    def from_pcm(cls, filename, pcmreader,
                 compression=None,
                 total_pcm_frames=None,
                 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 AudioFile-compatible object

        may raise EncodingError if some problem occurs when
        encoding the input file.  This includes an error
        in the input stream, a problem writing the output file,
        or even an EncodingError subclass such as
        "UnsupportedBitsPerSample" if the input stream
        is formatted in a way this class is unable to support
        """

        from audiotools import (BufferedPCMReader,
                                CounterPCMReader,
                                transfer_data,
                                EncodingError)
        # from audiotools.py_encoders import encode_tta
        from audiotools.encoders import encode_tta
        from audiotools.bitstream import BitstreamWriter

        # open output file right away
        # so we can fail as soon as possible
        try:
            file = open(filename, "wb")
        except IOError as err:
            pcmreader.close()
            raise EncodingError(str(err))

        writer = BitstreamWriter(file, True)
        counter = CounterPCMReader(pcmreader)
        try:
            if (total_pcm_frames is not None):
                # write header to disk
                write_header(writer,
                             pcmreader.channels,
                             pcmreader.bits_per_sample,
                             pcmreader.sample_rate,
                             total_pcm_frames)

                block_size = (pcmreader.sample_rate * 256) // 245
                total_tta_frames = div_ceil(total_pcm_frames, block_size)

                # write temporary seektable to disk
                writer.mark()
                write_seektable(writer, [0] * total_tta_frames)
                writer.flush()

                # write frames to disk
                try:
                    frame_sizes = \
                        (encode_tta if encoding_function is None
                         else encoding_function)(file,
                                                 BufferedPCMReader(counter))
                except (IOError, ValueError) as err:
                    cls.__unlink__(filename)
                    raise EncodingError(str(err))

                # ensure written number of PCM frames
                # matches total_pcm_frames
                if (counter.frames_written != total_pcm_frames):
                    from audiotools.text import ERR_TOTAL_PCM_FRAMES_MISMATCH
                    cls.__unlink__(filename)
                    raise EncodingError(ERR_TOTAL_PCM_FRAMES_MISMATCH)

                assert(len(frame_sizes) == total_tta_frames)

                # go back and rewrite seektable with completed one
                writer.rewind()
                write_seektable(writer, frame_sizes)
                writer.unmark()
            else:
                import tempfile

                frames = tempfile.TemporaryFile()

                # encode TTA frames to temporary file
                try:
                    frame_sizes = \
                        (encode_tta if encoding_function is None
                         else encoding_function)(frames,
                                                 BufferedPCMReader(counter))
                except (IOError, ValueError) as err:
                    frames.close()
                    cls.__unlink__(filename)
                    raise EncodingError(str(err))

                # write header to disk
                write_header(writer,
                             pcmreader.channels,
                             pcmreader.bits_per_sample,
                             pcmreader.sample_rate,
                             counter.frames_written)

                # write seektable to disk
                write_seektable(writer, frame_sizes)

                # transfer TTA frames from temporary space to disk
                frames.seek(0, 0)
                transfer_data(frames.read, writer.write_bytes)
                frames.close()
        finally:
            counter.close()
            if (writer.has_mark()):
                writer.unmark()
            writer.close()

        return cls(filename)
Ejemplo n.º 24
0
    def from_aiff(cls,
                  filename,
                  header,
                  pcmreader,
                  footer,
                  compression=None,
                  block_size=256,
                  encoding_function=None):
        """encodes a new file from AIFF data

        takes a filename string, header string,
        PCMReader object, footer string
        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 AiffAudio object

        header + pcm data + footer should always result
        in the original AIFF file being restored
        without need for any padding bytes

        may raise EncodingError if some problem occurs when
        encoding the input file"""

        from audiotools import (CounterPCMReader, BufferedPCMReader,
                                UnsupportedBitsPerSample, EncodingError)
        from audiotools.aiff import (validate_header, validate_footer)

        if (encoding_function is None):
            from audiotools.encoders import encode_shn
        else:
            encode_shn = encoding_function

        if (pcmreader.bits_per_sample not in (8, 16)):
            raise UnsupportedBitsPerSample(filename, pcmreader.bits_per_sample)

        # ensure header is valid
        try:
            (total_size, ssnd_size) = validate_header(header)
        except ValueError as err:
            raise EncodingError(str(err))

        counter = CounterPCMReader(pcmreader)

        try:
            if (len(footer) == 0):
                encode_shn(filename=filename,
                           pcmreader=BufferedPCMReader(counter),
                           is_big_endian=True,
                           signed_samples=True,
                           header_data=header,
                           block_size=block_size)
            else:
                encode_shn(filename=filename,
                           pcmreader=BufferedPCMReader(counter),
                           is_big_endian=True,
                           signed_samples=True,
                           header_data=header,
                           footer_data=footer,
                           block_size=block_size)

            ssnd_bytes_written = counter.bytes_written()

            # ensure output data size matches the "SSND" chunk's size
            if (ssnd_size != ssnd_bytes_written):
                from audiotools.text import ERR_AIFF_TRUNCATED_SSND_CHUNK
                raise EncodingError(ERR_AIFF_TRUNCATED_SSND_CHUNK)

            # ensure footer validates correctly
            try:
                validate_footer(footer, ssnd_bytes_written)
            except ValueError as err:
                raise EncodingError(str(err))

            # ensure total size is correct
            if ((len(header) + ssnd_size + len(footer)) != total_size):
                from audiotools.text import ERR_AIFF_INVALID_SIZE
                raise EncodingError(ERR_AIFF_INVALID_SIZE)

            return cls(filename)
        except IOError as err:
            cls.__unlink__(filename)
            raise EncodingError(str(err))
        except Exception as err:
            cls.__unlink__(filename)
            raise err