Answers.Body: <p>The <a href="https://amara.org/en/" rel="nofollow noreferrer">Amara website</a> offers a free service that accepts audio and text files, synchronizes them, and lets you download a .srt file (synchronized SubTitle). Source of suggestion: <a href="https://photography.tutsplus.com/tutorials/3-ways-to-subtitle-and-caption-your-videos-automatically-using-artificial-intelligence--cms-26834" rel="nofollow noreferrer">Photography TutsPlus</a>.</p>
  <p>YouTube also <a href="https://support.google.com/youtube/answer/2734799" rel="nofollow noreferrer">accepts text files without time coding as SubTitle</a> files and then you can enable auto-sync, you ought to be able to download a .srt file after processing is completed (not tested by me).</p>
  <hr />
  <p>To do it manually (with some automation) try the following.</p>
  <p>If you convert the text file to a .ass or .srt file then you can use the following commands:</p>
  <blockquote>
  <p>ffmpeg.exe -i subtitles.srt subtitles.ass</p>
  <p>ffmpeg.exe -i video.mp4 -vf ass=subtitles.ass video-new.mp4</p>
  </blockquote>
  <p>That will show the words hardsubbed on the video synchronized with the audio. The <em>video</em> can be a moving image (video) or a static image.</p>
  <p>Using a .ass editor allows more control over color and other font features than using .srt files.</p>
  <p>Without using a SubTitle Format file you won't get synchronized text.</p>
  <p>You can add the audio to a video and upload it to YouTube, then wait 15 minutes, after which YouTube will have used audio recognition to convert the audio to subtitles (with better than 80% accuracy). Then you can download the .srt file from the Video Manager and edit the SubTitle file by comparing it to your (presumably accurate) text file.</p>
  <p>If you were hoping for a program that automatically syncs raw text files with audio and makes a video I have found nothing by Googling (outside of pay services).</p>
  <p>There are a few questions over at SO, but they remain unanswered.</p>
  <p>I will do some more searching and improve this answer in a few hours.</p>
  <p>Not a one-mouseclick solution but it's about as automated as I can suggest, for free (other than Amara).</p>
  <p>[I welcome Mulvya to edit and improve this answer.]</p>
  
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2017-12-11T06:00:50.470Z
Answers.LastActivityDate: 2017-12-11T09:06:59.117Z
Answers.LastEditDate: 2020-06-17T09:53:03.607Z
Answers.UserDisplayName: Rob
Answers.Body: <p>I wrote a Python script create a video that simply displays the text with the audio file playing in the background.</p>
  
  <p>Example of file structure before running the script (in this example, the three pairs of audio file + transcript):</p>
  
  <pre><code>C:\Users\Franck\Documents\GitHub\code&gt;tree /f
  Folder PATH listing
  C:.
  │   generate_videos.py
  │
  ├───audio
  │       file1.wav
  │       file2.wav
  │       file3.wav
  │
  └───transcripts
          file1.txt
          file2.txt
          file3.txt
  </code></pre>
  
  <p>After running the script (<code>output.mp4</code> is the concatenation of <code>videos\*.mp4</code>):</p>
  
  <pre><code>C:\Users\Franck\Documents\GitHub\code&gt;tree /f
  Folder PATH listing
  C:.
  │   generate_videos.py
  │   output.mp4
  │
  ├───audio
  │       file1.wav
  │       file2.wav
  │       file3.wav
  │
  ├───images
  │       file1.png
  │       file2.png
  │       file3.png
  │
  ├───transcripts
  │       file1.txt
  │       file2.txt
  │       file3.txt
  │
  └───videos
          file1.mp4
          file2.mp4
          file3.mp4
  </code></pre>
  
  <p>Code:</p>
  
  <pre><code>from PIL import Image, ImageDraw, ImageFont
  import textwrap
  from pathlib import Path
  import glob
  import os
  import shlex
  import subprocess
  
  def draw_multiple_line_text(image, text, font, text_color, text_start_height):
      '''
      From unutbu on [python PIL draw multiline text on image](https://stackoverflow.com/a/7698300/395857)
      '''
      draw = ImageDraw.Draw(image)
      image_width, image_height = image.size
      y_text = text_start_height
      lines = textwrap.wrap(text, width=40)
      for line in lines:
          line_width, line_height = font.getsize(line)
          draw.text(((image_width - line_width) / 2, y_text),
                    line, font=font, fill=text_color)
          y_text += line_height
  
  
  def generate_image(transcript_filepath, image_filepath):
      '''
  
      '''
      #image_width
      image = Image.new('RGB', (800, 600), color = (0, 0, 0))
      fontsize = 30  # starting font size
      font = ImageFont.truetype("arial.ttf", fontsize)
      #text1 = "I try to add text at the bottom of image and actually I've done it, but in case of my text is longer then image width it is cut from both sides, to simplify I would like text to be in multiple lines if it is longer than image width."
      #text2 = "You could use textwrap.wrap to break text into a list of strings, each at most width characters long"
  
      text1 = open(transcript_filepath, 'r').read()
      text_color = (200, 200, 200)
      text_start_height = 0
      draw_multiple_line_text(image, text1, font, text_color, text_start_height)
      text2 = transcript_filepath
      draw_multiple_line_text(image, text2, font, text_color, 400)
  
      image.save(image_filepath)
  
  
  def create_folder_if_not_exists(directory):
      '''
      Create the folder if it doesn't exist already.
      '''
      if not os.path.exists(directory):
          os.makedirs(directory)
  
  def get_basename_without_extension(filepath):
      '''
      Getting the basename of the filepath without the extension
      E.g. 'data/formatted/movie_reviews.pickle' -&gt; 'movie_reviews'
      '''
      return os.path.basename(os.path.splitext(filepath)[0])
  
  def run_command(command):
      print('command: {0}'.format(command))
      process = subprocess.Popen(shlex.split(command), stdout=subprocess.PIPE)
      while True:
          output = process.stdout.readline()
          print(output.strip())
          if output == b'' and process.poll() is not None:
              print('Done running the command.')
              break
          if output:
              print(output.strip())
      rc = process.poll()
      return rc
  
  def main():
      '''
      Generate videos based on image+text
      '''
      transcript_file_extension = 'txt'
      speech_file_extension = 'wav'
      data_folder = 'transcripts'
      transcript_filepaths = list(glob.glob('{1}/**.{0}'.format(transcript_file_extension, data_folder)))
      transcript_filepaths.sort()
      speech_filepaths = list(glob.glob('{1}/**.{0}'.format(speech_file_extension, data_folder)))
      speech_filepaths.sort()
      print('transcript_filepaths: {0}'.format(transcript_filepaths))
      print('speech_filepaths: {0}'.format(speech_filepaths))
  
      output_folder = 'images'
      audio_folder = 'audio'
      video_output_folder = 'videos'
      create_folder_if_not_exists(output_folder)
      create_folder_if_not_exists(video_output_folder)
      output_folder = os.path.abspath(output_folder)
      print('output_folder: {0}'.format(output_folder))
  
  
      ffmpeg_concat_filepath = os.path.abspath('ffmpeg_concat_file.txt')
      ffmpeg_concat_file = open(ffmpeg_concat_filepath, 'w')
      for transcript_filepath  in transcript_filepaths:
          image_filename = get_basename_without_extension(transcript_filepath)
          image_filepath = os.path.join(output_folder, '{0}.png'.format(image_filename))
          generate_image(transcript_filepath, image_filepath)
          audio_filepath = os.path.join(audio_folder, '{0}.wav'.format(image_filename))
          video_filepath = os.path.join(video_output_folder, '{0}.mp4'.format(image_filename))
          os.system('ffmpeg -loop 1 -y -i {0} -i {2} -shortest {1}'.format(image_filepath, video_filepath, audio_filepath))
          ffmpeg_concat_file.write("file '{0}'\n".format(video_filepath))
  
      ffmpeg_concat_file.close()
      # [How to concatenate two MP4 files using FFmpeg?](https://stackoverflow.com/a/11175851/395857)
      # Note: the following command only works in Microsoft Windows. 
      # See the Stack Exchange link for the command for Linux and Mac OS X
      os.system('ffmpeg -safe 0 -f concat -i {0} -c copy output.mp4'.format(ffmpeg_concat_filepath))
  
  
  
  
  if __name__ == "__main__":
      main()
      #cProfile.run('main()') # if you want to do some profiling
  </code></pre>
  
  <p>Tested with:</p>
  
  <ul>
  <li>Python 3.6</li>
  <li>Pillow 5.3.0 </li>
  <li>ffmpeg version N-50911-g9efcfbe Copyright (c) 2000-2013 the FFmpeg developers, built on Mar 13 2013 21:26:48 with gcc 4.7.2 (GCC)</li>
  <li>Windows 7 SP1 x64 Ultimate:</li>
  </ul>
  
  <p>It should work on any operating system as long as ffmpeg is available (e.g., in the path on Microsoft Windows).</p>
  
  <p>Video output example:</p>
  
  <p><a href="https://i.sstatic.net/ZfW6f.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/ZfW6f.png" alt="enter image description here"></a></p>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-05-19T08:08:03.523Z
