Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ var/
*.egg-info/
.installed.cfg
*.egg
*.eggs

# Installer logs
pip-log.txt
Expand Down
26 changes: 26 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
language: python
addons:
apt:
sources:
- sourceline: "ppa:mc3man/trusty-media"
update: true
packages:
- ffmpeg
- pandoc

before_install:
- pip install --upgrade pip
- pip install --upgrade codecov pypandoc pytest pytest-cov pytest-mock
install: "pip install --no-cache-dir -e ."
# Lets do python tests later.
#script: py.test -vv -s --cov=$TRAVIS_BUILD_DIR/au/ --cov-report term-missing
script: make Makefile test
#after_success: codecov
#deploy:
# provider: pypi
# user: username
# password:
# secure: token
# on:
# tags: true
# branch: master
46 changes: 23 additions & 23 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,25 @@
# 2014-09-20 Dan Ellis dpwe@ee.columbia.edu

#AUDFPRINT=python audfprint.py --skip-existing --continue-on-error
AUDFPRINT=python audfprint.py --density 100 --skip-existing
AUDFPRINT=audfprint --density 100 --skip-existing

test: test_onecore test_onecore_precomp test_onecore_newmerge test_onecore_precomppk test_mucore test_mucore_precomp test_remove
rm -rf precompdir precompdir_mu
rm -f fpdbase*.pklz

test_onecore: fpdbase.pklz
${AUDFPRINT} match --dbase fpdbase.pklz query.mp3
${AUDFPRINT} match --dbase fpdbase.pklz tests/data/query.mp3

test_remove: fpdbase.pklz
${AUDFPRINT} remove --dbase fpdbase.pklz Nine_Lives/05-Full_Circle.mp3 Nine_Lives/01-Nine_Lives.mp3
${AUDFPRINT} remove --dbase fpdbase.pklz tests/data/Nine_Lives/05-Full_Circle.mp3 tests/data/Nine_Lives/01-Nine_Lives.mp3
${AUDFPRINT} list --dbase fpdbase.pklz
${AUDFPRINT} add --dbase fpdbase.pklz Nine_Lives/01-Nine_Lives.mp3 Nine_Lives/05-Full_Circle.mp3
${AUDFPRINT} add --dbase fpdbase.pklz tests/data/Nine_Lives/01-Nine_Lives.mp3 tests/data/Nine_Lives/05-Full_Circle.mp3
${AUDFPRINT} list --dbase fpdbase.pklz
${AUDFPRINT} match --dbase fpdbase.pklz query.mp3
${AUDFPRINT} match --dbase fpdbase.pklz tests/data/query.mp3

fpdbase.pklz: audfprint.py audfprint_analyze.py audfprint_match.py hash_table.py
${AUDFPRINT} new --dbase fpdbase.pklz Nine_Lives/0*.mp3
${AUDFPRINT} add --dbase fpdbase.pklz Nine_Lives/1*.mp3
fpdbase.pklz: audfprint audfprint/audfprint_analyze.py audfprint/audfprint_match.py audfprint/hash_table.py
${AUDFPRINT} new --dbase fpdbase.pklz tests/data/Nine_Lives/0*.mp3
${AUDFPRINT} add --dbase fpdbase.pklz tests/data/Nine_Lives/1*.mp3

test_onecore_precomp: precompdir
${AUDFPRINT} new --dbase fpdbase0.pklz precompdir/Nine_Lives/0*
Expand All @@ -42,11 +42,11 @@ test_onecore_newmerge: precompdir
${AUDFPRINT} newmerge --dbase fpdbase2.pklz fpdbase0.pklz fpdbase1.pklz
${AUDFPRINT} match --dbase fpdbase2.pklz precompdir/query.afpt

