Created
March 29, 2024 18:53
-
-
Save JanWilczek/c2103897d9a93fce0b02b690ca87d36d to your computer and use it in GitHub Desktop.
Easily plot the magnitude spectrum of any audio signal and save it as a png file using Python and Matplotlib.Pyplot library. Includes styling the figure so that it looks reasonably well. You can use decibels full scale (dBFS) for the magnitude axis and a logarithmic frequency axis with ISO-standardized frequencies. Feel free to copy, paste & mod…
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import matplotlib.pyplot as plt | |
| import numpy as np | |
| from pathlib import Path | |
| import soundfile as sf | |
| import librosa | |
| COLOR = "#ef7600" | |
| IMG_OUTPUT_PATH = Path("img") | |
| SAVE_PARAMS = {"dpi": 300, "bbox_inches": "tight", "transparent": True} | |
| XTICKS = np.array([31.25, 62.5, 125, 250, 500, 1000, 2000, 4000, 8000]) | |
| XTICK_LABELS = np.array(["31.25", "62.5", "125", "250", "500", "1k", "2k", "4k", "8k"]) | |
| plt.rcParams.update({"font.size": 20}) | |
| def save_spectrum(output_path): | |
| output_path.parent.mkdir(parents=True, exist_ok=True) | |
| plt.savefig(output_path, **SAVE_PARAMS) | |
| def plot_spectrum_and_save(frequencies, magnitude_spectrum, output_path: Path): | |
| plt.figure(figsize=(12, 6)) | |
| plt.plot(frequencies, magnitude_spectrum, COLOR) | |
| xlim = [frequencies[0], frequencies[-1]] | |
| plt.xlim(xlim) | |
| plt.xlabel("frequency [Hz]") | |
| plt.hlines(0, xlim[0], xlim[1], colors="k") | |
| plt.xticks(None, None) | |
| plt.yticks([]) | |
| plt.ylabel("magnitude") | |
| ax = plt.gca() | |
| ax.spines["top"].set_visible(False) | |
| ax.spines["right"].set_visible(False) | |
| ax.spines["bottom"].set_visible(False) | |
| save_spectrum(output_path) | |
| plt.close() | |
| def plot_spectrum_db_and_save(frequencies, magnitude_spectrum, output_path: Path): | |
| plt.figure(figsize=(12, 6)) | |
| plt.plot(frequencies, magnitude_spectrum, COLOR) | |
| plt.xlim([0, frequencies[-1]]) | |
| plt.ylim([-60, 0]) | |
| plt.grid() | |
| plt.xlabel("frequency [Hz]") | |
| plt.ylabel("magnitude [dBFS]") | |
| ax = plt.gca() | |
| ax.spines["top"].set_visible(False) | |
| ax.spines["right"].set_visible(False) | |
| save_spectrum(output_path) | |
| plt.close() | |
| def plot_spectrum_db_in_octaves_and_save( | |
| frequencies, magnitude_spectrum, output_path: Path | |
| ): | |
| plt.figure(figsize=(12, 6)) | |
| plt.semilogx(frequencies, magnitude_spectrum, COLOR) | |
| plt.ylim([-60, 0]) | |
| plt.xticks(XTICKS, XTICK_LABELS) | |
| min_x = 29 | |
| plt.xlim([min_x, frequencies[-1]]) | |
| plt.grid() | |
| plt.xlabel("frequency [Hz]") | |
| plt.ylabel("magnitude [dBFS]") | |
| ax = plt.gca() | |
| ax.spines["top"].set_visible(False) | |
| ax.spines["right"].set_visible(False) | |
| # plt.show() # closes the figure | |
| save_spectrum(output_path) | |
| plt.close() | |
| def main(): | |
| signal, sample_rate = sf.read( | |
| Path(".") / "data" / "LibriSpeech-84-121123-0001.flac" | |
| ) | |
| print(f"Signal's sample rate: {sample_rate} Hz.") | |
| magnitude_spectrum = np.abs(np.fft.rfft(signal)) | |
| frequencies = np.fft.rfftfreq(signal.shape[0], 1 / sample_rate) | |
| plot_spectrum_and_save( | |
| frequencies, | |
| magnitude_spectrum, | |
| IMG_OUTPUT_PATH / "speech_magnitude_spectrum.png", | |
| ) | |
| normalized_magnitude_spectrum = magnitude_spectrum / np.amax(magnitude_spectrum) | |
| magnitude_spectrum_db = librosa.amplitude_to_db(normalized_magnitude_spectrum) | |
| plot_spectrum_db_and_save( | |
| frequencies, | |
| magnitude_spectrum_db, | |
| IMG_OUTPUT_PATH / "speech_magnitude_spectrum_db.png", | |
| ) | |
| plot_spectrum_db_in_octaves_and_save( | |
| frequencies, | |
| magnitude_spectrum_db, | |
| IMG_OUTPUT_PATH / "speech_magnitude_spectrum_db_in_octaves.png", | |
| ) | |
| if __name__ == "__main__": | |
| main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment