From 334d820b1ef63634d22afc3b0b42f061739877f3 Mon Sep 17 00:00:00 2001 From: wtq2255 Date: Mon, 1 Apr 2024 15:05:32 +0800 Subject: [PATCH 1/8] update doc --- python/audioflux/mir/pitch_yin.py | 1 + 1 file changed, 1 insertion(+) diff --git a/python/audioflux/mir/pitch_yin.py b/python/audioflux/mir/pitch_yin.py index 96bf304..876dafd 100644 --- a/python/audioflux/mir/pitch_yin.py +++ b/python/audioflux/mir/pitch_yin.py @@ -52,6 +52,7 @@ class PitchYIN(Base): >>> fre_arr, v1_arr, v2_arr = pitch_obj.pitch(audio_arr) Show pitch plot + >>> import matplotlib.pyplot as plt >>> times = np.arange(fre_arr.shape[-1]) * (pitch_obj.slide_length / sr) >>> fig, ax = plt.subplots(nrows=2, sharex=True) From 1067462a5983820e31bc5f20799036a806586cba Mon Sep 17 00:00:00 2001 From: wtq2255 Date: Fri, 24 May 2024 11:28:38 +0800 Subject: [PATCH 2/8] update synth_f0 --- docs/utils.rst | 1 + python/audioflux/utils/util.py | 78 +++++++++++++++++++++++++++++++++- src/util/flux_util.h | 2 +- 3 files changed, 79 insertions(+), 2 deletions(-) diff --git a/docs/utils.rst b/docs/utils.rst index aee9b37..b663c2a 100644 --- a/docs/utils.rst +++ b/docs/utils.rst @@ -63,6 +63,7 @@ Utils audioflux.utils.midi_to_hz audioflux.utils.hz_to_note audioflux.utils.hz_to_midi + audioflux.utils.synth_f0 Sample ------ diff --git a/python/audioflux/utils/util.py b/python/audioflux/utils/util.py index deb6716..874713e 100644 --- a/python/audioflux/utils/util.py +++ b/python/audioflux/utils/util.py @@ -1,5 +1,8 @@ import warnings import numpy as np +from ctypes import c_int, c_float, c_void_p, POINTER + +from audioflux.fftlib import get_fft_lib __all__ = [ 'ascontiguous_T', @@ -7,7 +10,8 @@ 'format_channel', 'revoke_channel', 'check_audio', - 'check_audio_length' + 'check_audio_length', + 'synth_f0' ] @@ -104,3 +108,75 @@ def check_audio_length(X, radix2_exp): f'only the first fft_length={fft_length} data are valid') X = X[..., :fft_length].copy() return X + + +def synth_f0(times, frequencies, samplate, amplitudes=None): + """ + Generate an audio array based on the frequency f0. + + Parameters + ---------- + times: ndarray [shape=(n)] + Time points for each frequency, in seconds. + + frequencies: ndarray [shape=(n)] + Array of frequencies, in Hz. + + samplate: int + The output sampling rate. + + amplitudes: ndarray [shape=(n)] + The amplitude of each frequency, ranging from 0 to 1. + + Default is None, which means that the amplitude is 1. Like: `np.ones((n,))` + + Returns + ------- + out: ndarray + Return the audio array generated based on the frequencies + + + Examples + -------- + + >>> import numpy as np + >>> f0_arr = np.ones((1024,)) * 220 + >>> times = np.arange(0, f0_arr.shape[0]) * (1024 / 32000) + >>> amplitude_arr = np.ones_like(f0_arr) * 0.4 + >>> audio_arr = af.utils.synth_f0(times, f0_arr, 32000, amplitude_arr) + + """ + times = np.asarray(times, dtype=np.float32, order='C') + if times.ndim != 1: + raise ValueError(f"times[ndim={times.ndim}] must be a 1D array") + + frequencies = np.asarray(frequencies, dtype=np.float32, order='C') + if frequencies.ndim != 1: + raise ValueError(f"frequencies[ndim={frequencies.ndim}] must be a 1D array") + + if times.shape[0] != frequencies.shape[0]: + raise ValueError(f"The lengths of times and frequencies must be the same.") + + if amplitudes is not None: + amplitudes = np.asarray(amplitudes, dtype=np.float32, order='C') + if amplitudes.ndim != 1: + raise ValueError(f"amplitudes[ndim={amplitudes.ndim}] must be a 1D array") + + if amplitudes.shape[0] != frequencies.shape[0]: + raise ValueError(f"The lengths of amplitudes and frequencies must be the same.") + + fn = get_fft_lib()['util_synthF0'] + fn.argtypes = [ + np.ctypeslib.ndpointer(dtype=np.float32, ndim=1, flags='C_CONTIGUOUS'), + np.ctypeslib.ndpointer(dtype=np.float32, ndim=1, flags='C_CONTIGUOUS'), + c_int, c_int, + POINTER(c_void_p) if amplitudes is None else np.ctypeslib.ndpointer(dtype=np.float32, ndim=1, flags='C_CONTIGUOUS'), + ] + fn.restype = c_void_p + + length = times.shape[0] + length1 = round(np.max(times) * samplate) + + p = fn(times, frequencies, c_int(length), c_int(samplate), amplitudes) + ret = np.frombuffer((c_float * length1).from_address(p), np.float32).copy() + return ret \ No newline at end of file diff --git a/src/util/flux_util.h b/src/util/flux_util.h index 67d8546..8653e05 100644 --- a/src/util/flux_util.h +++ b/src/util/flux_util.h @@ -82,7 +82,7 @@ void util_delta(float *dataArr1,int length,int order,float *dataArr2); void util_preEmphasis(float *vArr1,int length,float coef,float *vArr2); // synthesized f0; length1=floor(time*fs), ampArr can NULL, default is 1 -float *util_synthF0(float *timeArr,float *freArr,int samplate,int length,float *ampArr); +float *util_synthF0(float *timeArr,float *freArr,int length,int samplate,float *ampArr); // wave int util_readWave(char *name,float **dataArr); From c2afe9492a1bb45d693b9e71cd3e60e101936289 Mon Sep 17 00:00:00 2001 From: wtq2255 Date: Fri, 24 May 2024 11:29:26 +0800 Subject: [PATCH 3/8] Fix the minimum version of matplotlib. --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 670cfbd..87e55e2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ numpy scipy>=1.2.0 soundfile>=0.12.1 -matplotlib \ No newline at end of file +matplotlib >= 3.5.0 \ No newline at end of file From bb515fe73cf3f479442376e34763a8892c7cc5dd Mon Sep 17 00:00:00 2001 From: wtq2255 Date: Fri, 24 May 2024 11:30:10 +0800 Subject: [PATCH 4/8] Update the audioflux version to 0.1.9. --- python/audioflux/__version__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/audioflux/__version__.py b/python/audioflux/__version__.py index dba04e6..6b6e144 100644 --- a/python/audioflux/__version__.py +++ b/python/audioflux/__version__.py @@ -1,3 +1,3 @@ __title__ = 'audioflux' __description__ = 'A library for audio and music analysis, feature extraction.' -__version__ = '0.1.8' +__version__ = '0.1.9' From 714aacf06979dbaf60ecb3e5dcb6f790aeb26c6a Mon Sep 17 00:00:00 2001 From: wtq2255 Date: Fri, 24 May 2024 11:30:47 +0800 Subject: [PATCH 5/8] Update the documentation --- docs/changelog.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/changelog.rst b/docs/changelog.rst index dcbf6ca..31dea2b 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,5 +1,11 @@ ChangeLog ========= +v0.1.9 +* New features: + * Add `audioflux.utils.synth_f0` +* Fix bug: + * `#37 `__: Fix `audioflux.display.fill_spec` bug. + v0.1.8 ------ * New features: From d9464a2f2794b2ddb4eef85890b72e7e8a6256f4 Mon Sep 17 00:00:00 2001 From: wtq2255 Date: Fri, 24 May 2024 16:30:12 +0800 Subject: [PATCH 6/8] Fix fill_spec to support older versions of matplotlib --- python/audioflux/display/display.py | 9 +++++++-- requirements.txt | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/python/audioflux/display/display.py b/python/audioflux/display/display.py index 4b8da28..72f3590 100644 --- a/python/audioflux/display/display.py +++ b/python/audioflux/display/display.py @@ -1,9 +1,9 @@ import warnings import numpy as np +import matplotlib as mpl import matplotlib.pyplot as plt import matplotlib.axes as plaxes -from matplotlib import colormaps from matplotlib.ticker import Formatter, ScalarFormatter, MaxNLocator, SymmetricalLogLocator, FixedLocator from audioflux.utils import midi_to_note @@ -190,7 +190,12 @@ def fill_spec( if y_axis == 'chroma': y_coords = np.arange(data.shape[-2] + 1) - cmap = colormaps['plasma'] + if hasattr(mpl, 'colormaps'): + cmap = mpl.colormaps['plasma'] + else: + from matplotlib.cm import get_cmap + cmap = get_cmap('plasma') + collection = axes.pcolormesh(x_coords, y_coords, data, cmap=cmap) axes.set_xlim(np.min(x_coords), np.max(x_coords)) diff --git a/requirements.txt b/requirements.txt index 87e55e2..670cfbd 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ numpy scipy>=1.2.0 soundfile>=0.12.1 -matplotlib >= 3.5.0 \ No newline at end of file +matplotlib \ No newline at end of file From 34e22a4ad673a5f975e69fb103f9374bd976cf19 Mon Sep 17 00:00:00 2001 From: wtq2255 Date: Fri, 24 May 2024 16:30:26 +0800 Subject: [PATCH 7/8] Update conda version --- conda/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/meta.yaml b/conda/meta.yaml index b2f1c75..0e2d135 100644 --- a/conda/meta.yaml +++ b/conda/meta.yaml @@ -1,4 +1,4 @@ -{% set version = "0.1.8" %} +{% set version = "0.1.9" %} package: name: audioflux From f7e347f12d3d78b26aeb2def17a8624a04d46233 Mon Sep 17 00:00:00 2001 From: wtq2255 Date: Fri, 24 May 2024 17:02:06 +0800 Subject: [PATCH 8/8] Update doc --- docs/changelog.rst | 3 ++- python/audioflux/utils/util.py | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 31dea2b..1129935 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,8 +1,9 @@ ChangeLog ========= v0.1.9 +------ * New features: - * Add `audioflux.utils.synth_f0` + * Add `audioflux.utils.synth_f0`. * Fix bug: * `#37 `__: Fix `audioflux.display.fill_spec` bug. diff --git a/python/audioflux/utils/util.py b/python/audioflux/utils/util.py index 874713e..24c52ae 100644 --- a/python/audioflux/utils/util.py +++ b/python/audioflux/utils/util.py @@ -139,6 +139,7 @@ def synth_f0(times, frequencies, samplate, amplitudes=None): Examples -------- + >>> import audioflux as af >>> import numpy as np >>> f0_arr = np.ones((1024,)) * 220 >>> times = np.arange(0, f0_arr.shape[0]) * (1024 / 32000)