Last active
February 5, 2025 12:02
-
-
Save mixxorz/abb8a2f22adbdb6d387f to your computer and use it in GitHub Desktop.
Generate waveform images from audio files
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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! 👍