Python ile bir klasördeki tüm seslerin başından ve sonundan kırpma yapmak

Source

Selamlar 👋, bu makalede bir klasördeki tüm ses dosyalarımızın başından ve sonundan belli bir süreyi silip ortada kalan kısmı başka bir klasöre yazacağız.

Dinlediğim bir radyo tiyatrosunda ~40 saniyelik yüksek sesli bir müzik girişi ve ~10 saniyelik “Sonraki bölümde görüşürüz” gibi bir bitiriş + müzik vardı. Ben bunlardan rahatsız olduğum için seslerin bu iki kısmını silip ortasını kaydetmek istedim. Bu operasyon sonrasında ~41 saat olan radyo tiyatrosu ~38 saate indi. Bu yönden de ~3 saatlik bir zaman kazancım oldu.

Hadi bunu Python ile nasıl yapabileceğimize bakalım.

Öncelikle pip install ffmpeg ile kullanacağımız kütüphaneyi indirip kuralım. Daha sonra kurulduğu dosyayı Environment Variables -> Path altına ekleyelim. (C:\Users\YOUR_NAME\AppData\Local\ffmpegio\ffmpeg-downloader\ffmpeg\bin)

Daha sonra importlarımızı yapalım.

import os
import time

from pydub import AudioSegment

pydup üzerinde bir hata gözükürse, üzerine gelin ve Install Package butonuna basın.

Daha sonrasında constlarımızı ekleyelim.

DIRECTORY_PATH = "D:/asr-ı saadet radyo tiyatrosu"
ONE_SECOND = 1000
AUDIO_PREFIX_TO_TRIM = 40 * ONE_SECOND
AUDIO_SUFFIX_TO_TRIM = 10 * ONE_SECOND

Daha sonra bize verilen klasör yolunun var olup olmadığını aşağıdaki kod ile kontrol edelim.

def check_is_directory_exist(directory_path):
if not os.path.exists(directory_path):
raise NotADirectoryError(f"Path Not Found => {directory_path}")

Şimdi bir klasördeki tüm sesleri alan ve her birisi için başka bir fonksiyonu (gerçek trim etme fonksiyonunu) çağıran fonksiyonumuzu yazalım.


def trim_audios_in_directory(audios_directory_path, output_directory_name="output",
prefix_to_trim=AUDIO_PREFIX_TO_TRIM,
suffix_to_trim=AUDIO_SUFFIX_TO_TRIM):
check_is_directory_exist(audios_directory_path)

print("Started to trimming")
measurement_start_time = time.time()

output_directory_path = os.path.join(audios_directory_path, output_directory_name)
os.makedirs(output_directory_path, exist_ok=True)

for filename in os.listdir(audios_directory_path):
trim_audio_and_save_as_mp3(filename, audios_directory_path, output_directory_path, prefix_to_trim,
suffix_to_trim)

measurement_end_time = time.time()
passed_time = int(measurement_end_time - measurement_start_time)
print(f"All files in {audios_directory_path} trimmed in ~{passed_time} seconds.")

audios_directory_path ile seslerimizin bulunduğu klasörü alıyoruz. output_directory_name ile trim edilmiş seslerimizi kayıt edeceğimiz dosyanın ismini alıyoruz. Ben varsayılan değer olarak “output” verdim. prefix_to_trim ile seslerin başından keseceğimiz süreyi milisaniye cinsinden alıyoruz. suffix_to_trim ile de sondan keseceğimiz süreyi alıyoruz.

Öncelikle gelen kaynak klasörün var olup olmadığını kontrol ediyoruz.

Daha sonra trim edilmiş dosyaların yazılacağı klasörü oluşturuyoruz. Ana dosyanın içine verilen isimde bir dosya oluşturdum. Bunun için audios_directory_path ile output_directory_name birleştirdim. D:/asr-ı saadet radyo tiyatrosu/output gibi bir dosya yolu oluşturmuş olduk gibi düşünebiliriz. Siz isterseniz ufak bazı değişikliklerle hedef klasörünü kaynak klasörden daha farklı bir yerde de oluşturabilirsiniz. Hali hazırda hedef klasör varsa sistemin hata vermemesi için exist_ok = true parametresini de verdim. Aksi takdirde aşağıdaki gibi bir hata alırdık.

