Skip to content

Instantly share code, notes, and snippets.

@mixxorz
Last active January 19, 2023 15:46
Show Gist options
  • Star 33 You must be signed in to star a gist
  • Fork 7 You must be signed in to fork a gist
  • Save mixxorz/abb8a2f22adbdb6d387f to your computer and use it in GitHub Desktop.
Save mixxorz/abb8a2f22adbdb6d387f to your computer and use it in GitHub Desktop.
Generate waveform images from audio files
# Requires pydub (with ffmpeg) and Pillow
#
# Usage: python waveform.py <audio_file>
import sys
from pydub import AudioSegment
from PIL import Image, ImageDraw
class Waveform(object):
bar_count = 107
db_ceiling = 60
def __init__(self, filename):
self.filename = filename
audio_file = AudioSegment.from_file(
self.filename, self.filename.split('.')[-1])
self.peaks = self._calculate_peaks(audio_file)
def _calculate_peaks(self, audio_file):
""" Returns a list of audio level peaks """
chunk_length = len(audio_file) / self.bar_count
loudness_of_chunks = [
audio_file[i * chunk_length: (i + 1) * chunk_length].rms
for i in range(self.bar_count)]
max_rms = max(loudness_of_chunks) * 1.00
return [int((loudness / max_rms) * self.db_ceiling)
for loudness in loudness_of_chunks]
def _get_bar_image(self, size, fill):
""" Returns an image of a bar. """
width, height = size
bar = Image.new('RGBA', size, fill)
end = Image.new('RGBA', (width, 2), fill)
draw = ImageDraw.Draw(end)
draw.point([(0, 0), (3, 0)], fill='#c1c1c1')
draw.point([(0, 1), (3, 1), (1, 0), (2, 0)], fill='#555555')
bar.paste(end, (0, 0))
bar.paste(end.rotate(180), (0, height - 2))
return bar
def _generate_waveform_image(self):
""" Returns the full waveform image """
im = Image.new('RGB', (840, 128), '#f5f5f5')
for index, value in enumerate(self.peaks, start=0):
column = index * 8 + 2
upper_endpoint = 64 - value
im.paste(self._get_bar_image((4, value * 2), '#424242'),
(column, upper_endpoint))
return im
def save(self):
""" Save the waveform as an image """
png_filename = self.filename.replace(
self.filename.split('.')[-1], 'png')
with open(png_filename, 'wb') as imfile:
self._generate_waveform_image().save(imfile, 'PNG')
if __name__ == '__main__':
filename = sys.argv[1]
waveform = Waveform(filename)
waveform.save()
@Melanpan
Copy link

Melanpan commented Nov 1, 2015

You might want to change line 67 to with open(png_filename, 'wb') as imfile:

This will make the script run on Python3 as well! 👍

@mixxorz
Copy link
Author

mixxorz commented Nov 4, 2015

Cool thanks! Updated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment