Index: .circleci/config.yml
===================================================================
--- .circleci/config.yml	(revision 4bc10e20d16aaaefc7d6b4942a666facddd8e090)
+++ .circleci/config.yml	(revision 4bc10e20d16aaaefc7d6b4942a666facddd8e090)
@@ -0,0 +1,104 @@
+apt-run: &apt-install
+  name: Install apt packages
+  command: |
+    sudo apt-get update
+    sudo apt-get -y install make sox pkg-config libavcodec-dev libavformat-dev libavresample-dev libavutil-dev libsndfile1-dev libsamplerate-dev
+
+pip-install: &pip-install
+  name: Install pip dependencies
+  command: |
+    pip install --user -r requirements.txt
+
+build-wheel: &build-wheel
+  name: Build python wheel
+  command: |
+    pip wheel -v -v -v --wheel-dir=dist .
+
+install-wheel: &install-wheel
+  name: Install python wheel
+  command: |
+    pip install --user dist/aubio*.whl
+
+test-nose2: &test-nose2
+  name: Test python wheel
+  command: |
+    make create_test_sounds
+    PATH=/home/circleci/.local/bin:$PATH nose2 -v
+
+test-nose2-nosounds: &test-nose2-nosounds
+  name: Test python wheel
+  command: |
+    PATH=/home/circleci/.local/bin:$PATH nose2 -v
+
+uninstall-wheel: &uninstall-wheel
+  name: Uninstall python wheel
+  command: |
+    pip show -f aubio
+    pip uninstall --verbose --yes aubio
+
+version: 2
+jobs:
+  build-27:
+    docker:
+      - image: circleci/python:2.7
+    steps:
+      - checkout
+      - run: *apt-install
+      - run: *pip-install
+      - run: *build-wheel
+      - run: *install-wheel
+      - run: *test-nose2
+      - run: *uninstall-wheel
+      - store_artifacts:
+          path: dist/
+
+  build-36:
+    docker:
+      - image: circleci/python:3.6
+    steps:
+      - checkout
+      - run: *apt-install
+      - run: *pip-install
+      - run: *build-wheel
+      - run: *install-wheel
+      - run: *test-nose2
+      - run: *uninstall-wheel
+      - store_artifacts:
+          path: dist/
+
+  build-37:
+    docker:
+      - image: circleci/python:3.7
+    steps:
+      - checkout
+      - run: *apt-install
+      - run: *pip-install
+      - run: *build-wheel
+      - run: *install-wheel
+      - run: *test-nose2
+      - run: *uninstall-wheel
+      - store_artifacts:
+          path: dist/
+
+  build-37-nodeps:
+    docker:
+      - image: circleci/python:3.7
+    steps:
+      - checkout
+      - run: *pip-install
+      - run: *build-wheel
+      - run: *install-wheel
+      - run: *test-nose2-nosounds
+      - run: *uninstall-wheel
+      - store_artifacts:
+          path: dist/
+
+workflows:
+  version: 2
+
+  test-wheel:
+    jobs:
+      - build-27
+      - build-36
+      - build-37
+      - build-37-nodeps
Index: azure-pipelines.yml
===================================================================
--- azure-pipelines.yml	(revision 4bc10e20d16aaaefc7d6b4942a666facddd8e090)
+++ azure-pipelines.yml	(revision 4bc10e20d16aaaefc7d6b4942a666facddd8e090)
@@ -0,0 +1,38 @@
+#  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
+    displayName: 'make'
+    env:
+      # fail on error
+      CFLAGS: /WX
+
+- job: macos
+  pool:
+    vmIMage: macOS-10.13
+  steps:
+  - script: |
+      brew update
+      brew install pkg-config gnupg
+      brew install sox ffmpeg libsndfile lcov
+    displayName: 'brew install'
+  - script: |
+      make
+    displayName: 'make'
+    env:
+      CFLAGS: -Werror
Index: rcle.yml
===================================================================
--- circle.yml	(revision 357f81e2b95e86c7378fba81335b56a78ccee7b6)
+++ 	(revision )
@@ -1,9 +1,0 @@
-dependencies:
-  pre:
-    - sudo apt-get update; sudo apt-get install make sox pkg-config libavcodec-dev libavformat-dev libavresample-dev libavutil-dev libsndfile1-dev libsamplerate-dev
-
-test:
-  pre:
-    - make create_test_sounds
-  override:
-    - nose2 -v
Index: doc/about.rst
===================================================================
--- doc/about.rst	(revision 357f81e2b95e86c7378fba81335b56a78ccee7b6)
+++ doc/about.rst	(revision 4bc10e20d16aaaefc7d6b4942a666facddd8e090)
@@ -60,5 +60,5 @@
 -------
 
