Created
May 8, 2016 19:43
-
-
Save dela3499/e1627be3791e570a7b6b7101d929a68f to your computer and use it in GitHub Desktop.
Song thumbnails - take sections from the beginning, middle, and end of songs, and combine them into a discography-spanning summary of an artist's work.
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
{ | |
"cells": [ | |
{ | |
"cell_type": "code", | |
"execution_count": 1, | |
"metadata": { | |
"collapsed": false | |
}, | |
"outputs": [], | |
"source": [ | |
"from pydub import AudioSegment as AS\n", | |
"import numpy as np\n", | |
"import toolz as tz\n", | |
"import os" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 2, | |
"metadata": { | |
"collapsed": false | |
}, | |
"outputs": [], | |
"source": [ | |
"def list_song_files(directory, file_extension = '.wma'):\n", | |
" \"\"\" ---------------------\n", | |
" String -> String-> List String\n", | |
" ---------------------\n", | |
" Recursively list full path of every song \n", | |
" with given file extension in directory. \n", | |
" \"\"\"\n", | |
" def get_files((directory, folder, files)):\n", | |
" return [os.path.join(directory,f) for f in files if f.endswith('.wma')]\n", | |
" \n", | |
" return tz.thread_last(\n", | |
" directory,\n", | |
" os.walk,\n", | |
" (tz.mapcat, get_files),\n", | |
" list)\n", | |
"\n", | |
"def get_song_parts(song):\n", | |
" \"\"\" ---------------------------------\n", | |
" AudioSegment -> List AudioSegment\n", | |
" ---------------------------------\n", | |
" Given segment, return short segment from \n", | |
" beginning, middle, and end of song. \n", | |
" \"\"\"\n", | |
" t = 12000 # 12 seconds\n", | |
" halfway = len(song) / 2\n", | |
" start = song[:t]\n", | |
" middle = song[halfway:halfway + t]\n", | |
" ending_offset = 5000 # helps avoid last few seconds, which are often silence\n", | |
" end = song[-(t + ending_offset):-ending_offset]\n", | |
" return [start, middle, end]\n", | |
"\n", | |
"def crossfade_join(segments, seconds = 1.5):\n", | |
" \"\"\" ------------------------------------------\n", | |
" List AudioSegment -> Float -> AudioSegment\n", | |
" ------------------------------------------\n", | |
" Concatenate segments while fading one smoothly into the next. \n", | |
" \"\"\"\n", | |
" return reduce(lambda x, y: x.append(y, crossfade = seconds * 1000), segments)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 3, | |
"metadata": { | |
"collapsed": false | |
}, | |
"outputs": [], | |
"source": [ | |
"directory = \"/home/bioage/projects/music/Music/Rush\"\n", | |
"song_files = list_song_files(directory)\n", | |
"np.random.shuffle(song_files) # Just wanted to mix things up" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": { | |
"collapsed": false | |
}, | |
"outputs": [], | |
"source": [ | |
"songs = map(AS.from_file, song_files)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 5, | |
"metadata": { | |
"collapsed": false | |
}, | |
"outputs": [], | |
"source": [ | |
"merged = crossfade_join(tz.mapcat(get_song_parts, songs))" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 6, | |
"metadata": { | |
"collapsed": true | |
}, | |
"outputs": [], | |
"source": [ | |
"save_file = merged.export('test3.mp3', format = 'mp3')" | |
] | |
} | |
], | |
"metadata": { | |
"kernelspec": { | |
"display_name": "Python 2", | |
"language": "python", | |
"name": "python2" | |
}, | |
"language_info": { | |
"codemirror_mode": { | |
"name": "ipython", | |
"version": 2 | |
}, | |
"file_extension": ".py", | |
"mimetype": "text/x-python", | |
"name": "python", | |
"nbconvert_exporter": "python", | |
"pygments_lexer": "ipython2", | |
"version": "2.7.11" | |
} | |
}, | |
"nbformat": 4, | |
"nbformat_minor": 0 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment