0

I have a dozen or more mp3 audio files, which I need to concatenate into a single mp3 file. The files all have the same bitrate (320 kbps) and sample rate (44.1 kHz), but all of them have differing durations.

I have studied the three methods of concatenation recommended on stackoverflow (How to concatenate two MP4 files using FFmpeg). One method actually works, but when I play back the output file I find that there are noticeable audio artifacts (audible glitches) at each join point.

I've been told that this problem is caused by the input files not having identical duration. This seems likely, because I've had some successes in concatenating audio files with identical bit rate, sample rate, and duration.

I have seen, online, some much more complex scripts which are, at present, miles beyond my understanding. One solution I was directed to required a fairly deep knowledge of Python!

However, my research also included a site at audio-joiner.com - and this had the only completely successful method I've yet found, for files of non-identical duration. That site processed some of my input files, joined the multiple files into one, and the concatenated output file it produced did not have any audible glitches at the joins.

I looked into the process the site was using, hoping to get a clue as to where I've been going wrong, but the script on the site (which looks like ajax-based javascript) is too complex for me to follow.

Because the process seemed to take quite a long time, I wouldn't be too surprised to learn that the mp3 input files are being converted to some other audio format, joined, then converted back to mp3 for the output. But if so, that wouldn't put me off using the process.

Is anyone familiar with the approach being used, and can say whether it might be reproducible using ffmpeg?

.

ADDED -

There are 7 scripts, in all, listed in the source of the relevant page:

https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js
https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.0/jquery.min.js
https://static.123apps.com/js/socket.io.js
https://static.123apps.com/js/shared_0.js
https://static.123apps.com/js/shared_1.js
https://static.123apps.com/js/ajoiner.js
https://ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js

.

ADDED -

The successful (javascript) function seems to be this, but it isn't obvious to me why it is succeeding (too complex for me!). Can anyone suggest what approach it is taking? For example, is it transcoding the mp3 files to an intermediate format, and concatenating the intermediate files?

function start_join(e){
  l("start_join():"),l(e);
  var t;
  return(t=$.parseJSON(e)) && $("#ajoiner").ajoiner("set_params",t),!0
}

function cancel_join(e){
  return l("cancel_join():"),l(e),!0
}

!function(o){
  var t={
    init:function(e){
      var t=o(this),n=o.extend({lang:{cancel:"Cancel",download:"Download"}},e);
      o(this).data("ajoiner",{o:n,tmp_i:1,pid:-1,params:{}});
      t.data("ajoiner");
      t.ajoiner("_connect"),o("body").bind("socket_connected",function(){t.ajoiner("_connect")})
    },set_params:function(e){
      var t=o(this).data("ajoiner");
      isset(e)?(e.uid=Cookies.get("uid"),t.params=e,t.params.lang_id=lang_id,t.params.host=location.hostname,t.params.hostprotocol=location.protocol,l("socket emit join:"),l(t.params),socket.emit("join",t.params)):error("set_params: params not set")
    },_connect:function(){

      var t=o(this).data("ajoiner");

      l("_connect"),socket.on("join",function(e){
        "progress"==e.message_type?(t.tmp_i,t.tmp_i++,void 0!==getObj("theSWF")&&(getObj("theSWF").set_join_progress(parseInt(e.progress_value)),l("SWF.set_join_progress("+parseInt(e.progress_value)+")")),isset(e.pid)&&(t.pid=e.pid)):"final_result"==e.message_type?(void(e.tmp_i=0)!==getObj("theSWF")&&(getObj("theSWF").join_finished(o.stringifyJSON(e)),l("SWF.join_finished('"+o.stringifyJSON(e)+"')")),last_conv_result=e):"error"==e.message_type&&l(e.error_desc)
      }
    )},_cancel_convert:function(){
      var e=o(this).data("ajoiner");
      0<e.pid&&socket.emit("cancel_convert",{pid:e.pid})
    }
  };

  o.fn.ajoiner=function(e){
    return t[e]?t[e].apply(this,Array.prototype.slice.call(arguments,1)):"object"!=typeof e&&e?void o.error("Method "+e+" does not exist"):t.init.apply(this,arguments)
  }
}

(jQuery),$(document).ready(function(){$("#ajoiner").ajoiner()});
Ed999
  • 2,801
  • 2
  • 16
  • 19
  • Can you link to the site script? – Gyan May 14 '18 at 06:44
  • I reckon its https://static.123apps.com/js/ajoiner.js as the term 'ajoiner' is used elsewhere on their site as shorthand for their 'audio joiner' function. – Ed999 May 14 '18 at 10:35
  • @Ed999 Which ffmpeg concat methods did you try? – llogan Apr 08 '19 at 18:29
  • I tried all 3 of the following methods, and the final one worked, but it leaves brief gaps at the join points (causing audible glitches): https://stackoverflow.com/questions/7333232/how-to-concatenate-two-mp4-files-using-ffmpeg – Ed999 Apr 09 '19 at 10:01
  • For the avoidance of doubt, I need a solution for _Windows 7_. The 3 methods in question are those described in the _accepted_ answer on the page in question, i.e. posted by **rogerdpack** on 24 June 2012 (concat filter, concat demuxer, concat protocol). – Ed999 Apr 09 '19 at 10:17

1 Answers1

1

Above there is a tiny python script to do such thing with ffmpeg.
The script was configured to run in the same folder of yours mp3, but you can adapt.

import os

def main():

    # ::.inputs
    extensions = '.mp3'
    path_folder_input = '.'
    path_file_output = 'set_joined.mp3'

    # ::. Make a path_file list
    list_files = []
    for root, dirs, files in os.walk(path_folder_input):
        for file in files:
            if file.endswith(extensions):
                print(file)
                list_files.append(os.path.join(root, file))

    # ::. Make a ffmpeg command
    index_final = len(list_files)-1
    stringa = "ffmpeg -i \"concat:"
    for index, path_file in enumerate(list_files):
        stringa += path_file
        if index != index_final:
            stringa += "|"
        else:
            stringa += f"\" -acodec copy " + \
                       f"{path_file_output}"

    # ::. Start join
    os.system(stringa)


main()
the_RR
  • 311
  • 2
  • 9
  • Thank you, I'll try this suggestion. – Ed999 Jun 13 '20 at 16:09
  • Having extensively tested this suggestion, it doesn't work. Although the mp3 files do get concatenated, a gap is left at each join point, which causes audible artifacts at each join. At present, I know of no way to get a perfect (i.e. gap-free) join, except by re-encoding the audio. Maybe that is what the audio-joiner.com website's script does, but that script is too complex for me to understand with my limited knowledge of javascript. – Ed999 Jun 29 '20 at 23:12