### Start Jupyter Notebook Server Source: https://github.com/meinardmueller/synctoolbox/blob/master/README.md Start the Jupyter notebook server to access and run the example notebooks locally. ```bash jupyter notebook ``` -------------------------------- ### Install Jupyter for Local Notebooks Source: https://github.com/meinardmueller/synctoolbox/blob/master/README.md Install the Jupyter package using pip after cloning the repository to run example notebooks locally. ```bash pip install jupyter ``` -------------------------------- ### Install Sync Toolbox with Testing Requirements Source: https://github.com/meinardmueller/synctoolbox/blob/master/README.md Install the Sync Toolbox along with the necessary dependencies for running automated tests. This command ensures all testing frameworks and libraries are available. ```bash pip install 'synctoolbox[tests]' pytest tests ``` -------------------------------- ### Install Sync Toolbox with pip Source: https://github.com/meinardmueller/synctoolbox/blob/master/README.md Install the Sync Toolbox package locally using pip. Recommended within a conda or virtual environment. ```bash pip install synctoolbox ``` -------------------------------- ### Install libtsm Library Source: https://github.com/meinardmueller/synctoolbox/blob/master/sync_audio_audio_full.ipynb Installs the libtsm library, which is used for time-scale modification and pitch-shifting of audio signals. ```python !pip install libtsm ``` -------------------------------- ### Clone Sync Toolbox Repository Source: https://github.com/meinardmueller/synctoolbox/blob/master/README.md Clone the Sync Toolbox repository from GitHub to run example notebooks locally. ```bash git clone https://github.com/meinardmueller/synctoolbox.git ``` -------------------------------- ### Import Libraries and Define Constants Source: https://github.com/meinardmueller/synctoolbox/blob/master/sync_audio_score_full.ipynb Imports necessary libraries and defines constants for audio processing and synchronization. Ensure all listed libraries are installed. ```python import IPython.display as ipd from libfmp.b import list_to_pitch_activations, plot_chromagram, plot_signal, plot_matrix, \ sonify_pitch_activations_with_signal import librosa.display import matplotlib.pyplot as plt import numpy as np import pandas as pd import scipy.interpolate from synctoolbox.dtw.mrmsdtw import sync_via_mrmsdtw from synctoolbox.dtw.utils import compute_optimal_chroma_shift, shift_chroma_vectors, make_path_strictly_monotonic from synctoolbox.feature.csv_tools import read_csv_to_df, df_to_pitch_features, df_to_pitch_onset_features from synctoolbox.feature.chroma import pitch_to_chroma, quantize_chroma, quantized_chroma_to_CENS from synctoolbox.feature.dlnco import pitch_onset_features_to_DLNCO from synctoolbox.feature.pitch import audio_to_pitch_features from synctoolbox.feature.pitch_onset import audio_to_pitch_onset_features from synctoolbox.feature.utils import estimate_tuning %matplotlib inline Fs = 22050 feature_rate = 50 step_weights = np.array([1.5, 1.5, 2.0]) threshold_rec = 10 ** 6 ``` -------------------------------- ### Create Conda Environment for Sync Toolbox Source: https://github.com/meinardmueller/synctoolbox/blob/master/README.md Create a conda environment named 'synctoolbox' using the provided environment.yml file. This installs the package and Jupyter for demo files. ```bash conda env create -f environment.yml ``` -------------------------------- ### Download and Extract Schubert Winterreise Dataset Source: https://github.com/meinardmueller/synctoolbox/blob/master/ismir2021lbd_using_the_synctoolbox_for_an_experiment.ipynb Installs necessary tools and downloads the Schubert Winterreise Dataset (SWD) for experimental use. Ensures the dataset is extracted and the zip file is removed. ```python !apt-get install unzip wget !wget "https://zenodo.org/record/5139893/files/Schubert_Winterreise_Dataset_v2-0.zip?download=1" -O winterreise.zip !unzip winterreise -d winterreise !rm -r winterreise.zip ``` -------------------------------- ### Time-Scale Annotation with Warping Path Source: https://github.com/meinardmueller/synctoolbox/blob/master/sync_audio_score_full.ipynb Applies a computed warping path to time-scale annotation data, interpolating start and end times to synchronize with the audio. Requires the annotation DataFrame and the warping path. ```python df_annotation_warped = df_annotation.copy(deep=True) df_annotation_warped["end"] = df_annotation_warped["start"] + df_annotation_warped["duration"] df_annotation_warped[['start', 'end']] = scipy.interpolate.interp1d(wp[1] / feature_rate, wp[0] / feature_rate, kind='linear', fill_value="extrapolate")(df_annotation[['start', 'end']]) df_annotation_warped["duration"] = df_annotation_warped["end"] - df_annotation_warped["start"] note_list = df_annotation_warped[['start', 'duration', 'pitch', 'velocity']].values.tolist() ``` -------------------------------- ### Convert MIDI to MusicXML using Musescore Source: https://github.com/meinardmueller/synctoolbox/blob/master/docs/build/html/_modules/synctoolbox/feature/csv_tools.html Converts a MIDI file to a MusicXML (.mxl) score using the Musescore executable. Requires Musescore to be installed and accessible via the provided executable path. The function checks for Musescore's availability and reports success or failure. ```python def midi_to_music_xml_musescore(midi_filepath: str, musescore_executable: str = "musescore"): """Convert a midi file to a music xml score using musescore. This only works for score-based midis, not performed midis. Even for score-based midis, errors may occur. The resulting music xml should always be checked manually. For this method to work, musescore must be installed on the system. Parameters ---------- midi_filepath: Path to the midi file. A corresponding .mxl file of the same name will be created in the same directory. musescore_executable: Path to or name of the musescore executable. """ if subprocess.getstatusoutput(musescore_executable)[0] != 0: assert False, f"Could not call musescore via command {musescore_executable}. To use midi_to_music_xml_musescore, make sure musescore is installed." musicxml_filepath = midi_filepath[:midi_filepath.rindex(".")] + ".mxl" exitcode, output = subprocess.getstatusoutput(f"{musescore_executable} -o '{musicxml_filepath}' '{midi_filepath}'") if exitcode != 0: assert False, f"Could not convert {midi_filepath} to musicxml. Musescore output: {output}" else: print(f"Successfully converted {midi_filepath} to {musicxml_filepath} using musescore") ``` -------------------------------- ### sync_via_mrmsdtw_with_anchors Source: https://context7.com/meinardmueller/synctoolbox/llms.txt Extends `sync_via_mrmsdtw` by dividing the alignment task into intervals defined by anchor pairs (in seconds). Each interval is synchronized independently, allowing for known alignment points to constrain and guide the algorithm. ```APIDOC ## sync_via_mrmsdtw_with_anchors ### Description Extends `sync_via_mrmsdtw` by dividing the alignment task into intervals defined by anchor pairs (in seconds). Each interval is synchronized independently, allowing for known alignment points (e.g., section boundaries) to constrain and guide the algorithm. Intervals can optionally be assigned a diagonal (linear) path for silence or non-musical segments. ### Parameters - **f_chroma1** (np.ndarray) - Chroma features of the first audio sequence. - **f_chroma2** (np.ndarray) - Chroma features of the second audio sequence. - **f_onset1** (np.ndarray, optional) - Onset features of the first audio sequence. - **f_onset2** (np.ndarray, optional) - Onset features of the second audio sequence. - **input_feature_rate** (int) - The feature rate of the input chroma and onset features. - **anchors1** (np.ndarray) - Anchor points in seconds for the first sequence. - **anchors2** (np.ndarray) - Anchor points in seconds for the second sequence. - **step_sizes** (np.ndarray) - Defines the allowed steps in the DTW matrix. - **step_weights** (np.ndarray) - Weights for each step size. - **threshold_rec** (int) - Recursion threshold for the DTW algorithm. - **win_len_smooth** (np.ndarray) - Window lengths for smoothing at different scales. - **downsamp_smooth** (np.ndarray) - Downsampling factors for smoothing at different scales. - **verbose** (bool, optional) - Whether to print verbose output. Defaults to False. - **alpha** (float, optional) - Weighting factor for combining features. Defaults to 0.5. ### Returns - **wp** (np.ndarray) - A numpy array of shape (2, T) representing the warping path, where `wp[0, :]` are frame indices of sequence 1 and `wp[1, :]` are corresponding frame indices of sequence 2. ``` -------------------------------- ### Calculate Alignment Statistics Source: https://github.com/meinardmueller/synctoolbox/blob/master/ismir2021lbd_using_the_synctoolbox_for_an_experiment.ipynb Computes mean, standard deviation, and misalignment percentages for audio features based on provided annotations and tolerances. Requires pandas, scipy, and numpy. Ensure 'wp' is a tuple of feature arrays and 'measure_ann_filepath_1/2' point to CSV files with a 'start' column. ```python measure_ann_1 = pd.read_csv(filepath_or_buffer=measure_ann_filepath_1, delimiter=';')['start'] measure_ann_2 = pd.read_csv(filepath_or_buffer=measure_ann_filepath_2, delimiter=';')['start'] measure_positions_1_transferred_to_2 = scipy.interpolate.interp1d(wp[0] / feature_rate, wp[1] / feature_rate, kind='linear')(measure_ann_1) absolute_errors_at_measures = np.abs(measure_positions_1_transferred_to_2 - measure_ann_2) misalignments = np.zeros(len(tolerances)) for idx, tolerance in enumerate(tolerances): # in milliseconds misalignments[idx] = np.mean((absolute_errors_at_measures>tolerance/1000.0)) mean = np.mean(absolute_errors_at_measures) * 1000.0 std = np.std(absolute_errors_at_measures) * 1000.0 return mean, std, np.array(misalignments), absolute_errors_at_measures ``` -------------------------------- ### Get Quantized Chroma Features from Audio Source: https://github.com/meinardmueller/synctoolbox/blob/master/ismir2021lbd_using_the_synctoolbox_for_an_experiment.ipynb Extracts quantized chroma features from an audio signal. Requires audio data, tuning offset, and optionally sampling frequency and feature rate. This function first computes pitch features, then converts them to chroma, and finally quantizes the chroma representation. ```python def get_chroma_features_from_audio(audio, tuning_offset, Fs=Fs, feature_rate=FEATURE_RATE, verbose=False): f_pitch = audio_to_pitch_features(f_audio=audio, Fs=Fs, tuning_offset=tuning_offset, feature_rate=feature_rate, verbose=verbose) f_chroma = pitch_to_chroma(f_pitch=f_pitch) f_chroma_quantized = quantize_chroma(f_chroma=f_chroma) return f_chroma_quantized ``` -------------------------------- ### Get Audio Duration from DataFrame Source: https://github.com/meinardmueller/synctoolbox/blob/master/docs/build/html/_modules/synctoolbox/feature/csv_tools.html Calculates the total duration of an audio file from a pandas DataFrame. It checks for an 'end' column or computes it from 'start' and 'duration' columns. ```python def __get_audio_duration_from_df(df: pd.DataFrame) -> float: """Gets the duration of the symbolic file (end of the last sound event) Parameters ---------- df : pd.Dataframe Input dataframe having 'start' and 'duration' OR 'end' Returns ------- duration : float Duration of the audio. """ for column in df.columns: if column == 'end': duration = df[column].max() return duration if 'start' not in df.columns or 'duration' not in df.columns: raise ValueError('start and duration OR end must be within the columns of the' \ 'dataframe.') df['end'] = df['start'] + df['duration'] duration = df['end'].max() return duration ``` -------------------------------- ### Load Modules and Define Constants for Sync Toolbox Experiments Source: https://github.com/meinardmueller/synctoolbox/blob/master/ismir2021lbd_using_the_synctoolbox_for_an_experiment.ipynb Imports necessary libraries and defines constants for audio processing, feature extraction, and synchronization parameters. Ensures the figure directory exists. ```python import IPython.display as ipd import matplotlib.pyplot as plt import librosa.display import numpy as np import os import pandas as pd import scipy.interpolate from synctoolbox.dtw.mrmsdtw import sync_via_mrmsdtw from synctoolbox.dtw.utils import compute_optimal_chroma_shift, shift_chroma_vectors, make_path_strictly_monotonic from synctoolbox.feature.chroma import pitch_to_chroma, quantize_chroma, quantized_chroma_to_CENS from synctoolbox.feature.dlnco import pitch_onset_features_to_DLNCO from synctoolbox.feature.novelty import spectral_flux from synctoolbox.feature.pitch import audio_to_pitch_features from synctoolbox.feature.pitch_onset import audio_to_pitch_onset_features from synctoolbox.feature.utils import estimate_tuning %matplotlib inline Fs = 22050 FEATURE_RATE = 50 STEP_WEIGHTS = np.array([1.5, 1.5, 2.0]) THRESHOLD_REC = 10 ** 6 FIG_SIZE = (9, 3) GAMMA = 10.0 AUDIO_DIR = 'winterreise/01_RawData/audio_wav/' MEASURE_ANN_DIR = 'winterreise/02_Annotations/ann_audio_measure/' FILENAME_PREFIX = 'Schubert_D911-' FIGURE_DIR = 'figs' # Create a directory for the figures, if not exists if not os.path.exists(FIGURE_DIR): os.makedirs(FIGURE_DIR) ``` -------------------------------- ### Load Modules and Define Constants Source: https://github.com/meinardmueller/synctoolbox/blob/master/sync_audio_audio_simple.ipynb Imports necessary libraries and defines constants for audio processing, feature extraction, and plotting. Sets up parameters like sampling frequency (Fs), FFT window size (N), and hop length (H). ```python # Loading some modules and defining some constants used later import time import librosa.display import matplotlib.pyplot as plt import IPython.display as ipd from libfmp.b.b_plot import plot_signal, plot_chromagram from libfmp.c3.c3s2_dtw_plot import plot_matrix_with_points from synctoolbox.dtw.core import compute_warping_path from synctoolbox.dtw.cost import cosine_distance from synctoolbox.dtw.mrmsdtw import sync_via_mrmsdtw %matplotlib inline Fs = 22050 N = 2048 H = 1024 feature_rate = int(22050 / H) figsize = (9, 3) ``` -------------------------------- ### midi_to_music_xml_musescore Source: https://github.com/meinardmueller/synctoolbox/blob/master/docs/build/html/feature/csv_tools.html Converts a MIDI file to a MusicXML score using the musescore executable. This function is suitable for score-based MIDI files and requires musescore to be installed. ```APIDOC ## midi_to_music_xml_musescore ### Description Converts a midi file to a music xml score using musescore. This only works for score-based midis, not performed midis. Even for score-based midis, errors may occur. The resulting music xml should always be checked manually. For this method to work, musescore must be installed on the system. ### Parameters * **midi_filepath** (str) - Path to the midi file. A corresponding .mxl file of the same name will be created in the same directory. * **musescore_executable** (str) - Path to or name of the musescore executable. Defaults to 'musescore'. ### Returns None ``` -------------------------------- ### Load Modules and Define Constants for SyncToolbox Source: https://github.com/meinardmueller/synctoolbox/blob/master/sync_audio_audio_full.ipynb Imports necessary libraries and defines constants for audio processing and synchronization tasks. Includes modules for plotting, DTW, feature extraction, and utility functions. ```python import numpy as np import pandas as pd import librosa.display import matplotlib.pyplot as plt import IPython.display as ipd import scipy.interpolate from libfmp.b.b_plot import plot_signal, plot_chromagram from libfmp.c3.c3s2_dtw_plot import plot_matrix_with_points from synctoolbox.dtw.mrmsdtw import sync_via_mrmsdtw from synctoolbox.dtw.utils import compute_optimal_chroma_shift, shift_chroma_vectors, make_path_strictly_monotonic, evaluate_synchronized_positions from synctoolbox.feature.chroma import pitch_to_chroma, quantize_chroma, quantized_chroma_to_CENS from synctoolbox.feature.dlnco import pitch_onset_features_to_DLNCO from synctoolbox.feature.pitch import audio_to_pitch_features from synctoolbox.feature.pitch_onset import audio_to_pitch_onset_features from synctoolbox.feature.utils import estimate_tuning %matplotlib inline Fs = 22050 feature_rate = 50 step_weights = np.array([1.5, 1.5, 2.0]) threshold_rec = 10 ** 6 figsize = (9, 3) ``` -------------------------------- ### music_xml_to_csv_musical_time Source: https://github.com/meinardmueller/synctoolbox/blob/master/docs/build/html/feature/csv_tools.html Converts a MusicXML file into a list of note events, representing starts and durations as fractions of measures, and saves it as a CSV file in libfmp format. ```APIDOC ## music_xml_to_csv_musical_time ### Description Convert a music xml file to a list of note events, with starts and durations as fractions of measures, and stores it as a csv file in libfmp format. ### Parameters * **xml** (str or music21.stream.Score) - Either a path to a music xml file or a music21.stream.Score. * **csv_filepath** (str) - Filepath to the .csv file. ### Returns None ``` -------------------------------- ### Load Audio Version 1 Source: https://github.com/meinardmueller/synctoolbox/blob/master/sync_audio_audio_simple.ipynb Loads the first audio recording using librosa and plots its waveform. Displays the audio player for playback. ```python audio_1, _ = librosa.load('data_music/Schubert_D911-01_HU33.wav', sr=Fs) plot_signal(audio_1, Fs=Fs, ylabel='Amplitude', title='Version 1', figsize=figsize) ipd.display(ipd.Audio(audio_1, rate=Fs)) ``` -------------------------------- ### Load and Plot Audio Version 1 Source: https://github.com/meinardmueller/synctoolbox/blob/master/sync_audio_audio_full.ipynb Loads the first audio recording using librosa and visualizes its waveform. This step is crucial for initial audio inspection. ```python audio_1, _ = librosa.load('data_music/Schubert_D911-03_HU33.wav', sr=Fs) plot_signal(audio_1, Fs=Fs, ylabel='Amplitude', title='Version 1', figsize=figsize) ipd.display(ipd.Audio(audio_1, rate=Fs)) ``` -------------------------------- ### Split Feature Sequences Source: https://github.com/meinardmueller/synctoolbox/blob/master/docs/build/html/_modules/synctoolbox/dtw/mrmsdtw.html Splits feature sequences based on provided start and end points (anchors) and a feature rate. Handles cases where anchors are not provided or indicate the end of the sequence. ```python def __split_features(f_chroma1: np.ndarray, f_onset1: np.ndarray, f_chroma2: np.ndarray, f_onset2: np.ndarray, cur_a1: float, cur_a2: float, prev_a1: float, prev_a2: float, feature_rate: int) -> Tuple[np.ndarray, Optional[np.ndarray], np.ndarray, Optional[np.ndarray]]: if cur_a1 == -1: f_chroma1_split = f_chroma1[:, int(prev_a1 * feature_rate):] if f_onset1 is not None: f_onset1_split = f_onset1[:, int(prev_a1 * feature_rate):] else: f_onset1_split = None else: # Split the features f_chroma1_split = f_chroma1[:, int(prev_a1 * feature_rate):int(cur_a1 * feature_rate)] if f_onset1 is not None: f_onset1_split = f_onset1[:, int(prev_a1 * feature_rate):int(cur_a1 * feature_rate)] else: f_onset1_split = None if cur_a2 == -1: f_chroma2_split = f_chroma2[:, int(prev_a2 * feature_rate):] if f_onset2 is not None: f_onset2_split = f_onset2[:, int(prev_a2 * feature_rate):] else: f_onset2_split = None else: f_chroma2_split = f_chroma2[:, int(prev_a2 * feature_rate):int(cur_a2 * feature_rate)] if f_onset2 is not None: f_onset2_split = f_onset2[:, int(prev_a2 * feature_rate):int(cur_a2 * feature_rate)] else: f_onset2_split = None return f_chroma1_split, f_onset1_split, f_chroma2_split, f_onset2_split ``` -------------------------------- ### Load Audio Version 2 Source: https://github.com/meinardmueller/synctoolbox/blob/master/sync_audio_audio_simple.ipynb Loads the second audio recording using librosa and plots its waveform. Displays the audio player for playback. ```python audio_2, _ = librosa.load('data_music/Schubert_D911-01_SC06.wav', sr=Fs) plot_signal(audio_2, Fs=Fs, ylabel='Amplitude', title='Version 2', figsize=figsize) ipd.display(ipd.Audio(audio_2, rate=Fs)) ``` -------------------------------- ### read_csv_to_df Source: https://context7.com/meinardmueller/synctoolbox/llms.txt Reads a CSV file containing symbolic music (note events) into a pandas DataFrame. Column names are normalized to lowercase. Expected columns: `start`, `duration`, `pitch`, `velocity`, `instrument`. ```APIDOC ## read_csv_to_df ### Description Reads a CSV file containing symbolic music (note events) into a pandas DataFrame. Column names are normalized to lowercase. Expected columns: `start`, `duration`, `pitch`, `velocity`, `instrument`. ### Method `read_csv_to_df` ### Parameters - **csv_filepath** (str) - Path to the CSV file. - **csv_delimiter** (str) - Delimiter used in the CSV file. ### Request Example ```python from synctoolbox.feature.csv_tools import read_csv_to_df df = read_csv_to_df( csv_filepath="data_csv/Schubert_D911-01_SC06.csv", csv_delimiter=";" ) print(df.head()) # start duration pitch velocity instrument # 0 0.00 0.50 60 80.0 Piano # ... ``` ### Response - **df** (pandas.DataFrame) - DataFrame containing the symbolic music data. ``` -------------------------------- ### Load and Plot Audio Version 2 Source: https://github.com/meinardmueller/synctoolbox/blob/master/sync_audio_audio_full.ipynb Loads the second audio recording and displays its waveform. This allows for a visual comparison with the first version. ```python audio_2, _ = librosa.load('data_music/Schubert_D911-03_SC06.wav', sr=Fs) plot_signal(audio_2, Fs=Fs, ylabel='Amplitude', title='Version 2', figsize=figsize) ipd.display(ipd.Audio(audio_2, rate=Fs)) ``` -------------------------------- ### Pitch Onset Detection and Visualization Source: https://github.com/meinardmueller/synctoolbox/blob/master/docs/build/html/_modules/synctoolbox/feature/pitch_onset.html Processes audio features to detect pitch onsets, converts them to a matrix, and optionally visualizes the results. Handles multiple time resolutions and applies thresholds for peak detection. ```python f_onset = np.diff(f_energy) f_onset *= f_onset > 0 f_len = f_onset.size win_len = WINDOW_LENGTHS[index] sample_first = 1 thresh = np.zeros(f_onset.shape, dtype=np.float64) while sample_first <= f_len: sample_last = np.minimum(sample_first + win_len - 1, f_len) win_max = np.max(f_onset[sample_first-1:sample_last]) thr = 2 * win_max / 3 thresh[sample_first-1:sample_last] = np.array([thr] * (sample_last-sample_first+1), np.float64) sample_first += win_len res = RES_FAC[index] res_center = np.ceil(res/2) time_peaks = __find_peaks(W=f_onset, dir=1, abs_thresh=thresh) val_peaks = f_onset[time_peaks.astype(int)] time_peaks = (time_peaks * res - res_center) * 1000 / Fs if manual_offset != 0: time_peaks += manual_offset non_negative_indices = np.argwhere(time_peaks > 0) time_peaks = time_peaks[non_negative_indices] val_peaks = val_peaks[non_negative_indices] f_peaks[midi_pitch] = np.array([time_peaks, val_peaks]) if verbose: print("") highest_time_res = np.min(DOWNSAMPLING_FACTORS / np.array([Fs, Fs/5, Fs/25], np.float64)) imagedata = __f_peaks_to_matrix(f_audio.size / Fs, f_peaks, highest_time_res, midi_max, midi_min) __visualize_pitch(imagedata.T, midi_min, midi_max, feature_rate=1 / highest_time_res, plot_title=visualization_title, log_comp_gamma=visualization_log_gamma) plt.show() return f_peaks ``` -------------------------------- ### Visualize Step 1 of DTW Alignment Source: https://github.com/meinardmueller/synctoolbox/blob/master/docs/build/html/_modules/synctoolbox/dtw/mrmsdtw.html Generates a visualization for the first step of the DTW alignment, showing cost matrices and the initial warping path. Requires verbose output to be enabled. ```python fig, ax = sync_visualize_step1( cost_matrices_step1, num_rows_step1, num_cols_step1, anchors, wp ) ``` -------------------------------- ### Generate Sonification with Colored Clicks Source: https://github.com/meinardmueller/synctoolbox/blob/master/sync_audio_score_full.ipynb Generates a monaural audio signal using colored clicks based on note information (start time, pitch, velocity) and specified harmonics. This is a component of the sonification process. ```python # TODO This sonification procedure is very slow for long recordings and will be improved in a future version of synctoolbox. x_peaks = np.zeros(len(audio)) for row in note_list: second, duration, pitch, velocity = row freq = 2 ** ((pitch - 69) / 12) * 440 for harmonic_num, harmonic_weight in enumerate(harmonics): x_peaks += velocity / 128 * harmonic_weight * librosa.clicks(times=second, sr=Fs, click_freq=(harmonic_num+1)*freq, length=len(audio), click_duration=0.1) ``` -------------------------------- ### midi_to_music_xml_musescore Source: https://github.com/meinardmueller/synctoolbox/blob/master/docs/build/html/_modules/synctoolbox/feature/csv_tools.html Converts a MIDI file to a MusicXML score using the MuseScore executable. This function is suitable for score-based MIDI files and requires MuseScore to be installed on the system. The output MusicXML file should be manually verified for accuracy. ```APIDOC ## midi_to_music_xml_musescore ### Description Convert a midi file to a music xml score using musescore. This only works for score-based midis, not performed midis. Even for score-based midis, errors may occur. The resulting music xml should always be checked manually. For this method to work, musescore must be installed on the system. ### Parameters #### Path Parameters - **midi_filepath** (str) - Required - Path to the midi file. A corresponding .mxl file of the same name will be created in the same directory. - **musescore_executable** (str) - Optional - Path to or name of the musescore executable. Defaults to "musescore". ### Request Example ```python midi_to_music_xml_musescore(midi_filepath='/path/to/your/midi.mid', musescore_executable='/usr/bin/musescore') ``` ### Response #### Success Response (200) - **None** - This function does not return a value, but prints a success message upon successful conversion. #### Response Example ``` Successfully converted /path/to/your/midi.mid to /path/to/your/midi.mxl using musescore ``` ``` -------------------------------- ### Compare Runtime of DTW Algorithms Source: https://github.com/meinardmueller/synctoolbox/blob/master/sync_audio_audio_simple.ipynb Measures and prints the execution time for both the full DTW and MrMsDTW algorithms when aligning the chroma features of the two audio recordings. This comparison highlights the performance difference between the two methods. ```python start_time = time.time() C = cosine_distance(chroma_1, chroma_2) compute_warping_path(C=C) end_time = time.time() print(f'Full DTW took {end_time - start_time}s') start_time = time.time() sync_via_mrmsdtw(f_chroma1=chroma_1, f_chroma2=chroma_2, input_feature_rate=feature_rate, verbose=False) end_time = time.time() print(f'MrMsDTW took {end_time - start_time}s') ``` -------------------------------- ### Load Symbolic Music CSV to DataFrame Source: https://context7.com/meinardmueller/synctoolbox/llms.txt Reads a CSV file containing symbolic music (note events) into a pandas DataFrame. Column names are normalized to lowercase. Expected columns: `start`, `duration`, `pitch`, `velocity`, `instrument`. ```python from synctoolbox.feature.csv_tools import read_csv_to_df df = read_csv_to_df( csv_filepath="data_csv/Schubert_D911-01_SC06.csv", csv_delimiter=";" ) print(df.head()) # start duration pitch velocity instrument # 0 0.00 0.50 60 80.0 Piano # ... ``` -------------------------------- ### Audio Alignment with MrMsDTW using SyncToolbox Source: https://github.com/meinardmueller/synctoolbox/blob/master/ismir2021lbd_using_the_synctoolbox_for_an_experiment.ipynb Performs audio alignment using MrMsDTW with Chroma, Chroma & DLNCO, and Chroma & Spectral Flux features. Requires audio files, feature extraction functions, and SyncToolbox's `sync_via_mrmsdtw`. ```python wp_dict = dict() for song_id in range(1, 25): if song_id < 10: song_id = '0' + str(song_id) else: song_id = str(song_id) filename_1 = FILENAME_PREFIX + song_id + '_HU33' filename_2 = FILENAME_PREFIX + song_id + '_SC06' print(f"\nRunning for the Song ID {song_id} in SWD.") # read audio audio_1, _ = librosa.load(os.path.join(AUDIO_DIR, filename_1 + '.wav'), sr=Fs) audio_2, _ = librosa.load(os.path.join(AUDIO_DIR, filename_2 + '.wav'), sr=Fs) # estimate tuning tuning_offset_1 = estimate_tuning(audio_1, Fs) tuning_offset_2 = estimate_tuning(audio_2, Fs) # generate chroma features f_chroma_quantized_1 = get_chroma_features_from_audio( audio=audio_1, tuning_offset=tuning_offset_1) f_chroma_quantized_2 = get_chroma_features_from_audio( audio=audio_2, tuning_offset=tuning_offset_2) # generate novelty features (i.e. spectral flux) f_sf_1 = get_spectral_flux_from_audio( audio=audio_1, feature_sequence_length=f_chroma_quantized_1.shape[1]) f_sf_2 = get_spectral_flux_from_audio( audio=audio_2, feature_sequence_length=f_chroma_quantized_2.shape[1]) # generate DLNCO features f_DLNCO_1 = get_DLNCO_features_from_audio( audio=audio_1, tuning_offset=tuning_offset_1, feature_sequence_length=f_chroma_quantized_1.shape[1]) f_DLNCO_2 = get_DLNCO_features_from_audio( audio=audio_2, tuning_offset=tuning_offset_2, feature_sequence_length=f_chroma_quantized_2.shape[1]) # compute the optimal chroma shift and shift the chroma-based features of the second recording opt_chroma_shift = compute_optimal_chroma_shift( quantized_chroma_to_CENS(f_chroma_quantized_1, 201, 50, FEATURE_RATE)[0], quantized_chroma_to_CENS(f_chroma_quantized_2, 201, 50, FEATURE_RATE)[0]) f_chroma_quantized_2 = shift_chroma_vectors(f_chroma_quantized_2, opt_chroma_shift) f_DLNCO_2 = shift_chroma_vectors(f_DLNCO_2, opt_chroma_shift) # run MrMsDTW for chroma wp_chroma = sync_via_mrmsdtw( f_chroma1=f_chroma_quantized_1, f_chroma2=f_chroma_quantized_2, input_feature_rate=FEATURE_RATE, step_weights=STEP_WEIGHTS, threshold_rec=THRESHOLD_REC, verbose=False) # run MrMsDTW for chroma & DLNCO wp_chroma_dlnco = sync_via_mrmsdtw( f_chroma1=f_chroma_quantized_1, f_onset1=f_DLNCO_1, f_chroma2=f_chroma_quantized_2, f_onset2=f_DLNCO_2, input_feature_rate=FEATURE_RATE, step_weights=STEP_WEIGHTS, threshold_rec=THRESHOLD_REC, verbose=False) # run MrMsDTW for chroma & spectral flux wp_chroma_sf = sync_via_mrmsdtw( f_chroma1=f_chroma_quantized_1, f_onset1=f_sf_1, f_chroma2=f_chroma_quantized_2, f_onset2=f_sf_2, input_feature_rate=FEATURE_RATE, step_weights=STEP_WEIGHTS, threshold_rec=THRESHOLD_REC, verbose=False) wp_dict[song_id] = dict() wp_dict[song_id]['wp_chroma'] = wp_chroma wp_dict[song_id]['wp_chroma_dlnco'] = wp_chroma_dlnco wp_dict[song_id]['wp_chroma_sf'] = wp_chroma_sf ``` -------------------------------- ### Validate Anchor Pairs in MRMSDTW Source: https://github.com/meinardmueller/synctoolbox/blob/master/docs/build/html/_modules/synctoolbox/dtw/mrmsdtw.html This code validates anchor pairs to ensure they meet specific criteria for dynamic time warping. It checks for positive starting points, bounds relative to audio lengths, uniqueness, and monotonic increase. ```python prev_a1 = 0 prev_a2 = 0 for anchor_pair in anchor_pairs: a1, a2 = anchor_pair if a1 <= 0 or a2 <= 0: raise ValueError('Starting point must be a positive number!') if a1 > f_len1 / feature_rate or a2 > f_len2 / feature_rate: raise ValueError('Anchor points cannot be greater than the length of the input audio files!') if a1 == f_len1 and a2 == f_len2: raise ValueError('Both anchor points cannot be equal to the length of the audio files.') if a1 == prev_a1 and a2 == prev_a2: raise ValueError('Duplicate anchor pairs are not allowed!') if a1 < prev_a1 or a2 < prev_a2: raise ValueError('Anchor points must be monotonously increasing.') prev_a1 = a1 prev_a2 = a2 ``` -------------------------------- ### Compute Audio Features (Chroma and DLNCO) Source: https://github.com/meinardmueller/synctoolbox/blob/master/sync_audio_score_full.ipynb Computes quantized chroma and DLNCO features from audio data. Requires audio, tuning offset, sample rate, and desired feature rate. Visualization can be enabled. ```python def get_features_from_audio(audio, tuning_offset, Fs, feature_rate, visualize=True): f_pitch = audio_to_pitch_features(f_audio=audio, Fs=Fs, tuning_offset=tuning_offset, feature_rate=feature_rate, verbose=visualize) f_chroma = pitch_to_chroma(f_pitch=f_pitch) f_chroma_quantized = quantize_chroma(f_chroma=f_chroma) if visualize: plot_chromagram(f_chroma_quantized, title='Quantized chroma features - Audio', Fs=feature_rate, figsize=(9,3)) f_pitch_onset = audio_to_pitch_onset_features(f_audio=audio, Fs=Fs, tuning_offset=tuning_offset, verbose=visualize) f_DLNCO = pitch_onset_features_to_DLNCO(f_peaks=f_pitch_onset, feature_rate=feature_rate, feature_sequence_length=f_chroma_quantized.shape[1], visualize=visualize) return f_chroma_quantized, f_DLNCO f_chroma_quantized_audio, f_DLNCO_audio = get_features_from_audio(audio, tuning_offset, Fs, feature_rate) ``` -------------------------------- ### Get Spectral Flux Features from Audio Source: https://github.com/meinardmueller/synctoolbox/blob/master/ismir2021lbd_using_the_synctoolbox_for_an_experiment.ipynb Computes the spectral flux from an audio signal. This function calculates the novelty curve and ensures it matches the required feature sequence length by padding if necessary. It uses log compression for the novelty curve calculation. ```python def get_spectral_flux_from_audio(audio, feature_sequence_length, gamma=GAMMA, # log compression param Fs=Fs, feature_rate=FEATURE_RATE): f_novelty = spectral_flux(audio, Fs=Fs, feature_rate=feature_rate, gamma=gamma) if f_novelty.size < feature_sequence_length: # The feature sequence length of the chroma features are not same as the novelty curve # due to the padding while the computation of STFT for chroma features and # the differentiation in spectral flux diff = feature_sequence_length - f_novelty.size pad = int(diff / 2) f_novelty = np.concatenate((np.zeros(pad), f_novelty, np.zeros(pad))) return f_novelty.reshape(1, -1) ``` -------------------------------- ### audio_to_pitch_onset_features Source: https://context7.com/meinardmueller/synctoolbox/llms.txt Computes pitch onset features by detecting energy onsets per MIDI pitch. Returns a dictionary mapping each MIDI pitch to a 2xN array of onset times and magnitudes. ```APIDOC ## audio_to_pitch_onset_features ### Description Computes pitch onset features using the same IIR filterbank, then detects energy onsets per MIDI pitch using local peak picking. Returns a dictionary mapping each MIDI pitch to a 2×N array (onset times in ms, peak magnitudes). Used as input for DLNCO feature computation and high-resolution synchronization. ### Parameters - **f_audio** (np.ndarray) - Input audio time series. - **Fs** (int) - Sampling frequency of the audio. - **midi_min** (int) - Lowest MIDI pitch to extract features for. - **midi_max** (int) - Highest MIDI pitch to extract features for. - **tuning_offset** (float) - Cents offset for non-standard tuning. - **manual_offset** (float) - Shift onset times back by a specified number of milliseconds. - **verbose** (bool) - If True, prints verbose output. ### Returns - **f_peaks** (dict) - A dictionary where keys are MIDI pitches and values are NumPy arrays of shape (2, K), containing onset times in milliseconds and corresponding magnitudes. ``` -------------------------------- ### Get DLNCO Features from Audio Source: https://github.com/meinardmueller/synctoolbox/blob/master/ismir2021lbd_using_the_synctoolbox_for_an_experiment.ipynb Extracts DLNCO (Downbeat-aligned Localized Note Onset) features from audio. This involves computing pitch onset features first and then converting them to the DLNCO representation. It requires audio, tuning offset, and desired feature sequence length. ```python def get_DLNCO_features_from_audio(audio, tuning_offset, feature_sequence_length, Fs=Fs, feature_rate=FEATURE_RATE, verbose=False): f_pitch_onset = audio_to_pitch_onset_features(f_audio=audio, Fs=Fs, tuning_offset=tuning_offset, verbose=verbose) f_DLNCO = pitch_onset_features_to_DLNCO(f_peaks=f_pitch_onset, feature_rate=feature_rate, feature_sequence_length=feature_sequence_length, visualize=verbose) return f_DLNCO ``` -------------------------------- ### Compute Warping Path from Cost Matrix using DTW Source: https://context7.com/meinardmueller/synctoolbox/llms.txt Applies DTW directly to a precomputed cost matrix to find the optimal warping path. Supports 'synctoolbox' (Numba JIT) and 'librosa' backends. Ensure step_sizes and step_weights are correctly defined for the desired DTW constraints. ```python from synctoolbox.dtw.core import compute_warping_path from synctoolbox.dtw.cost import cosine_distance import numpy as np # Build a cosine distance cost matrix between two chroma sequences C = cosine_distance(f_chroma1[:, :200], f_chroma2[:, :200]) D, E, wp = compute_warping_path( C=C, step_sizes=np.array([[1, 0], [0, 1], [1, 1]], np.int64), step_weights=np.array([1.0, 1.0, 1.0], np.float64), implementation='synctoolbox' # or 'librosa' ) # D.shape == C.shape (accumulated cost matrix) # E.shape == C.shape (step index matrix) # wp.shape == (2, T) (warping path) print(f"DTW cost: {D[-1, -1]:.4f}, path length: {wp.shape[1]}") ``` -------------------------------- ### Calculate Feature Statistics Source: https://github.com/meinardmueller/synctoolbox/blob/master/ismir2021lbd_using_the_synctoolbox_for_an_experiment.ipynb Initializes and populates arrays with the mean and standard deviation of Chroma, Chroma & DLNCO, and Chroma & Spectral Flux features for each song. Assumes 'stats_dict' is pre-populated. ```python chroma_means = np.zeros(len(stats_dict)) chroma_std = np.zeros(len(stats_dict)) chroma_dlnco_means = np.zeros(len(stats_dict)) chroma_dlnco_std = np.zeros(len(stats_dict)) chroma_sf_means = np.zeros(len(stats_dict)) chroma_sf_std = np.zeros(len(stats_dict)) for idx, song_id in enumerate(stats_dict): chroma_means[idx] = stats_dict[song_id]['chroma']['mean'] chroma_std[idx] = stats_dict[song_id]['chroma']['std'] chroma_dlnco_means[idx] = stats_dict[song_id]['chroma_dlnco']['mean'] chroma_dlnco_std[idx] = stats_dict[song_id]['chroma_dlnco']['std'] chroma_sf_means[idx] = stats_dict[song_id]['chroma_sf']['mean'] chroma_sf_std[idx] = stats_dict[song_id]['chroma_sf']['std'] ``` -------------------------------- ### Load Audio Recording Source: https://github.com/meinardmueller/synctoolbox/blob/master/sync_audio_score_full.ipynb Loads an audio file using librosa and plots its waveform. Ensure the audio file path is correct. ```python audio, _ = librosa.load('data_music/Chopin_Op010-03-Measures1-8_Igoshina.wav', sr=Fs) plot_signal(x=audio, Fs=Fs, figsize=(9,3)) plt.title('Etude Op.10 No.3 in E Major by Frederic Chopin\n Performer: Valentina Igoshina') ipd.display(ipd.Audio(audio, rate=Fs)) ```