mkdir(name, mode)
FileExistsError: [WinError 183] Cannot create a file when that file already exists: 'D:/asr-ı saadet radyo tiyatrosu\\output'

Son olarak kaynak klasörümüzdeki tüm dosyaları for döngüsü ile sırayla alıp, trim etmesi için trim_audio_and_save_as_mp3 fonksiyonunu çağırıyoruz.

Ben operasyonun ne kadar sürede biteceğini merak ettiğim için time.time() kullanarak başlangıç zamanı sakladım. Daha sonra işlemler bitince tekrar zamanı sakladım. Ve aralarındaki farkı da (geçen süre) en sonunda yazdırdım.

Şimdi asıl işin döndüğü fonksiyonumuza geçelim.


def trim_audio_and_save_as_mp3(filename,
audios_directory_path,
output_directory_path,
prefix_to_trim,
suffix_to_trim):
if filename.endswith(".m4a"):
measurement_start_time = time.time()

file_path = os.path.join(audios_directory_path, filename)
audio = AudioSegment.from_file(file_path)

middle_part_of_audio = audio[prefix_to_trim:-suffix_to_trim]

filename = filename.replace(".m4a",".mp3")
new_file_path = os.path.join(output_directory_path, filename)
middle_part_of_audio.export(new_file_path, format="mp3")

measurement_end_time = time.time()
passed_time = int(measurement_end_time - measurement_start_time)
print(f"The {filename} file trimmed in ~{passed_time} seconds.")
else:
print(f"The {filename} is not a type of m4a.")

Elimdeki ses dosyaları m4a uzantısına sahip olduğu için öncelikle bununla ilgili ufak bir kontrol yapıyoruz. Buraya ses dosyası dışında bir dosyanın gönderilmesinin önüne geçmiş oluyoruz. Buraya mp3 için de bir koşul konulabilirdi.

if filename.endswith(".m4a") or filename.endswith(".mp3"):

Veya tüm bu koşullar kaldırıladabilir isterseniz. (Ama output gibi bir klasör geldiğinde problem yaşatabilir.)

Daha sonra ses dosyasını elde etmek için kaynak klasörümüz ve dosya ismini birleştirip dosyanın yolunu elde ediyoruz.

(ŞİMDİ EN CAN ALICI NOKTAYA GELİYORUZ 🚀.)

Ses dosyasını elde ederken bir AudioSegment nesnesi olarak elde ediyoruz. AudioSegment nesneleri milisaniyeler cinsinden parçalanabilen yapıdadırlar. Bkz;

Ek örnek; last_5_seconds = song[-5000:]

Bizde sesin almak istemediğimiz ilk 40 saniyesinden (prefix) başlatıp sondaki 10 saniyeye (suffix) kadar olan aralığı seçmek için aşağıdaki gibi bir kod yazıyoruz. Sondan bir zaman dilimini belirtmek için “—” kullanıyoruz.

middle_part_of_audio = audio[prefix_to_trim:-suffix_to_trim]

Bu şekilde elde etmek istediğimiz ses aralığını bulmuş olduk. Daha sonrasında bu sesi aynı isimde olacak şekilde hedef klasörümüze kayıt (export) ediyoruz. Kayıt ederken format seçebiliyoruz. ‘mp3’, ‘wav’, ‘raw’, ‘ogg’ gibi formatlar seçebiliyoruz. Varsayılan değer ‘mp3’ tür.

