Data Makes Music – Spotify writes Udio Pompts
01
Trending
The rise of the Music AI
In recent weeks, innovative music tools like Suno and udio entered the stage and captured significant attention. By simply inputting text prompts, users can generate amazingly dense, natural, and beautiful songs. Although these tools have drawn considerable criticism from artists concerning their opaque sources of training material, users have flocked to them to try out their services.
While early adopters were sharing their creations, I noticed a recurring theme: Non-musicians (like myself) often struggle to form their preferences into effective prompts. Consequently, many experiment with these powerful services are using absurd, quirky prompts such as “18th-century synthesizer techno about the Heisenberg phenomenon.” While they marvel at the novelty, they soon turn away.
In the course of this post, we will develop a Python script to transform the songs and styles you really like into data, and then into prompts. This creative exploration translates Spotify’s detailed audio metrics into highly descriptive tokens for udio.
02
Start here
Prerequisites
- - A well curated Spotify account that reflects your listening habits.
- - Optional: access to the openAI API to improve the lyric analysis and generation.
- - Basic knowledge how to setup and run Python scripts on your computer
03
Basics
Spotify’s music data
In 2014, Spotify acquired the the music intelligence service “The Echo Nest”. By then, Echo Nest already had 10 years experience in sourcing music data and telling creative narratives around it. This laid the foundation for Spotify’s extensive music data expertise. Spotify not only stores title and artist information but also calculates detailed audio features for each track for analysis and recommendations. You can find out more in Spotify’s developer documentation — a set of helpful resources that explains which features are used and how you can build your own awesome projects on top of it.
For this exploration you will access your top track information from Spotify. You will get the audio features for each track to combine and translate them into a prompt. Acousticness, Danceability, Energy, Tempo and others are an awesome foundation for descriptive prompts. Moreover, you will need the genre information for the track’s artist.
04
Code
Authentication
We will use the spotipy library to connect to your Spotify account. This requires to set up a Spotify developer app. The workflow can be a little tricky. If you encounter problems, check out Ian Annase’s comprehensive walkthrough on Youtube. On your browser, head to the Spotify developer dashboard and click “Create app”.
Enter the information in the form:
App name: `promptmaker`
(or any app name you prefer)
Redirect URI: `http://www.google.com/`
(This can be any valid URL. Just make sure to put a forward slash at the end)
Click “settings” and copy the relevant information. Switch to your Terminal window and add the info as secrets to your environent. For each line, paste the information between the quotation marks and hit enter.
mkdir promptmaker
cd promptmaker
# setup to isolate the installation
virtualenv env
# activate environment
source env/bin/activate
# install necessary libraries
pip3 install spotipy openai
export SPOTIPY_CLIENT_ID='your-spotify-client-id'
export SPOTIPY_CLIENT_SECRET='your-spotify-client-secret'
export SPOTIPY_REDIRECT_URI='your-app-redirect-url'
# Again, make sure you have the forward slash at the end
# If you want to analyze the song titles
# and have access to openAI API, enter the key
export OPENAI_API_KEY='your-open-ai-api-key'
05
Code
Set up
Now let’s fire up a text editor or code editor and create a file prompt_maker.py. In the first part, set the imports, init some variables and instantiate the necessary objects.
import spotipy
from spotipy.oauth2 import SpotifyOAuth
from math import floor
from collections import Counter
from openai import OpenAI
number_of_top_tracks = 10 # keep it between 3 and 50
scope = 'user-top-read' # submitted to spotify for the authentication process
sp = spotipy.Spotify(auth_manager=SpotifyOAuth(scope=scope))
results = sp.current_user_top_tracks(limit=number_of_top_tracks,
offset=0,
time_range='long_term')
# helper function for prompt building
def prompt_from_range(input_list, input_val):
"""returns the value matching the input on a range 0 to 1"""
return_item = input_list[floor(input_val * len(input_list))]
return f'{return_item}, '
# init variables
counter = 0
acousticness_sum = 0
danceability_sum = 0
energy_sum = 0
tempo_sum = 0
valence_sum = 0
instrumentalness_sum = 0
liveness_sum = 0
mode_sum = 0
genre_list = []
title_list = []
06
Code
Analyze your tracks
Here, we iterate over your favourite tracks and collect the features to calculate the average.
for i, track in enumerate(results['items']):
print('---')
title = track['name']
artist_name = track['artists'][0]['name']
print(f'{i} {title} – {artist_name}')
track_id = track['id']
audio_features = sp.audio_features(track_id)
speechiness = audio_features[0]['speechiness']
if speechiness > 0.5:
# ignore spoken content
print(f'speechiness: {speechiness} – ignoring as spoken content')
else:
counter += 1
title_list.append(title)
acousticness = audio_features[0]['acousticness']
acousticness_sum += acousticness
danceability = audio_features[0]['danceability']
danceability_sum += danceability
energy = audio_features[0]['energy']
energy_sum += energy
tempo = audio_features[0]['tempo']
tempo_sum += tempo
valence = audio_features[0]['valence']
valence_sum += valence
instrumentalness = audio_features[0]['instrumentalness']
instrumentalness_sum += instrumentalness
liveness = audio_features[0]['liveness']
liveness_sum += liveness
mode = audio_features[0]['mode']
mode_sum += mode
artist_id = track['artists'][0]['id']
artist_info = sp.artist(artist_id)
genres = artist_info.get('genres')
print(f'Genres: {genres}')
genre_list += genres #build a genre list
07
Code
Add genres
Let’s add the most popular and the most peculiar genres.
try:
# get the most prominent genres
genre_counts = Counter(genre_list) # creates a list of tuples
common_genres = genre_counts.most_common(3) # sort and limit
keys = [genre for genre, count in common_genres]
# find the longest genre description which is often the funniest
max_length = max(len(genre) for genre in genre_list)
peculiar_genre = [genre for genre in genre_list
if len(genre) == max_length]
peculiar_genre = peculiar_genre[0]
genre_prompt = f'A {keys[0]} song with {keys[1]} and {keys[2]} elements.'
genre_prompt += f'Spice it up with some {peculiar_genre}, '
prompt = genre_prompt + prompt
except Exception as e:
# sometimes no genres are defined and the handling fails.
print(f'Error {e} while handling genres. Proceeding without genres.')
08
Code
Get topic with AI
Now let’s ask chatGPT to find a meta-topic in the first 10 track titles. If we don’t provide an openAI API key, the script will fall back to a simpler instruction.
try:
client = OpenAI()
# chose the model: "gpt-3.5-turbo" (cheaper) or "gpt-4" (costier, better).
model = "gpt-4"
system_prompt = """You are a record company's portfolio
manager who analyzes
societal, behavioural, emotional topics in song titles.
He considers several titles and transforms the most
striking meta-topic into brief for a lyricist that starts:
Write a song about [meta-topic]."""
# Extrapolate the topic from your top 10 tracks
user_prompt = f"""Please have a look at these song titles {title_list[:10]}
and turn them into a short single-sentence brief."""
completion = client.chat.completions.create(
model=model,
messages=[ {"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt}])
lyrics_prompt = completion.choices[0].message.content + " "
except Exception as e:
print(f'Error {e} while fetching lyrics. Proceeding with generic prompt')
lyrics_prompt = f'A song about \'{title_list[0]}\' '
lyrics_prompt += f'from someone who adores \'{title_list[1]}\' '
lyrics_prompt += f'while thinking \'{title_list[2]}\'.'
prompt = lyrics_prompt + prompt
### That’s all we need for the prompt. Print it to the Terminal:
print('\n\nHere is the prompt generated from your data.')
print('Copy and paste it into your song generation tool.')
print('---')
print(prompt)
print('---')