Skip to content

Instantly share code, notes, and snippets.

@dela3499
Created May 8, 2016 19:43
Show Gist options
  • Save dela3499/e1627be3791e570a7b6b7101d929a68f to your computer and use it in GitHub Desktop.
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.
Display the source blob
Display the rendered blob
Raw
{
"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