Ses dosyamızın uzantısı m4a olduğu için ve mp3 olarak kayıt edeceğimiz için export etmeden önce dosya ismindeki m4a’yı mp3 ile değiştirdik (replace). Gelen parametre üzerinde değişiklik yapmak iyi bir pratik olmayabilir. İsterseniz aşağıdaki gibi de yapabilirsiniz.

new_file_path = new_file_path.replace(".m4a",".mp3")

Her bir ses dosyasının ne kadar sürede tamamlandığını merak ettiğim için için yine geçen yaklaşık süreyi hesaplayıp ekrana yazdırdık.

Projeyi çalıştırdığımızda aşağıdaki gibi bir sonuç alırız. 1 saat 27 dk 41 saniyelik 81.2 MBlık 5 ses dosyası ~110 saniyede 1 saat 25 dk 40 saniyelik 76.4 MBlık 5 dosyaya çevrilmiş oldu.

~41 saatlik, ~2.2 GB 160 dosyalık tüm oynatma listesini kırpmak ise ~51dk sürdü ve 2.07 GB boyuta indi.

Eğer m4a formatındaki dosyalarınızı yine m4a formatında kaydetmek isteserseniz aşağıdaki gibi yapabilirsiniz.

import subprocess


# Trim m4a file and save it as m4a
def trim_m4a_audio_and_save_as_m4a(filename,
audios_directory_path,
output_directory_path,
prefix_to_trim,
suffix_to_trim):
if filename.endswith(".m4a"):
measurement_start_time = time.time()

file_path = os.path.join(audios_directory_path, filename)
audio = AudioSegment.from_file(file_path)

middle_part_of_audio = audio[prefix_to_trim:-suffix_to_trim]

# Save the middle of the sound as wav
temp_wav_file_path = os.path.join(output_directory_path, "temp_file.wav")
middle_part_of_audio.export(temp_wav_file_path, format="wav")

# Convert wav file to m4a
new_file_path = os.path.join(output_directory_path, filename)
convertWavToM4a(temp_wav_file_path, new_file_path)

# Remove temp file
os.remove(temp_wav_file_path)

measurement_end_time = time.time()
print(f"The {filename} file trimmed in ~{str(int(measurement_end_time - measurement_start_time))} seconds.")
else:
print(f"The {filename} is not a type of m4a.")


def convert_wav_to_M4a(temp_wav_file_path, m4a_file_path):
ffmpeg_cmd = [
"ffmpeg",
"-y",
"-i",
temp_wav_file_path,
"-c:a",
"aac",
m4a_file_path
]
subprocess.run(ffmpeg_cmd)

Öncelikle kaydetmek istediğimiz ses aralığını wav formatında kayıt (export) ediyoruz. Daha sonra elimizdeki wav dosyasını m4a olarak kayıt ediyoruz. Son olarak oluşturduğumuz geçici wav dosyasını yer tutmaması için siliyoruz. Gelin convert_wav_to_m4a fonksiyonunun nasıl çalıştığını ChatGPT’ye soralım.

Ek bilgi; AAC — M4A ilişkisi

Bu makalemizden de bu kadar 😎. Tüm kodlara şu github linkinden ulaşabilirsiniz.

Makaleleri 50'ye kadar alkışlayabileceğinizi biliyor muydunuz? Eğer bu makaleyi yararlı ve eğlenceli bulduysanız alkış ikonuna basılı tutarak bu özelliği deneyebilirsiniz.

Source

Python’da acemiyim. İyileştirilebilecek noktalar için her zaman geri bildirimlerinizi iletebilirsiz🤩. Keyifli Kodlamalar 👩‍💻.Okuduğunuz için teşekkürler🤗. Sonraki yazılarda görüşmek üzere👋.

Referanslar

https://chat.openai.com/

--

--

Cengiz Toru (🇵🇸 #FreePalestineFromGenocide)

(🇵🇸 #FreePalestineFromGenocide 🍉) | Muslim, Computer Engineer & Android Developer @ Hepsiburada (NASDAQ: HEPS ) , ex; Huawei, T-Soft, Arneca