Phyks (Lucas Verney)
345383e3a5
Now using 3 tempo values, updated Bliss version. _Note_: You should rebuild your database after upgrading to this commit. Next major breaking changes will be handled by dedicated update scripts to avoid having to rebuild the entire database.
106 lines
3.9 KiB
Python
Executable File
106 lines
3.9 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
import logging
|
|
import math
|
|
import os
|
|
import sqlite3
|
|
|
|
logging.basicConfig(level=logging.DEBUG)
|
|
|
|
if "XDG_DATA_HOME" in os.environ:
|
|
_BLISSIFY_DATA_HOME = os.path.expandvars("$XDG_DATA_HOME/blissify")
|
|
else:
|
|
_BLISSIFY_DATA_HOME = os.path.expanduser("~/.local/share/blissify")
|
|
|
|
|
|
def main():
|
|
db_path = os.path.join(_BLISSIFY_DATA_HOME, "db.sqlite3")
|
|
logging.debug("Using DB path: %s." % (db_path,))
|
|
conn = sqlite3.connect(db_path)
|
|
conn.row_factory = sqlite3.Row
|
|
conn.execute('pragma foreign_keys=ON')
|
|
cur = conn.cursor()
|
|
|
|
# Get cached distances from db
|
|
cur.execute("SELECT song1, song2, distance, similarity FROM distances")
|
|
cached_distances = cur.fetchall()
|
|
|
|
# Get all songs
|
|
cur.execute("SELECT id, tempo1, tempo2, tempo3, amplitude, frequency, attack, filename FROM songs")
|
|
all_songs = cur.fetchall()
|
|
|
|
for i in range(len(all_songs)):
|
|
for j in range(i + 1, len(all_songs)):
|
|
song1 = all_songs[i]
|
|
song2 = all_songs[j]
|
|
is_cached = len([i for i in cached_distances
|
|
if(i["song1"] == song1["id"] and
|
|
i["song2"] == song2["id"]) or
|
|
(i["song1"] == song2["id"] and
|
|
i["song2"] == song1["id"])]) > 0
|
|
if is_cached:
|
|
# Pass pair if cached value is already there
|
|
continue
|
|
# Compute distance
|
|
distance = math.sqrt(
|
|
(song1["tempo1"] - song2["tempo1"])**2 +
|
|
(song1["tempo2"] - song2["tempo2"])**2 +
|
|
(song1["tempo3"] - song2["tempo3"])**2 +
|
|
(song1["amplitude"] - song2["amplitude"])**2 +
|
|
(song1["frequency"] - song2["frequency"])**2 +
|
|
(song1["attack"] - song2["attack"])**2
|
|
)
|
|
similarity = (
|
|
(song1["tempo1"] * song2["tempo1"] +
|
|
song1["tempo2"] * song2["tempo2"] +
|
|
song1["tempo3"] * song2["tempo3"] +
|
|
song1["amplitude"] * song2["amplitude"] +
|
|
song1["frequency"] * song2["frequency"] +
|
|
song1["attack"] * song2["attack"]) /
|
|
(
|
|
math.sqrt(
|
|
song1["tempo1"]**2 +
|
|
song1["tempo2"]**2 +
|
|
song1["tempo3"]**2 +
|
|
song1["amplitude"]**2 +
|
|
song1["frequency"]**2 +
|
|
song1["attack"]**2) *
|
|
math.sqrt(
|
|
song2["tempo1"]**2 +
|
|
song2["tempo2"]**2 +
|
|
song2["tempo3"]**2 +
|
|
song2["amplitude"]**2 +
|
|
song2["frequency"]**2 +
|
|
song2["attack"]**2)
|
|
)
|
|
)
|
|
|
|
logging.debug("Distance between %s and %s is (%f, %f)." %
|
|
(song1["filename"], song2["filename"], distance,
|
|
similarity))
|
|
# Store distance in db cache
|
|
try:
|
|
logging.debug("Storing distance in database.")
|
|
conn.execute(
|
|
"INSERT INTO distances(song1, song2, distance, similarity) VALUES(?, ?, ?, ?)",
|
|
(song1["id"], song2["id"], distance, similarity))
|
|
conn.commit()
|
|
# Update cached_distances list
|
|
cached_distances.append({
|
|
"song1": song1["id"],
|
|
"song2": song2["id"],
|
|
"distance": distance,
|
|
"similarity": similarity
|
|
})
|
|
except sqlite3.IntegrityError:
|
|
logging.warning("Unable to insert distance in database.")
|
|
conn.rollback()
|
|
# Close connection
|
|
conn.close()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
try:
|
|
main()
|
|
except KeyboardInterrupt:
|
|
pass
|