4.9 - Assign moods
Introduction
The application has got a feature to filter based on the moods of a track. The Spotify API doesn't provide an mood endpoint. Because of this we made a little algorithm to detect moods in tracks. This is also the base for the recommended tracks.
How it works
Below is an short explanation how we assign moods to tracks. If you want to know more about the way it works, you can find a detailed description here.
When a user searches we get the search results from the Spotify API. With the Spotify API we request the audio features. From these audio features we use energy
, valence
and danceability
. These endpoints are on a scale from 0.0
to 1.0
. We divided this scale in to five sections with steps of 1/6
. Based on a tracks energy, valence and danceability value it decides which mood the track probably got.
There are three functions to calculate the mood. One for energy, one for valence and one for danceability. These functions are more or less the same so we show just one. n
is the value that we get back from the Spotify API. Based on this number the function returns the certainty of the moods in percentage of ten.
function energy(n) {
if (n < 1 / 6) {
const min = 0,
max = 1 / 6;
return {
relaxingCalm: 10,
dark: 8,
sadTense: 6,
happy: 4,
energetic: 2,
values: {
min: 0,
max: max.toFixed(2),
},
};
} else if (n < 1 / 3) {
const min = 1 / 6,
max = 1 / 3;
return {
dark: 10,
relaxingCalm: 8,
sadTense: 6,
happy: 4,
energetic: 2,
values: {
min: min.toFixed(2),
max: max.toFixed(2),
},
};
} else if (n < 2 / 3) {
const min = 1 / 3,
max = 2 / 3;
return {
sadTense: 10,
dark: 8,
happy: 6,
relaxingCalm: 4,
energetic: 2,
values: {
min: min.toFixed(2),
max: max.toFixed(2),
},
};
} else if (n < 5 / 6) {
const min = 2 / 3,
max = 5 / 6;
return {
happy: 10,
energetic: 8,
sadTense: 6,
dark: 4,
relaxingCalm: 2,
values: {
min: min.toFixed(2),
max: max.toFixed(2),
},
};
} else {
const min = 5 / 6,
max = 1;
return {
energetic: 10,
happy: 8,
sadTense: 6,
dark: 4,
relaxingCalm: 2,
values: {
min: min.toFixed(2),
max: 1,
},
};
}
}
After this is done the code below will calculate the total percentage of all moods.
const moods = ['relaxingCalm', 'dark', 'sadTense', 'happy', 'energetic'];
function sumMood(song, mood) {
const _energy = energy(song.energy),
_valence = valence(song.valence),
_danceability = danceability(song.danceability);
return _energy[mood] + _valence[mood] + _danceability[mood];
}
function moodScore(song) {
let total = {};
moods.forEach(function (mood) {
total[mood] = sumMood(song, mood);
});
return total;
}
The mood with the highest percentage is the mood we want. The code below gets the highest percentage. If there is more than one highest mood it will return No mood detected...
.
function getMood(song) {
const total = moodScore(song);
const highest = Object.keys(total).filter((x) => {
return total[x] == Math.max.apply(null, Object.values(total));
});
highest.length > 1 ? 'No mood detected...' : highest;
}
At last we add the mood to the song and return the song with the mood.
function getValues(song) {
const _energy = energy(song.energy),
_valence = valence(song.valence),
_danceability = danceability(song.danceability);
return {
energyValues: _energy.values,
valenceValues: _valence.values,
danceabilityValues: _danceability.values,
};
}
function addMood(song) {
const mood = getMood(song);
song['mood'] = mood;
song['values'] = getValues(song);
return song;
}
Last updated
Was this helpful?