Beispiel #1
0
    def to_pcm(self):
        if (self.filename.endswith(".wv")):
            if ('-r' in WavPackAudio.__wvunpack_help__()):
                sub = subprocess.Popen([
                    BIN['wvunpack'], '-q', '-y', self.filename, '-r', '-o', '-'
                ],
                                       stdout=subprocess.PIPE,
                                       stderr=file(os.devnull, 'ab'))

                return PCMReader(sub.stdout,
                                 sample_rate=self.sample_rate(),
                                 channels=self.channels(),
                                 channel_mask=int(self.channel_mask()),
                                 bits_per_sample=self.bits_per_sample(),
                                 process=sub)
            else:
                sub = subprocess.Popen(
                    [BIN['wvunpack'], '-q', '-y', self.filename, '-o', '-'],
                    stdout=subprocess.PIPE,
                    stderr=file(os.devnull, 'ab'))

                return WaveReader(sub.stdout,
                                  sample_rate=self.sample_rate(),
                                  channels=self.channels(),
                                  channel_mask=int(self.channel_mask()),
                                  bits_per_sample=self.bits_per_sample(),
                                  process=sub)
        else:
            #create a temporary symlink to the current file
            #rather than rewrite the whole thing
            (tempdir, symlink) = SymlinkPCMReader.new(self.filename, ".wv")
            return SymlinkPCMReader(
                WavPackAudio(symlink).to_pcm(), tempdir, symlink)
Beispiel #2
0
    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)
Beispiel #3
0
    def to_wave(self, wave_filename):
        devnull = file(os.devnull, 'ab')

        #WavPack stupidly refuses to run if the filename doesn't end with .wv
        if (self.filename.endswith(".wv")):
            sub = subprocess.Popen([
                BIN['wvunpack'], '-q', '-y', self.filename, '-o', wave_filename
            ],
                                   stdout=devnull,
                                   stderr=devnull)
            if (sub.wait() != 0):
                raise EncodingError()
        else:
            #create a temporary symlink to the current file
            #rather than rewrite the whole thing
            import tempfile

            tempdir = tempfile.mkdtemp()
            symlink = os.path.join(tempdir,
                                   os.path.basename(self.filename) + ".wv")
            try:
                os.symlink(os.path.abspath(self.filename), symlink)
                WavPackAudio(symlink).to_wave(wave_filename)
            finally:
                os.unlink(symlink)
                os.rmdir(tempdir)
Beispiel #4
0
    def from_pcm(cls, filename, pcmreader, compression=None):
        """Returns a PCMReader object containing the track's PCM data."""

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

        devnull = file(os.devnull, 'ab')

        sub = subprocess.Popen([
            BIN['oggenc'], '-Q', '-r', '-B',
            str(pcmreader.bits_per_sample), '-C',
            str(pcmreader.channels), '-R',
            str(pcmreader.sample_rate), '--raw-endianness',
            str(0), '-q', compression, '-o', filename, '-'
        ],
                               stdin=subprocess.PIPE,
                               stdout=devnull,
                               stderr=devnull,
                               preexec_fn=ignore_sigint)

        if ((pcmreader.channels <= 2) or (int(pcmreader.channel_mask) == 0)):
            try:
                transfer_framelist_data(pcmreader, sub.stdin.write)
            except (IOError, ValueError), err:
                sub.stdin.close()
                sub.wait()
                cls.__unlink__(filename)
                raise EncodingError(str(err))
            except Exception, err:
                sub.stdin.close()
                sub.wait()
                cls.__unlink__(filename)
                raise err
Beispiel #5
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'])
Beispiel #6
0
    def to_pcm(self):
        sub = subprocess.Popen([
            BIN['oggdec'], '-Q', '-b',
            str(16), '-e',
            str(0), '-s',
            str(1), '-R', '-o', '-', self.filename
        ],
                               stdout=subprocess.PIPE,
                               stderr=file(os.devnull, "a"))

        pcmreader = PCMReader(sub.stdout,
                              sample_rate=self.sample_rate(),
                              channels=self.channels(),
                              channel_mask=int(self.channel_mask()),
                              bits_per_sample=self.bits_per_sample(),
                              process=sub)

        if (self.channels() <= 2):
            return pcmreader
        elif (self.channels() <= 8):
            #these mappings transform Vorbis order into ChannelMask order
            standard_channel_mask = self.channel_mask()
            vorbis_channel_mask = VorbisChannelMask(self.channel_mask())
            return ReorderedPCMReader(pcmreader, [
                vorbis_channel_mask.channels().index(channel)
                for channel in standard_channel_mask.channels()
            ])
        else:
            return pcmreader
Beispiel #7
0
 def __help_output__(cls):
     import cStringIO
     help_data = cStringIO.StringIO()
     sub = subprocess.Popen([BIN['lame'],'--help'],
                            stdout=subprocess.PIPE)
     transfer_data(sub.stdout.read,help_data.write)
     sub.wait()
     return help_data.getvalue()
Beispiel #8
0
 def __wvunpack_help__(cls):
     devnull = open(os.devnull, "wb")
     sub = subprocess.Popen([BIN["wvunpack"], "--help"],
                            stdout=subprocess.PIPE,
                            stderr=devnull)
     help_data = sub.stdout.read()
     sub.stdout.close()
     devnull.close()
     sub.wait()
     return help_data
    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))
Beispiel #10
0
    def from_pcm(cls, filename, pcmreader, compression=None):
        if (compression not in cls.COMPRESSION_MODES):
            compression = cls.DEFAULT_COMPRESSION

        devnull = file(os.devnull, 'ab')

        sub = subprocess.Popen([
            BIN['oggenc'], '-Q', '-r', '-B',
            str(pcmreader.bits_per_sample), '-C',
            str(pcmreader.channels), '-R',
            str(pcmreader.sample_rate), '--raw-endianness',
            str(0), '-q', compression, '-o', filename, '-'
        ],
                               stdin=subprocess.PIPE,
                               stdout=devnull,
                               stderr=devnull,
                               preexec_fn=ignore_sigint)

        if ((pcmreader.channels <= 2) or (int(pcmreader.channel_mask) == 0)):
            transfer_framelist_data(pcmreader, sub.stdin.write)
        elif (pcmreader.channels <= 8):
            if (int(pcmreader.channel_mask) 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
                ):
                standard_channel_mask = ChannelMask(pcmreader.channel_mask)
                vorbis_channel_mask = VorbisChannelMask(standard_channel_mask)
            else:
                raise UnsupportedChannelMask()

            transfer_framelist_data(
                ReorderedPCMReader(pcmreader, [
                    standard_channel_mask.channels().index(channel)
                    for channel in vorbis_channel_mask.channels()
                ]), sub.stdin.write)
        else:
            raise UnsupportedChannelMask()

        try:
            pcmreader.close()
        except DecodingError:
            raise EncodingError()
        sub.stdin.close()

        devnull.close()

        if (sub.wait() == 0):
            return VorbisAudio(filename)
        else:
            raise EncodingError(BIN['oggenc'])
Beispiel #11
0
 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)
Beispiel #12
0
    def from_wave(cls, filename, wave_filename, compression=None):
        if (str(compression) not in cls.COMPRESSION_MODES):
            compression = cls.DEFAULT_COMPRESSION

        devnull = file(os.devnull, "wb")
        sub = subprocess.Popen(
            [BIN['mac'], wave_filename, filename,
             "-c%s" % (compression)],
            stdout=devnull,
            stderr=devnull)
        sub.wait()
        devnull.close()
        return ApeAudio(filename)
Beispiel #13
0
 def to_wave(self, wave_filename):
     if (self.filename.endswith(".ape")):
         devnull = file(os.devnull, "wb")
         sub = subprocess.Popen(
             [BIN['mac'], self.filename, wave_filename, '-d'],
             stdout=devnull,
             stderr=devnull)
         sub.wait()
         devnull.close()
     else:
         devnull = file(os.devnull, 'ab')
         import tempfile
         ape = tempfile.NamedTemporaryFile(suffix='.ape')
         f = file(self.filename, 'rb')
         transfer_data(f.read, ape.write)
         f.close()
         ape.flush()
         sub = subprocess.Popen([BIN['mac'], ape.name, wave_filename, '-d'],
                                stdout=devnull,
                                stderr=devnull)
         sub.wait()
         ape.close()
         devnull.close()
Beispiel #14
0
    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 MP2Audio 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)) or
            (pcmreader.bits_per_sample != 16)):
            pcmreader = PCMConverter(
                pcmreader,
                sample_rate=[32000, 32000, 44100, 48000][bisect.bisect(
                        [32000, 44100, 48000], pcmreader.sample_rate)],
                channels=min(pcmreader.channels, 2),
                channel_mask=pcmreader.channel_mask,
                bits_per_sample=16)

        devnull = file(os.devnull, 'ab')

        sub = subprocess.Popen([BIN['twolame'], "--quiet",
                                "-r",
                                "-s", str(pcmreader.sample_rate),
                                "--samplesize", str(pcmreader.bits_per_sample),
                                "-N", str(pcmreader.channels),
                                "-m", "a",
                                "-b", compression,
                                "-",
                                filename],
                               stdin=subprocess.PIPE,
                               stdout=devnull,
                               stderr=devnull,
                               preexec_fn=ignore_sigint)

        try:
            transfer_framelist_data(pcmreader, sub.stdin.write)
        except (ValueError, IOError), err:
            sub.stdin.close()
            sub.wait()
            cls.__unlink__(filename)
            raise EncodingError(str(err))
