Смешивание / наложение аудиофайлов wav в Python

Я искал решение для наложения / микширования двух аудиофайлов WAV вместе, используя ТОЛЬКО волновую библиотеку.

Я нашел следующее решение: Смешивание двух аудиофайлов вместе с Python

И один из ответов содержит следующий код:

import wave

w1 = wave.open("/path/to/wav/1")
w2 = wave.open("/path/to/wav/2")

#get samples formatted as a string.
samples1 = w1.readframes(w1.getnframes())
samples2 = w2.readframes(w2.getnframes())

#takes every 2 bytes and groups them together as 1 sample. ("123456" -> ["12", "34", "56"])
samples1 = [samples1[i:i+2] for i in xrange(0, len(samples1), 2)]
samples2 = [samples2[i:i+2] for i in xrange(0, len(samples2), 2)]

#convert samples from strings to ints
def bin_to_int(bin):
    as_int = 0
    for char in bin[::-1]: #iterate over each char in reverse (because little-endian)
        #get the integer value of char and assign to the lowest byte of as_int, shifting the rest up
        as_int <<= 8
        as_int += ord(char) 
    return as_int

samples1 = [bin_to_int(s) for s in samples1] #['\x04\x08'] -> [0x0804]
samples2 = [bin_to_int(s) for s in samples2]

#average the samples:
samples_avg = [(s1+s2)/2 for (s1, s2) in zip(samples1, samples2)]

Код написан на Python 2, а ord () обесценился в Python 3, поэтому код выглядит следующим образом: ord () удален и удваивается // в samples_avg, чтобы избежать создания числа с плавающей запятой.

import wave

w1 = wave.open("/path/to/wav/1")
w2 = wave.open("/path/to/wav/2")

#get samples formatted as a string.
samples1 = w1.readframes(w1.getnframes())
samples2 = w2.readframes(w2.getnframes())

#takes every 2 bytes and groups them together as 1 sample. ("123456" -> ["12", "34", "56"])
samples1 = [samples1[i:i+2] for i in range(0, len(samples1), 2)]
samples2 = [samples2[i:i+2] for i in range(0, len(samples2), 2)]

#convert samples from strings to ints
def bin_to_int(bin):
    as_int = 0
    for char in bin[::-1]: #iterate over each char in reverse (because little-endian)
        #get the integer value of char and assign to the lowest byte of as_int, shifting the rest up
        as_int <<= 8
        as_int += char
    return as_int

samples1 = [bin_to_int(s) for s in samples1] #['\x04\x08'] -> [0x0804]
samples2 = [bin_to_int(s) for s in samples2]

#average the samples:
samples_avg = [(s1+s2)//2 for (s1, s2) in zip(samples1, samples2)]

Код только частичный. Чего не хватает, так это вернуть samples_avg обратно в двоичную строку. Вот где у меня проблемы. Я пробовал следующий код для bin (), chr (), используя следующий код

samples_avg = [ chr(s) for s in samples_avg]

samples_avg = [ bin(s) + "'" for s in samples_avg]

и я испробовал миллион других решений, которые я слишком стесняюсь публиковать, и все они потерпели неудачу.

Может ли кто-нибудь помочь закончить этот код? Я думаю, что это был бы действительно полезный код для сообщества, поскольку он зависит только от волновой библиотеки и может использоваться в виртуальных средах.

Я новичок в Python и совершенно новичок в обработке звука, поэтому прошу прощения за любые глупые вопросы и ошибки.

Просто чтобы прояснить, что я имею в виду под смешением / переполнением. Если у меня есть два аудиофайла длиной 4 секунды каждый, я хочу смешать их вместе в один аудиофайл длиной 4 секунды, в котором два аудиофайла воспроизводятся одновременно.

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
0
1 479
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Итак, после небольшого пробного использования ошибки и помощи от @Ponkadoodle у меня все заработало. Это сработало для двух записей, которые я сделал на одном компьютере с использованием quicktime и онлайн-конвертера wav. Если бы я использовал wav-файлы из Интернета, конечный образец звучал бы действительно неправильно, я не знаю, связано ли это с частотой и т. д.

Вот окончательный код

import wave
import array


w1 = wave.open("path/to/file/audiofile1.wav")
w2 = wave.open("path/to/file/audiofile2.wav")

#get samples formatted as a string.
samples1 = w1.readframes(w1.getnframes())
samples2 = w2.readframes(w2.getnframes())


#takes every 2 bytes and groups them together as 1 sample. ("123456" -> ["12", "34", "56"])
samples1 = [samples1[i:i+2] for i in range(0, len(samples1), 2)]
samples2 = [samples2[i:i+2] for i in range(0, len(samples2), 2)]

#convert samples from strings to ints
def bin_to_int(bin):
    as_int = 0
    for char in bin[::-1]: #iterate over each char in reverse (because little-endian)
        #get the integer value of char and assign to the lowest byte of as_int, shifting the rest up
        as_int <<= 8
        as_int += char
    return as_int

samples1 = [bin_to_int(s) for s in samples1] #['\x04\x08'] -> [0x0804]
samples2 = [bin_to_int(s) for s in samples2]

#average the samples:
samples_avg = [(s1+s2) for (s1, s2) in zip(samples1, samples2)]

samples_array = array.array('i')
samples_array.fromlist(samples_avg)

wave_out = wave.open ("out.wav", "wb")
wave_out.setnchannels(1)
wave_out.setsampwidth(2)
wave_out.setframerate(w1.getframerate()*4) 
wave_out.writeframes(samples_array)

У меня все еще проблема с setframerate (). Я умножил его на 4, и это сработало, опять же, это может зависеть от частоты / частоты кадров и т. д. Вашей исходной записи.

wave_out.setframerate(w1.getframerate()*4) 

Другие вопросы по теме