ref: ed596f7df20df54e45e0a0bd76da6d9cb98ad67f
parent: f9400d0a209858397aaf3f8dfc5d754e1a4ecf3f
parent: 4bc10e20d16aaaefc7d6b4942a666facddd8e090
author: Paul Brossier <piem@piem.org>
date: Tue Oct 30 09:22:44 EDT 2018
Merge branch 'master' into feature/docstrings
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -1,17 +1,19 @@
# configuration file for azure continuous integration
jobs:
+
- job: linux
pool:
vmImage: 'Ubuntu 16.04'
-
steps:
- script: |
make
displayName: 'make'
+ env:
+ CFLAGS: -Werror
+
- job: windows
pool:
vmIMage: 'VS2017-Win2016'
-
steps:
- script: |
make
@@ -23,7 +25,6 @@
- job: macos
pool:
vmIMage: macOS-10.13
-
steps:
- script: |
brew update
@@ -33,3 +34,5 @@
- script: |
make
displayName: 'make'
+ env:
+ CFLAGS: -Werror
--- a/doc/about.rst
+++ b/doc/about.rst
@@ -59,7 +59,7 @@
License
-------
-aubio is a `free <http://www.debian.org/intro/free>`_ and `open source
+aubio is a `free <https://www.debian.org/intro/free>`_ and `open source
<http://www.opensource.org/docs/definition.php>`_ software; **you** can
redistribute it and/or modify it under the terms of the `GNU
<https://www.gnu.org/>`_ `General Public License
--- a/doc/aubiomfcc.txt
+++ b/doc/aubiomfcc.txt
@@ -51,7 +51,7 @@
according to Malcolm Slaney's Auditory Toolbox, available at the following
url:
- http://cobweb.ecn.purdue.edu/~malcolm/interval/1998-010/ (see file mfcc.m)
+ https://engineering.purdue.edu/~malcolm/interval/1998-010/ (see file mfcc.m)
SEE ALSO
--- a/doc/aubionotes.txt
+++ b/doc/aubionotes.txt
@@ -6,7 +6,7 @@
aubionotes source
aubionotes [[-i] source]
[-r rate] [-B win] [-H hop]
- [-O method] [-t thres]
+ [-O method] [-t thres] [-d drop]
[-p method] [-u unit] [-l thres]
[-T time-format]
[-s sil]
@@ -67,6 +67,10 @@
-s, --silence sil Set the silence threshold, in dB, under which the pitch
will not be detected. A value of -20.0 would eliminate most onsets but the
loudest ones. A value of -90.0 would select all onsets. Defaults to -90.0.
+
+ -d, --release-drop Set the release drop threshold, in dB. If the level is
+ found to drop more than this amount since the last note has started, the
+ note will be turned-off. Defaults to 10.
-T, --timeformat format Set time format (samples, ms, seconds). Defaults to
seconds.
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -45,7 +45,7 @@
# General information about the project.
project = u'aubio'
-copyright = u'2016, Paul Brossier'
+copyright = u'2018, Paul Brossier'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
--- a/doc/python_module.rst
+++ b/doc/python_module.rst
@@ -79,4 +79,3 @@
.. _python demos folder: https://github.com/aubio/aubio/blob/master/python/demos
.. _demo_filter.py: https://github.com/aubio/aubio/blob/master/python/demos/demo_filter.py
.. _python tests: https://github.com/aubio/aubio/blob/master/python/tests
-
--- a/examples/aubionotes.c
+++ b/examples/aubionotes.c
@@ -21,6 +21,7 @@
#include "utils.h"
#define PROG_HAS_PITCH 1
#define PROG_HAS_ONSET 1
+#define PROG_HAS_NOTES 1
#define PROG_HAS_SILENCE 1
#define PROG_HAS_JACK 1
// TODO add PROG_HAS_OUTPUT
@@ -80,6 +81,12 @@
if (aubio_notes_set_silence (notes, silence_threshold) != 0) {
errmsg ("failed setting notes silence threshold to %.2f\n",
silence_threshold);
+ }
+ }
+ if (release_drop != 10.) {
+ if (aubio_notes_set_release_drop (notes, release_drop) != 0) {
+ errmsg ("failed setting notes release drop to %.2f\n",
+ release_drop);
}
}
--- a/examples/parse_args.h
+++ b/examples/parse_args.h
@@ -47,6 +47,7 @@
extern char_t * tempo_method;
// more general stuff
extern smpl_t silence_threshold;
+extern smpl_t release_drop;
extern uint_t mix_input;
// midi tap
extern smpl_t miditap_note;
@@ -107,6 +108,10 @@
" -s --silence select silence threshold\n"
" a value in dB, for instance -70, or -100; default=-90\n"
#endif /* PROG_HAS_SILENCE */
+#ifdef PROG_HAS_NOTES
+ " -d --release-drop select release drop threshold\n"
+ " a positive value in dB; default=10\n"
+#endif
" -T --time-format select time values output format\n"
" (samples, ms, seconds) default=seconds\n"
#ifdef PROG_HAS_OUTPUT
@@ -157,6 +162,9 @@
#ifdef PROG_HAS_SILENCE
"s:"
#endif /* PROG_HAS_SILENCE */
+#ifdef PROG_HAS_NOTES
+ "d:"
+#endif /* PROG_HAS_SILENCE */
#ifdef PROG_HAS_OUTPUT
"mf"
#endif /* PROG_HAS_OUTPUT */
@@ -192,6 +200,9 @@
#ifdef PROG_HAS_SILENCE
{"silence", 1, NULL, 's'},
#endif /* PROG_HAS_SILENCE */
+#ifdef PROG_HAS_NOTES
+ {"release-drop", 1, NULL, 'd'},
+#endif /* PROG_HAS_NOTES */
{"time-format", 1, NULL, 'T'},
#ifdef PROG_HAS_OUTPUT
{"mix-input", 0, NULL, 'm'},
@@ -273,6 +284,9 @@
break;
case 's': /* silence threshold */
silence_threshold = (smpl_t) atof (optarg);
+ break;
+ case 'd': /* release-drop threshold */
+ release_drop = (smpl_t) atof (optarg);
break;
case 'm': /* mix_input flag */
mix_input = 1;
--- a/examples/utils.c
+++ b/examples/utils.c
@@ -54,6 +54,7 @@
char_t * tempo_method = "default";
// more general stuff
smpl_t silence_threshold = -90.;
+smpl_t release_drop = 10.;
uint_t mix_input = 0;
uint_t force_overwrite = 0;
--- a/python/demos/demo_bpm_extract.py
+++ b/python/demos/demo_bpm_extract.py
@@ -22,7 +22,7 @@
elif params.mode in ['default']:
pass
else:
- print("unknown mode {:s}".format(params.mode))
+ raise ValueError("unknown mode {:s}".format(params.mode))
# manual settings
if 'samplerate' in params:
samplerate = params.samplerate
@@ -69,9 +69,9 @@
parser = argparse.ArgumentParser()
parser.add_argument('-m', '--mode',
help="mode [default|fast|super-fast]",
- dest="mode")
+ dest="mode", default='default')
parser.add_argument('sources',
- nargs='*',
+ nargs='+',
help="input_files")
args = parser.parse_args()
for f in args.sources:
--- a/python/ext/aubiomodule.c
+++ b/python/ext/aubiomodule.c
@@ -117,7 +117,9 @@
smpl_t input, samplerate, fftsize;
smpl_t output;
- if (!PyArg_ParseTuple (args, "|" AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR , &input, &samplerate, &fftsize)) {
+ if (!PyArg_ParseTuple (args,
+ "" AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR,
+ &input, &samplerate, &fftsize)) {
return NULL;
}
@@ -132,7 +134,9 @@
smpl_t input, samplerate, fftsize;
smpl_t output;
- if (!PyArg_ParseTuple (args, "|" AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR , &input, &samplerate, &fftsize)) {
+ if (!PyArg_ParseTuple (args,
+ "" AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR,
+ &input, &samplerate, &fftsize)) {
return NULL;
}
@@ -147,7 +151,9 @@
smpl_t input, samplerate, fftsize;
smpl_t output;
- if (!PyArg_ParseTuple (args, "|" AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR, &input, &samplerate, &fftsize)) {
+ if (!PyArg_ParseTuple (args,
+ "" AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR,
+ &input, &samplerate, &fftsize)) {
return NULL;
}
@@ -162,7 +168,9 @@
smpl_t input, samplerate, fftsize;
smpl_t output;
- if (!PyArg_ParseTuple (args, "|" AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR, &input, &samplerate, &fftsize)) {
+ if (!PyArg_ParseTuple (args,
+ "" AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR,
+ &input, &samplerate, &fftsize)) {
return NULL;
}
--- a/python/ext/py-filterbank.c
+++ b/python/ext/py-filterbank.c
@@ -94,7 +94,7 @@
if (self->vec.length != self->win_s / 2 + 1) {
PyErr_Format(PyExc_ValueError,
- "input cvec has length %d, but fft expects length %d",
+ "input cvec has length %d, but filterbank expects length %d",
self->vec.length, self->win_s / 2 + 1);
return NULL;
}
@@ -139,7 +139,7 @@
&(self->freqs), samplerate);
if (err > 0) {
PyErr_SetString (PyExc_ValueError,
- "error when setting filter to A-weighting");
+ "error when running set_triangle_bands");
return NULL;
}
Py_RETURN_NONE;
@@ -158,7 +158,7 @@
err = aubio_filterbank_set_mel_coeffs_slaney (self->o, samplerate);
if (err > 0) {
PyErr_SetString (PyExc_ValueError,
- "error when setting filter to A-weighting");
+ "error when running set_mel_coeffs_slaney");
return NULL;
}
Py_RETURN_NONE;
--- a/python/lib/aubio/cmd.py
+++ b/python/lib/aubio/cmd.py
@@ -101,6 +101,8 @@
help='estimate midi-like notes (monophonic)')
subparser.add_input()
subparser.add_buf_hop_size()
+ subparser.add_silence()
+ subparser.add_release_drop()
subparser.add_time_format()
subparser.add_verbose_help()
subparser.set_defaults(process=process_notes)
@@ -207,6 +209,12 @@
action="store", dest="silence", default=-70,
help="silence threshold")
+ def add_release_drop(self):
+ self.add_argument("-d", "--release-drop",
+ metavar = "<value>", type=float,
+ action="store", dest="release_drop", default=10,
+ help="release drop threshold")
+
def add_minioi(self, default="12ms"):
self.add_argument("-M", "--minioi",
metavar = "<value>", type=str,
@@ -382,6 +390,10 @@
def __init__(self, args):
self.parse_options(args, self.valid_opts)
self.notes = aubio.notes(**self.options)
+ if args.silence is not None:
+ self.notes.set_silence(args.silence)
+ if args.release_drop is not None:
+ self.notes.set_release_drop(args.release_drop)
super(process_notes, self).__init__(args)
def __call__(self, block):
return self.notes(block)
@@ -502,7 +514,24 @@
def main():
parser = aubio_parser()
- args = parser.parse_args()
+ if sys.version_info[0] != 3:
+ # on py2, create a dummy ArgumentParser to workaround the
+ # optional subcommand issue. See https://bugs.python.org/issue9253
+ # This ensures that:
+ # - version string is shown when only '-V' is passed
+ # - help is printed if '-V' is passed with any other argument
+ # - any other argument get forwarded to the real parser
+ parser_root = argparse.ArgumentParser(add_help=False)
+ parser_root.add_argument('-V', '--version', help="show version",
+ action="store_true", dest="show_version")
+ args, extras = parser_root.parse_known_args()
+ if args.show_version == False: # no -V, forward to parser
+ args = parser.parse_args(extras, namespace=args)
+ elif len(extras) != 0: # -V with other arguments, print help
+ parser.print_help()
+ sys.exit(1)
+ else: # in py3, we can simply use parser directly
+ args = parser.parse_args()
if 'show_version' in args and args.show_version:
sys.stdout.write('aubio version ' + aubio.version + '\n')
sys.exit(0)
--- a/python/lib/aubio/midiconv.py
+++ b/python/lib/aubio/midiconv.py
@@ -1,9 +1,11 @@
# -*- coding: utf-8 -*-
""" utilities to convert midi note number to and from note names """
-__all__ = ['note2midi', 'midi2note', 'freq2note']
+__all__ = ['note2midi', 'midi2note', 'freq2note', 'note2freq']
import sys
+from ._aubio import freqtomidi, miditofreq
+
py3 = sys.version_info[0] == 3
if py3:
str_instances = str
@@ -63,10 +65,11 @@
}
_valid_octaves = range(-1, 10)
if not isinstance(note, str_instances):
- raise TypeError("a string is required, got %s (%s)" % (note, str(type(note))))
+ msg = "a string is required, got {:s} ({:s})"
+ raise TypeError(msg.format(str(type(note)), repr(note)))
if len(note) not in range(2, 5):
- raise ValueError("string of 2 to 4 characters expected, got %d (%s)" \
- % (len(note), note))
+ msg = "string of 2 to 4 characters expected, got {:d} ({:s})"
+ raise ValueError(msg.format(len(note), note))
notename, modifier, octave = [None]*3
if len(note) == 4:
@@ -90,7 +93,8 @@
if octave not in _valid_octaves:
raise ValueError("%s is not a valid octave" % octave)
- midi = 12 + octave * 12 + _valid_notenames[notename] + _valid_modifiers[modifier]
+ midi = 12 + octave * 12 + _valid_notenames[notename] \
+ + _valid_modifiers[modifier]
if midi > 127:
raise ValueError("%s is outside of the range C-2 to G8" % note)
return midi
@@ -129,8 +133,10 @@
if not isinstance(midi, int_instances):
raise TypeError("an integer is required, got %s" % midi)
if midi not in range(0, 128):
- raise ValueError("an integer between 0 and 127 is excepted, got %d" % midi)
- _valid_notenames = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B']
+ msg = "an integer between 0 and 127 is excepted, got {:d}"
+ raise ValueError(msg.format(midi))
+ _valid_notenames = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#',
+ 'A', 'A#', 'B']
return _valid_notenames[midi % 12] + str(int(midi / 12) - 1)
def freq2note(freq):
@@ -153,5 +159,28 @@
>>> aubio.freq2note(220.1)
'A3'
"""
- from aubio import freqtomidi
- return midi2note(int(freqtomidi(freq)))
+ nearest_note = int(freqtomidi(freq) + .5)
+ return midi2note(nearest_note)
+
+def note2freq(note):
+ """Convert note name to corresponding frequency, in Hz.
+
+ Parameters
+ ----------
+ note : str
+ input note name
+
+ Returns
+ -------
+ freq : float [0, 23000[
+ frequency, in Hz
+
+ Example
+ -------
+ >>> aubio.note2freq('A4')
+ 440
+ >>> aubio.note2freq('A3')
+ 220.1
+ """
+ midi = note2midi(note)
+ return miditofreq(midi)
--- a/python/tests/test_aubio_cmd.py
+++ b/python/tests/test_aubio_cmd.py
@@ -19,13 +19,16 @@
class aubio_cmd_utils(TestCase):
def test_samples2seconds(self):
- self.assertEqual(aubio.cmd.samples2seconds(3200, 32000), "0.100000\t")
+ self.assertEqual(aubio.cmd.samples2seconds(3200, 32000),
+ "0.100000\t")
def test_samples2milliseconds(self):
- self.assertEqual(aubio.cmd.samples2milliseconds(3200, 32000), "100.000000\t")
+ self.assertEqual(aubio.cmd.samples2milliseconds(3200, 32000),
+ "100.000000\t")
def test_samples2samples(self):
- self.assertEqual(aubio.cmd.samples2samples(3200, 32000), "3200\t")
+ self.assertEqual(aubio.cmd.samples2samples(3200, 32000),
+ "3200\t")
if __name__ == '__main__':
main()
--- a/python/tests/test_note2midi.py
+++ b/python/tests/test_note2midi.py
@@ -3,7 +3,7 @@
from __future__ import unicode_literals
-from aubio import note2midi, freq2note
+from aubio import note2midi, freq2note, note2freq, float_type
from nose2.tools import params
import unittest
@@ -111,9 +111,26 @@
class freq2note_simple_test(unittest.TestCase):
- def test_freq2note(self):
+ def test_freq2note_above(self):
" make sure freq2note(441) == A4 "
self.assertEqual("A4", freq2note(441))
+
+ def test_freq2note_under(self):
+ " make sure freq2note(439) == A4 "
+ self.assertEqual("A4", freq2note(439))
+
+class note2freq_simple_test(unittest.TestCase):
+
+ def test_note2freq(self):
+ " make sure note2freq('A3') == 220"
+ self.assertEqual(220, note2freq("A3"))
+
+ def test_note2freq_under(self):
+ " make sure note2freq(A4) == 440"
+ if float_type == 'float32':
+ self.assertEqual(440, note2freq("A4"))
+ else:
+ self.assertLess(abs(note2freq("A4")-440), 1.e-12)
if __name__ == '__main__':
import nose2
--- a/python/tests/test_notes.py
+++ b/python/tests/test_notes.py
@@ -5,6 +5,7 @@
from aubio import notes
AUBIO_DEFAULT_NOTES_SILENCE = -70.
+AUBIO_DEFAULT_NOTES_RELEASE_DROP = 10.
AUBIO_DEFAULT_NOTES_MINIOI_MS = 30.
class aubio_notes_default(TestCase):
@@ -37,6 +38,19 @@
val = -50
self.o.set_silence(val)
assert_equal (self.o.get_silence(), val)
+
+ def test_get_release_drop(self):
+ assert_equal (self.o.get_release_drop(), AUBIO_DEFAULT_NOTES_RELEASE_DROP)
+
+ def test_set_release_drop(self):
+ val = 50
+ self.o.set_release_drop(val)
+ assert_equal (self.o.get_release_drop(), val)
+
+ def test_set_release_drop_wrong(self):
+ val = -10
+ with self.assertRaises(ValueError):
+ self.o.set_release_drop(val)
from .utils import list_all_sounds
list_of_sounds = list_all_sounds('sounds')
--- a/python/tests/test_slicing.py
+++ b/python/tests/test_slicing.py
@@ -34,13 +34,13 @@
def test_slice_start_every_blocksize(self):
hopsize = 200
- regions_start = [i*hopsize for i in range(1, n_slices)]
+ regions_start = [i*hopsize for i in range(0, n_slices)]
slice_source_at_stamps(self.source_file, regions_start, output_dir = self.output_dir,
hopsize = 200)
def test_slice_start_every_half_blocksize(self):
hopsize = 200
- regions_start = [i*hopsize//2 for i in range(1, n_slices)]
+ regions_start = [i*hopsize//2 for i in range(0, n_slices)]
slice_source_at_stamps(self.source_file, regions_start,
output_dir = self.output_dir, hopsize = 200)
--- a/src/io/source_avcodec.c
+++ b/src/io/source_avcodec.c
@@ -34,7 +34,7 @@
// determine whether we use libavformat from ffmpeg or from libav
#define FFMPEG_LIBAVFORMAT (LIBAVFORMAT_VERSION_MICRO > 99 )
-// max_analyze_duration2 was used from ffmpeg libavformat 55.43.100 through 57.2.100
+// max_analyze_duration2 was used from ffmpeg libavformat 55.43.100 -> 57.2.100
#define FFMPEG_LIBAVFORMAT_MAX_DUR2 FFMPEG_LIBAVFORMAT && ( \
(LIBAVFORMAT_VERSION_MAJOR == 55 && LIBAVFORMAT_VERSION_MINOR >= 43) \
|| (LIBAVFORMAT_VERSION_MAJOR == 56) \
@@ -92,9 +92,12 @@
uint_t multi;
};
-// hack to create or re-create the context the first time _do or _do_multi is called
-void aubio_source_avcodec_reset_resampler(aubio_source_avcodec_t * s, uint_t multi);
-void aubio_source_avcodec_readframe(aubio_source_avcodec_t *s, uint_t * read_samples);
+// create or re-create the context when _do or _do_multi is called
+void aubio_source_avcodec_reset_resampler(aubio_source_avcodec_t * s,
+ uint_t multi);
+// actually read a frame
+void aubio_source_avcodec_readframe(aubio_source_avcodec_t *s,
+ uint_t * read_samples);
uint_t aubio_source_avcodec_has_network_url(aubio_source_avcodec_t *s);
@@ -111,7 +114,8 @@
}
-aubio_source_avcodec_t * new_aubio_source_avcodec(const char_t * path, uint_t samplerate, uint_t hop_size) {
+aubio_source_avcodec_t * new_aubio_source_avcodec(const char_t * path,
+ uint_t samplerate, uint_t hop_size) {
aubio_source_avcodec_t * s = AUBIO_NEW(aubio_source_avcodec_t);
AVFormatContext *avFormatCtx = s->avFormatCtx;
AVCodecContext *avCodecCtx = s->avCodecCtx;
@@ -128,11 +132,13 @@
goto beach;
}
if ((sint_t)samplerate < 0) {
- AUBIO_ERR("source_avcodec: Can not open %s with samplerate %d\n", path, samplerate);
+ AUBIO_ERR("source_avcodec: Can not open %s with samplerate %d\n",
+ path, samplerate);
goto beach;
}
if ((sint_t)hop_size <= 0) {
- AUBIO_ERR("source_avcodec: Can not open %s with hop_size %d\n", path, hop_size);
+ AUBIO_ERR("source_avcodec: Can not open %s with hop_size %d\n",
+ path, hop_size);
goto beach;
}
@@ -172,8 +178,8 @@
if ( (err = avformat_find_stream_info(avFormatCtx, NULL)) < 0 ) {
char errorstr[256];
av_strerror (err, errorstr, sizeof(errorstr));
- AUBIO_ERR("source_avcodec: Could not find stream information " "for %s (%s)\n", s->path,
- errorstr);
+ AUBIO_ERR("source_avcodec: Could not find stream information "
+ "for %s (%s)\n", s->path, errorstr);
goto beach;
}
@@ -213,8 +219,9 @@
/* Allocate a codec context for the decoder */
avCodecCtx = avcodec_alloc_context3(codec);
if (!avCodecCtx) {
- AUBIO_ERR("source_avcodec: Failed to allocate the %s codec context for path %s\n",
- av_get_media_type_string(AVMEDIA_TYPE_AUDIO), s->path);
+ AUBIO_ERR("source_avcodec: Failed to allocate the %s codec context "
+ "for path %s\n", av_get_media_type_string(AVMEDIA_TYPE_AUDIO),
+ s->path);
goto beach;
}
#else
@@ -229,8 +236,9 @@
#if FF_API_LAVF_AVCTX
/* Copy codec parameters from input stream to output codec context */
if ((err = avcodec_parameters_to_context(avCodecCtx, codecpar)) < 0) {
- AUBIO_ERR("source_avcodec: Failed to copy %s codec parameters to decoder context for %s\n",
- av_get_media_type_string(AVMEDIA_TYPE_AUDIO), s->path);
+ AUBIO_ERR("source_avcodec: Failed to copy %s codec parameters to "
+ "decoder context for %s\n",
+ av_get_media_type_string(AVMEDIA_TYPE_AUDIO), s->path);
goto beach;
}
#endif
@@ -238,7 +246,8 @@
if ( ( err = avcodec_open2(avCodecCtx, codec, NULL) ) < 0) {
char errorstr[256];
av_strerror (err, errorstr, sizeof(errorstr));
- AUBIO_ERR("source_avcodec: Could not load codec for %s (%s)\n", s->path, errorstr);
+ AUBIO_ERR("source_avcodec: Could not load codec for %s (%s)\n", s->path,
+ errorstr);
goto beach;
}
@@ -265,7 +274,8 @@
}
/* allocate output for avr */
- s->output = (smpl_t *)av_malloc(AUBIO_AVCODEC_MAX_BUFFER_SIZE * sizeof(smpl_t));
+ s->output = (smpl_t *)av_malloc(AUBIO_AVCODEC_MAX_BUFFER_SIZE
+ * sizeof(smpl_t));
s->read_samples = 0;
s->read_index = 0;
@@ -293,7 +303,9 @@
return NULL;
}
-void aubio_source_avcodec_reset_resampler(aubio_source_avcodec_t * s, uint_t multi) {
+void aubio_source_avcodec_reset_resampler(aubio_source_avcodec_t * s,
+ uint_t multi)
+{
// create or reset resampler to/from mono/multi-channel
if ( (multi != s->multi) || (s->avr == NULL) ) {
int err;
@@ -308,15 +320,15 @@
SwrContext *oldavr = s->avr;
#endif /* HAVE_AVRESAMPLE || HAVE_SWRESAMPLE */
- av_opt_set_int(avr, "in_channel_layout", input_layout, 0);
- av_opt_set_int(avr, "out_channel_layout", output_layout, 0);
- av_opt_set_int(avr, "in_sample_rate", s->input_samplerate, 0);
- av_opt_set_int(avr, "out_sample_rate", s->samplerate, 0);
+ av_opt_set_int(avr, "in_channel_layout", input_layout, 0);
+ av_opt_set_int(avr, "out_channel_layout", output_layout, 0);
+ av_opt_set_int(avr, "in_sample_rate", s->input_samplerate, 0);
+ av_opt_set_int(avr, "out_sample_rate", s->samplerate, 0);
av_opt_set_int(avr, "in_sample_fmt", s->avCodecCtx->sample_fmt, 0);
#if HAVE_AUBIO_DOUBLE
- av_opt_set_int(avr, "out_sample_fmt", AV_SAMPLE_FMT_DBL, 0);
+ av_opt_set_int(avr, "out_sample_fmt", AV_SAMPLE_FMT_DBL, 0);
#else
- av_opt_set_int(avr, "out_sample_fmt", AV_SAMPLE_FMT_FLT, 0);
+ av_opt_set_int(avr, "out_sample_fmt", AV_SAMPLE_FMT_FLT, 0);
#endif
// TODO: use planar?
//av_opt_set_int(avr, "out_sample_fmt", AV_SAMPLE_FMT_FLTP, 0);
@@ -328,8 +340,8 @@
{
char errorstr[256];
av_strerror (err, errorstr, sizeof(errorstr));
- AUBIO_ERR("source_avcodec: Could not open resampling context for %s (%s)\n",
- s->path, errorstr);
+ AUBIO_ERR("source_avcodec: Could not open resampling context"
+ " for %s (%s)\n", s->path, errorstr);
return;
}
s->avr = avr;
@@ -346,7 +358,9 @@
}
}
-void aubio_source_avcodec_readframe(aubio_source_avcodec_t *s, uint_t * read_samples) {
+void aubio_source_avcodec_readframe(aubio_source_avcodec_t *s,
+ uint_t * read_samples)
+{
AVFormatContext *avFormatCtx = s->avFormatCtx;
AVCodecContext *avCodecCtx = s->avCodecCtx;
AVFrame *avFrame = s->avFrame;
@@ -387,7 +401,8 @@
if (err != 0) {
char errorstr[256];
av_strerror (err, errorstr, sizeof(errorstr));
- AUBIO_ERR("source_avcodec: could not read frame in %s (%s)\n", s->path, errorstr);
+ AUBIO_ERR("source_avcodec: could not read frame in %s (%s)\n",
+ s->path, errorstr);
s->eof = 1;
goto beach;
}
@@ -405,10 +420,12 @@
}
if (ret < 0) {
if (ret == AVERROR(EAGAIN)) {
- //AUBIO_WRN("source_avcodec: output is not available right now - user must try to send new input\n");
+ //AUBIO_WRN("source_avcodec: output is not available right now - "
+ // "user must try to send new input\n");
goto beach;
} else if (ret == AVERROR_EOF) {
- AUBIO_WRN("source_avcodec: the decoder has been fully flushed, and there will be no more output frames\n");
+ AUBIO_WRN("source_avcodec: the decoder has been fully flushed, "
+ "and there will be no more output frames\n");
} else {
AUBIO_ERR("source_avcodec: decoding errors on %s\n", s->path);
goto beach;
@@ -423,7 +440,8 @@
}
#endif
if (got_frame == 0) {
- AUBIO_WRN("source_avcodec: did not get a frame when reading %s\n", s->path);
+ AUBIO_WRN("source_avcodec: did not get a frame when reading %s\n",
+ s->path);
goto beach;
}
@@ -430,10 +448,12 @@
#if LIBAVUTIL_VERSION_MAJOR > 52
if (avFrame->channels != (sint_t)s->input_channels) {
AUBIO_WRN ("source_avcodec: trying to read from %d channel(s),"
- "but configured for %d; is '%s' corrupt?\n", avFrame->channels,
- s->input_channels, s->path);
+ "but configured for %d; is '%s' corrupt?\n",
+ avFrame->channels, s->input_channels, s->path);
goto beach;
}
+#else
+#warning "avutil < 53 is deprecated, crashes might occur on corrupt files"
#endif
#ifdef HAVE_AVRESAMPLE
@@ -454,7 +474,8 @@
(const uint8_t **)avFrame->data, in_samples);
#endif /* HAVE_AVRESAMPLE || HAVE_SWRESAMPLE */
if (out_samples <= 0) {
- AUBIO_WRN("source_avcodec: no sample found while converting frame (%s)\n", s->path);
+ AUBIO_WRN("source_avcodec: no sample found while converting frame (%s)\n",
+ s->path);
goto beach;
}
@@ -472,7 +493,8 @@
av_packet_unref(&avPacket);
}
-void aubio_source_avcodec_do(aubio_source_avcodec_t * s, fvec_t * read_data, uint_t * read){
+void aubio_source_avcodec_do(aubio_source_avcodec_t * s, fvec_t * read_data,
+ uint_t * read) {
uint_t i;
uint_t end = 0;
uint_t total_wrote = 0;
@@ -504,7 +526,8 @@
*read = total_wrote;
}
-void aubio_source_avcodec_do_multi(aubio_source_avcodec_t * s, fmat_t * read_data, uint_t * read){
+void aubio_source_avcodec_do_multi(aubio_source_avcodec_t * s,
+ fmat_t * read_data, uint_t * read) {
uint_t i,j;
uint_t end = 0;
uint_t total_wrote = 0;
@@ -550,7 +573,8 @@
}
uint_t aubio_source_avcodec_seek (aubio_source_avcodec_t * s, uint_t pos) {
- int64_t resampled_pos = (uint_t)ROUND(pos * (s->input_samplerate * 1. / s->samplerate));
+ int64_t resampled_pos =
+ (uint_t)ROUND(pos * (s->input_samplerate * 1. / s->samplerate));
int64_t min_ts = MAX(resampled_pos - 2000, 0);
int64_t max_ts = MIN(resampled_pos + 2000, INT64_MAX);
int seek_flags = AVSEEK_FLAG_FRAME | AVSEEK_FLAG_ANY;
@@ -558,7 +582,8 @@
if (s->avFormatCtx != NULL && s->avr != NULL) {
ret = AUBIO_OK;
} else {
- AUBIO_ERR("source_avcodec: failed seeking in %s (file not opened?)", s->path);
+ AUBIO_ERR("source_avcodec: failed seeking in %s (file not opened?)",
+ s->path);
return ret;
}
if ((sint_t)pos < 0) {
@@ -569,7 +594,8 @@
ret = avformat_seek_file(s->avFormatCtx, s->selected_stream,
min_ts, resampled_pos, max_ts, seek_flags);
if (ret < 0) {
- AUBIO_ERR("source_avcodec: failed seeking to %d in file %s", pos, s->path);
+ AUBIO_ERR("source_avcodec: failed seeking to %d in file %s",
+ pos, s->path);
}
// reset read status
s->eof = 0;
--- a/src/mathutils.c
+++ b/src/mathutils.c
@@ -522,7 +522,7 @@
if (freq < 2. || freq > 100000.) return 0.; // avoid nans and infs
/* log(freq/A-2)/log(2) */
midi = freq / 6.875;
- midi = LOG (midi) / 0.69314718055995;
+ midi = LOG (midi) / 0.6931471805599453;
midi *= 12;
midi -= 3;
return midi;
@@ -534,7 +534,7 @@
smpl_t freq;
if (midi > 140.) return 0.; // avoid infs
freq = (midi + 3.) / 12.;
- freq = EXP (freq * 0.69314718055995);
+ freq = EXP (freq * 0.6931471805599453);
freq *= 6.875;
return freq;
}
--- a/src/notes/notes.c
+++ b/src/notes/notes.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2014 Paul Brossier <piem@aubio.org>
+ Copyright (C) 2014-2018 Paul Brossier <piem@aubio.org>
This file is part of aubio.
@@ -25,6 +25,7 @@
#include "notes/notes.h"
#define AUBIO_DEFAULT_NOTES_SILENCE -70.
+#define AUBIO_DEFAULT_NOTES_RELEASE_DROP 10.
// increase to 10. for .1 cent precision
// or to 100. for .01 cent precision
#define AUBIO_DEFAULT_CENT_PRECISION 1.
@@ -56,6 +57,9 @@
smpl_t silence_threshold;
uint_t isready;
+
+ smpl_t last_onset_level;
+ smpl_t release_drop_level;
};
aubio_notes_t * new_aubio_notes (const char_t * method,
@@ -101,6 +105,9 @@
aubio_notes_set_silence(o, AUBIO_DEFAULT_NOTES_SILENCE);
aubio_notes_set_minioi_ms (o, AUBIO_DEFAULT_NOTES_MINIOI_MS);
+ o->last_onset_level = AUBIO_DEFAULT_NOTES_SILENCE;
+ o->release_drop_level = AUBIO_DEFAULT_NOTES_RELEASE_DROP;
+
return o;
fail:
@@ -140,6 +147,23 @@
return aubio_onset_get_minioi_ms(o->onset);
}
+uint_t aubio_notes_set_release_drop(aubio_notes_t *o, smpl_t release_drop_level)
+{
+ uint_t err = AUBIO_OK;
+ if (release_drop_level <= 0.) {
+ AUBIO_ERR("notes: release_drop should be >= 0, got %f\n", release_drop_level);
+ err = AUBIO_FAIL;
+ } else {
+ o->release_drop_level = release_drop_level;
+ }
+ return err;
+}
+
+smpl_t aubio_notes_get_release_drop(const aubio_notes_t *o)
+{
+ return o->release_drop_level;
+}
+
/** append new note candidate to the note_buffer and return filtered value. we
* need to copy the input array as fvec_median destroy its input data.*/
static void
@@ -184,6 +208,7 @@
//send_noteon(o->curnote,0);
//notes->data[0] = o->curnote;
//notes->data[1] = 0.;
+ //AUBIO_WRN("notes: sending note-off at onset, not enough level\n");
notes->data[2] = o->curnote;
} else {
if (o->median) {
@@ -191,6 +216,7 @@
} else {
/* kill old note */
//send_noteon(o->curnote,0, o->samplerate);
+ //AUBIO_WRN("notes: sending note-off at onset, new onset detected\n");
notes->data[2] = o->curnote;
/* get and send new one */
//send_noteon(new_pitch,127+(int)floor(curlevel), o->samplerate);
@@ -198,9 +224,22 @@
notes->data[1] = 127 + (int)floor(curlevel);
o->curnote = new_pitch;
}
+ o->last_onset_level = curlevel;
}
} else {
- if (o->median) {
+ if (curlevel < o->last_onset_level - o->release_drop_level)
+ {
+ // send note off
+ //AUBIO_WRN("notes: sending note-off, release detected\n");
+ notes->data[0] = 0;
+ notes->data[1] = 0;
+ notes->data[2] = o->curnote;
+ // reset last_onset_level to silence_threshold
+ o->last_onset_level = o->silence_threshold;
+ o->curnote = 0;
+ }
+ else if (o->median)
+ {
if (o->isready > 0)
o->isready++;
if (o->isready == o->median)
@@ -207,7 +246,11 @@
{
/* kill old note */
//send_noteon(curnote,0);
- notes->data[2] = o->curnote;
+ if (o->curnote != 0)
+ {
+ //AUBIO_WRN("notes: sending note-off, new note detected\n");
+ notes->data[2] = o->curnote;
+ }
o->newnote = aubio_notes_get_latest_note(o);
o->curnote = o->newnote;
/* get and send new one */
--- a/src/notes/notes.h
+++ b/src/notes/notes.h
@@ -106,6 +106,36 @@
*/
uint_t aubio_notes_set_minioi_ms (aubio_notes_t *o, smpl_t minioi_ms);
+/** get notes object release drop level, in dB
+
+ \param o notes detection object as returned by new_aubio_notes()
+
+ \return current release drop level, in dB
+
+ */
+smpl_t aubio_notes_get_release_drop (const aubio_notes_t *o);
+
+/** set note release drop level, in dB
+
+ This function sets the release_drop_level parameter, in dB. When a new note
+ is found, the current level in dB is measured. If the measured level drops
+ under that initial level - release_drop_level, then a note-off will be
+ emitted.
+
+ Defaults to `10`, in dB.
+
+ \note This parameter was added in version `0.4.8`. Results obtained with
+ earlier versions can be reproduced by setting this value to `100`, so that
+ note-off will not be played until the next note.
+
+ \param o notes detection object as returned by new_aubio_notes()
+ \param release_drop new release drop level, in dB
+
+ \return 0 on success, non-zero otherwise
+
+*/
+uint_t aubio_notes_set_release_drop (aubio_notes_t *o, smpl_t release_drop);
+
#ifdef __cplusplus
}
#endif
--- a/src/spectral/filterbank_mel.h
+++ b/src/spectral/filterbank_mel.h
@@ -58,8 +58,9 @@
\param samplerate audio sampling rate
The filter coefficients are built according to Malcolm Slaney's Auditory
- Toolbox, available at http://engineering.purdue.edu/~malcolm/interval/1998-010/
- (see file mfcc.m).
+ Toolbox, available online at the following address (see file mfcc.m):
+
+ https://engineering.purdue.edu/~malcolm/interval/1998-010/
*/
uint_t aubio_filterbank_set_mel_coeffs_slaney (aubio_filterbank_t * fb,
--- a/src/spectral/mfcc.h
+++ b/src/spectral/mfcc.h
@@ -26,9 +26,10 @@
This object computes MFCC coefficients on an input cvec_t.
The implementation follows the specifications established by Malcolm Slaney
- in its Auditory Toolbox, available online (see file mfcc.m).
+ in its Auditory Toolbox, available online at the following address (see
+ file mfcc.m):
- http://engineering.ecn.purdue.edu/~malcolm/interval/1998-010/
+ https://engineering.purdue.edu/~malcolm/interval/1998-010/
\example spectral/test-mfcc.c
--- a/src/spectral/phasevoc.c
+++ b/src/spectral/phasevoc.c
@@ -212,3 +212,13 @@
for (i = 0; i < pv->end; i++)
synthold[i] += synth[i + pv->hop_s] * pv->scale;
}
+
+uint_t aubio_pvoc_get_win(aubio_pvoc_t* pv)
+{
+ return pv->win_s;
+}
+
+uint_t aubio_pvoc_get_hop(aubio_pvoc_t* pv)
+{
+ return pv->hop_s;
+}
--- a/src/spectral/phasevoc.h
+++ b/src/spectral/phasevoc.h
@@ -88,6 +88,7 @@
*/
uint_t aubio_pvoc_get_win(aubio_pvoc_t* pv);
+
/** get hop size
\param pv phase vocoder to get the hop size from
--- a/src/synth/wavetable.c
+++ b/src/synth/wavetable.c
@@ -164,7 +164,7 @@
//aubio_wavetable_set_freq (s, 0.);
aubio_wavetable_set_amp (s, 0.);
//s->last_pos = 0;
- return aubio_wavetable_set_playing (s, 1);
+ return aubio_wavetable_set_playing (s, 0);
}
uint_t aubio_wavetable_set_freq ( aubio_wavetable_t * s, smpl_t freq )
--- a/src/synth/wavetable.h
+++ b/src/synth/wavetable.h
@@ -51,16 +51,6 @@
*/
aubio_wavetable_t * new_aubio_wavetable(uint_t samplerate, uint_t hop_size);
-/** load source in wavetable
-
- \param o wavetable, created by new_aubio_wavetable()
- \param uri the uri of the source to load
-
- \return 0 if successful, non-zero otherwise
-
-*/
-uint_t aubio_wavetable_load( aubio_wavetable_t * o, const char_t * uri );
-
/** process wavetable function
\param o wavetable, created by new_aubio_wavetable()