Beispiel #15
0
    def add_replay_gain(cls, filenames):
        track_names = [track.filename for track in
                       open_files(filenames) if
                       isinstance(track,cls)]

        if ((len(track_names) > 0) and (BIN.can_execute(BIN['mp3gain']))):
            devnull = file(os.devnull,'ab')
            sub = subprocess.Popen([BIN['mp3gain'],'-f','-k','-q','-r'] + \
                                       track_names,
                                   stdout=devnull,
                                   stderr=devnull)
            sub.wait()

            devnull.close()
Beispiel #16
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'])
Beispiel #17
0
    def from_pcm(cls, filename, pcmreader,
                 compression="192"):
        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)) or
            (pcmreader.bits_per_sample != 16)):
            pcmreader = PCMConverter(
                pcmreader,
                sample_rate=[32000,32000,44100,48000][bisect.bisect(
                        [32000,44100,48000],pcmreader.sample_rate)],
                channels=min(pcmreader.channels,2),
                channel_mask=pcmreader.channel_mask,
                bits_per_sample=16)

        devnull = file(os.devnull,'ab')

        sub = subprocess.Popen([BIN['twolame'],"--quiet",
                                "-r",
                                "-s",str(pcmreader.sample_rate),
                                "--samplesize",str(pcmreader.bits_per_sample),
                                "-N",str(pcmreader.channels),
                                "-m","a",
                                "-b",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 MP2Audio(filename)
        else:
            raise EncodingError(BIN['twolame'])
    def __to_wave__(self, wave_filename):
        devnull = file(os.devnull, "wb")
        try:
            sub = subprocess.Popen([BIN['mpcdec'],
                                    self.filename,
                                    wave_filename],
                                   stdout=devnull,
                                   stderr=devnull)

            #FIXME - small files (~5 seconds) result in an error by mpcdec,
            #even if they decode correctly.
            #Not much we can do except try to workaround its bugs.
            if (sub.wait() not in [0, 250]):
                raise DecodingError()
        finally:
            devnull.close()
    def __from_wave__(cls, filename, wave_filename, compression=None):
        if (str(compression) not in cls.COMPRESSION_MODES):
            compression = cls.DEFAULT_COMPRESSION

        #mppenc requires files to end with .mpc for some reason
        if (not filename.endswith(".mpc")):
            import tempfile
            actual_filename = filename
            tempfile = tempfile.NamedTemporaryFile(suffix=".mpc")
            filename = tempfile.name
        else:
            actual_filename = tempfile = None

        ###Musepack SV7###
        #sub = subprocess.Popen([BIN['mppenc'],
        #                        "--silent",
        #                        "--overwrite",
        #                        "--%s" % (compression),
        #                        wave_filename,
        #                        filename],
        #                       preexec_fn=ignore_sigint)

        ###Musepack SV8###
        sub = subprocess.Popen([BIN['mpcenc'],
                                "--silent",
                                "--overwrite",
                                "--%s" % (compression),
                                wave_filename,
                                filename])

        if (sub.wait() == 0):
            if (tempfile is not None):
                filename = actual_filename
                f = file(filename, 'wb')
                tempfile.seek(0, 0)
                transfer_data(tempfile.read, f.write)
                f.close()
                tempfile.close()

            return MusepackAudio(filename)
        else:
            if (tempfile is not None):
                tempfile.close()
            raise EncodingError(u"error encoding file with mpcenc")
Beispiel #20
0
    def from_wave(cls, filename, wave_filename, compression=None):
        if (str(compression) not in cls.COMPRESSION_MODES):
            compression = cls.DEFAULT_COMPRESSION

        compression_param = {
            "fast": ["-f"],
            "standard": [],
            "high": ["-h"],
            "veryhigh": ["-hh"]
        }

        #wavpack will add a .wv suffix if there isn't one
        #this isn't desired behavior
        if (filename.endswith(".wv")):
            devnull = file(os.devnull, 'ab')

            sub = subprocess.Popen([BIN['wavpack'],
                                    wave_filename] + \
                                   compression_param[compression] + \
                                   ['-q','-y','-o',
                                    filename],
                                   stdout=devnull,
                                   stderr=devnull,
                                   preexec_fn=ignore_sigint)

            devnull.close()

            if (sub.wait() == 0):
                return WavPackAudio(filename)
            else:
                raise EncodingError(BIN['wavpack'])
        else:
            import tempfile

            tempdir = tempfile.mkdtemp()
            symlink = os.path.join(tempdir, os.path.basename(filename) + ".wv")
            try:
                os.symlink(os.path.abspath(filename), symlink)
                cls.from_wave(symlink, wave_filename, compression)
                return WavPackAudio(filename)
            finally:
                os.unlink(symlink)
                os.rmdir(tempdir)
Beispiel #21
0
    def add_replay_gain(cls, filenames):
        """Adds ReplayGain values to a list of filename strings.

        All the filenames must be of this AudioFile type.
        Raises ValueError if some problem occurs during ReplayGain application.
        """

        track_names = [track.filename for track in
                       open_files(filenames) if
                       isinstance(track, cls)]

        if ((len(track_names) > 0) and (BIN.can_execute(BIN['mp3gain']))):
            devnull = file(os.devnull, 'ab')
            sub = subprocess.Popen([BIN['mp3gain'], '-f', '-k', '-q', '-r'] + \
                                       track_names,
                                   stdout=devnull,
                                   stderr=devnull)
            sub.wait()

            devnull.close()
Beispiel #22
0
    def from_pcm(cls, filename, pcmreader, compression=None):
        compression_param = {
            "fast": ["-f"],
            "standard": [],
            "high": ["-h"],
            "veryhigh": ["-hh"]
        }

        if (str(compression) not in cls.COMPRESSION_MODES):
            compression = cls.DEFAULT_COMPRESSION

        if ('--raw-pcm' in cls.__wavpack_help__()):
            if (filename.endswith(".wv")):
                devnull = file(os.devnull, 'ab')

                if (pcmreader.channels > 18):
                    raise UnsupportedChannelMask()
                elif (pcmreader.channels > 2):
                    order_map = {
                        "front_left": "FL",
                        "front_right": "FR",
                        "front_center": "FC",
                        "low_frequency": "LFE",
                        "back_left": "BL",
                        "back_right": "BR",
                        "front_left_of_center": "FLC",
                        "front_right_of_center": "FRC",
                        "back_center": "BC",
                        "side_left": "SL",
                        "side_right": "SR",
                        "top_center": "TC",
                        "top_front_left": "TFL",
                        "top_front_center": "TFC",
                        "top_front_right": "TFR",
                        "top_back_left": "TBL",
                        "top_back_center": "TBC",
                        "top_back_right": "TBR"
                    }

                    channel_order = [
                        "--channel-order=%s" % (",".join([
                            order_map[channel] for channel in ChannelMask(
                                pcmreader.channel_mask).channels()
                        ]))
                    ]
                else:
                    channel_order = []

                sub = subprocess.Popen([BIN['wavpack']] + \
                                           compression_param[compression] + \
                                           ['-q','-y',
                                            "--raw-pcm=%(sr)s,%(bps)s,%(ch)s"%\
                                              {"sr":pcmreader.sample_rate,
                                               "bps":pcmreader.bits_per_sample,
                                               "ch":pcmreader.channels}] + \
                                           channel_order + \
                                           ['-','-o',filename],
                                       stdout=devnull,
                                       stderr=devnull,
                                       stdin=subprocess.PIPE,
                                       preexec_fn=ignore_sigint)

                transfer_framelist_data(pcmreader, sub.stdin.write)
                devnull.close()
                sub.stdin.close()

                if (sub.wait() == 0):
                    return WavPackAudio(filename)
                else:
                    raise EncodingError(BIN['wavpack'])
            else:
                import tempfile

                tempdir = tempfile.mkdtemp()
                symlink = os.path.join(tempdir,
                                       os.path.basename(filename) + ".wv")
                try:
                    os.symlink(os.path.abspath(filename), symlink)
                    cls.from_pcm(symlink, pcmreader, compression)
                    return WavPackAudio(filename)
                finally:
                    os.unlink(symlink)
                    os.rmdir(tempdir)
        else:
            import tempfile

            f = tempfile.NamedTemporaryFile(suffix=".wav")
            w = WaveAudio.from_pcm(f.name, pcmreader)

            try:
                return cls.from_wave(filename, w.filename, compression)
            finally:
                del (w)
                f.close()
Beispiel #23
0
    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))