precompdir: audfprint.py audfprint_analyze.py audfprint_match.py hash_table.py
precompdir: audfprint/audfprint.cli.py audfprint/audfprint_analyze.py audfprint/audfprint_match.py audfprint/hash_table.py
rm -rf precompdir
mkdir precompdir
${AUDFPRINT} precompute --precompdir precompdir Nine_Lives/*.mp3
${AUDFPRINT} precompute --precompdir precompdir --shifts 4 query.mp3
${AUDFPRINT} precompute --precompdir precompdir tests/data/Nine_Lives/*.mp3
${AUDFPRINT} precompute --precompdir precompdir --shifts 4 tests/data/query.mp3

test_onecore_precomppk: precomppkdir
${AUDFPRINT} new --dbase fpdbase0.pklz precomppkdir/Nine_Lives/0*
Expand All @@ -55,31 +55,31 @@ test_onecore_precomppk: precomppkdir
${AUDFPRINT} match --dbase fpdbase1.pklz precomppkdir/query.afpk
rm -rf precomppkdir

precomppkdir: audfprint.py audfprint_analyze.py audfprint_match.py hash_table.py
precomppkdir: audfprint audfprint/audfprint_analyze.py audfprint/audfprint_match.py audfprint/hash_table.py
rm -rf precomppkdir
mkdir precomppkdir
${AUDFPRINT} precompute --precompute-peaks --precompdir precomppkdir Nine_Lives/*.mp3
${AUDFPRINT} precompute --precompute-peaks --precompdir precomppkdir --shifts 4 query.mp3
${AUDFPRINT} precompute --precompute-peaks --precompdir precomppkdir tests/data/Nine_Lives/*.mp3
${AUDFPRINT} precompute --precompute-peaks --precompdir precomppkdir --shifts 4 tests/data/query.mp3

test_mucore: fpdbase_mu.pklz
${AUDFPRINT} match --dbase fpdbase_mu.pklz --ncores 4 query.mp3
${AUDFPRINT} match --dbase fpdbase_mu.pklz --ncores 4 tests/data/query.mp3

fpdbase_mu.pklz: audfprint.py audfprint_analyze.py audfprint_match.py hash_table.py
${AUDFPRINT} new --dbase fpdbase_mu.pklz --ncores 4 Nine_Lives/0*.mp3
${AUDFPRINT} add --dbase fpdbase_mu.pklz --ncores 4 Nine_Lives/1*.mp3
fpdbase_mu.pklz: audfprint audfprint/audfprint_analyze.py audfprint/audfprint_match.py audfprint/hash_table.py
${AUDFPRINT} new --dbase fpdbase_mu.pklz --ncores 4 tests/data/Nine_Lives/0*.mp3
${AUDFPRINT} add --dbase fpdbase_mu.pklz --ncores 4 tests/data/Nine_Lives/1*.mp3

test_mucore_precomp: precompdir_mu
${AUDFPRINT} new --dbase fpdbase_mu0.pklz --ncores 4 precompdir_mu/Nine_Lives/0*
${AUDFPRINT} new --dbase fpdbase_mu.pklz --ncores 4 precompdir_mu/Nine_Lives/1*
${AUDFPRINT} merge --dbase fpdbase_mu.pklz fpdbase_mu0.pklz
${AUDFPRINT} match --dbase fpdbase_mu.pklz --ncores 4 precompdir_mu/query.afpt precompdir_mu/query.afpt precompdir_mu/query.afpt precompdir_mu/query.afpt precompdir_mu/query.afpt precompdir_mu/query.afpt precompdir_mu/query.afpt

precompdir_mu: audfprint.py audfprint_analyze.py audfprint_match.py hash_table.py
precompdir_mu: audfprint/cli.py audfprint/audfprint_analyze.py audfprint/audfprint_match.py audfprint/hash_table.py
rm -rf precompdir_mu
mkdir precompdir_mu
${AUDFPRINT} precompute --ncores 4 --precompdir precompdir_mu Nine_Lives/*.mp3
${AUDFPRINT} precompute --ncores 4 --precompdir precompdir_mu --shifts 4 query.mp3 query.mp3 query.mp3 query.mp3 query.mp3 query.mp3
${AUDFPRINT} precompute --ncores 4 --precompdir precompdir_mu tests/data/Nine_Lives/*.mp3
${AUDFPRINT} precompute --ncores 4 --precompdir precompdir_mu --shifts 4 tests/data/query.mp3 tests/data/query.mp3 tests/data/query.mp3 tests/data/query.mp3 tests/data/query.mp3 tests/data/query.mp3

test_hash_mask:
${AUDFPRINT} new --dbase fpdbase.pklz --hashbits 16 Nine_Lives/*.mp3
${AUDFPRINT} match --dbase fpdbase.pklz query.mp3
${AUDFPRINT} new --dbase fpdbase.pklz --hashbits 16 tests/data/Nine_Lives/*.mp3
${AUDFPRINT} match --dbase fpdbase.pklz tests/data/query.mp3
1 change: 0 additions & 1 deletion __init__.py

This file was deleted.

5 changes: 5 additions & 0 deletions audfprint/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# coding=utf-8
import logging

LOG = logging.getLogger(__name__)
LOG.addHandler(logging.NullHandler())
32 changes: 20 additions & 12 deletions audfprint_analyze.py → audfprint/audfprint_analyze.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,12 @@
import glob
import time

import audio_read
from . import LOG
from . import audio_read
# For utility, glob2hashtable
import hash_table
import stft
from . import hash_table

from . import stft

# ############### Globals ############### #
# Special extension indicating precomputed fingerprint
Expand Down Expand Up @@ -86,7 +88,7 @@ def landmarks2hashes(landmarks):
landmarks = np.array(landmarks)
# Deal with special case of empty landmarks.
if landmarks.shape[0] == 0:
return np.zeros((0, 2), dtype=np.int32)
return np.zeros((0, 2), dtype=np.int32)
hashes = np.zeros((landmarks.shape[0], 2), dtype=np.int32)
hashes[:, 0] = landmarks[:, 0]
hashes[:, 1] = (((landmarks[:, 1] & B1_MASK) << B1_SHIFT)
Expand Down Expand Up @@ -287,7 +289,8 @@ def find_peaks(self, d, sr):
else:
# The sgram is identically zero, i.e., the input signal was identically
# zero. Not good, but let's let it through for now.
print("find_peaks: Warning: input signal is identically zero.")
LOG.debug('find_peaks: Warning: input signal is identically zero.')
# print("find_peaks: Warning: input signal is identically zero.")
# High-pass filter onset emphasis
# [:-1,] discards top bin (nyquist) of sgram so bins fit in 8 bits
sgram = np.array([scipy.signal.lfilter([1, -1],
Expand Down Expand Up @@ -329,7 +332,7 @@ def peaks2landmarks(self, pklist):
for peak in peaks_at[col]:
pairsthispeak = 0
for col2 in range(col + self.mindt,
min(scols, col + self.targetdt)):
min(scols, col + self.targetdt)):
if pairsthispeak < self.maxpairsperpeak:
for peak2 in peaks_at[col2]:
if abs(peak2 - peak) < self.targetdf:
Expand Down Expand Up @@ -357,11 +360,13 @@ def wavfile2peaks(self, filename, shifts=None):
# [d, sr] = librosa.load(filename, sr=self.target_sr)
d, sr = audio_read.audio_read(filename, sr=self.target_sr, channels=1)
except Exception as e: # audioread.NoBackendError:
message = "wavfile2peaks: Error reading " + filename
message = "wavfile2peaks: Error reading %s" % filename
if self.fail_on_error:
print(e)
# print(e)
LOG.error('%s', message)
raise IOError(message)
print(message, "skipping")
LOG.debug('%s skipping', message)
# print(message, "skipping")
d = []
sr = self.target_sr
# Store duration in a global because it's hard to handle
Expand Down Expand Up @@ -569,13 +574,16 @@ def glob2hashtable(pattern, density=20.0):
totdur = 0.0
tothashes = 0
for ix, file_ in enumerate(filelist):
print(time.ctime(), "ingesting #", ix, ":", file_, "...")
LOG.debug('Ingesting #%s: %s ...', ix, file_)
# print(time.ctime(), "ingesting #", ix, ":", file_, "...")
dur, nhash = g2h_analyzer.ingest(ht, file_)
totdur += dur
tothashes += nhash
elapsedtime = time.clock() - initticks
print("Added", tothashes, "(", tothashes / totdur, "hashes/sec) at ",
elapsedtime / totdur, "x RT")
LOG.debug('Added %s %s hashes/sec at %s x RT',
tothashes, (tothashes / totdur), (elapsedtime / totdur))
# print("Added", tothashes, "(", tothashes / totdur, "hashes/sec) at ",
# elapsedtime / totdur, "x RT")
return ht


Expand Down
27 changes: 17 additions & 10 deletions audfprint_match.py → audfprint/audfprint_match.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@
except:
pass

import audfprint_analyze
import audio_read
import stft
from . import LOG

from . import audfprint_analyze
from . import audio_read
from . import stft


def process_info():
Expand All @@ -40,7 +42,8 @@ def process_info():

def log(message):
""" log info with stats """
print('%s physmem=%s utime=%s %s' % (time.ctime(), process_info()))
LOG.debug('physmem=%s utime=%s %s' % process_info(), message)
# print('%s physmem=%s utime=%s %s' % (time.ctime(), process_info()))


def encpowerof2(val):
Expand Down Expand Up @@ -368,16 +371,19 @@ def match_file(self, analyzer, ht, filename, number=None):
numberstring = "#%d" % number
else:
numberstring = ""
print(time.ctime(), "Analyzed", numberstring, filename, "of",
('%.3f' % durd), "s "
"to", len(q_hashes), "hashes")
LOG.debug('Analyzed %s %s of %.3f s to %s hashes',
numberstring, filename, durd, len(q_hashes))
# print(time.ctime(), "Analyzed", numberstring, filename, "of",
# ('%.3f' % durd), "s "
# "to", len(q_hashes), "hashes")
# Run query
rslts = self.match_hashes(ht, q_hashes)
# Post filtering
if self.sort_by_time:
rslts = rslts[(-rslts[:, 2]).argsort(), :]
return rslts[:self.max_returns, :], durd, len(q_hashes)

# WTF should we do about this.
def file_match_to_msgs(self, analyzer, ht, qry, number=None):
""" Perform a match on a single input file, return list
of message strings """
Expand Down Expand Up @@ -459,10 +465,11 @@ def illustrate_match(self, analyzer, ht, filename):
np.array([[x[1], x[2]] for x in mlms]).T,
'.-r')
# Add title
plt.title(filename + " : Matched as " + ht.names[results[0][0]]
+ (" with %d of %d hashes" % (len(matchhashes),
len(q_hashes))))
title = '%s :Matched as %s (with %d of %d hashes' % (
ht.names[results[0][0]], len(matchhashes), len(q_hashes))

# Display
plt.title(title)
plt.show()
# Return
return results
Expand Down
12 changes: 6 additions & 6 deletions audio_read.py → audfprint/audio_read.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,12 @@
HAVE_FFMPEG = True

def wavread(filename):
"""Read in audio data from a wav file. Return d, sr."""
# Read in wav file.
samplerate, wave_data = wav.read(filename)
# Normalize short ints to floats in range [-1..1).
data = np.asfarray(wave_data) / 32768.0
return data, samplerate
"""Read in audio data from a wav file. Return d, sr."""
# Read in wav file.
samplerate, wave_data = wav.read(filename)
# Normalize short ints to floats in range [-1..1).
data = np.asfarray(wave_data) / 32768.0
return data, samplerate


def audio_read(filename, sr=None, channels=None):
Expand Down
Loading