Skip to content

Instantly share code, notes, and snippets.

@mixxorz
Last active February 5, 2025 12:02
Show Gist options
  • Select an option

  • Save mixxorz/abb8a2f22adbdb6d387f to your computer and use it in GitHub Desktop.

Select an option

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()
@mixxorz
Copy link
Copy Markdown
Author

mixxorz commented Oct 30, 2015

You're right, I didn't notice that. Updated.

@Melanpan
Copy link
Copy Markdown

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
Copy Markdown
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