Skip to content

Commit

Permalink
refactor writing of tempo in MIREX format
Browse files Browse the repository at this point in the history
  • Loading branch information
Sebastian Böck committed Feb 13, 2018
1 parent c30defb commit 7d44527
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 14 deletions.
46 changes: 44 additions & 2 deletions bin/TempoDetector
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,56 @@ from __future__ import absolute_import, division, print_function

import argparse

import numpy as np

from madmom.audio import SignalProcessor
from madmom.features import (ActivationsProcessor, RNNBeatProcessor,
TempoEstimationProcessor)
from madmom.io import write_events, write_tempo
from madmom.processors import IOProcessor, io_arguments


def write_mirex(tempi, filename):
"""
Write the most dominant tempi and the relative strength to a file (in
MIREX format).
Parameters
----------
tempi : numpy array
Array with the detected tempi (first column) and their strengths
(second column).
filename : str or file handle
Output file.
"""
# make the given tempi a 2d array
tempi = np.array(tempi, ndmin=2)
# default values
t1 = t2 = strength = np.nan
# only one tempo was detected
if len(tempi) == 1:
t1 = tempi[0][0]
strength = 1.
# generate a fake second tempo (safer to output a real value than NaN)
# the boundary of 68 bpm is taken from Tzanetakis 2013 ICASSP paper
if t1 < 68:
t2 = t1 * 2.
else:
t2 = t1 / 2.
# consider only the two strongest tempi and strengths
elif len(tempi) > 1:
t1, t2 = tempi[:2, 0]
strength = tempi[0, 1] / sum(tempi[:2, 1])
# for MIREX, the lower tempo must be given first
if t1 > t2:
t1, t2, strength = t2, t1, 1. - strength
# format as a numpy array
out = np.array([t1, t2, strength], ndmin=2)
# write to output
np.savetxt(filename, out, fmt=['%.2f', '%.2f', '%.2f'], delimiter='\t')


def main():
"""TempoDetector"""

Expand Down Expand Up @@ -97,8 +140,7 @@ def main():
# output handler
if args.tempo_format == 'mirex':
# output in the MIREX format (i.e. slower tempo first)
from functools import partial
output = partial(write_tempo, mirex=True)
output = write_mirex
elif args.tempo_format in ('raw', 'all'):
# borrow the event writer for outputting multiple values
output = write_events
Expand Down
20 changes: 10 additions & 10 deletions madmom/io/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,7 @@ def load_tempo(filename, split_value=1., sort=None, norm_strengths=None,
return np.vstack((tempi[:max_len], strengths[:max_len])).T


def write_tempo(tempi, filename, delimiter='\t', mirex=False):
def write_tempo(tempi, filename, delimiter='\t', mirex=None):
"""
Write the most dominant tempi and the relative strength to a file.
Expand All @@ -426,23 +426,23 @@ def write_tempo(tempi, filename, delimiter='\t', mirex=False):
# make the given tempi a 2d array
tempi = np.array(tempi, ndmin=2)
# default values
t1, t2, strength = 0., 0., 1.
t1 = t2 = strength = np.nan
# only one tempo was detected
if len(tempi) == 1:
t1 = tempi[0][0]
# generate a fake second tempo
# the boundary of 68 bpm is taken from Tzanetakis 2013 ICASSP paper
if t1 < 68:
t2 = t1 * 2.
else:
t2 = t1 / 2.
strength = 1.
# consider only the two strongest tempi and strengths
elif len(tempi) > 1:
t1, t2 = tempi[:2, 0]
strength = tempi[0, 1] / sum(tempi[:2, 1])
# for MIREX, the lower tempo must be given first
if mirex and t1 > t2:
t1, t2, strength = t2, t1, 1. - strength
if mirex is not None:
import warnings
warnings.warn('`mirex` argument is deprecated as of version 0.16 '
'and will be removed in version 0.17. Please sort the '
'tempi manually')
if t1 > t2:
t1, t2, strength = t2, t1, 1. - strength
# format as a numpy array
out = np.array([t1, t2, strength], ndmin=2)
# write to output
Expand Down
12 changes: 12 additions & 0 deletions tests/test_bin.py
Original file line number Diff line number Diff line change
Expand Up @@ -1013,6 +1013,18 @@ def test_online(self):
result = np.loadtxt(tmp_result)
self.assertTrue(np.allclose(result, self.online_results))

def test_mirex(self):
run_single(self.bin, sample_file, tmp_result, args=['--mirex'])
result = np.loadtxt(tmp_result)
self.assertTrue(np.allclose(result, [117.65, 176.47, 0.27]))

def test_all_tempi(self):
run_single(self.bin, sample_file, tmp_result, args=['--all'])
result = np.loadtxt(tmp_result)
self.assertTrue(np.allclose(
result, [[176.471, 0.475], [117.647, 0.177], [240.000, 0.154],
[68.966, 0.099], [82.192, 0.096]]))


# clean up
def teardown():
Expand Down
6 changes: 4 additions & 2 deletions tests/test_features_tempo.py
Original file line number Diff line number Diff line change
Expand Up @@ -418,10 +418,12 @@ def test_types(self):
def test_values(self):
# only one tempo given (>68 bpm)
result = write_tempo(COMB_TEMPI[0], self.out_file)
self.assertTrue(np.allclose(result, [176.47, 88.235, 1], atol=0.001))
self.assertTrue(np.allclose(result, [176.47, np.nan, 1],
atol=1e-4, equal_nan=True))
# only one tempo given (<68 bpm)
result = write_tempo(COMB_TEMPI[3] / 2, self.out_file)
self.assertTrue(np.allclose(result, [34.483, 68.966, 1], atol=0.01))
self.assertTrue(np.allclose(result, [34.483, np.nan, 1],
atol=1e-4, equal_nan=True))
# multiple tempi given
result = write_tempo(COMB_TEMPI, self.out_file)
self.assertTrue(np.allclose(result, [176.47, 117.647, 0.728],
Expand Down

0 comments on commit 7d44527

Please sign in to comment.