Библиотека Python для разделения и объединения mp3 файлов - PullRequest
39 голосов
/ 01 июня 2010

Существует много библиотек для работы с mp3-тегами, но мне нужно всего две функции - разделить mp3-файл на 2 части и вторую объединить 5 mp3.

Можете ли вы предложить что-нибудь? Спасибо!

Ответы [ 5 ]

92 голосов
/ 14 ноября 2013

Я написал библиотеку ( pydub ) для почти такого точного варианта использования:

from pydub import AudioSegment

sound = AudioSegment.from_mp3("/path/to/file.mp3")

# len() and slicing are in milliseconds
halfway_point = len(sound) / 2
second_half = sound[halfway_point:]

# Concatenation is just adding
second_half_3_times = second_half + second_half + second_half

# writing mp3 files is a one liner
second_half_3_times.export("/path/to/new/file.mp3", format="mp3")
6 голосов
/ 02 июня 2010

Посмотрите на структуру файла MP3 в Википедии. Используйте режим двоичного чтения в Python для редактирования файла MP3. s = open(file_name, 'rb').read() поместит весь файл в строковый объект, представляющий необработанные байты в вашем файле (например, \xeb\xfe\x80). Затем вы можете искать и редактировать строку, обращаясь к смещению байтов с помощью индексов в скобках: s[n]. Наконец, просто сделайте двоичную запись желаемых MP3-кадров в ваших новых файлах, добавив заголовок ID3 к набору кадров, которые вы хотите создать в каждом файле.

2 голосов
/ 16 сентября 2011

Проверьте GStreamer и его оболочку Python Gst-Python .

1 голос
/ 22 августа 2018

Вот моя попытка разбить MP3 с использованием Python без перекодирования. Поддерживаются не все разновидности файлов MP3, и я с удовольствием приветствую предложения или улучшения. Скрипт жестко запрограммирован на разделение за 55 секунд, но код демонстрирует общие принципы.

from __future__ import print_function
import struct
import sys

#MP3 frames are not independent because of the byte reservoir. This script does not account for
#that in determining where to do the split.

def SplitMp3(fi, splitSec, out):

    #Constants for MP3
    bitrates = {0x0: "free", 0x1: 32, 0x2: 40, 0x3: 48, 0x4: 56, 0x5: 64, 0x6: 80, 0x7: 96, 0x8: 112,
        0x9: 128, 0xa: 160, 0xb: 192, 0xc: 224, 0xd: 256, 0xe: 320, 0xf: "bad"}
    freqrates = {0x0: 44100, 0x1: 48000, 0x2: 32000, 0x3: "reserved"}
    countMpegFrames = 0
    frameDuration = 0.026
    unrecognizedBytes = 0
    splitFrame = int(round(splitSec / frameDuration))

    while True:

        startPos = fi.tell()

        #Check for 3 byte headers
        id3Start = fi.read(3)
        if len(id3Start) == 3:

            if id3Start == b'TAG':
                print ("Found ID3 v1/1.1 header")
                fi.seek(startPos + 256)
                continue

            if id3Start == b'ID3':
                #Possibly a ID3v2 header
                majorVer, minorVer, flags, encSize = struct.unpack(">BBBI", fi.read(7))
                if majorVer != 0xFF and minorVer != 0xFF:
                    encSize1 = (encSize & 0x7f000000) >> 24
                    encSize2 = (encSize & 0x7f0000) >> 16
                    encSize3 = (encSize & 0x7f00) >> 8
                    encSize4 = (encSize & 0x7f)
                    if encSize1 < 0x80 and encSize2 < 0x80 and encSize3 < 0x80 and encSize4 < 0x80:
                        size = ((encSize & 0x7f000000) >> 3) + ((encSize & 0x7f0000) >> 2) + ((encSize & 0x7f00) >> 1) + (encSize & 0x7f)
                        unsync = (flags >> 7) & 0x1
                        extendedHeader = (flags >> 6) & 0x1
                        experimental = (flags >> 5) & 0x1
                        print ("Found ID3v2 header")
                        print ("version", majorVer, minorVer, unsync, extendedHeader, experimental)
                        print ("size", size)
                        #TODO extendedHeader not supported yet

                        fi.seek(startPos + 10 + size)
                        continue

        #Check for 4 byte headers
        fi.seek(startPos)
        headerRaw = fi.read(4)
        if len(headerRaw) == 4:
            headerWord = struct.unpack(">I", headerRaw)[0]

            #Check for MPEG-1 audio frame
            if headerWord & 0xfff00000 == 0xfff00000:
                print ("Possible MPEG-1 audio header", hex(headerWord))
                countMpegFrames += 1
                ver = (headerWord & 0xf0000) >> 16
                bitrateEnc = (headerWord & 0xf000) >> 12
                freqEnc = (headerWord & 0xf00) >> 8
                mode = (headerWord & 0xf0) >> 4
                cpy = (headerWord & 0xf)
                if ver & 0xe == 0xa and freqEnc != 0xf:
                    print ("Probably an MP3 frame")
                    bitrate = bitrates[bitrateEnc]
                    freq = freqrates[freqEnc >> 2]
                    padding = ((freqEnc >> 1) & 0x1) == 1
                    print ("bitrate", bitrate, "kbps")
                    print ("freq", freq, "Hz")
                    print ("padding", padding)
                    frameLen = int((144 * bitrate * 1000 / freq ) + padding)

                    #Copy frame to output
                    fi.seek(startPos)
                    frameData = fi.read(frameLen)
                    if countMpegFrames >= splitFrame:
                        out.write(frameData)

                    fi.seek(startPos + frameLen)
                    continue
                else:
                    raise RuntimeError("Unsupported format:", hex(ver), "header:", hex(headerWord))

        #If no header can be detected, move on to the next byte
        fi.seek(startPos)
        nextByteRaw = fi.read(1)
        if len(nextByteRaw) == 0:
            break #End of file
        unrecognizedBytes += 1

    print ("unrecognizedBytes", unrecognizedBytes)
    print ("countMpegFrames", countMpegFrames)
    print ("duration", countMpegFrames * frameDuration, "sec")

if __name__=="__main__":
    fi = open(sys.argv[1], "rb")
    out = open("test.mp3", "wb")
    SplitMp3(fi, 55.0, out)
    out.close()

Слияние будет аналогичным случаем извлечения и добавления кадров из двух отдельных входных файлов MP3.

0 голосов
/ 12 мая 2013

используйте команду Unix split:

split -b 200k file.mp3 output_

это выведет output_a, output_b, output_c, ..

затем вы можете получить mp3 файлы, просто переименовав

for file in ./output_*; do mv "$file" "$(basename $file).mp3"; done

это выведет output_a.mp3, output_b.mp3, output_c.mp3 ... все они (кроме последнего, может быть) имеют размер 200 КБ, а общий размер файла output_x такой же, как и у файла. mp3

вы можете использовать команду du (использование диска), чтобы получить номер файла в байтах, а затем решить, сколько байтов нужно вырезать.

du -sh file.mp3

затем, чтобы присоединиться, используйте команду cat:

cat output_2.mp3 output_3.mp3 output_4.mp3 > output.mp3

конечно, вы можете поместить все это в скрипт оболочки и вызывать его из python.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...