Answers.LastActivityDate: 2019-05-19T08:40:52.380Z
Answers.LastEditDate: 2019-05-19T08:40:52.380Z
Answers.UserDisplayName: Franck Dernoncourt
Body: <p>I have a text and an audio file. I want to create a video that simply displays the text with the audio file playing in the background.  I have to create many such videos, so I'm looking for an automated solution. What program/script  could achieve that?</p>
  
Comments.ContentLicense: CC BY-SA 3.0
Comments.CreationDate: 2017-12-09T15:55:31.820Z
Comments.Text: So, subtitling, basically?
Comments.UserDisplayName: Gyan
Comments.ContentLicense: CC BY-SA 3.0
Comments.CreationDate: 2017-12-10T01:42:59.140Z
Comments.Text: @Mulvya I guess that could be one approach, one difference being that we don't have any video as input.
Comments.UserDisplayName: Franck Dernoncourt
Comments.ContentLicense: CC BY-SA 3.0
Comments.CreationDate: 2017-12-10T06:03:07.100Z
Comments.Text: ffmpeg can do it. Like Mulvya says I'd use subtitles if you want the te\xt to change over the course of the video.
Comments.UserDisplayName: stib
Comments.ContentLicense: CC BY-SA 3.0
Comments.CreationDate: 2017-12-10T06:12:05.980Z
Comments.Text: ffmpeg can create a blank video as canvas. I mentioned subtitling because I assume you want the displayed text to sync with the audio. If not, you can scroll the text - see https://superuser.com/q/1273424/114058
Comments.UserDisplayName: Gyan
Tags: <software-recommendation>
Title: Creating a video from a text and an audio file
UserDisplayName: Franck Dernoncourt
ThreadText: # Creating a video from a text and an audio file
  
  (Asked by: username_0 on 2017-12-08)
  
  I have a text and an audio file. I want to create a video that simply displays the text with the audio file playing in the background. I have to create many such videos, so I'm looking for an automated solution. What program/script could achieve that?
  
  **Tags:** software-recommendation
  
  > **Comments:**
  > **username_1**: So, subtitling, basically?  
  > **username_0**: @Mulvya I guess that could be one approach, one difference being that we don't have any video as input.  
  > **username_2**: ffmpeg can do it. Like Mulvya says I'd use subtitles if you want the te\xt to change over the course of the video.  
  > **username_1**: ffmpeg can create a blank video as canvas. I mentioned subtitling because I assume you want the displayed text to sync with the audio. If not, you can scroll the text - see https://superuser.com/q/1273424/114058  
  
  ---
  
  ## 2 answers
  
  ### Answer by username_3 on 2017-12-11. Score: 4
  
  The [Amara website](https://amara.org/en/) offers a free service that accepts audio and text files, synchronizes them, and lets you download a .srt file (synchronized SubTitle). Source of suggestion: [Photography TutsPlus](https://photography.tutsplus.com/tutorials/3-ways-to-subtitle-and-caption-your-videos-automatically-using-artificial-intelligence--cms-26834).
  
  YouTube also [accepts text files without time coding as SubTitle](https://support.google.com/youtube/answer/2734799) files and then you can enable auto-sync, you ought to be able to download a .srt file after processing is completed (not tested by me).
  
  ---
  
  To do it manually (with some automation) try the following.
  
  If you convert the text file to a .ass or .srt file then you can use the following commands:
  
  > ffmpeg.exe -i subtitles.srt subtitles.ass
  >
  > ffmpeg.exe -i video.mp4 -vf ass=subtitles.ass video-new.mp4
  
  That will show the words hardsubbed on the video synchronized with the audio. The *video* can be a moving image (video) or a static image.
  
  Using a .ass editor allows more control over color and other font features than using .srt files.
  
  Without using a SubTitle Format file you won't get synchronized text.
  
  You can add the audio to a video and upload it to YouTube, then wait 15 minutes, after which YouTube will have used audio recognition to convert the audio to subtitles (with better than 80% accuracy). Then you can download the .srt file from the Video Manager and edit the SubTitle file by comparing it to your (presumably accurate) text file.
  
  If you were hoping for a program that automatically syncs raw text files with audio and makes a video I have found nothing by Googling (outside of pay services).
  
  There are a few questions over at SO, but they remain unanswered.
  
  I will do some more searching and improve this answer in a few hours.
  
  Not a one-mouseclick solution but it's about as automated as I can suggest, for free (other than Amara).
  
  [I welcome Mulvya to edit and improve this answer.]
  
  
  ---
  
  ### Answer by username_0 on 2019-05-19. Score: 1
  
  I wrote a Python script create a video that simply displays the text with the audio file playing in the background.
  
  Example of file structure before running the script (in this example, the three pairs of audio file + transcript):
  
  ```
  C:\Users\username_0\Documents\GitHub\code>tree /f
  Folder PATH listing
  C:.
  │   generate_videos.py
  │
  ├───audio
  │       file1.wav
  │       file2.wav
  │       file3.wav
  │
  └───transcripts
          file1.txt
          file2.txt
          file3.txt
  
  ```
  
  After running the script (`output.mp4` is the concatenation of `videos\*.mp4`):
  
  ```
  C:\Users\username_0\Documents\GitHub\code>tree /f
  Folder PATH listing
  C:.
  │   generate_videos.py
  │   output.mp4
  │
  ├───audio
  │       file1.wav
  │       file2.wav
  │       file3.wav
  │
  ├───images
  │       file1.png
  │       file2.png
  │       file3.png
  │
  ├───transcripts
  │       file1.txt
  │       file2.txt
  │       file3.txt
  │
  └───videos
          file1.mp4
          file2.mp4
          file3.mp4
  
  ```
  
  Code:
  
  ```
  from PIL import Image, ImageDraw, ImageFont
  import textwrap
  from pathlib import Path
  import glob
  import os
  import shlex
  import subprocess
  
  def draw_multiple_line_text(image, text, font, text_color, text_start_height):
      '''
      From unutbu on [python PIL draw multiline text on image](https://stackoverflow.com/a/7698300/395857)
      '''
      draw = ImageDraw.Draw(image)
      image_width, image_height = image.size
      y_text = text_start_height
      lines = textwrap.wrap(text, width=40)
      for line in lines:
          line_width, line_height = font.getsize(line)
          draw.text(((image_width - line_width) / 2, y_text),
                    line, font=font, fill=text_color)
          y_text += line_height
  
  def generate_image(transcript_filepath, image_filepath):
      '''
  
      '''
      #image_width
      image = Image.new('RGB', (800, 600), color = (0, 0, 0))
      fontsize = 30  # starting font size
      font = ImageFont.truetype("arial.ttf", fontsize)
      #text1 = "I try to add text at the bottom of image and actually I've done it, but in case of my text is longer then image width it is cut from both sides, to simplify I would like text to be in multiple lines if it is longer than image width."
      #text2 = "You could use textwrap.wrap to break text into a list of strings, each at most width characters long"
  
      text1 = open(transcript_filepath, 'r').read()
      text_color = (200, 200, 200)
      text_start_height = 0
      draw_multiple_line_text(image, text1, font, text_color, text_start_height)
      text2 = transcript_filepath
      draw_multiple_line_text(image, text2, font, text_color, 400)
  
      image.save(image_filepath)
  
  def create_folder_if_not_exists(directory):
      '''
      Create the folder if it doesn't exist already.
      '''
      if not os.path.exists(directory):
          os.makedirs(directory)
  
  def get_basename_without_extension(filepath):
      '''
      Getting the basename of the filepath without the extension
      E.g. 'data/formatted/movie_reviews.pickle' -> 'movie_reviews'
      '''
      return os.path.basename(os.path.splitext(filepath)[0])
  
  def run_command(command):
      print('command: {0}'.format(command))
      process = subprocess.Popen(shlex.split(command), stdout=subprocess.PIPE)
      while True:
          output = process.stdout.readline()
          print(output.strip())
          if output == b'' and process.poll() is not None:
              print('Done running the command.')
              break
          if output:
              print(output.strip())
      rc = process.poll()
      return rc
  
  def main():
      '''
      Generate videos based on image+text
      '''
      transcript_file_extension = 'txt'
      speech_file_extension = 'wav'
      data_folder = 'transcripts'
      transcript_filepaths = list(glob.glob('{1}/**.{0}'.format(transcript_file_extension, data_folder)))
      transcript_filepaths.sort()
      speech_filepaths = list(glob.glob('{1}/**.{0}'.format(speech_file_extension, data_folder)))
      speech_filepaths.sort()
      print('transcript_filepaths: {0}'.format(transcript_filepaths))
      print('speech_filepaths: {0}'.format(speech_filepaths))
  
      output_folder = 'images'
      audio_folder = 'audio'
      video_output_folder = 'videos'
      create_folder_if_not_exists(output_folder)
      create_folder_if_not_exists(video_output_folder)
      output_folder = os.path.abspath(output_folder)
      print('output_folder: {0}'.format(output_folder))
  
      ffmpeg_concat_filepath = os.path.abspath('ffmpeg_concat_file.txt')
      ffmpeg_concat_file = open(ffmpeg_concat_filepath, 'w')
      for transcript_filepath  in transcript_filepaths:
          image_filename = get_basename_without_extension(transcript_filepath)
          image_filepath = os.path.join(output_folder, '{0}.png'.format(image_filename))
          generate_image(transcript_filepath, image_filepath)
          audio_filepath = os.path.join(audio_folder, '{0}.wav'.format(image_filename))
          video_filepath = os.path.join(video_output_folder, '{0}.mp4'.format(image_filename))
          os.system('ffmpeg -loop 1 -y -i {0} -i {2} -shortest {1}'.format(image_filepath, video_filepath, audio_filepath))
          ffmpeg_concat_file.write("file '{0}'\n".format(video_filepath))
  
      ffmpeg_concat_file.close()
      # [How to concatenate two MP4 files using FFmpeg?](https://stackoverflow.com/a/11175851/395857)
      # Note: the following command only works in Microsoft Windows. 
      # See the Stack Exchange link for the command for Linux and Mac OS X
      os.system('ffmpeg -safe 0 -f concat -i {0} -c copy output.mp4'.format(ffmpeg_concat_filepath))
  
  if __name__ == "__main__":
      main()
      #cProfile.run('main()') # if you want to do some profiling
  
  ```
  
  Tested with:
  
  * Python 3.6
  * Pillow 5.3.0
  * ffmpeg version N-50911-g9efcfbe Copyright (c) 2000-2013 the FFmpeg developers, built on Mar 13 2013 21:26:48 with gcc 4.7.2 (GCC)
  * Windows 7 SP1 x64 Ultimate:
  
  It should work on any operating system as long as ffmpeg is available (e.g., in the path on Microsoft Windows).
  
  Video output example:
  
  [![enter image description here](https://i.sstatic.net/ZfW6f.png)](https://i.sstatic.net/ZfW6f.png)
  
  
  ---
  
  