Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update 0.1.9 #39

Merged
merged 11 commits into from
May 24, 2024
2 changes: 1 addition & 1 deletion conda/meta.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{% set version = "0.1.8" %}
{% set version = "0.1.9" %}

package:
name: audioflux
Expand Down
7 changes: 7 additions & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
ChangeLog
=========
v0.1.9
------
* New features:
* Add `audioflux.utils.synth_f0`.
* Fix bug:
* `#37 <https://github.com/libAudioFlux/audioFlux/issues/37>`__: Fix `audioflux.display.fill_spec` bug.

v0.1.8
------
* New features:
Expand Down
1 change: 1 addition & 0 deletions docs/utils.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
------
Expand Down
2 changes: 1 addition & 1 deletion python/audioflux/__version__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
__title__ = 'audioflux'
__description__ = 'A library for audio and music analysis, feature extraction.'
__version__ = '0.1.8'
__version__ = '0.1.9'
9 changes: 7 additions & 2 deletions python/audioflux/display/display.py
Original file line number Diff line number Diff line change
@@ -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

Expand Down Expand Up @@ -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))
Expand Down
1 change: 1 addition & 0 deletions python/audioflux/mir/pitch_yin.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
79 changes: 78 additions & 1 deletion python/audioflux/utils/util.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
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',
'ascontiguous_swapaxex',
'format_channel',
'revoke_channel',
'check_audio',
'check_audio_length'
'check_audio_length',
'synth_f0'
]


Expand Down Expand Up @@ -104,3 +108,76 @@ 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 audioflux as af
>>> 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
2 changes: 1 addition & 1 deletion src/util/flux_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Loading