-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
Index: doc/aubiomfcc.txt
===================================================================
--- doc/aubiomfcc.txt	(revision 357f81e2b95e86c7378fba81335b56a78ccee7b6)
+++ doc/aubiomfcc.txt	(revision 4bc10e20d16aaaefc7d6b4942a666facddd8e090)
@@ -52,5 +52,5 @@
   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
Index: doc/conf.py
===================================================================
--- doc/conf.py	(revision 357f81e2b95e86c7378fba81335b56a78ccee7b6)
+++ doc/conf.py	(revision 4bc10e20d16aaaefc7d6b4942a666facddd8e090)
@@ -46,5 +46,5 @@
 # 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
Index: doc/python_module.rst
===================================================================
--- doc/python_module.rst	(revision 357f81e2b95e86c7378fba81335b56a78ccee7b6)
+++ doc/python_module.rst	(revision 4bc10e20d16aaaefc7d6b4942a666facddd8e090)
@@ -80,3 +80,2 @@
 .. _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
-
Index: examples/parse_args.h
===================================================================
--- examples/parse_args.h	(revision 357f81e2b95e86c7378fba81335b56a78ccee7b6)
+++ examples/parse_args.h	(revision 4bc10e20d16aaaefc7d6b4942a666facddd8e090)
@@ -66,6 +66,6 @@
 extern int blocks;
 
-extern fvec_t *ibuf;
-extern fvec_t *obuf;
+extern fvec_t *input_buffer;
+extern fvec_t *output_buffer;
 
 const char *prog_name;
@@ -212,9 +212,9 @@
   };
 #endif /* HAVE_GETOPT_H */
-  prog_name = argv[0];
+  // better safe than sorry
   if (argc < 1) {
     usage (stderr, 1);
-    return -1;
-  }
+  }
+  prog_name = argv[0];
 #ifdef HAVE_GETOPT_H
   do {
Index: examples/utils.c
===================================================================
--- examples/utils.c	(revision 357f81e2b95e86c7378fba81335b56a78ccee7b6)
+++ examples/utils.c	(revision 4bc10e20d16aaaefc7d6b4942a666facddd8e090)
@@ -64,6 +64,6 @@
 aubio_source_t *this_source = NULL;
 aubio_sink_t *this_sink = NULL;
-fvec_t *ibuf;
-fvec_t *obuf;
+fvec_t *input_buffer;
+fvec_t *output_buffer;
 
 smpl_t miditap_note = 69.;
@@ -127,6 +127,6 @@
 #endif /* HAVE_JACK */
   }
-  ibuf = new_fvec (hop_size);
-  obuf = new_fvec (hop_size);
+  input_buffer = new_fvec (hop_size);
+  output_buffer = new_fvec (hop_size);
 
 }
