Source code for compiam.melody.tonic_identification.tonic_multipitch
import os
import numpy as np
from compiam.utils import get_logger, stereo_to_mono
logger = get_logger(__name__)
[docs]
class TonicIndianMultiPitch:
"""MultiPitch approach to extract the tonic from IAM music signals."""
def __init__(
self,
bin_resolution=10,
frame_size=2048,
harmonic_weight=0.8,
hop_size=128,
magnitude_compression=1,
magnitude_threshold=40,
max_tonic_frequency=375,
min_tonic_frequency=100,
num_harmonics=20,
ref_frequency=55,
sample_rate=44100,
):
"""Tonic extraction init method.
For a complete and detailed list of the parameters see the documentation on the
following link: https://essentia.upf.edu/reference/std_TonicIndianArtMusic.html.
Naming convention of the arguments has been stadardized to compIAM-friendly format.
"""
### IMPORTING OPTIONAL DEPENDENCIES
try:
global estd
import essentia.standard as estd
except:
raise ImportError(
"In order to use this tool you need to have essentia installed. "
"Install compIAM with essentia support: pip install 'compiam[essentia]'"
)
###
self.bin_resolution = bin_resolution
self.frame_size = frame_size
self.harmonic_weight = harmonic_weight
self.hop_size = hop_size
self.magnitude_compression = magnitude_compression
self.magnitude_threshold = magnitude_threshold
self.max_tonic_frequency = max_tonic_frequency
self.min_tonic_frequency = min_tonic_frequency
self.num_harmonics = num_harmonics
self.ref_frequency = ref_frequency
self.sample_rate = sample_rate
[docs]
def extract(self, input_data, input_sr=44100):
"""Extract the tonic from a given file.
:param input_data: path to audio file or numpy array like audio signal
:param input_sr: sampling rate of the input array of data (if any). This variable is only
relevant if the input is an array of data instead of a filepath.
:returns: a floating point number representing the tonic of the input recording.
"""
if isinstance(input_data, str):
if not os.path.exists(input_data):
raise FileNotFoundError("Target audio not found.")
audio = estd.MonoLoader(filename=input_data, sampleRate=self.sample_rate)()
elif isinstance(input_data, np.ndarray):
if len(input_data.shape) == 2:
input_data = stereo_to_mono(input_data)
if len(input_data.shape) > 2:
raise ValueError("Input must be an unbatched audio signal")
logger.warning(
f"Resampling... (input sampling rate is {input_sr}Hz, make sure this is correct)"
)
resampling = estd.Resample(
inputSampleRate=input_sr, outputSampleRate=self.sample_rate
)
audio = resampling(input_data)
else:
raise ValueError("Input must be path to audio signal or an audio array")
extractor = estd.TonicIndianArtMusic(
binResolution=self.bin_resolution,
frameSize=self.frame_size,
harmonicWeight=self.harmonic_weight,
hopSize=self.hop_size,
magnitudeCompression=self.magnitude_compression,
magnitudeThreshold=self.magnitude_threshold,
maxTonicFrequency=self.max_tonic_frequency,
minTonicFrequency=self.min_tonic_frequency,
numberHarmonics=self.num_harmonics,
referenceFrequency=self.ref_frequency,
sampleRate=self.sample_rate,
)
return extractor(audio)