From e88878a1b3cd6cc0ef7287776c11e46f9c758323 Mon Sep 17 00:00:00 2001 From: Mikkeli Matlock Date: Wed, 10 Apr 2024 20:22:59 +0900 Subject: [PATCH] GUI frame --- files.txt | 7 +++ main.py | 160 +++++++++++-------------------------------------- master-core.py | 123 +++++++++++++++++++++++++++++++++++++ 3 files changed, 166 insertions(+), 124 deletions(-) create mode 100644 files.txt create mode 100644 master-core.py diff --git a/files.txt b/files.txt new file mode 100644 index 0000000..4cf4f82 --- /dev/null +++ b/files.txt @@ -0,0 +1,7 @@ +f:/ncmr/vocaloid/randomcovers/zorra/zorra_release1.mp3 +f:/ncmr/vocaloid/randomcovers/zorra/zorra_release2.mp3 +f:/ncmr/vocaloid/randomcovers/zorra/zorra_release4.mp3 +f:/ncmr/vocaloid/randomcovers/silti/silti_release1.mp3 +f:/ncmr/vocaloid/northwichcase/transparency/rover_release12.mp3 +I:/musiikki/[160518] THE IDOLM@STER CINDERELLA GIRLS STARLIGHT MASTER 02 Tulip [320K]/01. Tulip (M@STER VERSION).mp3 +I:/musiikki/556t - MELTING POT/01. ココロ.mp3 \ No newline at end of file diff --git a/main.py b/main.py index b42a7b0..0fe5e63 100644 --- a/main.py +++ b/main.py @@ -1,128 +1,40 @@ -import librosa -import numpy as np -import os +import sys +from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QLabel +from PyQt5.QtCore import Qt -import matplotlib.pyplot as plt -import matplotlib.colors as mcolors -import matplotlib.cm as cm - -from mutagen.mp3 import MP3 -from mutagen.easyid3 import EasyID3 - -def try_mp3_tags(file_path): - try: - # if there is metadata - audio = MP3(file_path, ID3=EasyID3) - return audio - except Exception as e: - print(f"Error reading ID3 tags: {e}") - return None - -def read_mp3_tags(file_path): - if (audio := try_mp3_tags(file_path)) is not None: - print(f"File name: {os.path.basename(file_path)}") - print(f"{audio['artist'][0]} - {audio['title'][0]}") - else: - print(f"File name: {os.path.basename(file_path)}") - -def analyze_track_librosa(file_path): - # Load the audio file - # y is the audio time series and sr is the sampling rate - y, sr = librosa.load(file_path) - - # Calculate the maximum amplitude - # Librosa's load function normalizes the audio to [-1, 1], so we scale it back - max_amplitude = np.max(np.abs(y)) - # Average amplitude - avg_amplitude = np.mean(np.abs(y)) - - # Convert max amplitude to dBFS - max_amplitude_dBFS = librosa.amplitude_to_db([max_amplitude], ref=1.0) - avg_amplitude_dBFS = librosa.amplitude_to_db([avg_amplitude], ref=1.0) - - # Calculate RMS in dB - S, phase = librosa.magphase(librosa.stft(y)) - rms_stft = librosa.feature.rms(S=S) - rms = librosa.feature.rms(y=y) - avg_power_dBFS_stft = 20 * np.log10(np.mean(rms_stft)) - avg_power_dBFS = 20 * np.log10(np.mean(rms)) - - return max_amplitude_dBFS[0], avg_amplitude_dBFS[0], avg_power_dBFS, avg_power_dBFS_stft - -def plot_macro_time_power_graph(file_path): - # Load the audio file - y, sr = librosa.load(file_path, mono=True) - - # Define the window and hop length - # 10 seconds window and 1 second hop - window_length = int(sr * 10) # 10 seconds in samples - hop_length = int(sr * 1) # 1 second in samples - - # Calculate RMS over the rolling windows - rms = librosa.feature.rms(y=y, frame_length=window_length, hop_length=hop_length) - - # Convert frame indices to time - times = librosa.frames_to_time(np.arange(rms.shape[1]), sr=sr, hop_length=hop_length) - - # Normalize RMS for color mapping - norm = mcolors.Normalize(vmin=0, vmax=0.4) - - # Choose a colormap - cmap = cm.autumn - - # Plot - fig, ax = plt.subplots(figsize=(10, 4)) - ax.set_ylim(0., 0.4) - for i in range(len(times)-1): - ax.fill_between(times[i:i+2], 0, rms[0][i], color=cmap(norm(rms[0][i])), edgecolor='none') +class AudioDragDropWidget(QWidget): + def __init__(self): + super().__init__() + self.initUI() - # Adding a colorbar to indicate the scale of RMS values - sm = cm.ScalarMappable(cmap=cmap, norm=norm) - sm.set_array([]) - cbar = plt.colorbar(sm, ax=ax, label='RMS Power') - # cbar.ax.set_yticklabels([f"{x-60.0:.0f} dBFS" for x in cbar.get_ticks()]) # Adjust labels to show true dBFS values + def initUI(self): + self.setWindowTitle('Drag and Drop Audio Analysis') + self.setGeometry(100, 100, 400, 200) # x, y, width, height + self.setAcceptDrops(True) + + # Layout and label for displaying messages + layout = QVBoxLayout() + self.label = QLabel('Drag and drop an audio file here', self) + self.label.setAlignment(Qt.AlignCenter) + layout.addWidget(self.label) + self.setLayout(layout) - ax.set_ylabel('Power') - ax.set_xlabel('Time') - ax.set_title(f'{os.path.basename(file_path)}') - # plt.ylabel('Power') - # plt.xlabel('Time (s)') - # plt.title(f'{os.path.basename(file_path)}') - plt.show(block=False) - plt.pause(0.001) + def dragEnterEvent(self, event): + if event.mimeData().hasUrls(): + event.accept() + else: + event.ignore() + + def dropEvent(self, event): + files = [u.toLocalFile() for u in event.mimeData().urls()] + for file_path in files: + self.label.setText(f'File dropped: {file_path}') + # Here, you would call your plot function with the dropped file path + # For example: plot_macro_time_power_graph_colormap(file_path) + break # This example only processes the first dropped file - - -def find_mp3_files(directory): - mp3_files = [] - # Walk through the directory - for root, dirs, files in os.walk(directory): - # Filter and append .mp3 files - for file in files: - if file.endswith(".mp3"): - mp3_files.append(os.path.join(root, file)) - return mp3_files - - -# Replace 'path/to/your/audiofile.mp3' with the path to your audio file -file_path = [] -# file_path.append('f:/ncmr/vocaloid/randomcovers/zorra/zorra_release1.mp3') -# file_path.append('f:/ncmr/vocaloid/randomcovers/zorra/zorra_release2.mp3') -file_path.append('f:/ncmr/vocaloid/randomcovers/zorra/zorra_release4.mp3') -# file_path.append('f:/ncmr/vocaloid/randomcovers/silti/silti_release1.mp3') -# file_path.append('f:/ncmr/vocaloid/northwichcase/transparency/rover_release12.mp3') -file_path.append('I:/musiikki/[160518] THE IDOLM@STER CINDERELLA GIRLS STARLIGHT MASTER 02 Tulip [320K]/01. Tulip (M@STER VERSION).mp3') -file_path.append('I:/musiikki/556t - MELTING POT/01. ココロ.mp3') - - - -for file in file_path: - max_amplitude, avg_amplitude, avg_power, avg_power_stft = analyze_track_librosa(file) - read_mp3_tags(file) - print(f"Maximum Amplitude: {max_amplitude:.2f} dBFS") - print(f"Average Amplitude: {avg_amplitude:.2f} dBFS") - print(f"Average Power: {avg_power:.2f} dBFS") - print(f"Average Power (STFT): {avg_power_stft:.2f} dBFS") - plot_macro_time_power_graph(file) - -plt.show() +if __name__ == '__main__': + app = QApplication(sys.argv) + ex = AudioDragDropWidget() + ex.show() + sys.exit(app.exec_()) \ No newline at end of file diff --git a/master-core.py b/master-core.py new file mode 100644 index 0000000..7c2cf3e --- /dev/null +++ b/master-core.py @@ -0,0 +1,123 @@ +import librosa +import numpy as np +import os + +import matplotlib.pyplot as plt +import matplotlib.colors as mcolors +import matplotlib.cm as cm + +from mutagen.mp3 import MP3 +from mutagen.easyid3 import EasyID3 + +def try_mp3_tags(file_path): + try: + # if there is metadata + audio = MP3(file_path, ID3=EasyID3) + return audio + except Exception as e: + print(f"Error reading ID3 tags: {e}") + return None + +def read_mp3_tags(file_path): + if (audio := try_mp3_tags(file_path)) is not None: + print(f"File name: {os.path.basename(file_path)}") + print(f"{audio['artist'][0]} - {audio['title'][0]}") + else: + print(f"File name: {os.path.basename(file_path)}") + +def analyze_track_librosa(file_path): + # Load the audio file + # y is the audio time series and sr is the sampling rate + y, sr = librosa.load(file_path) + + # Calculate the maximum amplitude + # Librosa's load function normalizes the audio to [-1, 1], so we scale it back + max_amplitude = np.max(np.abs(y)) + # Average amplitude + avg_amplitude = np.mean(np.abs(y)) + + # Convert max amplitude to dBFS + max_amplitude_dBFS = librosa.amplitude_to_db([max_amplitude], ref=1.0) + avg_amplitude_dBFS = librosa.amplitude_to_db([avg_amplitude], ref=1.0) + + # Calculate RMS in dB + S, phase = librosa.magphase(librosa.stft(y)) + rms_stft = librosa.feature.rms(S=S) + rms = librosa.feature.rms(y=y) + avg_power_dBFS_stft = 20 * np.log10(np.mean(rms_stft)) + avg_power_dBFS = 20 * np.log10(np.mean(rms)) + + return max_amplitude_dBFS[0], avg_amplitude_dBFS[0], avg_power_dBFS, avg_power_dBFS_stft + +def plot_macro_time_power_graph(file_path): + # Load the audio file + y, sr = librosa.load(file_path, mono=True) + + # Define the window and hop length + # 10 seconds window and 1 second hop + window_length = int(sr * 10) # 10 seconds in samples + hop_length = int(sr * 1) # 1 second in samples + + # Calculate RMS over the rolling windows + rms = librosa.feature.rms(y=y, frame_length=window_length, hop_length=hop_length) + + # Convert frame indices to time + times = librosa.frames_to_time(np.arange(rms.shape[1]), sr=sr, hop_length=hop_length) + + # Normalize RMS for color mapping + norm = mcolors.Normalize(vmin=0, vmax=0.4) + + # Choose a colormap + cmap = cm.autumn + + # Plot + fig, ax = plt.subplots(figsize=(10, 4)) + ax.set_ylim(0., 0.4) + for i in range(len(times)-1): + ax.fill_between(times[i:i+2], 0, rms[0][i], color=cmap(norm(rms[0][i])), edgecolor='none') + + # Adding a colorbar to indicate the scale of RMS values + sm = cm.ScalarMappable(cmap=cmap, norm=norm) + sm.set_array([]) + cbar = plt.colorbar(sm, ax=ax, label='RMS Power') + # cbar.ax.set_yticklabels([f"{x-60.0:.0f} dBFS" for x in cbar.get_ticks()]) # Adjust labels to show true dBFS values + + ax.set_ylabel('Power') + ax.set_xlabel('Time') + ax.set_title(f'{os.path.basename(file_path)}') + # plt.ylabel('Power') + # plt.xlabel('Time (s)') + # plt.title(f'{os.path.basename(file_path)}') + plt.show(block=False) + plt.pause(0.001) + + + +def find_mp3_files(directory): + mp3_files = [] + # Walk through the directory + for root, dirs, files in os.walk(directory): + # Filter and append .mp3 files + for file in files: + if file.endswith(".mp3"): + mp3_files.append(os.path.join(root, file)) + return mp3_files + + +# Replace 'path/to/your/audiofile.mp3' with the path to your audio file +file_path = [] +with open('./files.txt', 'r') as f: + for line in f: + if line[0] != '#': + file_path.append(line.strip()) + +for file in file_path: + max_amplitude, avg_amplitude, avg_power, avg_power_stft = analyze_track_librosa(file) + read_mp3_tags(file) + print(f"Maximum Amplitude: {max_amplitude:.2f} dBFS") + print(f"Average Amplitude: {avg_amplitude:.2f} dBFS") + print(f"Average Power: {avg_power:.2f} dBFS") + print(f"Average Power (STFT): {avg_power_stft:.2f} dBFS") + plot_macro_time_power_graph(file) + +plt.show()