@@ -134,6 +134,6 @@
 void examples_common_del (void)
 {
-  del_fvec (ibuf);
-  del_fvec (obuf);
+  del_fvec (input_buffer);
+  del_fvec (output_buffer);
   aubio_cleanup ();
   fflush(stderr);
@@ -167,6 +167,6 @@
 
     do {
-      aubio_source_do (this_source, ibuf, &read);
-      process_func (ibuf, obuf);
+      aubio_source_do (this_source, input_buffer, &read);
+      process_func (input_buffer, output_buffer);
       // print to console if verbose or no output given
       if (verbose || sink_uri == NULL) {
@@ -174,5 +174,5 @@
       }
       if (this_sink) {
-        aubio_sink_do (this_sink, obuf, hop_size);
+        aubio_sink_do (this_sink, output_buffer, hop_size);
       }
       blocks++;
Index: python/demos/demo_bpm_extract.py
===================================================================
--- python/demos/demo_bpm_extract.py	(revision 357f81e2b95e86c7378fba81335b56a78ccee7b6)
+++ python/demos/demo_bpm_extract.py	(revision 4bc10e20d16aaaefc7d6b4942a666facddd8e090)
@@ -23,5 +23,5 @@
             pass
         else:
-            print("unknown mode {:s}".format(params.mode))
+            raise ValueError("unknown mode {:s}".format(params.mode))
     # manual settings
     if 'samplerate' in params:
@@ -70,7 +70,7 @@
     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()
Index: python/ext/aubiomodule.c
===================================================================
--- python/ext/aubiomodule.c	(revision 357f81e2b95e86c7378fba81335b56a78ccee7b6)
+++ python/ext/aubiomodule.c	(revision 4bc10e20d16aaaefc7d6b4942a666facddd8e090)
@@ -118,5 +118,7 @@
   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;
   }
@@ -133,5 +135,7 @@
   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;
   }
@@ -148,5 +152,7 @@
   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;
   }
@@ -163,5 +169,7 @@
   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;
   }
Index: python/ext/py-filterbank.c
===================================================================
--- python/ext/py-filterbank.c	(revision 357f81e2b95e86c7378fba81335b56a78ccee7b6)
+++ python/ext/py-filterbank.c	(revision 4bc10e20d16aaaefc7d6b4942a666facddd8e090)
@@ -95,5 +95,5 @@
   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;
@@ -140,5 +140,5 @@
   if (err > 0) {
     PyErr_SetString (PyExc_ValueError,
-        "error when setting filter to A-weighting");
+        "error when running set_triangle_bands");
     return NULL;
   }
@@ -159,5 +159,5 @@
   if (err > 0) {
     PyErr_SetString (PyExc_ValueError,
-        "error when setting filter to A-weighting");
+        "error when running set_mel_coeffs_slaney");
     return NULL;
   }
Index: python/lib/aubio/cmd.py
===================================================================
--- python/lib/aubio/cmd.py	(revision 357f81e2b95e86c7378fba81335b56a78ccee7b6)
+++ python/lib/aubio/cmd.py	(revision 4bc10e20d16aaaefc7d6b4942a666facddd8e090)
@@ -256,4 +256,7 @@
                 action = "store", dest = "cut_until_nslices", default = None,
                 help="how many extra slices should be added at the end of each slice")
+        self.add_argument("--create-first",
+                action = "store_true", dest = "create_first", default = False,
+                help="always include first slice")
 
 # some utilities
@@ -512,5 +515,22 @@
 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')
Index: python/lib/aubio/cut.py
===================================================================
--- python/lib/aubio/cut.py	(revision 357f81e2b95e86c7378fba81335b56a78ccee7b6)
+++ python/lib/aubio/cut.py	(revision 4bc10e20d16aaaefc7d6b4942a666facddd8e090)
@@ -102,5 +102,5 @@
     s = source(source_uri, samplerate, hopsize)
     if samplerate == 0:
-        samplerate = s.get_samplerate()
+        samplerate = s.samplerate
         options.samplerate = samplerate
 
@@ -151,5 +151,6 @@
                 timestamps, timestamps_end = timestamps_end,
                 output_dir = options.output_directory,
