PYTHON_VERSION: 2.7.x
PYTHON_ARCH: 64
- - PYTHONDIR: C:\Python35
- PYTHON_VERSION: 3.5.x
- PYTHON_ARCH: 32
-
- - PYTHONDIR: C:\Python35-x64
- PYTHON_VERSION: 3.5.x
- PYTHON_ARCH: 64
-
- PYTHONDIR: C:\Python36
PYTHON_VERSION: 3.6.x
PYTHON_ARCH: 32
PYTHON_VERSION: 3.7.x
PYTHON_ARCH: 64
+ - PYTHONDIR: C:\Python38
+ PYTHON_VERSION: 3.8.x
+ PYTHON_ARCH: 32
+
+ - PYTHONDIR: C:\Python38-x64
+ PYTHON_VERSION: 3.8.x
+ PYTHON_ARCH: 64
+
install:
- ECHO "Installed SDKs:"
- ps: "ls \"C:/Program Files/Microsoft SDKs/Windows\""
+# python circleci 2.1 configuration
+# see https://circleci.com/docs/2.1/language-python/
+version: 2.1
+
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
+ sudo apt-get -y install make sox pkg-config libavcodec-dev libavformat-dev libswresample-dev libavutil-dev libsndfile1-dev libsamplerate-dev librubberband-dev libvorbis-dev libflac-dev
pip-install: &pip-install
name: Install pip dependencies
pip show -f aubio
pip uninstall --verbose --yes aubio
-version: 2
jobs:
- build-27:
+ build-36:
docker:
- - image: circleci/python:2.7
+ - image: cimg/python:3.6
steps:
- checkout
- run: *apt-install
- store_artifacts:
path: dist/
- build-36:
+ build-310:
docker:
- - image: circleci/python:3.6
+ - image: cimg/python:3.10
steps:
- checkout
- run: *apt-install
- store_artifacts:
path: dist/
- build-37:
+ build-310-nodeps:
+ docker:
+ - image: cimg/python:3.10
+ steps:
+ - checkout
+ - run: *pip-install
+ - run: *build-wheel
+ - run: *install-wheel
+ - run: *test-pytest-nosounds
+ - run: *uninstall-wheel
+ - store_artifacts:
+ path: dist/
+
+ build-312:
docker:
- - image: circleci/python:3.7
+ - image: cimg/python:3.12
steps:
- checkout
- run: *apt-install
- store_artifacts:
path: dist/
- build-37-nodeps:
+ build-312-nodeps:
docker:
- - image: circleci/python:3.7
+ - image: cimg/python:3.12
steps:
- checkout
- run: *pip-install
test-wheel:
jobs:
- - build-27
- build-36
- - build-37
- - build-37-nodeps
+ - build-310
+ - build-310-nodeps
+ - build-312
+ - build-312-nodeps
RE:examples/[a-z]*
# ignore compiled test programs
-RE:tests/src/test-[a-z-_]*$
-RE:tests/cpp/test-[a-z-_]*$
+RE:tests/src/test-[a-z_-]*$
+RE:tests/cpp/test-[a-z_-]*$
# only sgml manpages count
doc/*.1
--- /dev/null
+# see https://docs.readthedocs.io/en/stable/config-file/
+version: 2
+
+build:
+ os: ubuntu-22.04
+ tools:
+ python: "3.12"
+
+python:
+ install:
+ - requirements: requirements.txt
+ - method: pip
+ path: .
+
+sphinx:
+ configuration: doc/conf.py
matrix:
include:
- - python: 3.6
+ - name: "Linux (Python 3.8)"
+ python: 3.8
os: linux
- compiler: gcc
- - python: 3.5
+ distro: bionic
+ - name: "Linux (Python 3.6)"
+ python: 3.6
os: linux
- compiler: gcc
env: WAFOPTS="--build-type=debug"
- - python: 2.7
+ - name: "Linux (Python 2.7, nodeps)"
+ python: 2.7
os: linux
- compiler: gcc
- - python: "pypy3.5"
+ distro: trusty
+ env: WAFOPTS="--nodeps"
+ - name: "Linux (Python pypy3.5)"
+ language: python
+ python: "pypy3.5"
os: linux
- compiler: gcc
- env: CFLAGS="-Os" WAFOPTS="--disable-avcodec"
- - python: 3.6
+ - name: "Linux (double, fftw3)"
+ python: 3.8
os: linux
- compiler: gcc
- env: CFLAGS="-Os" WAFOPTS="--disable-samplerate"
- - python: 3.5
- os: linux
- compiler: gcc
env: HAVE_AUBIO_DOUBLE=1 CFLAGS="-O3" WAFOPTS="--enable-fftw3"
- - python: 2.7
+ - name: "Linux (default, dpkg-buildflags)"
os: linux
- compiler: gcc
env: CFLAGS="`dpkg-buildflags --get CFLAGS`" LDFLAGS="`dpkg-buildflags --get LDFLAGS`"
- - language: C
+
+ - name: "macOS (xcode11)"
+ language: shell
os: osx
- compiler: clang
- - language: C
+ osx_image: xcode11
+ - name: "macOS (xcode12, lib only)"
+ language: shell
os: osx
- compiler: clang
- env: CFLAGS="-Os" HAVE_AUBIO_DOUBLE=1 WAFOPTS="--disable-accelerate"
- - language: C
+ osx_image: xcode12
+ script:
+ - make test_lib_only_clean
+ - name: "macOS (xcode10, noopt, nodeps)"
+ language: shell
os: osx
- compiler: clang
- env: WAFOPTS="--enable-fat --disable-avcodec --disable-sndfile --disable-samplerate"
- - language: C
+ osx_image: xcode10
+ env: CFLAGS="-Os" HAVE_AUBIO_DOUBLE=1 WAFOPTS="--disable-accelerate --nodeps"
+ - name: "iOS"
+ language: shell
os: osx
- compiler: clang
- env: WAFOPTS="--with-target-platform=ios --disable-avcodec --disable-sndfile --disable-samplerate" AUBIO_NOTESTS=1
- - language: C
+ env: WAFOPTS="--with-target-platform=ios --nodeps" AUBIO_NOTESTS=1
+ - name: "iOSSimulator"
+ language: shell
os: osx
- compiler: clang
- env: WAFOPTS="--with-target-platform=iosimulator --disable-avcodec --disable-sndfile --disable-samplerate" AUBIO_NOTESTS=1
+ env: WAFOPTS="--with-target-platform=iosimulator --nodeps" AUBIO_NOTESTS=1
-# use trusty
-dist: trusty
-sudo: required
+# - name: "Windows (Python 3.8.0, lib only)"
+# language: shell
+# os: windows
+# before_install:
+# - choco install python --version 3.8.0
+# - choco install make
+# - python -m pip install --upgrade pip
+# env: PATH=/c/Python38:/c/Python38/Scripts:$PATH AUBIO_NOTESTS=1
addons:
apt:
- bzip2
- libavcodec-dev
- libavformat-dev
- - libavresample-dev
+ - libswresample-dev
- libavutil-dev
- libsndfile1-dev
- libsamplerate-dev
+ - libvorbis-dev
+ - libflac-dev
- libjack-dev
- libasound2-dev
- libfftw3-dev
+ - librubberband-dev
- sox
- lcov
homebrew:
- sox
- ffmpeg
- libsndfile
+ - libvorbis
+ - flac
+ - libsamplerate
+ - rubberband
- lcov
update: true
-before_install:
- - |
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
- export PATH="$HOME/Library/Python/2.7/bin/:$PATH"
- fi;
-
install:
- - |
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
- alias pip=pip2
- fi;
- - travis_retry pip install --upgrade pip
- - travis_retry make getwaf expandwaf deps_python
+ - make getwaf deps_python
- which pip
- pip --version
- pip install coverage
-$(SOX) -r 22050 -b 16 -n "$(TESTSOUNDS)/22050Hz_5s_brownnoise.wav" synth 5 brownnoise vol 0.9
-$(SOX) -r 32000 -b 16 -n "$(TESTSOUNDS)/32000Hz_127f_sine440.wav" synth 127s sine 440 vol 0.9
-$(SOX) -r 8000 -b 16 -n "$(TESTSOUNDS)/8000Hz_30s_silence.wav" trim 0 30
- -$(SOX) -r 48000 -b 32 -n "$(TESTSOUNDS)/48000Hz_60s_sweep.wav" synth 60 sine 100-20000 vol 0.9
+ -$(SOX) -r 48000 -b 16 -n "$(TESTSOUNDS)/48000Hz_60s_sweep.wav" synth 60 sine 100-20000 vol 0.9
-$(SOX) -r 44100 -b 16 -n "$(TESTSOUNDS)/44100Hz_44100f_sine441.wav" synth 44100s sine 441 vol 0.9
-$(SOX) -r 44100 -b 16 -n "$(TESTSOUNDS)/44100Hz_100f_sine441.wav" synth 100s sine 441 vol 0.9
aubio
=====
-[![Travis build status](https://travis-ci.org/aubio/aubio.svg?branch=master)](https://travis-ci.org/aubio/aubio "Travis build status")
+[![CircleCI build status](https://circleci.com/gh/aubio/aubio.svg?style=shield)](https://circleci.com/gh/aubio/aubio "CircleCI build status")
+[![Azure Pipelines](https://dev.azure.com/aubio/aubio/_apis/build/status/aubio.aubio)](https://dev.azure.com/aubio/aubio "Azure build status")
[![Appveyor build status](https://img.shields.io/appveyor/ci/piem/aubio/master.svg)](https://ci.appveyor.com/project/piem/aubio "Appveyor build status")
-[![Commits since last release](https://img.shields.io/github/commits-since/aubio/aubio/latest.svg)](https://github.com/aubio/aubio "Commits since last release")
+[![Pypi Downloads](https://img.shields.io/pypi/dm/aubio.svg?label=Pypi%20downloads)](https://pypi.org/project/aubio/)
+[![Conda Downloads](https://img.shields.io/conda/dn/conda-forge/aubio.svg?label=Conda%20downloads)](https://anaconda.org/conda-forge/aubio)
[![Documentation](https://readthedocs.org/projects/aubio/badge/?version=latest)](http://aubio.readthedocs.io/en/latest/?badge=latest "Latest documentation")
[![DOI](https://zenodo.org/badge/396389.svg)](https://zenodo.org/badge/latestdoi/396389)
+[![Commits since last release](https://img.shields.io/github/commits-since/aubio/aubio/latest.svg)](https://github.com/aubio/aubio "Commits since last release")
aubio is a library to label music and sounds. It listens to audio signals and
attempts to detect events. For instance, when a drum is hit, at which frequency
AUBIO_MAJOR_VERSION=0
AUBIO_MINOR_VERSION=5
AUBIO_PATCH_VERSION=0
-AUBIO_VERSION_STATUS='~alpha'
+AUBIO_VERSION_STATUS='-alpha'
LIBAUBIO_LT_CUR=5
LIBAUBIO_LT_REV=4
LIBAUBIO_LT_AGE=8
- job: linux
pool:
- vmImage: 'ubuntu-16.04'
+ vmImage: 'ubuntu-latest'
+ steps:
+ - script: |
+ sudo apt update
+ sudo apt install libsndfile-dev libavformat-dev librubberband-dev libvorbis-dev libflac-dev
+ displayName: 'deps'
+ - script: |
+ make
+ displayName: 'make'
+ env:
+ CFLAGS: -Werror
+
+- job: linux_double
+ pool:
+ vmImage: 'ubuntu-latest'
+ steps:
+ - script: |
+ sudo apt update
+ sudo apt install libfftw3-dev libsndfile-dev libavformat-dev librubberband-dev libvorbis-dev libflac-dev
+ displayName: 'deps'
+ - script: |
+ HAVE_AUBIO_DOUBLE=1 WAFOPTS="--enable-fftw3" make
+ displayName: 'make'
+ env:
+ CFLAGS: -Werror
+
+- job: linux_nodeps
+ pool:
+ vmImage: 'ubuntu-latest'
steps:
- script: |
make
- job: windows
pool:
- vmImage: 'vs2017-win2016'
+ vmImage: 'windows-latest'
steps:
- script: |
make
- job: macos
pool:
- vmImage: 'macos-10.13'
+ vmImage: 'macos-latest'
steps:
- script: |
brew update
brew install pkg-config gnupg
- brew install sox ffmpeg libsndfile lcov
+ brew install sox ffmpeg libsndfile libvorbis flac lcov
displayName: 'brew install'
- script: |
make
.. literalinclude:: ../tests/src/io/test-source.c
:language: C
- :lines: 22-24, 30-32, 34
+ :lines: 24-26, 30, 32-34
.. note::
With ``samplerate = 0``, ``aubio_source`` will be created with the file's
.. literalinclude:: ../tests/src/io/test-source.c
:language: C
- :lines: 40-44
+ :lines: 41-45
At the end of the processing loop, memory is deallocated:
.. literalinclude:: ../tests/src/io/test-source.c
:language: C
- :lines: 55-56
+ :lines: 55-58
See the complete example: :download:`test-source.c
<../tests/src/io/test-source.c>`.
.. literalinclude:: ../tests/src/spectral/test-phasevoc.c
:language: C
- :lines: 20-37
+ :lines: 27-44
Time to clean up the previously allocated memory:
.. literalinclude:: ../tests/src/spectral/test-phasevoc.c
:language: C
- :lines: 39-44
+ :lines: 47-50
See the complete example: :download:`test-phasevoc.c
<../tests/src/spectral/test-phasevoc.c>`.
- :ref:`check the list of optional dependencies <requirements>`::
# debian / ubuntu
- dpkg -l libavcodec-dev libavutil-dev libavformat-dev \
- libswresample-dev libavresample-dev \
+ dpkg -l libavcodec-dev libavutil-dev libavformat-dev libswresample-dev \
libsamplerate-dev libsndfile-dev \
txt2man doxygen
If ``pkg-config`` is not found in ``PATH``, the configure step will
succeed, but none of the external libraries will be used.
+To build aubio with no external libraries, use the ``--nodeps`` build option.
+
Media libraries
---------------
* libavcodec
* libavformat
* libavutil
-* libavresample
+* libswresample
To enable this option, configure with ``--enable-avcodec``. The build will then
failed if the required libraries are not found. To disable this option,
for (i = 0; i < ochan + omidichan; i++) {
if (i < ochan) {
jack_port_type = JACK_DEFAULT_AUDIO_TYPE;
- AUBIO_SPRINTF (name, "out_%d", i + 1);
+ AUBIO_SNPRINTF (name, sizeof (name), "out_%d", i + 1);
} else {
jack_port_type = JACK_DEFAULT_MIDI_TYPE;
- AUBIO_SPRINTF (name, "midi_out_%d", i - ochan + 1);
+ AUBIO_SNPRINTF (name, sizeof (name), "midi_out_%d", i - ochan + 1);
}
if ((jack_setup->oports[i] =
jack_port_register (jack_setup->client, name,
for (i = 0; i < ichan + imidichan; i++) {
if (i < ichan) {
jack_port_type = JACK_DEFAULT_AUDIO_TYPE;
- AUBIO_SPRINTF (name, "in_%d", i + 1);
+ AUBIO_SNPRINTF (name, sizeof (name), "in_%d", i + 1);
} else {
jack_port_type = JACK_DEFAULT_MIDI_TYPE;
- AUBIO_SPRINTF (name, "midi_in_%d", i - ichan + 1);
+ AUBIO_SNPRINTF (name, sizeof (name), "midi_in_%d", i - ichan + 1);
}
if ((jack_setup->iports[i] =
jack_port_register (jack_setup->client, name,
# draw a line at tolerance
ax3.plot(times, [tolerance]*len(confidences))
ax3.axis( xmin = times[0], xmax = times[-1])
-ax3.set_ylabel('condidence')
+ax3.set_ylabel('confidence')
set_xlabels_sample2time(ax3, times[-1], samplerate)
plt.show()
#plt.savefig(os.path.basename(filename) + '.svg')
--- /dev/null
+#! /usr/bin/env python
+
+import sys
+import aubio
+
+if __name__ == '__main__':
+ if len(sys.argv) < 3:
+ print('usage: %s <inputfile> <outputfile> [transpose] [samplerate] [hop_size] [mode]' % sys.argv[0])
+ print('available modes: default, crispness:0, crispness:1, ... crispness:6')
+ sys.exit(1)
+ if len(sys.argv) > 3: transpose = float(sys.argv[3])
+ else: transpose = 12.
+ if len(sys.argv) > 4: samplerate = int(sys.argv[4])
+ else: samplerate = 0
+ if len(sys.argv) > 5: hop_size = int(sys.argv[5])
+ else: hop_size = 64
+ if len(sys.argv) > 6: mode = sys.argv[6]
+ else: mode = "default"
+
+ source_read = aubio.source(sys.argv[1], samplerate, hop_size)
+ if samplerate == 0: samplerate = source_read.samplerate
+ sink_out = aubio.sink(sys.argv[2], samplerate)
+
+ pitchshifter = aubio.pitchshift(mode, 1., hop_size, samplerate)
+ if transpose: pitchshifter.set_transpose(transpose)
+
+ total_frames, read = 0, hop_size
+ transpose_range = 23.9
+ while read:
+ vec, read = source_read()
+ # transpose the samples
+ out = pitchshifter(vec)
+ # position in the file (between 0. and 1.)
+ percent_read = total_frames / float(source_read.duration)
+ # variable transpose rate (in semitones)
+ transpose = 2 * transpose_range * percent_read - transpose_range
+ # set transpose rate
+ pitchshifter.set_transpose(transpose)
+ # print the transposition
+ #print pitchshifter.get_transpose()
+ # write the output
+ sink_out(out, read)
+ total_frames += read
+
+ # end of file, print some results
+ outstr = "wrote %.2fs" % (total_frames / float(samplerate))
+ outstr += " (%d frames in" % total_frames
+ outstr += " %d blocks" % (total_frames // source_read.hop_size)
+ outstr += " at %dHz)" % source_read.samplerate
+ outstr += " from " + source_read.uri
+ outstr += " to " + sink_out.uri
+ print(outstr)
typedef smpl_t (*aubio_unary_func_t)(smpl_t input);
-static void aubio_PyUFunc_d_d(char **args, npy_intp *dimensions,
- npy_intp* steps, void* data)
+static void aubio_PyUFunc_d_d(char **args, const npy_intp *dimensions,
+ const npy_intp* steps, void* data)
{
npy_intp i;
npy_intp n = dimensions[0];
}
}
-static void aubio_PyUFunc_f_f_As_d_d(char **args, npy_intp *dimensions,
- npy_intp* steps, void* data)
+static void aubio_PyUFunc_f_f_As_d_d(char **args, const npy_intp *dimensions,
+ const npy_intp* steps, void* data)
{
npy_intp i;
npy_intp n = dimensions[0];
'ratio': '0.5',
'method': '"default"',
'uri': '"none"',
+ 'transpose': '0.',
}
member_types = {
'tempo': '1',
'filterbank': 'self->n_filters',
'tss': 'self->buf_size',
+ 'pitchshift': 'self->hop_size',
'dct': 'self->size',
}
'tempo': 'self->hop_size',
'wavetable': 'self->hop_size',
'tss': 'self->buf_size / 2 + 1',
+ 'pitchshift': 'self->hop_size',
}
def get_name(proto):
return self.check_valid_uint(p)
if p['type'] == 'char_t*':
return self.check_valid_char(p)
+ if p['type'] == 'smpl_t':
+ return self.check_valid_smpl(p)
else:
print ("ERROR, no idea how to check %s for validity" % p['type'])
}}
""".format(defval = aubiodefvalue[name], name = name)
+ def check_valid_smpl(self, p):
+ name = p['name']
+ return """
+ self->{name} = {defval};
+ if ({name} != 0.) {{
+ self->{name} = {name};
+ }}
+""".format(defval = aubiodefvalue[name], name = name)
+
def gen_init(self):
out = """
// init {shortname}
#'sampler',
'audio_unit',
'spectral_whitening',
+ 'timestretch', # TODO fix parsing of uint_t *read in _do
]
def add_external_deps(ext, usedouble = False):
# loof for additional packages
print("Info: looking for *optional* additional packages")
- packages = ['libavcodec', 'libavformat', 'libavutil',
- 'libswresample', 'libavresample',
+ packages = ['libavcodec', 'libavformat', 'libavutil', 'libswresample',
+ 'jack',
'sndfile',
+ 'rubberband',
#'fftw3f',
]
# samplerate only works with float
add_packages(packages, ext=ext)
if 'avcodec' in ext.libraries \
and 'avformat' in ext.libraries \
- and 'avutil' in ext.libraries:
- if 'swresample' in ext.libraries:
- ext.define_macros += [('HAVE_SWRESAMPLE', 1)]
- elif 'avresample' in ext.libraries:
- ext.define_macros += [('HAVE_AVRESAMPLE', 1)]
- if 'swresample' in ext.libraries or 'avresample' in ext.libraries:
- ext.define_macros += [('HAVE_LIBAV', 1)]
+ and 'avutil' in ext.libraries \
+ and 'swresample' in ext.libraries:
+ ext.define_macros += [('HAVE_LIBAV', 1)]
if 'sndfile' in ext.libraries:
ext.define_macros += [('HAVE_SNDFILE', 1)]
if 'samplerate' in ext.libraries:
ext.define_macros += [('HAVE_SAMPLERATE', 1)]
+ if 'rubberband' in ext.libraries:
+ ext.define_macros += [('HAVE_RUBBERBAND', 1)]
if 'fftw3f' in ext.libraries:
ext.define_macros += [('HAVE_FFTW3F', 1)]
ext.define_macros += [('HAVE_FFTW3', 1)]
--- /dev/null
+#! /usr/bin/env python
+
+from numpy.testing import TestCase
+from _tools import parametrize, skipTest
+import numpy as np
+import aubio
+
+class aubio_pitchshift(TestCase):
+
+ def setUp(self):
+ try:
+ self.o = aubio.pitchshift(hop_size = 128)
+ except RuntimeError as e:
+ self.skipTest("creating aubio.pitchshift {}".format(e))
+
+ def test_default_creation(self):
+ self.assertEqual(self.o.get_pitchscale(), 1)
+ self.assertEqual(self.o.get_transpose(), 0)
+
+ def test_on_zeros(self):
+ test_length = self.o.hop_size * 100
+ read = 0
+ # test on zeros
+ vec = aubio.fvec(self.o.hop_size)
+ transpose_range = 24
+ while read < test_length:
+ # transpose the samples
+ out = self.o(vec)
+ self.assertTrue((out == 0).all())
+ # position in the file (between 0. and 1.)
+ percent_read = read / float(test_length)
+ # variable transpose rate (in semitones)
+ transpose = 2 * transpose_range * percent_read - transpose_range
+ # set transpose rate
+ self.o.set_transpose(transpose)
+ read += len(vec)
+
+ def test_on_ones(self):
+ test_length = self.o.hop_size * 100
+ read = 0
+ # test on zeros
+ vec = aubio.fvec(self.o.hop_size) + 1
+ transpose_range = 1.24
+ while read < test_length:
+ # transpose the samples
+ out = self.o(vec)
+ # position in the file (between 0. and 1.)
+ percent_read = read / float(test_length)
+ # variable transpose rate (in semitones)
+ transpose = 2 * transpose_range * percent_read - transpose_range
+ # set transpose rate
+ self.o.set_transpose(transpose)
+ read += len(vec)
+
+ def test_transpose_too_high(self):
+ with self.assertRaises(ValueError):
+ self.o.set_transpose(24.3)
+
+ def test_transpose_too_low(self):
+ with self.assertRaises(ValueError):
+ self.o.set_transpose(-24.3)
+
+class aubio_pitchshift_wrong_params(TestCase):
+
+ def test_wrong_transpose(self):
+ with self.assertRaises(RuntimeError):
+ aubio.pitchshift("default", -123)
+
+class Test_aubio_pitchshift_testruns(object):
+
+ run_args = ['mode', 'pitchscale', 'hop_size', 'samplerate']
+ run_values = [
+ ("default", 1.2, 128, 44100),
+ ("crispness:0", 0.43, 64, 8000),
+ ("crispness:3", 0.53, 256, 8000),
+ ("crispness:3", 1.53, 512, 8000),
+ ("crispness:6", 2.3, 4096, 192000),
+ ]
+
+ @parametrize(run_args, run_values)
+ def test_run_with_params(self, mode, pitchscale, hop_size, samplerate):
+ try:
+ self.o = aubio.pitchshift(mode, pitchscale, hop_size, samplerate)
+ except RuntimeError as e:
+ skipTest("failed creating pitchshift ({})".format(e))
+ test_length = self.o.hop_size * 50
+ read = 0
+ # test on random
+ vec = np.random.rand(self.o.hop_size).astype(aubio.float_type)
+ transpose_range = self.o.get_transpose()
+ while read < test_length:
+ # transpose the samples
+ out = self.o(vec)
+ # position in the file (between 0. and 1.)
+ percent_read = read / float(test_length)
+ # variable transpose rate (in semitones)
+ transpose = transpose_range - 2 * transpose_range * percent_read
+ # set transpose rate
+ self.o.set_transpose(transpose)
+ read += len(vec)
+
+if __name__ == '__main__':
+ from _tools import run_module_suite
+ run_module_suite()
-#! /bin/bash
+#! /usr/bin/env bash
set -e
set -x
#VERSION+=+$(git log --pretty=format:"%h" -1)
CFLAGS="-Werror -Os"
-WAFCONF="--disable-sndfile --disable-avcodec --disable-samplerate --enable-fat" # --disable-memcpy --disable-accelerate"
+WAFCONF="--nodeps --enable-fat" # --disable-memcpy --disable-accelerate"
export VERSION
popd
}
-function create_framework_fat() {
- rm -rf $AUBIO_TMPDIR/framework-$3
- mkdir -p $AUBIO_TMPDIR/framework-$3/$1-$2.$3_framework/$1.framework
- cp -pr COPYING README.md $AUBIO_TMPDIR/framework-$3/$1-$2.$3_framework
- pushd $AUBIO_TMPDIR/framework-$3
- cp -pr $AUBIO_TMPDIR/framework-ios/$1-$2.ios_framework/$1.framework/Headers $1-$2.$3_framework/$1.framework
- cp -pr $AUBIO_TMPDIR/framework-ios/$1-$2.ios_framework/$1.framework/Modules $1-$2.$3_framework/$1.framework
- lipo $AUBIO_TMPDIR/framework-ios/$1-$2.ios_framework/$1.framework/$1 \
- $AUBIO_TMPDIR/framework-iosimulator/$1-$2.iosimulator_framework/$1.framework/$1 \
- -output $1-$2.$3_framework/$1.framework/$1 -create
- popd
-}
-
function create_framework_zip() {
# create zip
pushd $AUBIO_TMPDIR/framework-$3
#./waf dist --verbose
-for PLATFORM in darwin ios iosimulator
+for PLATFORM in darwin ios iosimulator watchos watchsimulator
do
rm -rf $AUBIO_TMPDIR/dist-$PLATFORM
WAF_OPTIONS="--verbose --destdir $AUBIO_TMPDIR/dist-$PLATFORM --with-target-platform $PLATFORM $WAFCONF"
create_framework $PACKAGE $VERSION $PLATFORM
if [ $PLATFORM == 'darwin' ]
then
- # on darwin, build a .tar.bz2 of /usr and a .zip of aubio.framework
+ # on darwin, build a .tar.bz2 of /usr
create_tarballs $PACKAGE $VERSION $PLATFORM
- create_framework_zip $PACKAGE $VERSION $PLATFORM
fi
+
+ # build a .zip of aubio.framework
+ create_framework_zip $PACKAGE $VERSION $PLATFORM
+
+ # clean up
./waf uninstall $WAF_OPTIONS
done
-# after both ios and iosimulator have been built
-PLATFORM=iosuniversal
-create_framework_fat $PACKAGE $VERSION $PLATFORM
-create_framework_zip $PACKAGE $VERSION $PLATFORM
-
./waf clean
./waf distclean
-#! /bin/bash
+#! /usr/bin/env bash
function checkprog() {
type $1 >/dev/null 2>&1 || { echo >&2 "$1 required but not found, aborting."; exit 1; }
-#! /bin/bash
+#! /usr/bin/env bash
# This script cross compiles aubio for windows using mingw, four times:
#
-#! /bin/bash
+#! /usr/bin/env bash
set -e
#set -x
-WAFVERSION=2.0.17
+WAFVERSION=2.0.26
WAFTARBALL=waf-$WAFVERSION.tar.bz2
WAFURL=https://waf.io/$WAFTARBALL
-WAFUPSTREAMKEY=https://gitlab.com/ita1024/waf/raw/master/utils/pubkey.asc
+WAFUPSTREAMKEY=https://gitlab.com/ita1024/waf/-/raw/waf-$WAFVERSION/utils/pubkey.asc
WAFBUILDDIR=`mktemp -d`
buildwaf
popd
-cp -prv $WAFBUILDDIR/waf-$WAFVERSION/waf $PWD
+cp -prv $WAFBUILDDIR/waf-$WAFVERSION/waf "$PWD"
chmod +x waf
cleanup
#include "pitch/pitchfcomb.h"
#include "pitch/pitchspecacf.h"
#include "tempo/beattracking.h"
+#include "effects/pitchshift.h"
+#include "effects/timestretch.h"
#include "utils/scale.h"
#include "utils/hist.h"
#endif
#define AUBIO_ERR(...) aubio_log(AUBIO_LOG_ERR, "AUBIO ERROR: " __VA_ARGS__)
#define AUBIO_INF(...) aubio_log(AUBIO_LOG_INF, "AUBIO INFO: " __VA_ARGS__)
#define AUBIO_MSG(...) aubio_log(AUBIO_LOG_MSG, __VA_ARGS__)
-#define AUBIO_DBG(...) aubio_log(AUBIO_LOG_DBG, __VA_ARGS__)
+#define _AUBIO_DBG(...) aubio_log(AUBIO_LOG_DBG, __VA_ARGS__)
#define AUBIO_WRN(...) aubio_log(AUBIO_LOG_WRN, "AUBIO WARNING: " __VA_ARGS__)
#else
#define AUBIO_ERR(format, args...) aubio_log(AUBIO_LOG_ERR, "AUBIO ERROR: " format , ##args)
#define AUBIO_INF(format, args...) aubio_log(AUBIO_LOG_INF, "AUBIO INFO: " format , ##args)
#define AUBIO_MSG(format, args...) aubio_log(AUBIO_LOG_MSG, format , ##args)
-#define AUBIO_DBG(format, args...) aubio_log(AUBIO_LOG_DBG, format , ##args)
+#define _AUBIO_DBG(format, args...) aubio_log(AUBIO_LOG_DBG, format , ##args)
#define AUBIO_WRN(format, args...) aubio_log(AUBIO_LOG_WRN, "AUBIO WARNING: " format, ##args)
#endif
+#ifdef DEBUG
+#define AUBIO_DBG _AUBIO_DBG
+#else
+// disable debug output
+#ifdef HAVE_C99_VARARGS_MACROS
+#define AUBIO_DBG(...) {}
+#else
+#define AUBIO_DBG(format, args...) {}
+#endif
+#endif
+
#define AUBIO_ERROR AUBIO_ERR
#define AUBIO_QUIT(_s) exit(_s)
-#define AUBIO_SPRINTF sprintf
+#define AUBIO_SNPRINTF snprintf
#define AUBIO_MAX_SAMPLERATE (192000*8)
#define AUBIO_MAX_CHANNELS 1024
#define isnan _isnan
#endif
-#if !defined(_MSC_VER)
+#if !defined(_WIN32)
#define AUBIO_STRERROR(errno,buf,len) strerror_r(errno, buf, len)
#else
#define AUBIO_STRERROR(errno,buf,len) strerror_s(buf, len, errno)
--- /dev/null
+/*
+ Copyright (C) 2016 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef AUBIO_PITCHSHIFT_H
+#define AUBIO_PITCHSHIFT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file
+
+ Pitch shifting object
+
+ ::aubio_pitchshift_t can be used to transpose a stream of blocks of frames.
+
+ \example effects/test-pitchshift.c
+
+*/
+
+/** pitch shifting object */
+typedef struct _aubio_pitchshift_t aubio_pitchshift_t;
+
+/** execute pitch shifting on an input signal frame
+
+ \param o pitch shifting object as returned by new_aubio_pitchshift()
+ \param in input signal of size [hop_size]
+ \param out output pitch candidates of size [1]
+
+*/
+void aubio_pitchshift_do (aubio_pitchshift_t * o, const fvec_t * in,
+ fvec_t * out);
+
+/** deletion of the pitch shifting object
+
+ \param o pitch shifting object as returned by new_aubio_pitchshift()
+
+*/
+void del_aubio_pitchshift (aubio_pitchshift_t * o);
+
+/** creation of the pitch shifting object
+
+ \param method set pitch shifting algorithm ("default")
+ \param transpose initial pitch transposition
+ \param hop_size step size between two consecutive analysis instant
+ \param samplerate sampling rate of the signal
+
+ \return newly created ::aubio_pitchshift_t
+
+*/
+aubio_pitchshift_t *new_aubio_pitchshift (const char_t * method,
+ smpl_t transpose, uint_t hop_size, uint_t samplerate);
+
+/** get the latency of the pitch shifting object, in samples
+
+ \param o pitch shifting object as returned by ::new_aubio_pitchshift()
+
+ \return latency of the pitch shifting object in samples
+
+*/
+uint_t aubio_pitchshift_get_latency (aubio_pitchshift_t * o);
+
+/** set the pitch scale of the pitch shifting object
+
+ \param o pitch shifting object as returned by new_aubio_pitchshift()
+ \param pitchscale new pitch scale of the pitch shifting object
+
+ pitchscale is a frequency ratio. It should be in the range [0.25, 4].
+
+ \return 0 if successfull, non-zero otherwise
+
+*/
+uint_t aubio_pitchshift_set_pitchscale (aubio_pitchshift_t * o,
+ smpl_t pitchscale);
+
+/** get the pitchscale of the pitch shifting object
+
+ \param o pitch shifting object as returned by ::new_aubio_pitchshift()
+
+ \return pitchscale of the pitch shifting object
+
+*/
+smpl_t aubio_pitchshift_get_pitchscale (aubio_pitchshift_t * o);
+
+/** set the transposition of the pitch shifting object, in semitones
+
+ \param o pitch shifting object as returned by new_aubio_pitchshift()
+ \param transpose new pitch transposition of the pitch shifting object,
+ expressed in semitones (should be in the range [-24;+24])
+
+ \return 0 if successfull, non-zero otherwise
+
+*/
+uint_t aubio_pitchshift_set_transpose (aubio_pitchshift_t * o,
+ smpl_t transpose);
+
+/** get the transposition of the pitch shifting object, in semitones
+
+ \param o pitch shifting object as returned by ::new_aubio_pitchshift()
+
+ \return transposition of the pitch shifting object, in semitones
+
+*/
+smpl_t aubio_pitchshift_get_transpose (aubio_pitchshift_t * o);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_PITCHSHIFT_H */
--- /dev/null
+/*
+ Copyright (C) 2016 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "aubio_priv.h"
+
+#ifndef HAVE_RUBBERBAND
+
+#include "fvec.h"
+#include "effects/pitchshift.h"
+
+// TODO fallback pitch shifting implementation
+
+struct _aubio_pitchshift_t
+{
+ void *dummy;
+};
+
+void aubio_pitchshift_do (aubio_pitchshift_t * o UNUSED, const fvec_t * in UNUSED,
+ fvec_t * out UNUSED) {
+}
+
+void del_aubio_pitchshift (aubio_pitchshift_t * o UNUSED) {
+}
+
+aubio_pitchshift_t *new_aubio_pitchshift (const char_t * method UNUSED,
+ smpl_t pitchscale UNUSED, uint_t hop_size UNUSED, uint_t samplerate UNUSED)
+{
+ AUBIO_ERR ("aubio was not compiled with rubberband\n");
+ return NULL;
+}
+
+uint_t aubio_pitchshift_set_pitchscale (aubio_pitchshift_t * o UNUSED, smpl_t pitchscale UNUSED)
+{
+ return AUBIO_FAIL;
+}
+
+smpl_t aubio_pitchshift_get_pitchscale (aubio_pitchshift_t * o UNUSED)
+{
+ return 1.;
+}
+
+uint_t aubio_pitchshift_set_transpose (aubio_pitchshift_t * o UNUSED, smpl_t transpose UNUSED) {
+ return AUBIO_FAIL;
+}
+
+smpl_t aubio_pitchshift_get_transpose (aubio_pitchshift_t * o UNUSED) {
+ return 0.;
+}
+
+uint_t aubio_pitchshift_get_latency (aubio_pitchshift_t * o UNUSED) {
+ return 0.;
+}
+
+// end of dummy implementation
+
+#endif /* HAVE_RUBBERBAND */
--- /dev/null
+/*
+ Copyright (C) 2016 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "aubio_priv.h"
+
+#ifdef HAVE_RUBBERBAND
+
+#include "fvec.h"
+#include "effects/pitchshift.h"
+
+#include <rubberband/rubberband-c.h>
+
+/** generic pitch shifting structure */
+struct _aubio_pitchshift_t
+{
+ uint_t samplerate; /**< samplerate */
+ uint_t hopsize; /**< hop size */
+ smpl_t pitchscale; /**< pitch scale */
+
+ RubberBandState rb;
+ RubberBandOptions rboptions;
+};
+
+extern RubberBandOptions aubio_get_rubberband_opts(const char_t *mode);
+
+aubio_pitchshift_t *
+new_aubio_pitchshift (const char_t * mode,
+ smpl_t transpose, uint_t hopsize, uint_t samplerate)
+{
+ aubio_pitchshift_t *p = AUBIO_NEW (aubio_pitchshift_t);
+ p->samplerate = samplerate;
+ p->hopsize = hopsize;
+ p->pitchscale = 1.;
+ p->rb = NULL;
+ if ((sint_t)hopsize <= 0) {
+ AUBIO_ERR("pitchshift: hop_size should be >= 0, got %d\n", hopsize);
+ goto beach;
+ }
+ if ((sint_t)samplerate <= 0) {
+ AUBIO_ERR("pitchshift: samplerate should be >= 0, got %d\n", samplerate);
+ goto beach;
+ }
+
+ p->rboptions = aubio_get_rubberband_opts(mode);
+ if (p->rboptions < 0) {
+ AUBIO_ERR("pitchshift: unknown pitch shifting method %s\n", mode);
+ goto beach;
+ }
+
+ //AUBIO_MSG("pitchshift: using pitch shifting method %s\n", mode);
+
+ p->rb = rubberband_new(samplerate, 1, p->rboptions, 1., p->pitchscale);
+ rubberband_set_max_process_size(p->rb, p->hopsize);
+ //rubberband_set_debug_level(p->rb, 10);
+
+ if (aubio_pitchshift_set_transpose(p, transpose)) goto beach;
+
+#if 1
+ // warm up rubber band
+ unsigned int latency = MAX(p->hopsize, rubberband_get_latency(p->rb));
+ int available = rubberband_available(p->rb);
+ fvec_t *zeros = new_fvec(p->hopsize);
+ while (available <= (int)latency) {
+ rubberband_process(p->rb,
+ (const float* const*)&(zeros->data), p->hopsize, 0);
+ available = rubberband_available(p->rb);
+ }
+ del_fvec(zeros);
+#endif
+
+ return p;
+
+beach:
+ del_aubio_pitchshift(p);
+ return NULL;
+}
+
+void
+del_aubio_pitchshift (aubio_pitchshift_t * p)
+{
+ if (p->rb) {
+ rubberband_delete(p->rb);
+ }
+ AUBIO_FREE (p);
+}
+
+uint_t aubio_pitchshift_get_latency (aubio_pitchshift_t * p) {
+ return rubberband_get_latency(p->rb);
+}
+
+uint_t
+aubio_pitchshift_set_pitchscale (aubio_pitchshift_t * p, smpl_t pitchscale)
+{
+ if (pitchscale >= 0.25 && pitchscale <= 4.) {
+ p->pitchscale = pitchscale;
+ rubberband_set_pitch_scale(p->rb, p->pitchscale);
+ return AUBIO_OK;
+ } else {
+ AUBIO_ERR("pitchshift: could not set pitchscale to '%f',"
+ " should be in the range [0.25, 4.].\n", pitchscale);
+ return AUBIO_FAIL;
+ }
+}
+
+smpl_t
+aubio_pitchshift_get_pitchscale (aubio_pitchshift_t * p)
+{
+ return p->pitchscale;
+}
+
+uint_t
+aubio_pitchshift_set_transpose(aubio_pitchshift_t * p, smpl_t transpose)
+{
+ if (transpose >= -24. && transpose <= 24.) {
+ smpl_t pitchscale = POW(2., transpose / 12.);
+ return aubio_pitchshift_set_pitchscale(p, pitchscale);
+ } else {
+ AUBIO_ERR("pitchshift: could not set transpose to '%f',"
+ " should be in the range [-24; 24.].\n", transpose);
+ return AUBIO_FAIL;
+ }
+}
+
+smpl_t
+aubio_pitchshift_get_transpose(aubio_pitchshift_t * p)
+{
+ return 12. * LOG(p->pitchscale) / LOG(2.0);
+}
+
+void
+aubio_pitchshift_do (aubio_pitchshift_t * p, const fvec_t * in, fvec_t * out)
+{
+ // third parameter is always 0 since we are never expecting a final frame
+ rubberband_process(p->rb, (const float* const*)&(in->data), p->hopsize, 0);
+ if (rubberband_available(p->rb) >= (int)p->hopsize) {
+ rubberband_retrieve(p->rb, (float* const*)&(out->data), p->hopsize);
+ } else {
+ AUBIO_WRN("pitchshift: catching up with zeros"
+ ", only %d available, needed: %d, current pitchscale: %f\n",
+ rubberband_available(p->rb), p->hopsize, p->pitchscale);
+ fvec_zeros(out);
+ }
+}
+
+#endif
--- /dev/null
+
+
+#include "aubio_priv.h"
+
+#ifdef HAVE_RUBBERBAND
+
+#include <rubberband/rubberband-c.h>
+
+// check rubberband is 1.8.1, warn if 1.3
+#if !((RUBBERBAND_API_MAJOR_VERSION >= 2) && \
+ (RUBBERBAND_API_MINOR_VERSION >= 5))
+#warning RubberBandOptionDetectorSoft not available, \
+ please upgrade rubberband to version 1.8.1 or higher
+#define RubberBandOptionDetectorSoft 0x00000000
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+char_t** aubio_split_str(const char_t* str, const char_t sep) {
+ char_t** result = 0;
+ uint_t count = 0;
+ char_t input[PATH_MAX];
+ char_t* in_ptr = input;
+ char_t* last_sep = 0;
+ char_t delim[2]; delim[0] = sep; delim[1] = 0;
+
+ strncpy(input, str, PATH_MAX);
+ input[PATH_MAX - 1] = '\0';
+
+ // count number of elements
+ while (*in_ptr) {
+ if (sep == *in_ptr) {
+ count++;
+ last_sep = in_ptr;
+ }
+ in_ptr++;
+ }
+ // add space for trailing token.
+ count += last_sep < (input + strlen(input) - 1);
+ count++;
+
+ result = AUBIO_ARRAY(char_t*, count);
+ if (result) {
+ uint_t idx = 0;
+ char_t* params = strtok(input, delim);
+ while (params) {
+ // make sure we don't got in the wild
+ if (idx >= count)
+ break;
+ *(result + idx++) = strdup(params);
+ params = strtok(0, delim);
+ }
+ // add null string at the end if needed
+ if (idx < count - 1)
+ *(result + idx) = 0;
+ }
+ return result;
+}
+
+RubberBandOptions aubio_get_rubberband_opts(const char_t *mode)
+{
+ RubberBandOptions rboptions = RubberBandOptionProcessRealTime;
+
+ if ( strcmp(mode,"crispness:0") == 0 ) {
+ rboptions |= RubberBandOptionTransientsSmooth;
+ rboptions |= RubberBandOptionWindowLong;
+ rboptions |= RubberBandOptionPhaseIndependent;
+ } else if ( strcmp(mode, "crispness:1") == 0 ) {
+ rboptions |= RubberBandOptionDetectorSoft;
+ rboptions |= RubberBandOptionTransientsSmooth;
+ rboptions |= RubberBandOptionWindowLong;
+ rboptions |= RubberBandOptionPhaseIndependent;
+ } else if ( strcmp(mode, "crispness:2") == 0 ) {
+ rboptions |= RubberBandOptionTransientsSmooth;
+ rboptions |= RubberBandOptionPhaseIndependent;
+ } else if ( strcmp(mode, "crispness:3") == 0 ) {
+ rboptions |= RubberBandOptionTransientsSmooth;
+ } else if ( strcmp(mode, "crispness:4") == 0 ) {
+ // same as "default"
+ } else if ( strcmp(mode, "crispness:5") == 0 ) {
+ rboptions |= RubberBandOptionTransientsCrisp;
+ } else if ( strcmp(mode, "crispness:6") == 0 ) {
+ rboptions |= RubberBandOptionTransientsCrisp;
+ rboptions |= RubberBandOptionWindowShort;
+ rboptions |= RubberBandOptionPhaseIndependent;
+ } else if ( strcmp(mode, "default") == 0 ) {
+ // nothing to do
+ } else {
+ // attempt to parse a list of options, separated with ','
+ char_t **params = aubio_split_str(mode, ':');
+ uint_t i = 0;
+ if (!params || !params[0]) {
+ // memory failure occurred or empty string was passed
+ AUBIO_ERR("rubberband_utils: failed parsing options\n");
+ rboptions = -1;
+ }
+ while (*(params + i) != NULL) {
+ if ( strcmp(params[i], "ProcessOffline" ) == 0 ) {
+ rboptions = RubberBandOptionProcessOffline;
+ // TODO: add wrapper to rb study(smpl_t *input, uint_t write)
+ AUBIO_ERR("rubberband_utils: RubberBandOptionProcessOffline is not available\n");
+ rboptions = -1;
+ }
+ else if ( strcmp(params[i], "ProcessRealTime" ) == 0 ) rboptions |= RubberBandOptionProcessRealTime;
+ else if ( strcmp(params[i], "StretchElastic" ) == 0 ) rboptions |= RubberBandOptionStretchElastic;
+ else if ( strcmp(params[i], "StretchPrecise" ) == 0 ) rboptions |= RubberBandOptionStretchPrecise;
+ else if ( strcmp(params[i], "TransientsCrisp" ) == 0 ) rboptions |= RubberBandOptionTransientsCrisp;
+ else if ( strcmp(params[i], "TransientsMixed" ) == 0 ) rboptions |= RubberBandOptionTransientsMixed;
+ else if ( strcmp(params[i], "TransientsSmooth" ) == 0 ) rboptions |= RubberBandOptionTransientsSmooth;
+ else if ( strcmp(params[i], "DetectorCompound" ) == 0 ) rboptions |= RubberBandOptionDetectorCompound;
+ else if ( strcmp(params[i], "DetectorPercussive" ) == 0 ) rboptions |= RubberBandOptionDetectorPercussive;
+ else if ( strcmp(params[i], "DetectorSoft" ) == 0 ) rboptions |= RubberBandOptionDetectorSoft;
+ else if ( strcmp(params[i], "PhaseLaminar" ) == 0 ) rboptions |= RubberBandOptionPhaseLaminar;
+ else if ( strcmp(params[i], "PhaseIndependent" ) == 0 ) rboptions |= RubberBandOptionPhaseIndependent;
+ else if ( strcmp(params[i], "ThreadingAuto" ) == 0 ) rboptions |= RubberBandOptionThreadingAuto;
+ else if ( strcmp(params[i], "ThreadingNever" ) == 0 ) rboptions |= RubberBandOptionThreadingNever;
+ else if ( strcmp(params[i], "ThreadingAlways" ) == 0 ) rboptions |= RubberBandOptionThreadingAlways;
+ else if ( strcmp(params[i], "WindowStandard" ) == 0 ) rboptions |= RubberBandOptionWindowStandard;
+ else if ( strcmp(params[i], "WindowShort" ) == 0 ) rboptions |= RubberBandOptionWindowShort;
+ else if ( strcmp(params[i], "WindowLong" ) == 0 ) rboptions |= RubberBandOptionWindowLong;
+ else if ( strcmp(params[i], "SmoothingOff" ) == 0 ) rboptions |= RubberBandOptionSmoothingOff;
+ else if ( strcmp(params[i], "SmoothingOn" ) == 0 ) rboptions |= RubberBandOptionSmoothingOn;
+ else if ( strcmp(params[i], "FormantShifted" ) == 0 ) rboptions |= RubberBandOptionFormantShifted;
+ else if ( strcmp(params[i], "FormantPreserved" ) == 0 ) rboptions |= RubberBandOptionFormantPreserved;
+ else if ( strcmp(params[i], "PitchHighSpeed" ) == 0 ) rboptions |= RubberBandOptionPitchHighSpeed;
+ else if ( strcmp(params[i], "PitchHighQuality" ) == 0 ) rboptions |= RubberBandOptionPitchHighQuality;
+ else if ( strcmp(params[i], "PitchHighConsistency" ) == 0 ) rboptions |= RubberBandOptionPitchHighConsistency;
+ else if ( strcmp(params[i], "ChannelsApart" ) == 0 ) rboptions |= RubberBandOptionChannelsApart;
+ else if ( strcmp(params[i], "ChannelsTogether" ) == 0 ) rboptions |= RubberBandOptionChannelsTogether;
+ else {
+ AUBIO_ERR("rubberband_utils: did not understand option '%s', should be one of: "
+ "StretchElastic|StretchPrecise, TransientsCrisp|TransientsMixed|TransientsSmooth, "
+ "DetectorCompound|DetectorPercussive|DetectorSoft, PhaseLaminar|PhaseIndependent, "
+ "ThreadingAuto|ThreadingNever|ThreadingAlways, WindowStandard|WindowLong|WindowShort, "
+ "SmoothingOn|SmoothingOff, FormantShifted|FormantPreserved, "
+ "PitchHighSpeed|PitchHighQuality|PitchHighConsistency, ChannelsApart|ChannelsTogether\n"
+ , params[i]);
+ rboptions = -1;
+ }
+ AUBIO_FREE(params[i]);
+ i++;
+ }
+ AUBIO_FREE(params);
+ }
+ return rboptions;
+}
+
+#endif
--- /dev/null
+/*
+ Copyright (C) 2016 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef AUBIO_TIMESTRETCH_H
+#define AUBIO_TIMESTRETCH_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file
+
+ time stretching object
+
+ ::aubio_timestretch_t can be used to open a source file, read samples from
+ it, time-stretch them, and write out the modified samples.
+
+ The time-stretching factor can be changed at any time using
+ aubio_timestretch_set_stretch().
+
+ A transposition can also be applied and changed at any time with
+ aubio_timestretch_set_transpose().
+
+ \example effects/test-timestretch.c
+
+*/
+
+/** time stretching object */
+typedef struct _aubio_timestretch_t aubio_timestretch_t;
+
+/** execute time stretching on an input signal frame
+
+ \param o time stretching object as returned by new_aubio_timestretch()
+ \param out timestretched output of size [hop_size]
+ \param read number of frames actually wrote out
+
+*/
+void aubio_timestretch_do (aubio_timestretch_t * o, fvec_t * out,
+ uint_t * read);
+
+/** deletion of the time stretching object
+
+ \param o time stretching object as returned by new_aubio_timestretch()
+
+*/
+void del_aubio_timestretch (aubio_timestretch_t * o);
+
+/** creation of the time stretching object
+
+ \param method time stretching algorithm ("default")
+ \param stretch initial time stretching factor
+ \param hop_size block size at which the frames should be produced
+ \param samplerate sampling rate of the signal
+
+ \return newly created ::aubio_timestretch_t
+
+*/
+aubio_timestretch_t *new_aubio_timestretch (const char_t * method,
+ smpl_t stretch, uint_t hop_size, uint_t samplerate);
+
+/** push length samples from in to time stretching object
+
+ \param o time stretching object as returned by ::new_aubio_timestretch()
+ \param in input vector of new samples to push to time stretching object
+ \param length number of new samples to push from input vector
+
+ \return number of currently available samples
+
+ */
+sint_t aubio_timestretch_push(aubio_timestretch_t * o, fvec_t *in,
+ uint_t length);
+
+/** get number of currently available samples from time stretching object
+
+ \param o time stretching object as returned by ::new_aubio_timestretch()
+
+ \return number of currently available samples
+
+ */
+sint_t aubio_timestretch_get_available(aubio_timestretch_t * o);
+
+/** get the latency of the time stretching object, in samples
+
+ \param o time stretching object as returned by ::new_aubio_timestretch()
+
+ \return latency of the time stretching object in samples
+
+*/
+uint_t aubio_timestretch_get_latency (aubio_timestretch_t * o);
+
+/** get the samplerate of the time stretching object
+
+ Call after new_aubio_timestretch() was called with 0 to match the original
+ samplerate of the input file.
+
+ \param o time stretching object as returned by new_aubio_timestretch()
+
+ \return samplerate of the time stretching object
+
+ */
+uint_t aubio_timestretch_get_samplerate (aubio_timestretch_t * o);
+
+/** set the stretching ratio of the time stretching object
+
+ \param o time stretching object as returned by new_aubio_timestretch()
+ \param stretch new time stretching ratio of the time stretching object
+ (should be in the range [0.025; 10.])
+
+ \return 0 if successfull, non-zero otherwise
+
+*/
+uint_t aubio_timestretch_set_stretch (aubio_timestretch_t * o, smpl_t stretch);
+
+/** get the transposition of the time stretching object, in semitones
+
+ \param o time stretching object as returned by ::new_aubio_timestretch()
+
+ \return time stretching ratio of the time stretching object, in the range
+ [0.025; 10.]
+
+*/
+smpl_t aubio_timestretch_get_stretch (aubio_timestretch_t * o);
+
+/** set the pitch scale of the time stretching object
+
+ \param o time stretching object as returned by new_aubio_timestretch()
+ \param pitchscale new pitch scale of the time stretching object
+
+ pitchscale is a frequency ratio. It should be in the range [0.25, 4].
+
+ \return 0 if successfull, non-zero otherwise
+
+*/
+uint_t aubio_timestretch_set_pitchscale (aubio_timestretch_t * o,
+ smpl_t pitchscale);
+
+/** get the pitchscale of the time stretching object
+
+ \param o time stretching object as returned by ::new_aubio_timestretch()
+
+ \return pitchscale of the time stretching object
+
+*/
+smpl_t aubio_timestretch_get_pitchscale (aubio_timestretch_t * o);
+
+/** set the transposition of the time stretching object, in semitones
+
+ \param o time stretching object as returned by new_aubio_timestretch()
+
+ \param transpose new pitch transposition of the time stretching object,
+ expressed in semitones (should be in the range [-24;+24])
+
+ \return 0 if successfull, non-zero otherwise
+
+*/
+uint_t aubio_timestretch_set_transpose (aubio_timestretch_t * o,
+ smpl_t transpose);
+
+/** get the transposition of the time stretching object, in semitones
+
+ \param o time stretching object as returned by ::new_aubio_timestretch()
+
+ \return transposition of the time stretching object, in semitones
+
+*/
+smpl_t aubio_timestretch_get_transpose (aubio_timestretch_t * o);
+
+/** reset the time stretching object
+
+ \param o time stretching object as returned by ::new_aubio_timestretch()
+
+ \return 0 on success, non-zero otherwise
+
+*/
+uint_t aubio_timestretch_reset(aubio_timestretch_t * o);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_TIMESTRETCH_H */
--- /dev/null
+/*
+ Copyright (C) 2016 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "aubio_priv.h"
+
+#ifndef HAVE_RUBBERBAND
+
+#include "fvec.h"
+#include "effects/timestretch.h"
+
+// TODO fallback time stretching implementation
+
+struct _aubio_timestretch_t
+{
+ void *dummy;
+};
+
+void
+aubio_timestretch_do (aubio_timestretch_t * o UNUSED, fvec_t * out UNUSED,
+ uint_t * read UNUSED)
+{
+}
+
+void del_aubio_timestretch (aubio_timestretch_t * o UNUSED) {
+}
+
+aubio_timestretch_t *
+new_aubio_timestretch (const char_t * method UNUSED,
+ smpl_t pitchscale UNUSED, uint_t hop_size UNUSED, uint_t samplerate UNUSED)
+{
+ AUBIO_ERR ("timestretch: aubio was not compiled with rubberband\n");
+ return NULL;
+}
+
+uint_t aubio_timestretch_set_stretch (aubio_timestretch_t * o UNUSED, smpl_t stretch UNUSED)
+{
+ return AUBIO_FAIL;
+}
+
+smpl_t aubio_timestretch_get_stretch (aubio_timestretch_t * o UNUSED)
+{
+ return 1.;
+}
+
+uint_t aubio_timestretch_set_pitchscale (aubio_timestretch_t * o UNUSED, smpl_t pitchscale UNUSED)
+{
+ return AUBIO_FAIL;
+}
+
+uint_t aubio_timestretch_get_samplerate (aubio_timestretch_t * o UNUSED) {
+ return 0;
+}
+
+smpl_t aubio_timestretch_get_pitchscale (aubio_timestretch_t * o UNUSED)
+{
+ return 1.;
+}
+
+uint_t aubio_timestretch_set_transpose (aubio_timestretch_t * o UNUSED, smpl_t transpose UNUSED) {
+ return AUBIO_FAIL;
+}
+
+smpl_t aubio_timestretch_get_transpose (aubio_timestretch_t * o UNUSED) {
+ return 0.;
+}
+
+uint_t aubio_timestretch_get_latency (aubio_timestretch_t * o UNUSED) {
+ return 0.;
+}
+
+uint_t aubio_timestretch_reset(aubio_timestretch_t *o UNUSED) {
+ return AUBIO_FAIL;
+}
+
+sint_t aubio_timestretch_push(aubio_timestretch_t * o UNUSED, fvec_t * in
+ UNUSED, uint_t length UNUSED) {
+ return AUBIO_FAIL;
+}
+
+sint_t aubio_timestretch_get_available(aubio_timestretch_t * o UNUSED) {
+ return AUBIO_FAIL;
+}
+// end of dummy implementation
+
+#endif /* HAVE_RUBBERBAND */
--- /dev/null
+/*
+ Copyright (C) 2016 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "aubio_priv.h"
+
+#ifdef HAVE_RUBBERBAND
+
+#include "fvec.h"
+#include "fmat.h"
+#include "io/source.h"
+#include "effects/timestretch.h"
+
+#include <rubberband/rubberband-c.h>
+
+#define MIN_STRETCH_RATIO 0.025
+#define MAX_STRETCH_RATIO 40.
+
+#define HAVE_THREADS 1
+#if 0
+#undef HAVE_THREADS
+#endif
+
+#ifdef HAVE_THREADS
+#include <pthread.h>
+#endif
+
+/** generic time stretching structure */
+struct _aubio_timestretch_t
+{
+ uint_t samplerate; /**< samplerate */
+ uint_t hopsize; /**< hop size */
+ smpl_t stretchratio; /**< time ratio */
+ smpl_t pitchscale; /**< pitch scale */
+
+ RubberBandState rb;
+ RubberBandOptions rboptions;
+};
+
+extern RubberBandOptions aubio_get_rubberband_opts(const char_t *mode);
+
+//static void aubio_timestretch_warmup (aubio_timestretch_t * p);
+
+aubio_timestretch_t *
+new_aubio_timestretch (const char_t * mode, smpl_t stretchratio, uint_t hopsize,
+ uint_t samplerate)
+{
+ aubio_timestretch_t *p = AUBIO_NEW (aubio_timestretch_t);
+ p->hopsize = hopsize;
+ p->pitchscale = 1.;
+
+ if ((sint_t)hopsize <= 0) {
+ AUBIO_ERR("timestretch: hopsize should be > 0, got %d\n", hopsize);
+ goto beach;
+ }
+
+ if ((sint_t)samplerate <= 0) {
+ AUBIO_ERR("timestretch: samplerate should be > 0, got %d\n", samplerate);
+ goto beach;
+ }
+
+ if (stretchratio <= MAX_STRETCH_RATIO && stretchratio >= MIN_STRETCH_RATIO) {
+ p->stretchratio = stretchratio;
+ } else {
+ AUBIO_ERR("timestretch: stretchratio should be in the range [%.3f, %.3f], got %f\n",
+ MIN_STRETCH_RATIO, MAX_STRETCH_RATIO, stretchratio);
+ goto beach;
+ }
+
+ p->rboptions = aubio_get_rubberband_opts(mode);
+ if (p->rboptions < 0) {
+ AUBIO_ERR("timestretch: unknown time stretching method %s\n", mode);
+ goto beach;
+ }
+
+ p->rb = rubberband_new(samplerate, 1, p->rboptions, p->stretchratio, p->pitchscale);
+ if (!p->rb) goto beach;
+
+ p->samplerate = samplerate;
+
+ //aubio_timestretch_warmup(p);
+
+ return p;
+
+beach:
+ del_aubio_timestretch(p);
+ return NULL;
+}
+
+#if 0
+static void
+aubio_timestretch_warmup (aubio_timestretch_t * p)
+{
+ // warm up rubber band
+ //AUBIO_WRN("timestretch: warming-up\n");
+ unsigned int latency = MAX(p->hopsize, rubberband_get_latency(p->rb));
+ fvec_t *input = new_fvec(p->hopsize);
+ while (aubio_timestretch_push(p, input, input->length) < (int)latency) {
+ //sint_t available = aubio_timestretch_get_available(p);
+ //AUBIO_WRN("timestretch: warmup got %d, latency: %d\n", available, latency);
+ }
+ del_fvec(input);
+}
+#endif
+
+void
+del_aubio_timestretch (aubio_timestretch_t * p)
+{
+ if (p->rb) {
+ rubberband_delete(p->rb);
+ }
+ AUBIO_FREE (p);
+}
+
+uint_t
+aubio_timestretch_get_samplerate (aubio_timestretch_t * p)
+{
+ return p->samplerate;
+}
+
+uint_t aubio_timestretch_get_latency (aubio_timestretch_t * p) {
+ return rubberband_get_latency(p->rb);
+}
+
+uint_t
+aubio_timestretch_set_stretch (aubio_timestretch_t * p, smpl_t stretch)
+{
+ if (!p->rb) {
+ AUBIO_ERR("timestretch: could not set stretch ratio,"
+ " rubberband not created\n");
+ return AUBIO_FAIL;
+ }
+ if (stretch >= MIN_STRETCH_RATIO && stretch <= MAX_STRETCH_RATIO) {
+ p->stretchratio = stretch;
+ rubberband_set_time_ratio(p->rb, 1./p->stretchratio);
+ return AUBIO_OK;
+ } else {
+ AUBIO_ERR("timestretch: could not set stretch ratio to '%f',"
+ " should be in the range [%.2f, %.2f].\n", stretch,
+ MIN_STRETCH_RATIO, MAX_STRETCH_RATIO);
+ return AUBIO_FAIL;
+ }
+}
+
+smpl_t
+aubio_timestretch_get_stretch (aubio_timestretch_t * p)
+{
+ return p->stretchratio;
+}
+
+uint_t
+aubio_timestretch_set_pitchscale (aubio_timestretch_t * p, smpl_t pitchscale)
+{
+ if (!p->rb) {
+ AUBIO_ERR("timestretch: could not set pitch scale,"
+ " rubberband not created\n");
+ return AUBIO_FAIL;
+ }
+ if (pitchscale >= 0.0625 && pitchscale <= 4.) {
+ p->pitchscale = pitchscale;
+ rubberband_set_pitch_scale(p->rb, p->pitchscale);
+ return AUBIO_OK;
+ } else {
+ AUBIO_ERR("timestretch: could not set pitchscale to '%f',"
+ " should be in the range [0.0625, 4.].\n", pitchscale);
+ return AUBIO_FAIL;
+ }
+}
+
+smpl_t
+aubio_timestretch_get_pitchscale (aubio_timestretch_t * p)
+{
+ return p->pitchscale;
+}
+
+uint_t
+aubio_timestretch_set_transpose(aubio_timestretch_t * p, smpl_t transpose)
+{
+ if (transpose >= -24. && transpose <= 24.) {
+ smpl_t pitchscale = POW(2., transpose / 12.);
+ return aubio_timestretch_set_pitchscale(p, pitchscale);
+ } else {
+ AUBIO_ERR("timestretch: could not set transpose to '%f',"
+ " should be in the range [-24; 24].\n", transpose);
+ return AUBIO_FAIL;
+ }
+}
+
+smpl_t
+aubio_timestretch_get_transpose(aubio_timestretch_t * p)
+{
+ return 12. * LOG(p->pitchscale) / LOG(2.0);
+}
+
+sint_t
+aubio_timestretch_push(aubio_timestretch_t *p, fvec_t *input, uint_t length)
+{
+ // push new samples to rubberband, return available
+ int available;
+ int eof = (input->length != length) ? 1 : 0;
+ rubberband_process(p->rb, (const float* const*)&(input->data), length, eof);
+ available = rubberband_available(p->rb);
+ //AUBIO_WRN("timestretch: processed %d, %d available, eof: %d\n",
+ // length, available, eof);
+ return available;
+}
+
+sint_t
+aubio_timestretch_get_available(aubio_timestretch_t *p) {
+ return rubberband_available(p->rb);
+}
+
+void
+aubio_timestretch_do(aubio_timestretch_t * p, fvec_t * out, uint_t * read)
+{
+ // now retrieve the samples and write them into out->data
+ int available = rubberband_available(p->rb);
+ if (available >= (int)out->length) {
+ rubberband_retrieve(p->rb, (float* const*)&(out->data), out->length);
+ *read = out->length;
+ } else if (available > 0) {
+ // this occurs each time the end of file is reached
+ //AUBIO_WRN("timestretch: short read\n");
+ rubberband_retrieve(p->rb, (float* const*)&(out->data), available);
+ fvec_t zeros; zeros.length = out->length - available; zeros.data = out->data + available;
+ fvec_zeros(&zeros);
+ *read = available;
+ } else {
+ // this may occur if the previous was a short read available == hopsize
+ fvec_zeros(out);
+ *read = 0;
+ }
+}
+
+uint_t
+aubio_timestretch_reset(aubio_timestretch_t *p)
+{
+ uint_t err = AUBIO_OK;
+ if (p->rb) {
+ rubberband_reset(p->rb);
+ }
+ return err;
+}
+
+#endif
del_aubio_sink_t s_del;
};
+extern uint_t aubio_str_path_has_extension(const char_t *filename,
+ const char_t *pattern);
+
+#ifdef HAVE_VORBISENC
+typedef struct _aubio_sink_vorbis_t aubio_sink_vorbis_t;
+extern aubio_sink_vorbis_t * new_aubio_sink_vorbis(const char_t *uri,
+ uint_t samplerate);
+extern void del_aubio_sink_vorbis (aubio_sink_vorbis_t *s);
+extern uint_t aubio_sink_vorbis_open(aubio_sink_vorbis_t *s);
+extern uint_t aubio_sink_vorbis_close(aubio_sink_vorbis_t *s);
+extern uint_t aubio_sink_vorbis_preset_channels(aubio_sink_vorbis_t *s,
+ uint_t channels);
+extern uint_t aubio_sink_vorbis_preset_samplerate(aubio_sink_vorbis_t *s,
+ uint_t samplerate);
+extern uint_t aubio_sink_vorbis_get_channels(aubio_sink_vorbis_t *s);
+extern uint_t aubio_sink_vorbis_get_samplerate(aubio_sink_vorbis_t *s);
+extern void aubio_sink_vorbis_do(aubio_sink_vorbis_t *s, fvec_t*
+ write_data, uint_t write);
+extern void aubio_sink_vorbis_do_multi(aubio_sink_vorbis_t *s, fmat_t*
+ write_data, uint_t write);
+#endif /* HAVE_VORBISENC */
+
+#ifdef HAVE_FLAC
+typedef struct _aubio_sink_flac_t aubio_sink_flac_t;
+extern aubio_sink_flac_t * new_aubio_sink_flac(const char_t *uri,
+ uint_t samplerate);
+extern void del_aubio_sink_flac (aubio_sink_flac_t *s);
+extern uint_t aubio_sink_flac_open(aubio_sink_flac_t *s);
+extern uint_t aubio_sink_flac_close(aubio_sink_flac_t *s);
+extern uint_t aubio_sink_flac_preset_channels(aubio_sink_flac_t *s,
+ uint_t channels);
+extern uint_t aubio_sink_flac_preset_samplerate(aubio_sink_flac_t *s,
+ uint_t samplerate);
+extern uint_t aubio_sink_flac_get_channels(aubio_sink_flac_t *s);
+extern uint_t aubio_sink_flac_get_samplerate(aubio_sink_flac_t *s);
+extern void aubio_sink_flac_do(aubio_sink_flac_t *s, fvec_t*
+ write_data, uint_t write);
+extern void aubio_sink_flac_do_multi(aubio_sink_flac_t *s, fmat_t*
+ write_data, uint_t write);
+#endif /* HAVE_FLAC */
+
aubio_sink_t * new_aubio_sink(const char_t * uri, uint_t samplerate) {
aubio_sink_t * s = AUBIO_NEW(aubio_sink_t);
+
+#ifdef HAVE_VORBISENC
+ // check if this uri could be for us
+ if (aubio_str_path_has_extension(uri, "ogg")) {
+ s->sink = (void *)new_aubio_sink_vorbis(uri, samplerate);
+ if (s->sink) {
+ s->s_do = (aubio_sink_do_t)(aubio_sink_vorbis_do);
+ s->s_do_multi = (aubio_sink_do_multi_t)(aubio_sink_vorbis_do_multi);
+ s->s_preset_samplerate = (aubio_sink_preset_samplerate_t)(aubio_sink_vorbis_preset_samplerate);
+ s->s_preset_channels = (aubio_sink_preset_channels_t)(aubio_sink_vorbis_preset_channels);
+ s->s_get_samplerate = (aubio_sink_get_samplerate_t)(aubio_sink_vorbis_get_samplerate);
+ s->s_get_channels = (aubio_sink_get_channels_t)(aubio_sink_vorbis_get_channels);
+ s->s_close = (aubio_sink_close_t)(aubio_sink_vorbis_close);
+ s->s_del = (del_aubio_sink_t)(del_aubio_sink_vorbis);
+ return s;
+ }
+ }
+#endif /* HAVE_VORBISENC */
+
+#ifdef HAVE_FLAC
+ // check if this uri could be for us
+ if (aubio_str_path_has_extension(uri, "flac")) {
+ s->sink = (void *)new_aubio_sink_flac(uri, samplerate);
+ if (s->sink) {
+ s->s_do = (aubio_sink_do_t)(aubio_sink_flac_do);
+ s->s_do_multi = (aubio_sink_do_multi_t)(aubio_sink_flac_do_multi);
+ s->s_preset_samplerate = (aubio_sink_preset_samplerate_t)(aubio_sink_flac_preset_samplerate);
+ s->s_preset_channels = (aubio_sink_preset_channels_t)(aubio_sink_flac_preset_channels);
+ s->s_get_samplerate = (aubio_sink_get_samplerate_t)(aubio_sink_flac_get_samplerate);
+ s->s_get_channels = (aubio_sink_get_channels_t)(aubio_sink_flac_get_channels);
+ s->s_close = (aubio_sink_close_t)(aubio_sink_flac_close);
+ s->s_del = (del_aubio_sink_t)(del_aubio_sink_flac);
+ return s;
+ }
+ }
+#endif /* HAVE_FLAC */
+
#ifdef HAVE_SINK_APPLE_AUDIO
s->sink = (void *)new_aubio_sink_apple_audio(uri, samplerate);
if (s->sink) {
#endif /* HAVE_WAVWRITE */
#if !defined(HAVE_WAVWRITE) && \
!defined(HAVE_SNDFILE) && \
- !defined(HAVE_SINK_APPLE_AUDIO)
+ !defined(HAVE_SINK_APPLE_AUDIO) && \
+ !defined(HAVE_VORBISENC) && \
+ !defined(HAVE_FLAC)
AUBIO_ERROR("sink: failed creating '%s' at %dHz (no sink built-in)\n", uri, samplerate);
#endif
del_aubio_sink(s);
uint_t aubio_sink_apple_audio_open(aubio_sink_apple_audio_t *s);
+uint_t aubio_str_extension_matches(const char_t *ext,
+ const char_t *pattern);
+const char_t *aubio_str_get_extension(const char_t *filename);
+
#define MAX_SIZE 4096 // the maximum number of frames that can be written at a time
void aubio_sink_apple_audio_write(aubio_sink_apple_audio_t *s, uint_t write);
AudioBufferList bufferList;
ExtAudioFileRef audioFile;
bool async;
+ AudioFileTypeID fileType;
};
aubio_sink_apple_audio_t * new_aubio_sink_apple_audio(const char_t * uri, uint_t samplerate) {
s->samplerate = 0;
s->channels = 0;
+ aubio_sink_apple_audio_preset_format(s, aubio_str_get_extension(uri));
+
// zero samplerate given. do not open yet
if ((sint_t)samplerate == 0) {
return s;
return AUBIO_OK;
}
+uint_t aubio_sink_apple_audio_preset_format(aubio_sink_apple_audio_t *s,
+ const char_t *fmt)
+{
+ if (aubio_str_extension_matches(fmt, "wav")) {
+ s->fileType = kAudioFileWAVEType;
+ } else if (aubio_str_extension_matches(fmt, "m4a")
+ || aubio_str_extension_matches(fmt, "mp4") ) {
+ // use alac for "mp4" and "m4a"
+ s->fileType = kAudioFileM4AType;
+ } else if (aubio_str_extension_matches(fmt, "aac") ) {
+ // only use lossy codec for "aac"
+ s->fileType = kAudioFileMPEG4Type;
+ } else if (aubio_str_extension_matches(fmt, "aiff") ) {
+ // only use lossy codec for "aac"
+ s->fileType = kAudioFileAIFFType;
+ } else {
+ s->fileType = kAudioFileWAVEType;
+ if (fmt && strnlen(fmt, PATH_MAX)) {
+ AUBIO_WRN("sink_apple_audio: could not guess format for %s,"
+ " using default (wav)\n", s->path);
+ return AUBIO_FAIL;
+ }
+ }
+ return AUBIO_OK;
+}
+
+static void aubio_sink_apple_audio_set_client_format(aubio_sink_apple_audio_t* s,
+ AudioStreamBasicDescription *clientFormat)
+{
+ memset(clientFormat, 0, sizeof(AudioStreamBasicDescription));
+ // always set samplerate and channels first
+ clientFormat->mSampleRate = (Float64)(s->samplerate);
+ clientFormat->mChannelsPerFrame = s->channels;
+
+ switch (s->fileType) {
+ case kAudioFileM4AType:
+ clientFormat->mFormatID = kAudioFormatAppleLossless;
+ break;
+ case kAudioFileMPEG4Type:
+ clientFormat->mFormatID = kAudioFormatMPEG4AAC;
+ clientFormat->mFormatFlags = kMPEG4Object_AAC_Main;
+ clientFormat->mFormatFlags |= kAppleLosslessFormatFlag_16BitSourceData;
+ clientFormat->mFramesPerPacket = 1024;
+ break;
+ case kAudioFileWAVEType:
+ clientFormat->mFormatID = kAudioFormatLinearPCM;
+ clientFormat->mFormatFlags = kAudioFormatFlagIsSignedInteger;
+ clientFormat->mFormatFlags |= kAudioFormatFlagIsPacked;
+ clientFormat->mBitsPerChannel = sizeof(short) * 8;
+ clientFormat->mFramesPerPacket = 1;
+ clientFormat->mBytesPerFrame = clientFormat->mBitsPerChannel * clientFormat->mChannelsPerFrame / 8;
+ clientFormat->mBytesPerPacket = clientFormat->mFramesPerPacket * clientFormat->mBytesPerFrame;
+ break;
+ case kAudioFileAIFFType:
+ clientFormat->mFormatID = kAudioFormatLinearPCM;
+ clientFormat->mFormatFlags = kAudioFormatFlagIsSignedInteger;
+ clientFormat->mFormatFlags |= kAudioFormatFlagIsPacked;
+ clientFormat->mFormatFlags |= kAudioFormatFlagIsBigEndian;
+ clientFormat->mBitsPerChannel = sizeof(short) * 8;
+ clientFormat->mFramesPerPacket = 1;
+ clientFormat->mBytesPerFrame = clientFormat->mBitsPerChannel * clientFormat->mChannelsPerFrame / 8;
+ clientFormat->mBytesPerPacket = clientFormat->mFramesPerPacket * clientFormat->mBytesPerFrame;
+ break;
+ default:
+ break;
+ }
+}
+
uint_t aubio_sink_apple_audio_get_samplerate(const aubio_sink_apple_audio_t *s)
{
return s->samplerate;
if (s->samplerate == 0 || s->channels == 0) return AUBIO_FAIL;
- AudioStreamBasicDescription clientFormat;
- memset(&clientFormat, 0, sizeof(AudioStreamBasicDescription));
- clientFormat.mFormatID = kAudioFormatLinearPCM;
- clientFormat.mSampleRate = (Float64)(s->samplerate);
- clientFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
- clientFormat.mChannelsPerFrame = s->channels;
- clientFormat.mBitsPerChannel = sizeof(short) * 8;
- clientFormat.mFramesPerPacket = 1;
- clientFormat.mBytesPerFrame = clientFormat.mBitsPerChannel * clientFormat.mChannelsPerFrame / 8;
- clientFormat.mBytesPerPacket = clientFormat.mFramesPerPacket * clientFormat.mBytesPerFrame;
- clientFormat.mReserved = 0;
-
- AudioFileTypeID fileType = kAudioFileWAVEType;
CFURLRef fileURL = createURLFromPath(s->path);
bool overwrite = true;
inputFormat.mFramesPerPacket = 1;
inputFormat.mBytesPerFrame = inputFormat.mBitsPerChannel * inputFormat.mChannelsPerFrame / 8;
inputFormat.mBytesPerPacket = inputFormat.mFramesPerPacket * inputFormat.mBytesPerFrame;
+
+ // get the in-file format
+ AudioStreamBasicDescription clientFormat;
+ aubio_sink_apple_audio_set_client_format(s, &clientFormat);
+
OSStatus err = noErr;
- err = ExtAudioFileCreateWithURL(fileURL, fileType, &clientFormat, NULL,
+ err = ExtAudioFileCreateWithURL(fileURL, s->fileType, &clientFormat, NULL,
overwrite ? kAudioFileFlags_EraseFile : 0, &s->audioFile);
CFRelease(fileURL);
if (err) {
goto beach;
}
+#if defined(kAppleSoftwareAudioCodecManufacturer)
+ // on iOS, set software based encoding before setting clientDataFormat
+ UInt32 codecManf = kAppleSoftwareAudioCodecManufacturer;
+ err = ExtAudioFileSetProperty(s->audioFile,
+ kExtAudioFileProperty_CodecManufacturer,
+ sizeof(UInt32), &codecManf);
+ if (err) {
+ char_t errorstr[20];
+ AUBIO_ERR("sink_apple_audio: error when trying to set sofware codec on %s "
+ "(%s)\n", s->path, getPrintableOSStatusError(errorstr, err));
+ goto beach;
+ }
+#endif
+
err = ExtAudioFileSetProperty(s->audioFile,
kExtAudioFileProperty_ClientDataFormat,
sizeof(AudioStreamBasicDescription), &inputFormat);
if (err) {
char_t errorstr[20];
if (err == kExtAudioFileError_AsyncWriteBufferOverflow) {
- sprintf(errorstr,"buffer overflow");
+ snprintf(errorstr, sizeof (errorstr), "buffer overflow");
} else if (err == kExtAudioFileError_AsyncWriteTooLarge) {
- sprintf(errorstr,"write too large");
+ snprintf(errorstr, sizeof (errorstr), "write too large");
} else {
// unknown error
getPrintableOSStatusError(errorstr, err);
/**
+ preset sink format
+
+ \param s sink, created with ::new_aubio_sink_apple_audio
+ \param fmt format of the file to create
+
+ \return 0 on success, 1 on error
+
+ Preset the format of the sink. Supported format strings:
+ - "wav": WAVE, 16 bit (default)
+ - "aiff": AIFF, 16 bit
+ - "m4a" or "mp4": Apple Audio Lossless Codec (ALAC)
+ - "aac": Audio Advanced Codec, lossy
+
+ Full list of supported encoding format is available in Table 1-2 of
+ `Multimedia Programming Guide
+ <https://developer.apple.com/library/archive/documentation/AudioVideo/Conceptual/MultimediaPG/UsingAudio/UsingAudio.html>`_.
+
+ */
+uint_t aubio_sink_apple_audio_preset_format(aubio_sink_apple_audio_t *s,
+ const char_t *fmt);
+
+/**
+
get samplerate of sink object
\param s sink object, created with ::new_aubio_sink_apple_audio
--- /dev/null
+/*
+ Copyright (C) 2018 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/*
+ This file is largely inspired by `examples/c/encode/file/main.c` in the
+ flac source package (versions 1.3.2 and later) available online at
+ https://xiph.org/flac/
+*/
+
+#include "aubio_priv.h"
+
+#ifdef HAVE_FLAC
+
+#include "fmat.h"
+#include "io/ioutils.h"
+
+#include <FLAC/metadata.h>
+#include <FLAC/stream_encoder.h>
+
+#define MAX_WRITE_SIZE 4096
+
+// swap host to little endian
+#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
+#define HTOLES(x) SWAPS(x)
+#elif defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
+#define HTOLES(x) x
+#else
+#ifdef HAVE_WIN_HACKS
+#define HTOLES(x) x
+#else
+#define HTOLES(x) SWAPS(htons(x))
+#endif
+#endif
+
+// convert to short, taking care of endianness
+#define FLOAT_TO_SHORT(x) (HTOLES((FLAC__int32)(x * 32768)))
+
+struct _aubio_sink_flac_t {
+ uint_t samplerate;
+ uint_t channels;
+ char_t *path;
+
+ FILE *fid; // file id
+ FLAC__StreamEncoder* encoder;
+ FLAC__int32 *buffer;
+ FLAC__StreamMetadata **metadata;
+};
+
+typedef struct _aubio_sink_flac_t aubio_sink_flac_t;
+
+uint_t aubio_sink_flac_preset_channels(aubio_sink_flac_t *s,
+ uint_t channels);
+uint_t aubio_sink_flac_preset_samplerate(aubio_sink_flac_t *s,
+ uint_t samplerate);
+uint_t aubio_sink_flac_open(aubio_sink_flac_t *s);
+uint_t aubio_sink_flac_close (aubio_sink_flac_t *s);
+void del_aubio_sink_flac (aubio_sink_flac_t *s);
+
+#if 0
+static void aubio_sink_flac_callback(const FLAC__StreamEncoder* encoder,
+ FLAC__uint64 bytes_written, FLAC__uint64 samples_written,
+ unsigned frames_writtten, unsigned total_frames_estimate,
+ void *client_data);
+#endif
+
+aubio_sink_flac_t * new_aubio_sink_flac (const char_t *uri,
+ uint_t samplerate)
+{
+ aubio_sink_flac_t * s = AUBIO_NEW(aubio_sink_flac_t);
+
+ if (!uri) {
+ AUBIO_ERROR("sink_flac: Aborted opening null path\n");
+ goto failure;
+ }
+
+ s->path = AUBIO_ARRAY(char_t, strnlen(uri, PATH_MAX) + 1);
+ strncpy(s->path, uri, strnlen(uri, PATH_MAX) + 1);
+ s->path[strnlen(uri, PATH_MAX)] = '\0';
+
+ s->channels = 0;
+ s->samplerate = 0;
+
+ if ((sint_t)samplerate == 0)
+ return s;
+
+ aubio_sink_flac_preset_samplerate(s, samplerate);
+ s->channels = 1;
+
+ if (aubio_sink_flac_open(s) != AUBIO_OK)
+ goto failure;
+
+ return s;
+
+failure:
+ del_aubio_sink_flac(s);
+ return NULL;
+}
+
+void del_aubio_sink_flac (aubio_sink_flac_t *s)
+{
+ if (s->fid)
+ aubio_sink_flac_close(s);
+ if (s->buffer)
+ AUBIO_FREE(s->buffer);
+ if (s->path)
+ AUBIO_FREE(s->path);
+ AUBIO_FREE(s);
+}
+
+uint_t aubio_sink_flac_open(aubio_sink_flac_t *s)
+{
+ uint_t ret = AUBIO_FAIL;
+ FLAC__bool ok = true;
+ FLAC__StreamEncoderInitStatus init_status;
+ FLAC__StreamMetadata_VorbisComment_Entry entry;
+ const unsigned comp_level = 5;
+ const unsigned bps = 16;
+
+ if (s->samplerate == 0 || s->channels == 0) return AUBIO_FAIL;
+
+ s->buffer = AUBIO_ARRAY(FLAC__int32, s->channels * MAX_WRITE_SIZE);
+ if (!s->buffer) {
+ AUBIO_ERR("sink_flac: failed allocating buffer for %s\n", s->path);
+ return AUBIO_FAIL;
+ }
+
+ s->fid = fopen((const char *)s->path, "wb");
+ if (!s->fid) {
+ AUBIO_STRERR("sink_flac: Failed opening %s (%s)\n", s->path, errorstr);
+ return AUBIO_FAIL;
+ }
+
+ if((s->encoder = FLAC__stream_encoder_new()) == NULL) {
+ AUBIO_ERR("sink_flac: failed allocating encoder for %s\n", s->path);
+ goto failure;
+ }
+ ok &= FLAC__stream_encoder_set_verify(s->encoder, true);
+ ok &= FLAC__stream_encoder_set_compression_level(s->encoder, comp_level);
+ ok &= FLAC__stream_encoder_set_channels(s->encoder, s->channels);
+ ok &= FLAC__stream_encoder_set_bits_per_sample(s->encoder, bps);
+ ok &= FLAC__stream_encoder_set_sample_rate(s->encoder, s->samplerate);
+ // the total number of samples can not be estimated (streaming)
+ // it will be set by the encoder in FLAC__stream_encoder_finish
+ //ok &= FLAC__stream_encoder_set_total_samples_estimate(s->encoder, 0);
+
+ if (!ok) {
+ AUBIO_ERR("sink_flac: failed setting metadata for %s\n", s->path);
+ goto failure;
+ }
+
+ s->metadata = AUBIO_ARRAY(FLAC__StreamMetadata*, 2);
+ if (!s->metadata) {
+ AUBIO_ERR("sink_flac: failed allocating memory for %s\n", s->path);
+ goto failure;
+ }
+
+ s->metadata[0] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT);
+ if (!s->metadata[0]) {
+ AUBIO_ERR("sink_flac: failed allocating vorbis comment %s\n", s->path);
+ goto failure;
+ }
+
+ s->metadata[1] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING);
+ if (!s->metadata[1]) {
+ AUBIO_ERR("sink_flac: failed allocating vorbis comment %s\n", s->path);
+ goto failure;
+ }
+
+ ok = FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry,
+ "encoder", "aubio");
+ ok &= FLAC__metadata_object_vorbiscomment_append_comment(s->metadata[0],
+ entry, false);
+ if (!ok) {
+ AUBIO_ERR("sink_flac: failed setting metadata for %s\n", s->path);
+ goto failure;
+ }
+
+ // padding length
+ s->metadata[1]->length = 1234;
+ if (!FLAC__stream_encoder_set_metadata(s->encoder, s->metadata, 2)) {
+ AUBIO_ERR("sink_flac: failed setting metadata for %s\n", s->path);
+ goto failure;
+ }
+
+ // initialize encoder
+ init_status = FLAC__stream_encoder_init_file(s->encoder, s->path,
+ NULL, NULL);
+ //aubio_sink_flac_callback, s);
+ if (init_status == FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_SAMPLE_RATE) {
+ AUBIO_ERR("sink_flac: failed initilizing encoder for %s"
+ " (invalid samplerate %d)\n", s->path, s->samplerate);
+ goto failure;
+ } else if (init_status ==
+ FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_NUMBER_OF_CHANNELS) {
+ AUBIO_ERR("sink_flac: failed initilizing encoder for %s"
+ " (invalid number of channel %d)\n", s->path, s->channels);
+ goto failure;
+ } else if (init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) {
+ AUBIO_ERR("sink_flac: failed initilizing encoder for %s (%d)\n",
+ s->path, (int)init_status);
+ goto failure;
+ }
+
+ // mark success
+ ret = AUBIO_OK;
+
+failure:
+
+ return ret;
+}
+
+uint_t aubio_sink_flac_preset_samplerate(aubio_sink_flac_t *s,
+ uint_t samplerate)
+{
+ if (aubio_io_validate_samplerate("sink_flac", s->path, samplerate))
+ return AUBIO_FAIL;
+ s->samplerate = samplerate;
+ if (s->samplerate != 0 && s->channels != 0)
+ return aubio_sink_flac_open(s);
+ return AUBIO_OK;
+}
+
+uint_t aubio_sink_flac_preset_channels(aubio_sink_flac_t *s,
+ uint_t channels)
+{
+ if (aubio_io_validate_channels("sink_flac", s->path, channels)) {
+ return AUBIO_FAIL;
+ }
+ s->channels = channels;
+ // automatically open when both samplerate and channels have been set
+ if (s->samplerate != 0 && s->channels != 0) {
+ return aubio_sink_flac_open(s);
+ }
+ return AUBIO_OK;
+}
+
+uint_t aubio_sink_flac_get_samplerate(const aubio_sink_flac_t *s)
+{
+ return s->samplerate;
+}
+
+uint_t aubio_sink_flac_get_channels(const aubio_sink_flac_t *s)
+{
+ return s->channels;
+}
+
+static void aubio_sink_write_frames(aubio_sink_flac_t *s, uint_t length)
+{
+ // send to encoder
+ if (!FLAC__stream_encoder_process_interleaved(s->encoder,
+ (const FLAC__int32*)s->buffer, length)) {
+ FLAC__StreamEncoderState state =
+ FLAC__stream_encoder_get_state(s->encoder);
+ AUBIO_WRN("sink_flac: error writing to %s (%s)\n",
+ s->path, FLAC__StreamEncoderStateString[state]);
+ }
+}
+
+void aubio_sink_flac_do(aubio_sink_flac_t *s, fvec_t *write_data,
+ uint_t write)
+{
+ uint_t c, v;
+ uint_t length = aubio_sink_validate_input_length("sink_flac", s->path,
+ MAX_WRITE_SIZE, write_data->length, write);
+ // fill buffer
+ if (!write) {
+ return;
+ } else {
+ for (c = 0; c < s->channels; c++) {
+ for (v = 0; v < length; v++) {
+ s->buffer[v * s->channels + c] = FLOAT_TO_SHORT(write_data->data[v]);
+ }
+ }
+ }
+ // send to encoder
+ aubio_sink_write_frames(s, length);
+}
+
+void aubio_sink_flac_do_multi(aubio_sink_flac_t *s, fmat_t *write_data,
+ uint_t write)
+{
+ uint_t c, v;
+ uint_t channels = aubio_sink_validate_input_channels("sink_flac", s->path,
+ s->channels, write_data->height);
+ uint_t length = aubio_sink_validate_input_length("sink_flac", s->path,
+ MAX_WRITE_SIZE, write_data->length, write);
+ // fill buffer
+ if (!write) {
+ return;
+ } else {
+ for (c = 0; c < channels; c++) {
+ for (v = 0; v < length; v++) {
+ s->buffer[v * s->channels + c] = FLOAT_TO_SHORT(write_data->data[c][v]);
+ }
+ }
+ }
+ // send to encoder
+ aubio_sink_write_frames(s, length);
+}
+
+uint_t aubio_sink_flac_close (aubio_sink_flac_t *s)
+{
+ uint_t ret = AUBIO_OK;
+
+ if (!s->fid) return AUBIO_FAIL;
+
+ if (s->encoder) {
+ // mark the end of stream
+ if (!FLAC__stream_encoder_finish(s->encoder)) {
+ FLAC__StreamEncoderState state =
+ FLAC__stream_encoder_get_state(s->encoder);
+ AUBIO_ERR("sink_flac: Error closing encoder for %s (%s)\n",
+ s->path, FLAC__StreamEncoderStateString[state]);
+ ret &= AUBIO_FAIL;
+ }
+
+ FLAC__stream_encoder_delete(s->encoder);
+ }
+
+ if (s->metadata) {
+ // clean up metadata after stream finished
+ if (s->metadata[0])
+ FLAC__metadata_object_delete(s->metadata[0]);
+ if (s->metadata[1])
+ FLAC__metadata_object_delete(s->metadata[1]);
+ AUBIO_FREE(s->metadata);
+ }
+
+ if (s->fid && fclose(s->fid)) {
+ AUBIO_STRERR("sink_flac: Error closing file %s (%s)\n", s->path, errorstr);
+ ret &= AUBIO_FAIL;
+ }
+ s->fid = NULL;
+
+ return ret;
+}
+
+#if 0
+static void aubio_sink_flac_callback(const FLAC__StreamEncoder* encoder UNUSED,
+ FLAC__uint64 bytes_written, FLAC__uint64 samples_written,
+ unsigned frames_written, unsigned total_frames_estimate,
+ void *client_data UNUSED)
+{
+ AUBIO_WRN("sink_flac: %d bytes_written, %d samples_written,"
+ " %d/%d frames writen\n",
+ bytes_written, samples_written, frames_written, total_frames_estimate);
+}
+#endif
+
+#endif /* HAVE_FLAC */
SNDFILE *handle;
uint_t scratch_size;
smpl_t *scratch_data;
+ int format;
};
uint_t aubio_sink_sndfile_open(aubio_sink_sndfile_t *s);
+uint_t aubio_str_extension_matches(const char_t *ext,
+ const char_t *pattern);
+const char_t *aubio_str_get_extension(const char_t *filename);
+
aubio_sink_sndfile_t * new_aubio_sink_sndfile(const char_t * path, uint_t samplerate) {
aubio_sink_sndfile_t * s = AUBIO_NEW(aubio_sink_sndfile_t);
s->max_size = MAX_SIZE;
s->samplerate = 0;
s->channels = 0;
+ aubio_sink_sndfile_preset_format(s, aubio_str_get_extension(path));
+
// zero samplerate given. do not open yet
if ((sint_t)samplerate == 0) {
return s;
return AUBIO_OK;
}
+uint_t aubio_sink_sndfile_preset_format(aubio_sink_sndfile_t *s,
+ const char_t *fmt)
+{
+ if (aubio_str_extension_matches(fmt, "wav")) {
+ s->format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
+ } else if (aubio_str_extension_matches(fmt, "aiff")) {
+ s->format = SF_FORMAT_AIFF | SF_FORMAT_PCM_16;
+ } else if (aubio_str_extension_matches(fmt, "flac")) {
+ s->format = SF_FORMAT_FLAC | SF_FORMAT_PCM_16;
+ } else if (aubio_str_extension_matches(fmt, "ogg")) {
+ s->format = SF_FORMAT_OGG | SF_FORMAT_VORBIS;
+ } else if (atoi(fmt) > 0x010000) {
+ s->format = atoi(fmt);
+ } else {
+ s->format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
+ if (fmt && strnlen(fmt, PATH_MAX)) {
+ AUBIO_WRN("sink_sndfile: could not guess format %s for %s,"
+ " using default (wav)\n", fmt, s->path);
+ return AUBIO_FAIL;
+ }
+ }
+ return AUBIO_OK;
+}
+
uint_t aubio_sink_sndfile_get_samplerate(const aubio_sink_sndfile_t *s)
{
return s->samplerate;
AUBIO_MEMSET(&sfinfo, 0, sizeof (sfinfo));
sfinfo.samplerate = s->samplerate;
sfinfo.channels = s->channels;
- sfinfo.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
+ sfinfo.format = s->format;
/* try creating the file */
s->handle = sf_open (s->path, SFM_WRITE, &sfinfo);
/**
+ preset sink format
+
+ \param s sink, created with ::new_aubio_sink_sndfile
+ \param fmt format of the file to create
+
+ \return 0 on success, 1 on error
+
+ Preset the format of the sink. Supported format strings:
+ - "wav": 16 bit (default)
+ - "aiff": aiff, 16 bit
+ - "flac": flac, 16 bit
+ - "ogg": ogg vorbis stream
+
+ Alternatively, any sndfile format can be set by passing the corresponding
+ integer as a string:
+
+ \code{.c}
+ char_t fmt[10];
+ snprintf(fmt, sizeof(fmt), "%d", SF_FORMAT_FLAC | SF_FORMAT_PCM_24);
+ aubio_sink_sndfile_preset_format(s, fmt);
+ \endcode
+
+ The file should have been created using a samplerate of 0.
+
+ This function should be called before aubio_sink_sndfile_preset_samplerate()
+ and aubio_sink_sndfile_preset_channels().
+
+*/
+uint_t aubio_sink_sndfile_preset_format(aubio_sink_sndfile_t *s,
+ const char_t* fmt);
+
+/**
+
get samplerate of sink object
\param s sink object, created with ::new_aubio_sink_sndfile
--- /dev/null
+/*
+ Copyright (C) 2018 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/*
+ This file is largely inspired by `examples/encoder_example.c` in the
+ libvorbis source package (versions 1.3.5 and later) available online at
+ https://xiph.org/vorbis/
+*/
+
+#include "aubio_priv.h"
+
+#ifdef HAVE_VORBISENC
+
+#include "fmat.h"
+#include "io/ioutils.h"
+
+#include <vorbis/vorbisenc.h>
+#include <string.h> // strerror
+#include <errno.h> // errno
+#include <time.h> // time
+
+#define MAX_SIZE 4096
+
+struct _aubio_sink_vorbis_t {
+ FILE *fid; // file id
+ ogg_stream_state os; // stream
+ ogg_page og; // page
+ ogg_packet op; // data packet
+ vorbis_info vi; // vorbis bitstream settings
+ vorbis_comment vc; // user comment
+ vorbis_dsp_state vd; // working state
+ vorbis_block vb; // working space
+
+ uint_t samplerate;
+ uint_t channels;
+ char_t *path;
+};
+
+typedef struct _aubio_sink_vorbis_t aubio_sink_vorbis_t;
+
+uint_t aubio_sink_vorbis_preset_channels(aubio_sink_vorbis_t *s,
+ uint_t channels);
+uint_t aubio_sink_vorbis_preset_samplerate(aubio_sink_vorbis_t *s,
+ uint_t samplerate);
+uint_t aubio_sink_vorbis_open(aubio_sink_vorbis_t *s);
+uint_t aubio_sink_vorbis_close (aubio_sink_vorbis_t *s);
+void del_aubio_sink_vorbis (aubio_sink_vorbis_t *s);
+
+static uint_t aubio_sink_vorbis_write_page(aubio_sink_vorbis_t *s);
+
+aubio_sink_vorbis_t * new_aubio_sink_vorbis (const char_t *uri,
+ uint_t samplerate)
+{
+ aubio_sink_vorbis_t * s = AUBIO_NEW(aubio_sink_vorbis_t);
+
+ if (!uri) {
+ AUBIO_ERROR("sink_vorbis: Aborted opening null path\n");
+ goto failure;
+ }
+
+ s->path = AUBIO_ARRAY(char_t, strnlen(uri, PATH_MAX) + 1);
+ strncpy(s->path, uri, strnlen(uri, PATH_MAX) + 1);
+ s->path[strnlen(uri, PATH_MAX)] = '\0';
+
+ s->channels = 0;
+
+ if ((sint_t)samplerate == 0)
+ return s;
+
+ aubio_sink_vorbis_preset_samplerate(s, samplerate);
+ s->channels = 1;
+
+ if (aubio_sink_vorbis_open(s) != AUBIO_OK)
+ goto failure;
+
+ return s;
+
+failure:
+ del_aubio_sink_vorbis(s);
+ return NULL;
+}
+
+void del_aubio_sink_vorbis (aubio_sink_vorbis_t *s)
+{
+ if (s->fid) aubio_sink_vorbis_close(s);
+ // clean up
+ ogg_stream_clear(&s->os);
+ vorbis_block_clear(&s->vb);
+ vorbis_dsp_clear(&s->vd);
+ vorbis_comment_clear(&s->vc);
+ vorbis_info_clear(&s->vi);
+
+ if (s->path) AUBIO_FREE(s->path);
+ AUBIO_FREE(s);
+}
+
+uint_t aubio_sink_vorbis_open(aubio_sink_vorbis_t *s)
+{
+ float quality_mode = .9;
+
+ if (s->samplerate == 0 || s->channels == 0) return AUBIO_FAIL;
+
+ s->fid = fopen((const char *)s->path, "wb");
+ if (!s->fid) {
+ AUBIO_STRERR("sink_vorbis: Error opening file \'%s\' (%s)\n",
+ s->path, errorstr);
+ return AUBIO_FAIL;
+ }
+
+ vorbis_info_init(&s->vi);
+ if (vorbis_encode_init_vbr(&s->vi, s->channels, s->samplerate, quality_mode))
+ {
+ AUBIO_ERR("sink_vorbis: vorbis_encode_init_vbr failed\n");
+ return AUBIO_FAIL;
+ }
+
+ // add comment
+ vorbis_comment_init(&s->vc);
+ vorbis_comment_add_tag(&s->vc, "ENCODER", "aubio");
+
+ // initalise analysis and block
+ vorbis_analysis_init(&s->vd, &s->vi);
+ vorbis_block_init(&s->vd, &s->vb);
+
+ // pick randome serial number
+ srand(time(NULL));
+ ogg_stream_init(&s->os, rand());
+
+ // write header
+ {
+ ogg_packet header;
+ ogg_packet header_comm;
+ ogg_packet header_code;
+
+ vorbis_analysis_headerout(&s->vd, &s->vc, &header, &header_comm,
+ &header_code);
+
+ ogg_stream_packetin(&s->os, &header);
+ ogg_stream_packetin(&s->os, &header_comm);
+ ogg_stream_packetin(&s->os, &header_code);
+
+ // make sure audio data will start on a new page
+ while (1)
+ {
+ if (!ogg_stream_flush(&s->os, &s->og)) break;
+ if (aubio_sink_vorbis_write_page(s)) return AUBIO_FAIL;
+ }
+ }
+
+ return AUBIO_OK;
+}
+
+uint_t aubio_sink_vorbis_preset_samplerate(aubio_sink_vorbis_t *s,
+ uint_t samplerate)
+{
+ if (aubio_io_validate_samplerate("sink_vorbis", s->path, samplerate))
+ return AUBIO_FAIL;
+ s->samplerate = samplerate;
+ if (/* s->samplerate != 0 && */ s->channels != 0)
+ return aubio_sink_vorbis_open(s);
+ return AUBIO_OK;
+}
+
+uint_t aubio_sink_vorbis_preset_channels(aubio_sink_vorbis_t *s,
+ uint_t channels)
+{
+ if (aubio_io_validate_channels("sink_vorbis", s->path, channels)) {
+ return AUBIO_FAIL;
+ }
+ s->channels = channels;
+ // automatically open when both samplerate and channels have been set
+ if (s->samplerate != 0 /* && s->channels != 0 */) {
+ return aubio_sink_vorbis_open(s);
+ }
+ return AUBIO_OK;
+}
+
+uint_t aubio_sink_vorbis_get_samplerate(const aubio_sink_vorbis_t *s)
+{
+ return s->samplerate;
+}
+
+uint_t aubio_sink_vorbis_get_channels(const aubio_sink_vorbis_t *s)
+{
+ return s->channels;
+}
+
+static
+uint_t aubio_sink_vorbis_write_page(aubio_sink_vorbis_t *s) {
+ int result;
+ size_t wrote;
+ wrote = fwrite(s->og.header, 1, s->og.header_len, s->fid);
+ result = (wrote == (unsigned)s->og.header_len);
+ wrote = fwrite(s->og.body, 1, s->og.body_len, s->fid);
+ result &= (wrote == (unsigned)s->og.body_len);
+ if (result == 0) {
+ AUBIO_STRERR("sink_vorbis: failed writing \'%s\' to disk (%s)\n",
+ s->path, errorstr);
+ return AUBIO_FAIL;
+ }
+ return AUBIO_OK;
+}
+
+static
+void aubio_sink_vorbis_write(aubio_sink_vorbis_t *s)
+{
+ // pre-analysis
+ while (vorbis_analysis_blockout(&s->vd, &s->vb) == 1) {
+
+ vorbis_analysis(&s->vb, NULL);
+ vorbis_bitrate_addblock(&s->vb);
+
+ while (vorbis_bitrate_flushpacket(&s->vd, &s->op))
+ {
+ ogg_stream_packetin(&s->os, &s->op);
+
+ while (1) {
+ if (!ogg_stream_pageout (&s->os, &s->og)) break;
+ aubio_sink_vorbis_write_page(s);
+ if (ogg_page_eos(&s->og)) break;
+ }
+ }
+ }
+}
+
+void aubio_sink_vorbis_do(aubio_sink_vorbis_t *s, fvec_t *write_data,
+ uint_t write)
+{
+ uint_t c, v;
+ uint_t length = aubio_sink_validate_input_length("sink_vorbis", s->path,
+ MAX_SIZE, write_data->length, write);
+ float **buffer = vorbis_analysis_buffer(&s->vd, (long)length);
+ // fill buffer
+ if (!write) {
+ return;
+ } else if (!buffer) {
+ AUBIO_WRN("sink_vorbis: failed fetching buffer of size %d\n", write);
+ return;
+ } else {
+ for (c = 0; c < s->channels; c++) {
+ for (v = 0; v < length; v++) {
+ buffer[c][v] = write_data->data[v];
+ }
+ }
+ // tell vorbis how many frames were written
+ vorbis_analysis_wrote(&s->vd, (long)length);
+ }
+ // write to file
+ aubio_sink_vorbis_write(s);
+}
+
+void aubio_sink_vorbis_do_multi(aubio_sink_vorbis_t *s, fmat_t *write_data,
+ uint_t write)
+{
+ uint_t c, v;
+ uint_t channels = aubio_sink_validate_input_channels("sink_vorbis", s->path,
+ s->channels, write_data->height);
+ uint_t length = aubio_sink_validate_input_length("sink_vorbis", s->path,
+ MAX_SIZE, write_data->length, write);
+ float **buffer = vorbis_analysis_buffer(&s->vd, (long)length);
+ // fill buffer
+ if (!write) {
+ return;
+ } else if (!buffer) {
+ AUBIO_WRN("sink_vorbis: failed fetching buffer of size %d\n", write);
+ return;
+ } else {
+ for (c = 0; c < channels; c++) {
+ for (v = 0; v < length; v++) {
+ buffer[c][v] = write_data->data[c][v];
+ }
+ }
+ // tell vorbis how many frames were written
+ vorbis_analysis_wrote(&s->vd, (long)length);
+ }
+
+ aubio_sink_vorbis_write(s);
+}
+
+uint_t aubio_sink_vorbis_close (aubio_sink_vorbis_t *s)
+{
+ if (!s->fid) return AUBIO_FAIL;
+ //mark the end of stream
+ vorbis_analysis_wrote(&s->vd, 0);
+
+ aubio_sink_vorbis_write(s);
+
+ if (s->fid && fclose(s->fid)) {
+ AUBIO_STRERR("sink_vorbis: Error closing file \'%s\' (%s)\n",
+ s->path, errorstr);
+ return AUBIO_FAIL;
+ }
+ s->fid = NULL;
+ return AUBIO_OK;
+}
+
+#endif /* HAVE_VORBISENC */
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
-#if defined(HAVE_SWRESAMPLE)
#include <libswresample/swresample.h>
-#elif defined(HAVE_AVRESAMPLE)
-#include <libavresample/avresample.h>
-#endif
#include <libavutil/opt.h>
// determine whether we use libavformat from ffmpeg or from libav
#define av_packet_unref av_free_packet
#endif
+#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(57,28,100)
+//#warning "libavutil < 57.28.100 is deprecated"
+#else
+#define LIBAVUTIL_HAS_CH_LAYOUT
+#endif
+
#include "aubio_priv.h"
#include "fvec.h"
#include "fmat.h"
#define AUBIO_AVCODEC_MAX_BUFFER_SIZE AV_INPUT_BUFFER_MIN_SIZE
#endif
+#if LIBAVCODEC_VERSION_MAJOR >= 59
+#define FF_API_LAVF_AVCTX 1
+#endif
+
struct _aubio_source_avcodec_t {
uint_t hop_size;
uint_t samplerate;
AVFormatContext *avFormatCtx;
AVCodecContext *avCodecCtx;
AVFrame *avFrame;
+#if FF_API_INIT_PACKET
+ AVPacket *avPacket;
+#else
AVPacket avPacket;
-#ifdef HAVE_AVRESAMPLE
- AVAudioResampleContext *avr;
-#elif defined(HAVE_SWRESAMPLE)
- SwrContext *avr;
#endif
+ SwrContext *avr;
smpl_t *output;
uint_t read_samples;
uint_t read_index;
AVFormatContext *avFormatCtx = NULL;
AVCodecContext *avCodecCtx = NULL;
AVFrame *avFrame = NULL;
+#if FF_API_INIT_PACKET
+ AVPacket *avPacket = NULL;
+#endif
sint_t selected_stream = -1;
#if FF_API_LAVF_AVCTX
AVCodecParameters *codecpar;
#endif
- AVCodec *codec;
+
+ const AVCodec *codec;
uint_t i;
int err;
if (path == NULL) {
/* get input specs */
s->input_samplerate = avCodecCtx->sample_rate;
+#ifdef LIBAVUTIL_HAS_CH_LAYOUT
+ s->input_channels = avCodecCtx->ch_layout.nb_channels;
+#else
s->input_channels = avCodecCtx->channels;
+#endif
//AUBIO_DBG("input_samplerate: %d\n", s->input_samplerate);
//AUBIO_DBG("input_channels: %d\n", s->input_channels);
avFrame = av_frame_alloc();
if (!avFrame) {
AUBIO_ERR("source_avcodec: Could not allocate frame for (%s)\n", s->path);
+ goto beach;
+ }
+
+#if FF_API_INIT_PACKET
+ avPacket = av_packet_alloc();
+ if (!avPacket) {
+ AUBIO_ERR("source_avcodec: Could not allocate packet for (%s)\n", s->path);
+ goto beach;
}
+#endif
/* allocate output for avr */
s->output = (smpl_t *)av_malloc(AUBIO_AVCODEC_MAX_BUFFER_SIZE
s->avFormatCtx = avFormatCtx;
s->avCodecCtx = avCodecCtx;
s->avFrame = avFrame;
+#if FF_API_INIT_PACKET
+ s->avPacket = avPacket;
+#endif
aubio_source_avcodec_reset_resampler(s);
// create or reset resampler to/from mono/multi-channel
if ( s->avr == NULL ) {
int err;
+ SwrContext *avr = swr_alloc();
+#ifdef LIBAVUTIL_HAS_CH_LAYOUT
+ AVChannelLayout input_layout;
+ AVChannelLayout output_layout;
+ av_channel_layout_default(&input_layout, s->input_channels);
+ av_channel_layout_default(&output_layout, s->input_channels);
+
+ av_opt_set_chlayout(avr, "in_channel_layout", &input_layout, 0);
+ av_opt_set_chlayout(avr, "out_channel_layout", &output_layout, 0);
+#else
int64_t input_layout = av_get_default_channel_layout(s->input_channels);
int64_t output_layout = av_get_default_channel_layout(s->input_channels);
-#ifdef HAVE_AVRESAMPLE
- AVAudioResampleContext *avr = avresample_alloc_context();
-#elif defined(HAVE_SWRESAMPLE)
- SwrContext *avr = swr_alloc();
-#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);
+#endif
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);
#endif
// TODO: use planar?
//av_opt_set_int(avr, "out_sample_fmt", AV_SAMPLE_FMT_FLTP, 0);
-#ifdef HAVE_AVRESAMPLE
- if ( ( err = avresample_open(avr) ) < 0)
-#elif defined(HAVE_SWRESAMPLE)
if ( ( err = swr_init(avr) ) < 0)
-#endif /* HAVE_AVRESAMPLE || HAVE_SWRESAMPLE */
{
char errorstr[256];
av_strerror (err, errorstr, sizeof(errorstr));
AVFormatContext *avFormatCtx = s->avFormatCtx;
AVCodecContext *avCodecCtx = s->avCodecCtx;
AVFrame *avFrame = s->avFrame;
- AVPacket avPacket = s->avPacket;
-#ifdef HAVE_AVRESAMPLE
- AVAudioResampleContext *avr = s->avr;
-#elif defined(HAVE_SWRESAMPLE)
+#if FF_API_INIT_PACKET
+ AVPacket *avPacket = s->avPacket;
+#else
+ AVPacket *avPacket = &s->avPacket;
+#endif
SwrContext *avr = s->avr;
-#endif /* HAVE_AVRESAMPLE || HAVE_SWRESAMPLE */
int got_frame = 0;
-#ifdef HAVE_AVRESAMPLE
- int in_linesize = 0;
- int in_samples = avFrame->nb_samples;
- int out_linesize = 0;
- int max_out_samples = AUBIO_AVCODEC_MAX_BUFFER_SIZE;
- int out_samples = 0;
-#elif defined(HAVE_SWRESAMPLE)
int in_samples = avFrame->nb_samples;
+#ifdef LIBAVUTIL_HAS_CH_LAYOUT
+ int max_out_samples = AUBIO_AVCODEC_MAX_BUFFER_SIZE / avCodecCtx->ch_layout.nb_channels;
+#else
int max_out_samples = AUBIO_AVCODEC_MAX_BUFFER_SIZE / avCodecCtx->channels;
+#endif
int out_samples = 0;
-#endif /* HAVE_AVRESAMPLE || HAVE_SWRESAMPLE */
smpl_t *output = s->output;
#ifndef FF_API_LAVF_AVCTX
int len = 0;
#else
int ret = 0;
#endif
- av_init_packet (&avPacket);
+#ifndef FF_API_INIT_PACKET
+ av_init_packet (avPacket);
+#endif
*read_samples = 0;
do
{
- int err = av_read_frame (avFormatCtx, &avPacket);
+ int err = av_read_frame (avFormatCtx, avPacket);
if (err == AVERROR_EOF) {
s->eof = 1;
goto beach;
s->eof = 1;
goto beach;
}
- } while (avPacket.stream_index != s->selected_stream);
+ } while (avPacket->stream_index != s->selected_stream);
#if FF_API_LAVF_AVCTX
- ret = avcodec_send_packet(avCodecCtx, &avPacket);
+ ret = avcodec_send_packet(avCodecCtx, avPacket);
if (ret < 0 && ret != AVERROR_EOF) {
AUBIO_ERR("source_avcodec: error when sending packet for %s\n", s->path);
goto beach;
}
}
#else
- len = avcodec_decode_audio4(avCodecCtx, avFrame, &got_frame, &avPacket);
+ len = avcodec_decode_audio4(avCodecCtx, avFrame, &got_frame, avPacket);
if (len < 0) {
AUBIO_ERR("source_avcodec: error while decoding %s\n", s->path);
}
#if LIBAVUTIL_VERSION_MAJOR > 52
- if (avFrame->channels != (sint_t)s->input_channels) {
+#ifdef LIBAVUTIL_HAS_CH_LAYOUT
+ int frame_channels = avFrame->ch_layout.nb_channels;
+#else
+ int frame_channels = avFrame->channels;
+#endif
+ if (frame_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);
+ frame_channels, s->input_channels, s->path);
goto beach;
}
#else
#warning "avutil < 53 is deprecated, crashes might occur on corrupt files"
#endif
-#ifdef HAVE_AVRESAMPLE
- in_linesize = 0;
- av_samples_get_buffer_size(&in_linesize, avCodecCtx->channels,
- avFrame->nb_samples, avCodecCtx->sample_fmt, 1);
in_samples = avFrame->nb_samples;
- out_linesize = 0;
max_out_samples = AUBIO_AVCODEC_MAX_BUFFER_SIZE;
- out_samples = avresample_convert ( avr,
- (uint8_t **)&output, out_linesize, max_out_samples,
- (uint8_t **)avFrame->data, in_linesize, in_samples);
-#elif defined(HAVE_SWRESAMPLE)
- in_samples = avFrame->nb_samples;
- max_out_samples = AUBIO_AVCODEC_MAX_BUFFER_SIZE / avCodecCtx->channels;
+ if (frame_channels > 0) max_out_samples /= frame_channels;
out_samples = swr_convert( avr,
(uint8_t **)&output, max_out_samples,
(const uint8_t **)avFrame->data, in_samples);
-#endif /* HAVE_AVRESAMPLE || HAVE_SWRESAMPLE */
if (out_samples < 0) {
AUBIO_WRN("source_avcodec: error while resampling %s (%d)\n",
s->path, out_samples);
*read_samples = out_samples;
beach:
- av_packet_unref(&avPacket);
+ av_packet_unref(avPacket);
}
void aubio_source_avcodec_do(aubio_source_avcodec_t * s, fvec_t * read_data,
s->eof = 0;
s->read_index = 0;
s->read_samples = 0;
-#ifdef HAVE_AVRESAMPLE
- // reset the AVAudioResampleContext
- avresample_close(s->avr);
- avresample_open(s->avr);
-#elif defined(HAVE_SWRESAMPLE)
swr_close(s->avr);
swr_init(s->avr);
-#endif
return ret;
}
uint_t aubio_source_avcodec_close(aubio_source_avcodec_t * s) {
if (s->avr != NULL) {
-#ifdef HAVE_AVRESAMPLE
- avresample_close( s->avr );
- av_free ( s->avr );
-#elif defined(HAVE_SWRESAMPLE)
swr_close ( s->avr );
swr_free ( &s->avr );
-#endif
}
s->avr = NULL;
if (s->avCodecCtx != NULL) {
avformat_close_input(&s->avFormatCtx);
s->avFormatCtx = NULL;
}
+#if FF_API_INIT_PACKET
+ if (s->avPacket) {
+ av_packet_unref(s->avPacket);
+ }
+#else
av_packet_unref(&s->avPacket);
+#endif
return AUBIO_OK;
}
av_frame_free( &(s->avFrame) );
}
s->avFrame = NULL;
+#if FF_API_INIT_PACKET
+ if (s->avPacket != NULL) {
+ av_packet_free( &(s->avPacket) );
+ }
+ s->avPacket = NULL;
+#endif
if (s->path) {
AUBIO_FREE(s->path);
}
str[6] = '\0';
} else
// no, format it as an integer
- sprintf(str, "%d", (int)error);
+ snprintf(str, 10, "%d", (int)error);
return str;
}
\param v vector to get level from
\param threshold threshold in dB SPL
- \return 0 if level is under the given threshold, 1 otherwise
+ \return 1 if level is under the given threshold, 0 otherwise
*/
uint_t aubio_silence_detection (const fvec_t * v, smpl_t threshold);
--- /dev/null
+/*
+ Copyright (C) 2018 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "aubio_priv.h"
+
+#ifdef HAVE_WIN_HACKS
+#define strncasecmp _strnicmp
+#endif
+
+const char_t *aubio_str_get_extension(const char_t *filename)
+{
+ // find last occurence of dot character
+ const char_t *ext;
+ if (!filename) return NULL;
+ ext = strrchr(filename, '.');
+ if (!ext || ext == filename) return "";
+ else return ext + 1;
+}
+
+uint_t aubio_str_extension_matches(const char_t *ext, const char_t *pattern)
+{
+ return ext && pattern && (strncasecmp(ext, pattern, PATH_MAX) == 0);
+}
+
+uint_t aubio_str_path_has_extension(const char_t *filename,
+ const char_t *pattern)
+{
+ const char_t *ext = aubio_str_get_extension(filename);
+ return aubio_str_extension_matches(ext, pattern);
+}
uselib += ['INTEL_IPP']
uselib += ['SAMPLERATE']
uselib += ['SNDFILE']
+uselib += ['RUBBERBAND']
uselib += ['AVCODEC']
uselib += ['AVFORMAT']
uselib += ['SWRESAMPLE']
-uselib += ['AVRESAMPLE']
uselib += ['AVUTIL']
+uselib += ['VORBISENC']
+uselib += ['FLAC']
uselib += ['BLAS']
source = ctx.path.ant_glob('*.c **/*.c')
--- /dev/null
+#define AUBIO_UNSTABLE 1
+#include <aubio.h>
+#include "utils_tests.h"
+
+int test_wrong_params(void);
+
+int main (int argc, char **argv)
+{
+ sint_t err = 0;
+
+ if (argc < 3) {
+ PRINT_ERR("not enough arguments, running tests\n");
+ err = test_wrong_params();
+ PRINT_MSG("usage: %s <input_path> <output_path> [transpose] ", argv[0]);
+ PRINT_MSG("[mode] [hop_size] [samplerate]\n");
+ PRINT_MSG(" with [transpose] a number of semi tones in the range "
+ " [-24, 24], and [mode] in 'default', 'crispness:0',"
+ " 'crispness:1', ... 'crispness:6'\n");
+ return err;
+ }
+
+#ifdef HAVE_RUBBERBAND
+ uint_t samplerate = 0;
+ uint_t hop_size = 64;
+ smpl_t transpose = 0.;
+ uint_t n_frames = 0, read = 0;
+
+ char_t *source_path = argv[1];
+ char_t *sink_path = argv[2];
+ char_t *mode = "default";
+
+ transpose = 0.;
+
+ if ( argc >= 4 ) transpose = atof(argv[3]);
+ if ( argc >= 5 ) mode = argv[4];
+ if ( argc >= 6 ) hop_size = atoi(argv[5]);
+ if ( argc >= 7 ) samplerate = atoi(argv[6]);
+
+ fvec_t *vec = new_fvec(hop_size);
+ fvec_t *out = new_fvec(hop_size);
+ if (!vec) { err = 1; goto beach_fvec; }
+
+ aubio_source_t *i = new_aubio_source(source_path, samplerate, hop_size);
+ if (!i) { err = 1; goto beach_source; }
+
+ if (samplerate == 0 ) samplerate = aubio_source_get_samplerate(i);
+
+ aubio_sink_t *o = new_aubio_sink(sink_path, samplerate);
+ if (!o) { err = 1; goto beach_sink; }
+
+ aubio_pitchshift_t *ps =
+ new_aubio_pitchshift(mode, transpose, hop_size, samplerate);
+ if (!ps) { err = 1; goto beach_pitchshift; }
+
+ do {
+ aubio_source_do(i, vec, &read);
+ //aubio_pitchshift_set_transpose(ps, tranpose);
+ aubio_pitchshift_do(ps, vec, out);
+ aubio_sink_do(o, out, read);
+ n_frames += read;
+ } while ( read == hop_size );
+
+ PRINT_MSG("read %d frames at %dHz (%d blocks) from %s\n",
+ n_frames, samplerate, n_frames / hop_size,
+ source_path);
+ PRINT_MSG("wrote to %s with hop_size: %d, samplerate: %d, latency %d\n",
+ sink_path, hop_size, samplerate, aubio_pitchshift_get_latency(ps));
+
+ del_aubio_pitchshift(ps);
+beach_pitchshift:
+ del_aubio_sink(o);
+beach_sink:
+ del_aubio_source(i);
+beach_source:
+ del_fvec(vec);
+ del_fvec(out);
+beach_fvec:
+ aubio_cleanup();
+#else
+ err = 0;
+ PRINT_ERR("aubio was not compiled with rubberband\n");
+#endif
+ return err;
+}
+
+int test_wrong_params(void)
+{
+ const char_t *mode = "default";
+ smpl_t transpose = 0.;
+ uint_t hop_size = 256;
+ uint_t samplerate = 44100;
+
+ if (new_aubio_pitchshift("??", transpose, hop_size, samplerate)) return 1;
+ if (new_aubio_pitchshift(mode, 28., hop_size, samplerate)) return 1;
+ if (new_aubio_pitchshift(mode, transpose, 0, samplerate)) return 1;
+ if (new_aubio_pitchshift(mode, transpose, hop_size, 0)) return 1;
+
+ aubio_pitchshift_t *p = new_aubio_pitchshift(mode, transpose,
+ hop_size, samplerate);
+#ifdef HAVE_RUBBERBAND
+ if (!p) return 1;
+ if (!aubio_pitchshift_set_pitchscale(p, 0.1)) return 1;
+ if (!aubio_pitchshift_set_transpose(p, -30)) return 1;
+ del_aubio_pitchshift(p);
+#else
+ if (p) return 1;
+#endif
+
+ return run_on_default_source_and_sink(main);
+}
--- /dev/null
+#define AUBIO_UNSTABLE 1
+#include <aubio.h>
+#include "utils_tests.h"
+
+int test_wrong_params(void);
+
+int main (int argc, char **argv)
+{
+ sint_t err = 0;
+
+ if (argc < 3 || argc >= 9) {
+ PRINT_ERR("wrong number of arguments, running tests\n");
+ err = test_wrong_params();
+ PRINT_MSG("usage: %s <input_path> <output_path> <stretch> [transpose] [mode] [hop_size] [samplerate]\n", argv[0]);
+ PRINT_MSG(" with <stretch> a time stretching ratio in the range [0.025, 10.]\n");
+ PRINT_MSG(" [transpose] a number of semi tones in the range [-24, 24]\n");
+ PRINT_MSG(" and [mode] in 'default', 'crispness:0', ..., 'crispness:6'\n");
+ return err;
+ }
+
+#ifdef HAVE_RUBBERBAND
+ uint_t samplerate = 0; // using source samplerate
+ uint_t hop_size = 64;
+ smpl_t transpose = 0.;
+ smpl_t stretch = 1.;
+ uint_t n_frames = 0, read = 0;
+ uint_t eof = 0, source_read = 0;
+
+ char_t *source_path = argv[1];
+ char_t *sink_path = argv[2];
+ char_t *mode = "default";
+
+ if ( argc >= 4 ) stretch = atof(argv[3]);
+ if ( argc >= 5 ) transpose = atof(argv[4]);
+ if ( argc >= 6 ) mode = argv[5];
+ if ( argc >= 7 ) hop_size = atoi(argv[6]);
+ if ( argc >= 8 ) samplerate = atoi(argv[7]);
+
+ uint_t source_hopsize = 2048;
+ aubio_source_t *s = new_aubio_source(source_path, samplerate, source_hopsize);
+ if (!s) { err = 1; goto beach_source; }
+ if (samplerate == 0) samplerate = aubio_source_get_samplerate(s);
+
+ fvec_t *in = new_fvec(source_hopsize);
+ fvec_t *out = new_fvec(hop_size);
+ if (!out || !in) { err = 1; goto beach_fvec; }
+
+ aubio_timestretch_t *ps = new_aubio_timestretch(mode, stretch, hop_size,
+ samplerate);
+ if (!ps) { err = 1; goto beach_timestretch; }
+ //if (samplerate == 0 ) samplerate = aubio_timestretch_get_samplerate(ps);
+
+ aubio_sink_t *o = new_aubio_sink(sink_path, samplerate);
+ if (!o) { err = 1; goto beach_sink; }
+
+ if (transpose != 0) aubio_timestretch_set_transpose(ps, transpose);
+
+ do {
+ //aubio_timestretch_set_stretch(ps, stretch);
+ //aubio_timestretch_set_transpose(ps, transpose);
+
+ while (aubio_timestretch_get_available(ps) < (sint_t)hop_size && !eof) {
+ aubio_source_do(s, in, &source_read);
+ aubio_timestretch_push(ps, in, source_read);
+ if (source_read < in->length) eof = 1;
+ }
+#if 0
+ if (n_frames == hop_size * 200) {
+ PRINT_MSG("sampler: setting stretch gave %d\n",
+ aubio_timestretch_set_stretch(ps, 2.) );
+ PRINT_MSG("sampler: getting stretch gave %f\n",
+ aubio_timestretch_get_stretch(ps) );
+ PRINT_MSG("sampler: setting transpose gave %d\n",
+ aubio_timestretch_set_transpose(ps, 12.) );
+ PRINT_MSG("sampler: getting transpose gave %f\n",
+ aubio_timestretch_get_transpose(ps) );
+ }
+#endif
+ aubio_timestretch_do(ps, out, &read);
+ aubio_sink_do(o, out, read);
+ n_frames += read;
+ } while ( read == hop_size );
+
+ PRINT_MSG("wrote %d frames at %dHz (%d blocks) from %s written to %s\n",
+ n_frames, samplerate, n_frames / hop_size,
+ source_path, sink_path);
+
+ del_aubio_sink(o);
+beach_sink:
+ del_aubio_timestretch(ps);
+beach_timestretch:
+ del_fvec(out);
+ del_fvec(in);
+beach_fvec:
+ del_aubio_source(s);
+beach_source:
+#else
+ err = 0;
+ PRINT_ERR("aubio was not compiled with rubberband\n");
+#endif
+ return err;
+}
+
+int test_wrong_params(void)
+{
+ const char_t *mode = "default";
+ smpl_t stretch = 1.;
+ uint_t hop_size = 256;
+ uint_t samplerate = 44100;
+
+ if (new_aubio_timestretch("ProcessOffline:?:", stretch, hop_size, samplerate)) return 1;
+ if (new_aubio_timestretch("", stretch, hop_size, samplerate)) return 1;
+ if (new_aubio_timestretch(mode, 41., hop_size, samplerate)) return 1;
+ if (new_aubio_timestretch(mode, stretch, 0, samplerate)) return 1;
+ if (new_aubio_timestretch(mode, stretch, hop_size, 0)) return 1;
+
+ aubio_timestretch_t *p = new_aubio_timestretch(mode, stretch, hop_size,
+ samplerate);
+#ifdef HAVE_RUBBERBAND
+ if (!p) return 1;
+
+ if (aubio_timestretch_get_latency(p) == 0) return 1;
+
+ if (aubio_timestretch_get_samplerate(p) != samplerate) return 1;
+
+ aubio_timestretch_reset(p);
+
+ if (aubio_timestretch_get_transpose(p) != 0) return 1;
+ if (aubio_timestretch_set_transpose(p, 2.)) return 1;
+ if (fabs(aubio_timestretch_get_transpose(p) - 2.) >= 1e-6) return 1;
+ if (!aubio_timestretch_set_transpose(p, 200.)) return 1;
+ if (!aubio_timestretch_set_transpose(p, -200.)) return 1;
+ if (aubio_timestretch_set_transpose(p, 0.)) return 1;
+
+ if (aubio_timestretch_get_pitchscale(p) != 1) return 1;
+ if (aubio_timestretch_set_pitchscale(p, 2.)) return 1;
+ if (fabs(aubio_timestretch_get_pitchscale(p) - 2.) >= 1e-6) return 1;
+ if (!aubio_timestretch_set_pitchscale(p, 0.)) return 1;
+ if (!aubio_timestretch_set_pitchscale(p, 6.)) return 1;
+
+ if (aubio_timestretch_get_stretch(p) != stretch) return 1;
+ if (aubio_timestretch_set_stretch(p, 2.)) return 1;
+ if (fabs(aubio_timestretch_get_stretch(p) - 2.) >= 1e-6) return 1;
+ if (!aubio_timestretch_set_stretch(p, 0.)) return 1;
+ if (!aubio_timestretch_set_stretch(p, 41.)) return 1;
+
+ del_aubio_timestretch(p);
+#else
+ if (p) return 1;
+#endif
+
+ return run_on_default_source_and_sink(main);
+}
--- /dev/null
+#define AUBIO_UNSTABLE 1
+#include <aubio.h>
+#include "utils_tests.h"
+
+#define aubio_sink_custom "flac"
+
+#ifdef HAVE_FLAC
+// functions not exposed in the headers, declared here
+typedef struct _aubio_sink_flac_t aubio_sink_flac_t;
+extern aubio_sink_flac_t * new_aubio_sink_flac(const char_t *uri,
+ uint_t samplerate);
+extern void del_aubio_sink_flac (aubio_sink_flac_t *s);
+extern uint_t aubio_sink_flac_open(aubio_sink_flac_t *s);
+extern uint_t aubio_sink_flac_close(aubio_sink_flac_t *s);
+extern uint_t aubio_sink_flac_preset_channels(aubio_sink_flac_t *s,
+ uint_t channels);
+extern uint_t aubio_sink_flac_preset_samplerate(aubio_sink_flac_t *s,
+ uint_t samplerate);
+extern void aubio_sink_flac_do(aubio_sink_flac_t *s, fvec_t* write_data,
+ uint_t write);
+extern void aubio_sink_flac_do_multi(aubio_sink_flac_t *s,
+ fmat_t *write_data, uint_t write);
+extern uint_t aubio_sink_flac_get_channels(aubio_sink_flac_t *s);
+extern uint_t aubio_sink_flac_get_samplerate(aubio_sink_flac_t *s);
+
+#define HAVE_AUBIO_SINK_CUSTOM
+#define aubio_sink_custom_t aubio_sink_flac_t
+#define new_aubio_sink_custom new_aubio_sink_flac
+#define del_aubio_sink_custom del_aubio_sink_flac
+#define aubio_sink_custom_do aubio_sink_flac_do
+#define aubio_sink_custom_do_multi aubio_sink_flac_do_multi
+#define aubio_sink_custom_close aubio_sink_flac_close
+#define aubio_sink_custom_preset_samplerate aubio_sink_flac_preset_samplerate
+#define aubio_sink_custom_preset_channels aubio_sink_flac_preset_channels
+#define aubio_sink_custom_get_samplerate aubio_sink_flac_get_samplerate
+#define aubio_sink_custom_get_channels aubio_sink_flac_get_channels
+#endif /* HAVE_FLAC */
+
+#include "base-sink_custom.h"
+
+// this file uses the unstable aubio api, please use aubio_sink instead
+// see src/io/sink.h and tests/src/sink/test-sink.c
+
+int main (int argc, char **argv)
+{
+ return base_main(argc, argv);
+}
--- /dev/null
+#define AUBIO_UNSTABLE 1
+#include <aubio.h>
+#include "utils_tests.h"
+
+#define aubio_sink_custom "vorbis"
+
+#ifdef HAVE_VORBISENC
+// functions not exposed in the headers, declared here
+typedef struct _aubio_sink_vorbis_t aubio_sink_vorbis_t;
+extern aubio_sink_vorbis_t * new_aubio_sink_vorbis(const char_t *uri,
+ uint_t samplerate);
+extern void del_aubio_sink_vorbis (aubio_sink_vorbis_t *s);
+extern uint_t aubio_sink_vorbis_open(aubio_sink_vorbis_t *s);
+extern uint_t aubio_sink_vorbis_close(aubio_sink_vorbis_t *s);
+extern uint_t aubio_sink_vorbis_preset_channels(aubio_sink_vorbis_t *s,
+ uint_t channels);
+extern uint_t aubio_sink_vorbis_preset_samplerate(aubio_sink_vorbis_t *s,
+ uint_t samplerate);
+extern void aubio_sink_vorbis_do(aubio_sink_vorbis_t *s, fvec_t *write_data,
+ uint_t write);
+extern void aubio_sink_vorbis_do_multi(aubio_sink_vorbis_t *s,
+ fmat_t *write_data, uint_t write);
+extern uint_t aubio_sink_vorbis_get_channels(aubio_sink_vorbis_t *s);
+extern uint_t aubio_sink_vorbis_get_samplerate(aubio_sink_vorbis_t *s);
+
+#define HAVE_AUBIO_SINK_CUSTOM
+#define aubio_sink_custom_t aubio_sink_vorbis_t
+#define new_aubio_sink_custom new_aubio_sink_vorbis
+#define del_aubio_sink_custom del_aubio_sink_vorbis
+#define aubio_sink_custom_do aubio_sink_vorbis_do
+#define aubio_sink_custom_do_multi aubio_sink_vorbis_do_multi
+#define aubio_sink_custom_close aubio_sink_vorbis_close
+#define aubio_sink_custom_preset_samplerate aubio_sink_vorbis_preset_samplerate
+#define aubio_sink_custom_preset_channels aubio_sink_vorbis_preset_channels
+#define aubio_sink_custom_get_samplerate aubio_sink_vorbis_get_samplerate
+#define aubio_sink_custom_get_channels aubio_sink_vorbis_get_channels
+#endif /* HAVE_VORBISENC */
+
+#include "base-sink_custom.h"
+
+// this file uses the unstable aubio api, please use aubio_sink instead
+// see src/io/sink.h and tests/src/sink/test-sink.c
+
+int main (int argc, char **argv)
+{
+ return base_main(argc, argv);
+}
#include <math.h>
#include "aubio.h"
+#include "aubio_priv.h"
#include "utils_tests.h"
int main (void)
aubio_dct_do (dct, in, dctout);
aubio_dct_rdo (dct, dctout, out);
for (j = 0; j < in->length; j++) {
- return_code += (fabsf(in->data[j] - out->data[j]) > 10.e-4);
+ return_code += (ABS(in->data[j] - out->data[j]) > 10.e-4);
}
}
# For more info about waf, see http://code.google.com/p/waf/ .
import sys
+import subprocess
APPNAME = 'aubio'
help = 'whether to compile with (--build-type=release)' \
' or without (--build-type=debug)' \
' compiler opimizations [default: release]')
+ ctx.add_option('--debug', action = 'store_const',
+ dest = 'build_type', const = 'debug',
+ help = 'build in debug mode (see --build-type)')
+ ctx.add_option('--nodeps', action = 'store_const',
+ dest = 'nodeps', const = 'debug',
+ help = 'build with no external dependencies')
add_option_enable_disable(ctx, 'fftw3f', default = False,
help_str = 'compile with fftw3f instead of ooura (recommended)',
help_disable_str = 'do not compile with fftw3f')
add_option_enable_disable(ctx, 'avcodec', default = None,
help_str = 'compile with libavcodec (auto)',
help_disable_str = 'disable libavcodec')
+ add_option_enable_disable(ctx, 'vorbis', default = None,
+ help_str = 'compile with libvorbis (auto)',
+ help_disable_str = 'disable libvorbis')
+ add_option_enable_disable(ctx, 'flac', default = None,
+ help_str = 'compile with libFLAC (auto)',
+ help_disable_str = 'disable libflac')
add_option_enable_disable(ctx, 'samplerate', default = None,
help_str = 'compile with samplerate (auto)',
help_disable_str = 'disable samplerate')
+ add_option_enable_disable(ctx, 'rubberband', default = None,
+ help_str = 'compile with rubberband (auto)',
+ help_disable_str = 'disable rubberband')
add_option_enable_disable(ctx, 'memcpy', default = True,
help_str = 'use memcpy hacks (default)',
help_disable_str = 'do not use memcpy hacks')
if ctx.options.target_platform:
target_platform = ctx.options.target_platform
+ if ctx.options.nodeps:
+ external_deps = [
+ 'sndfile',
+ 'samplerate',
+ 'jack',
+ 'rubberband',
+ 'avcodec',
+ 'blas',
+ 'fftw3',
+ 'fftw3f',
+ 'flac',
+ 'vorbis',
+ ]
+ for d in external_deps:
+ if not hasattr(ctx.options, 'enable_' + d):
+ raise ctx.errors.ConfigurationError ('--enable-%s missing from options' % d)
+ if getattr(ctx.options, 'enable_' + d) == True:
+ msg = 'Option --nodeps can not be used along with --enable-%s' % d
+ raise ctx.errors.ConfigurationError (msg)
+ elif getattr(ctx.options, 'enable_' + d) is None:
+ msg = 'Option --nodeps used but automatic detection with --enable-%s' % d
+ ctx.msg('Warning', msg)
+ setattr(ctx.options, 'enable_' + d, False)
+
from waflib import Options
if target_platform=='emscripten':
ctx.env['cshlib_PATTERN'] = 'lib%s.dll'
if target_platform == 'darwin' and ctx.options.enable_fat:
- ctx.env.CFLAGS += ['-arch', 'i386', '-arch', 'x86_64']
- ctx.env.LINKFLAGS += ['-arch', 'i386', '-arch', 'x86_64']
+ ctx.env.CFLAGS += ['-arch', 'arm64', '-arch', 'x86_64']
+ ctx.env.LINKFLAGS += ['-arch', 'arm64', '-arch', 'x86_64']
MINSDKVER="10.4"
ctx.env.CFLAGS += [ '-mmacosx-version-min=' + MINSDKVER ]
ctx.env.LINKFLAGS += [ '-mmacosx-version-min=' + MINSDKVER ]
- if target_platform in [ 'darwin', 'ios', 'iosimulator']:
+ if target_platform in [ 'darwin', 'ios', 'iosimulator' ]:
if (ctx.options.enable_apple_audio != False):
ctx.env.FRAMEWORK += ['CoreFoundation', 'AudioToolbox']
ctx.define('HAVE_SOURCE_APPLE_AUDIO', 1)
ctx.msg('Checking for Accelerate framework', 'no (disabled)',
color = 'YELLOW')
- if target_platform in [ 'ios', 'iosimulator' ]:
+ if target_platform in [ 'ios', 'iosimulator', 'watchos', 'watchsimulator' ]:
MINSDKVER="6.1"
+ xcodeslct_output = subprocess.check_output (['xcode-select', '--print-path'])
+ XCODEPATH = xcodeslct_output.decode(sys.stdout.encoding).strip()
+ if target_platform == 'ios':
+ SDKNAME = "iPhoneOS"
+ elif target_platform == 'iosimulator':
+ SDKNAME = "iPhoneSimulator"
+ elif target_platform == 'watchos':
+ SDKNAME = "WatchOS"
+ elif target_platform == 'watchsimulator':
+ SDKNAME = "WatchSimulator"
+ else:
+ raise ctx.errors.ConfigurationError ("Error: unknown target platform '"
+ + target_platform + "'")
+ DEVROOT = "%(XCODEPATH)s/Platforms/%(SDKNAME)s.platform/Developer" % locals()
+ SDKROOT = "%(DEVROOT)s/SDKs/%(SDKNAME)s.sdk" % locals()
ctx.env.CFLAGS += ['-std=c99']
- if (ctx.options.enable_apple_audio != False):
+ if ctx.options.enable_apple_audio != False and target_platform.startswith ('ios'):
ctx.define('HAVE_AUDIO_UNIT', 1)
#ctx.env.FRAMEWORK += ['CoreFoundation', 'AudioToolbox']
if target_platform == 'ios':
- DEVROOT = "/Applications/Xcode.app/Contents"
- DEVROOT += "/Developer/Platforms/iPhoneOS.platform/Developer"
- SDKROOT = "%(DEVROOT)s/SDKs/iPhoneOS.sdk" % locals()
ctx.env.CFLAGS += [ '-fembed-bitcode' ]
ctx.env.CFLAGS += [ '-arch', 'arm64' ]
ctx.env.CFLAGS += [ '-arch', 'armv7' ]
ctx.env.LINKFLAGS += ['-arch', 'armv7s']
ctx.env.CFLAGS += [ '-miphoneos-version-min=' + MINSDKVER ]
ctx.env.LINKFLAGS += [ '-miphoneos-version-min=' + MINSDKVER ]
- else:
- DEVROOT = "/Applications/Xcode.app/Contents"
- DEVROOT += "/Developer/Platforms/iPhoneSimulator.platform/Developer"
- SDKROOT = "%(DEVROOT)s/SDKs/iPhoneSimulator.sdk" % locals()
- ctx.env.CFLAGS += [ '-arch', 'i386' ]
+ elif target_platform == 'iosimulator':
ctx.env.CFLAGS += [ '-arch', 'x86_64' ]
- ctx.env.LINKFLAGS += ['-arch', 'i386']
+ ctx.env.CFLAGS += [ '-arch', 'arm64' ]
ctx.env.LINKFLAGS += ['-arch', 'x86_64']
+ ctx.env.LINKFLAGS += ['-arch', 'arm64']
ctx.env.CFLAGS += [ '-mios-simulator-version-min=' + MINSDKVER ]
ctx.env.LINKFLAGS += [ '-mios-simulator-version-min=' + MINSDKVER ]
+ elif target_platform == 'watchos':
+ ctx.env.CFLAGS += [ '-arch', 'armv7' ]
+ ctx.env.CFLAGS += [ '-arch', 'armv7s' ]
+ ctx.env.LINKFLAGS += ['-arch', 'armv7']
+ ctx.env.LINKFLAGS += ['-arch', 'armv7s']
+ ctx.env.CFLAGS += [ '-mwatchos-version-min=' + MINSDKVER ]
+ ctx.env.LINKFLAGS += [ '-mwatchos-version-min=' + MINSDKVER ]
+ elif target_platform == 'watchsimulator':
+ ctx.env.CFLAGS += [ '-arch', 'x86_64' ]
+ ctx.env.CFLAGS += [ '-arch', 'arm64' ]
+ ctx.env.LINKFLAGS += ['-arch', 'x86_64']
+ ctx.env.LINKFLAGS += ['-arch', 'arm64']
+ ctx.env.CFLAGS += [ '-mwatchsimulator-version-min=' + MINSDKVER ]
+ ctx.env.LINKFLAGS += [ '-mwatchsimulator-version-min=' + MINSDKVER ]
ctx.env.CFLAGS += [ '-isysroot' , SDKROOT]
ctx.env.LINKFLAGS += [ '-isysroot' , SDKROOT]
args = '--cflags --libs samplerate >= 0.0.15',
mandatory = ctx.options.enable_samplerate)
+ # check for librubberband
+ if (ctx.options.enable_rubberband != False):
+ ctx.check_cfg(package = 'rubberband', atleast_version = '1.3',
+ args = '--cflags --libs',
+ mandatory = ctx.options.enable_rubberband)
+
# check for jack
if (ctx.options.enable_jack != False):
ctx.check_cfg(package = 'jack',
args = '--cflags --libs libswresample >= 1.2.0',
uselib_store = 'SWRESAMPLE',
mandatory = False)
- if 'HAVE_SWRESAMPLE' not in ctx.env:
- ctx.check_cfg(package = 'libavresample',
- args = '--cflags --libs libavresample >= 1.0.1',
- uselib_store = 'AVRESAMPLE',
- mandatory = False)
msg_check = 'Checking for all libav libraries'
if 'HAVE_AVCODEC' not in ctx.env:
ctx.msg(msg_check, 'not found (missing avformat)', color = 'YELLOW')
elif 'HAVE_AVUTIL' not in ctx.env:
ctx.msg(msg_check, 'not found (missing avutil)', color = 'YELLOW')
- elif 'HAVE_SWRESAMPLE' not in ctx.env \
- and 'HAVE_AVRESAMPLE' not in ctx.env:
- resample_missing = 'not found (avresample or swresample required)'
+ elif 'HAVE_SWRESAMPLE' not in ctx.env :
+ resample_missing = 'not found (missing swresample)'
ctx.msg(msg_check, resample_missing, color = 'YELLOW')
else:
ctx.msg(msg_check, 'yes')
- if 'HAVE_SWRESAMPLE' in ctx.env:
- ctx.define('HAVE_SWRESAMPLE', 1)
- elif 'HAVE_AVRESAMPLE' in ctx.env:
- ctx.define('HAVE_AVRESAMPLE', 1)
ctx.define('HAVE_LIBAV', 1)
+ # check for vorbisenc
+ if (ctx.options.enable_vorbis != False):
+ ctx.check_cfg(package = 'vorbisenc vorbis ogg',
+ args = '--cflags --libs',
+ uselib_store = 'VORBISENC',
+ mandatory = ctx.options.enable_vorbis)
+
+ # check for flac
+ if (ctx.options.enable_flac != False):
+ ctx.check_cfg(package = 'flac',
+ args = '--cflags --libs',
+ uselib_store = 'FLAC',
+ mandatory = ctx.options.enable_flac)
+
if (ctx.options.enable_wavread != False):
ctx.define('HAVE_WAVREAD', 1)
ctx.msg('Checking if using source_wavread',
bld.recurse('src')
# add sub directories
- if bld.env['DEST_OS'] not in ['ios', 'iosimulator', 'android']:
+ if bld.env['DEST_OS'] not in ['ios', 'iosimulator', 'watchos', 'watchsimulator', 'android']:
if bld.env['DEST_OS']=='emscripten' and not bld.options.testcmd:
bld.options.testcmd = 'node %s'
if bld.options.enable_examples: