jiaaro / pydub

Manipulate audio with a simple and easy high level interface
http://pydub.com
MIT License
8.96k stars 1.05k forks source link

Workaround if user cannot add 'ffmpeg/bin' to Path in Windows #668

Open ChironeX1976 opened 2 years ago

ChironeX1976 commented 2 years ago

Hello, I have a piece of working Pydub-code on my personal laptop, with 'c:/ffmpeg/bin' added to path in de environment variables in windows. So far so good. I want to use this code on the company-laptop i use. I cannot access the environment variables to add 'c:/ffmpeg/bin' to path because i have no Admin rights. The system administrator won't change my permissions, which i understand completely.

Is there a workaround? I mean: can i force "audiosegment" to use the ffmpeg - program directly from the python code, without adding ffmpeg to path in windows?

Hereby i share my code :

import shutil
from pydub import AudioSegment
from pydub.effects import normalize

def get_list_of_files(dirname, extension, subdirtoo:bool):
    """ Create a list of files with a given extension in a directory
    dirname: path of the directory where we search for files with a given extension
    extension: get list of files with given extension eg: '.wav' or '' for all files
    subdirtoo: search also in subdirectories - True or False
    """
    list_of_file = os.listdir(dirname)
    all_files = list()
    # Iterate over all the entries
    for entry in list_of_file:
        # Create full path
        full_path = os.path.join(dirname, entry)
        # If entry is a directory then get the list of files in this directory
        if os.path.isdir(full_path):
            if subdirtoo:
                all_files = all_files + get_list_of_files(full_path, extension, subdirtoo)
        else:
            # filter the extension-files only
            if len(extension) > 2:
                if full_path.lower().endswith((extension, '.koekeliekoekelie')):
                    all_files.append(full_path)
            else:
                all_files.append(full_path)
    return all_files

def copy_allfilesinlist_to_fileswithsuffix(lst_files,str_suffix):
    """Copy all files in a list to a new file preceded by a suffix
    lst_files: a list of files with a full path
    str_suffix: a string with a suffix
    """
    for file in lst_files:
        path_head_tail = os.path.split(file)
        path = path_head_tail[0]
        filename_without_ext = os.path.splitext(path_head_tail[1])[0]
        extension = os.path.splitext(path_head_tail[1])[1]
        file_copytoname = path + '/' + filename_without_ext + str_suffix + extension
        shutil.copy(file, file_copytoname)
        # print('copied ', file_copytoname)

def normalize_audiofilesinfolder(path,str_filetype):
    """Normalise all audio-files in the root of a given folder
    Mp3-normalisation only works:
     - if ffmpeg is installed and
     - if it is added to the environment variabele 'path' in windows
    path: path to the folder with audio-files
    str_filetype: wav or mp3
    """
    if str_filetype == 'mp3':
        print('WARNING: mp3-files need installation of ffmpeg and adding to path, in windows environment. '
              'If not the procedure will fail!')
        print('')

    # get list of original files
    lst_files = get_list_of_files(path, '.' + str_filetype, subdirtoo=False)
    print('List of files to be normalised: ', lst_files)

    # alle originele wav-files backuppen met suffix _o
    print('Copy all original files in the folder to the same file-name with suffix _o')
    copy_allfilesinlist_to_fileswithsuffix(lst_files=lst_files, str_suffix='_o')

    # normalise each file in the list
    print('normalise files')
    for f in lst_files:
        print('...normalising ', f)
        if str_filetype == 'wav':
            sound_orig = AudioSegment.from_wav(file=f)
        elif str_filetype == 'mp3':
            sound_orig = AudioSegment.from_mp3(file=f)
        else:
            print('filetype not supported, only wav and mp3')
        sound_norm = normalize(sound_orig)
        sound_norm.export(f, format=str_filetype)

    print('done.')

# Where are the audio-files?
path = 'C:/tmp/audio/'
str_filetype = 'mp3' # mp3 or wav
normalize_audiofilesinfolder(path,str_filetype)
JaceyMarvin99 commented 2 years ago

I‘ve got the same question and look forward to the answer :(

JaceyMarvin99 commented 2 years ago

It works! Just simply add AudioSegment.converter = r"path_to_your_ffmpeg.exe" after from pydub import AudioSegment in your code. Then you don't need to add it to the environment variables.

ChironeX1976 commented 2 years ago

thank you for sharing!

jdegene commented 1 year ago

I have found that adding AudioSegment.converter = 'path/to/ffmpegexe' is not always sufficient when ffprobe.exe is needed as well. I have found many suggesting to add AudioSegment.ffprobe = 'path/to/ffprobe.exe' to ones code, but that seems to do nothing as of today

However, changing the returned value of the else clause in get_prober_name() in the utils.py to the absolute path of ffprobe.exe mitigates the issue.

Maybe it would be possible to make AudioSegment.ffprobe = 'path/to/ffprobe.exe' actually work, as I think that would be the most intiuitive solution!?

HericSilveira commented 1 week ago

I know this is a old issue, but just to help other people that are having the same problem but none of the others solutions worked, you can use the OS library to create a temporarily PATH Assignment this is just temporarily while your code runs so don't need to have admin rights

from os import environ, pathsep, path
environ["PATH"] += pathsep + path.abspath(f"absolute path to ffmpeg/ffplay/ffprobe folder")