-                samplerate = options.samplerate)
+                samplerate = options.samplerate,
+                create_first = options.create_first)
 
 def main():
Index: python/lib/aubio/midiconv.py
===================================================================
--- python/lib/aubio/midiconv.py	(revision 357f81e2b95e86c7378fba81335b56a78ccee7b6)
+++ python/lib/aubio/midiconv.py	(revision 4bc10e20d16aaaefc7d6b4942a666facddd8e090)
@@ -2,7 +2,9 @@
 """ 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:
@@ -25,8 +27,9 @@
     _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
 
@@ -52,5 +55,6 @@
         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)
@@ -62,10 +66,35 @@
         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):
     " convert frequency in Hz to nearest note name, e.g. [0, 22050.] -> [C-1, G9] "
-    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)
Index: python/lib/aubio/slicing.py
===================================================================
--- python/lib/aubio/slicing.py	(revision 357f81e2b95e86c7378fba81335b56a78ccee7b6)
+++ python/lib/aubio/slicing.py	(revision 4bc10e20d16aaaefc7d6b4942a666facddd8e090)
@@ -7,5 +7,6 @@
 
 def slice_source_at_stamps(source_file, timestamps, timestamps_end=None,
-                           output_dir=None, samplerate=0, hopsize=256):
+                           output_dir=None, samplerate=0, hopsize=256,
+                           create_first=False):
     """ slice a sound file at given timestamps """
 
@@ -13,5 +14,5 @@
         raise ValueError("no timestamps given")
 
-    if timestamps[0] != 0:
+    if timestamps[0] != 0 and create_first:
         timestamps = [0] + timestamps
         if timestamps_end is not None:
@@ -19,5 +20,7 @@
 
     if timestamps_end is not None:
-        if len(timestamps_end) != len(timestamps):
+        if len(timestamps_end) == len(timestamps) - 1:
+            timestamps_end = timestamps_end + [_max_timestamp]
+        elif len(timestamps_end) != len(timestamps):
             raise ValueError("len(timestamps_end) != len(timestamps)")
     else:
@@ -49,5 +52,5 @@
         vec, read = _source.do_multi()
         # if the total number of frames read will exceed the next region start
-        if len(regions) and total_frames + read >= regions[0][0]:
+        while len(regions) and total_frames + read >= regions[0][0]:
             #print "getting", regions[0], "at", total_frames
             # get next region
@@ -76,5 +79,5 @@
                     # write remaining samples from current region
                     _sink.do_multi(vec[:, start:remaining], remaining - start)
-                    #print "closing region", "remaining", remaining
+                    #print("closing region", "remaining", remaining)
                     # close this file
                     _sink.close()
@@ -83,4 +86,7 @@
                 _sink.do_multi(vec[:, start:read], read - start)
         total_frames += read
+        # remove old slices
+        slices = list(filter(lambda s: s['end_stamp'] > total_frames,
+            slices))
         if read < hopsize:
             break
Index: python/tests/test_aubio_cmd.py
===================================================================
--- python/tests/test_aubio_cmd.py	(revision 357f81e2b95e86c7378fba81335b56a78ccee7b6)
+++ python/tests/test_aubio_cmd.py	(revision 4bc10e20d16aaaefc7d6b4942a666facddd8e090)
@@ -20,11 +20,14 @@
 
     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__':
Index: python/tests/test_note2midi.py
===================================================================
--- python/tests/test_note2midi.py	(revision 357f81e2b95e86c7378fba81335b56a78ccee7b6)
+++ python/tests/test_note2midi.py	(revision 4bc10e20d16aaaefc7d6b4942a666facddd8e090)
@@ -4,5 +4,5 @@
 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
@@ -112,7 +112,24 @@
 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__':
Index: python/tests/test_slicing.py
===================================================================
--- python/tests/test_slicing.py	(revision 357f81e2b95e86c7378fba81335b56a78ccee7b6)
+++ python/tests/test_slicing.py	(revision 4bc10e20d16aaaefc7d6b4942a666facddd8e090)
@@ -24,16 +24,24 @@
     def test_slice_start_only_no_zero(self):
         regions_start = [i*1000 for i in range(1, n_slices)]
-        slice_source_at_stamps(self.source_file, regions_start, output_dir = self.output_dir)
+        slice_source_at_stamps(self.source_file, regions_start,
+                output_dir = self.output_dir, create_first=True)
 
     def test_slice_start_beyond_end(self):
         regions_start = [i*1000 for i in range(1, n_slices)]
         regions_start += [count_samples_in_file(self.source_file) + 1000]
-        slice_source_at_stamps(self.source_file, regions_start, output_dir = self.output_dir)
+        slice_source_at_stamps(self.source_file, regions_start,
+                output_dir = self.output_dir, create_first=True)
 
     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(0, n_slices)]
+        slice_source_at_stamps(self.source_file, regions_start,
+                output_dir = self.output_dir, hopsize = 200)
 
     def tearDown(self):
@@ -92,4 +100,17 @@
             "number of samples written different from number of original samples")
 
+    def test_slice_start_and_ends_with_missing_end(self):
+        regions_start = [i*1000 for i in range(n_slices)]
+        regions_ends = [r-1 for r in regions_start[1:]]
+        slice_source_at_stamps(self.source_file, regions_start, regions_ends,
+                output_dir = self.output_dir)
+        written_samples = count_samples_in_directory(self.output_dir)
+        original_samples = count_samples_in_file(self.source_file)
+        total_files = count_files_in_directory(self.output_dir)
+        assert_equal(n_slices, total_files,
+            "number of slices created different from expected")
+        assert_equal(written_samples, original_samples,
+            "number of samples written different from number of original samples")
+
     def tearDown(self):
         shutil.rmtree(self.output_dir)
@@ -134,5 +155,5 @@
         regions_end = None
         slice_source_at_stamps (self.source_file, regions_start, regions_end,
-                output_dir = self.output_dir)
+                output_dir = self.output_dir, create_first=True)
         total_files = count_files_in_directory(self.output_dir)
         assert_equal(n_slices, total_files,
Index: src/io/source_avcodec.c
===================================================================
--- src/io/source_avcodec.c	(revision 357f81e2b95e86c7378fba81335b56a78ccee7b6)
+++ src/io/source_avcodec.c	(revision 4bc10e20d16aaaefc7d6b4942a666facddd8e090)
@@ -35,5 +35,5 @@
 // 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) \
@@ -93,7 +93,10 @@
 };
 
-// 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);
@@ -112,5 +115,6 @@
 
 
-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;
@@ -129,9 +133,11 @@
   }
   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;
   }
@@ -173,6 +179,6 @@
     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;
   }
@@ -214,6 +220,7 @@
   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;
   }
@@ -230,6 +237,7 @@
   /* 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;
   }
@@ -239,5 +247,6 @@
     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;
   }
@@ -266,5 +275,6 @@
 
   /* 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;
@@ -294,5 +304,7 @@
 }
 
-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) ) {
@@ -309,13 +321,13 @@
 #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);
-#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_DBL,         0);
+#else
+    av_opt_set_int(avr, "out_sample_fmt",     AV_SAMPLE_FMT_FLT,         0);
 #endif
     // TODO: use planar?
@@ -329,6 +341,6 @@
       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;
     }
@@ -347,5 +359,7 @@
 }
 
-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;
@@ -388,5 +402,6 @@
       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;
@@ -406,8 +421,10 @@
   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);
@@ -424,5 +441,6 @@
 #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;
   }
@@ -431,8 +449,10 @@
   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);
-    goto beach;
-  }
+        "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
 
@@ -455,5 +475,6 @@
 #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;
   }
@@ -473,5 +494,6 @@
 }
 
-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;
@@ -505,5 +527,6 @@
 }
 
-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;
@@ -551,5 +574,6 @@
 
 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);
@@ -559,5 +583,6 @@
     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;
   }
@@ -570,5 +595,6 @@
       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
Index: src/mathutils.c
===================================================================
--- src/mathutils.c	(revision 357f81e2b95e86c7378fba81335b56a78ccee7b6)
+++ src/mathutils.c	(revision 4bc10e20d16aaaefc7d6b4942a666facddd8e090)
@@ -523,5 +523,5 @@
   /* log(freq/A-2)/log(2) */
   midi = freq / 6.875;
-  midi = LOG (midi) / 0.69314718055995;
+  midi = LOG (midi) / 0.6931471805599453;
   midi *= 12;
   midi -= 3;
@@ -535,5 +535,5 @@
   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;
Index: src/spectral/filterbank_mel.h
===================================================================
--- src/spectral/filterbank_mel.h	(revision 357f81e2b95e86c7378fba81335b56a78ccee7b6)
+++ src/spectral/filterbank_mel.h	(revision 4bc10e20d16aaaefc7d6b4942a666facddd8e090)
@@ -59,6 +59,7 @@
 
   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/
 
 */
Index: src/spectral/mfcc.h
===================================================================
--- src/spectral/mfcc.h	(revision 357f81e2b95e86c7378fba81335b56a78ccee7b6)
+++ src/spectral/mfcc.h	(revision 4bc10e20d16aaaefc7d6b4942a666facddd8e090)
@@ -27,7 +27,8 @@
 
   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
Index: src/spectral/phasevoc.c
===================================================================
--- src/spectral/phasevoc.c	(revision 357f81e2b95e86c7378fba81335b56a78ccee7b6)
+++ src/spectral/phasevoc.c	(revision 4bc10e20d16aaaefc7d6b4942a666facddd8e090)
@@ -213,2 +213,12 @@
     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;
+}
Index: src/spectral/phasevoc.h
===================================================================
--- src/spectral/phasevoc.h	(revision 357f81e2b95e86c7378fba81335b56a78ccee7b6)
+++ src/spectral/phasevoc.h	(revision 4bc10e20d16aaaefc7d6b4942a666facddd8e090)
@@ -89,4 +89,5 @@
 */
 uint_t aubio_pvoc_get_win(aubio_pvoc_t* pv);
+
 /** get hop size
 
Index: src/synth/wavetable.c
===================================================================
--- src/synth/wavetable.c	(revision 357f81e2b95e86c7378fba81335b56a78ccee7b6)
+++ src/synth/wavetable.c	(revision 4bc10e20d16aaaefc7d6b4942a666facddd8e090)
@@ -165,5 +165,5 @@
   aubio_wavetable_set_amp (s, 0.);
   //s->last_pos = 0;
-  return aubio_wavetable_set_playing (s, 1);
+  return aubio_wavetable_set_playing (s, 0);
 }
 
Index: src/synth/wavetable.h
===================================================================
--- src/synth/wavetable.h	(revision 357f81e2b95e86c7378fba81335b56a78ccee7b6)
+++ src/synth/wavetable.h	(revision 4bc10e20d16aaaefc7d6b4942a666facddd8e090)
@@ -51,14 +51,4 @@
 */
 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
Index: wscript
===================================================================
--- wscript	(revision 357f81e2b95e86c7378fba81335b56a78ccee7b6)
+++ wscript	(revision 4bc10e20d16aaaefc7d6b4942a666facddd8e090)
@@ -606,4 +606,5 @@
     ctx.excl += ' **/.landscape.yml'
     ctx.excl += ' **/.appveyor.yml'
-    ctx.excl += ' **/circle.yml'
+    ctx.excl += ' **/.circleci/*'
+    ctx.excl += ' **/azure-pipelines.yml'
     ctx.excl += ' **/.coveragerc'
