C:\Users\chris\PycharmProjects\VirtualEnvironment\Scripts\python.exe C:\Users\chris\OneDrive\Dokumente\GitHub\LLMsBooster\GuitarChordGenerator\SimpleChordGenerator.py 
C:\Users\chris\PycharmProjects\VirtualEnvironment\lib\site-packages\lazy_loader\__init__.py:202: RuntimeWarning: subpackages can technically be lazily loaded, but it causes the package to be eagerly loaded even if it is already lazily loaded.So, you probably shouldn't use subpackages with this lazy feature.
  warnings.warn(msg, RuntimeWarning)

Process finished with exit code 0

import numpy as np
from pydub import AudioSegment
from pydub.generators import Sine
import librosa
import librosa.display
import tkinter as tk
from tkinter import filedialog, messagebox
import matplotlib.pyplot as plt
import threading
import simpleaudio as sa  # For playback
import sys

# ============================
# Configuration and Constants
# ============================

# Define the frequencies for the basic chords (corrected)
CHORD_FREQUENCIES = {
    'G': [196.00, 246.94, 293.66],    # G major chord: G, B, D
    'Em': [164.81, 196.00, 246.94],   # E minor chord: E, G, B
    'Am': [220.00, 261.63, 329.63],   # A minor chord: A, C, E
    'C': [261.63, 329.63, 392.00],    # C major chord: C, E, G
}

# Define the sampling rate and duration
SAMPLE_RATE = 44100  # Hz
DURATION_MS = 1000   # milliseconds per chord

# Define chord progression as a flat list
CHORD_PROGRESSION = [
    'G', 'Am', 'G', 'C', 'G', 'Am', 'G', 'C'
]

# ============================
# Chord Generation Functions
# ============================

def generate_chord_sound(chord_name, duration_ms=DURATION_MS):
    """
    Generate a chord AudioSegment by overlaying sine waves of the constituent frequencies.
    """
    if chord_name not in CHORD_FREQUENCIES:
        raise ValueError(f"Chord '{chord_name}' not recognized.")

    frequencies = CHORD_FREQUENCIES[chord_name]
    chord = AudioSegment.silent(duration=duration_ms)
    for freq in frequencies:
        sine_wave = Sine(freq).to_audio_segment(duration=duration_ms).apply_gain(-5)  # Adjust gain as necessary
        chord = chord.overlay(sine_wave)

    return chord

# ============================
# Audio Sequence Generation
# ============================

def generate_audio_sequence():
    """
    Generate the full audio sequence based on the specified chord progression.
    """
    full_track = AudioSegment.silent(duration=0)
    for chord_name in CHORD_PROGRESSION:
        chord_sound = generate_chord_sound(chord_name).fade_in(50).fade_out(50)  # Apply fade per chord
        full_track += chord_sound
    return full_track

# ============================
# Saving Audio Functionality
# ============================

def save_audio():
    """
    Generate and save the audio sequence to a user-specified file path.
    """
    save_path = filedialog.asksaveasfilename(
        defaultextension=".wav",
        filetypes=[("WAV files", "*.wav")],
        title="Save Audio As"
    )
    if not save_path:
        return  # User canceled

    try:
        audio = generate_audio_sequence()
        audio.export(save_path, format="wav")
        messagebox.showinfo("Success", f"Audio saved to:\n{save_path}")
    except Exception as e:
        messagebox.showerror("Error", f"Failed to save audio.\n{e}")

# ============================
# Playback Functionality
# ============================

def play_audio(file_path):
    """
    Play the specified WAV audio file using simpleaudio.
    """
    try:
        wave_obj = sa.WaveObject.from_wave_file(file_path)
        play_obj = wave_obj.play()
        play_obj.wait_done()
    except Exception as e:
        messagebox.showerror("Error", f"Failed to play audio.\n{e}")

def play_selected_audio():
    """
    Open a file dialog to select and play a WAV audio file.
    """
    file_path = filedialog.askopenfilename(
        filetypes=[("WAV files", "*.wav")],
        title="Select Audio File to Play"
    )
    if file_path:
        threading.Thread(target=play_audio, args=(file_path,), daemon=True).start()

# ============================
# Chord Detection Functions
# ============================

def detect_chords(file_path):
    """
    Detect chords from the specified WAV audio file using librosa's chroma features.
    """
    try:
        y, sr = librosa.load(file_path, sr=SAMPLE_RATE, mono=True)
    except Exception as e:
        messagebox.showerror("Error", f"Failed to load audio file.\n{e}")
        return

    hop_length = 512
    try:
        # Compute chromagram from the audio signal
        chroma = librosa.feature.chroma_stft(y=y, sr=sr, hop_length=hop_length)
    except Exception as e:
        messagebox.showerror("Error", f"Failed to compute chroma features.\n{e}")
        return

    # Define chord duration in seconds
    chord_duration_sec = DURATION_MS / 1000.0
    # Compute number of frames per chord
    frames_per_chord = int(chord_duration_sec * sr / hop_length)

    num_frames = chroma.shape[1]
    num_chords = num_frames // frames_per_chord
    detected_chords = []

    for i in range(num_chords):
        start = i * frames_per_chord
        end = start + frames_per_chord
        chroma_slice = chroma[:, start:end]
        chroma_mean = np.mean(chroma_slice, axis=1)
        # Identify chord
        chord = identify_chord(chroma_mean)
        detected_chords.append(chord)

    # Handle remaining frames (if any)
    if num_frames % frames_per_chord != 0:
        chroma_slice = chroma[:, num_chords * frames_per_chord:]
        chroma_mean = np.mean(chroma_slice, axis=1)
        chord = identify_chord(chroma_mean)
        detected_chords.append(chord)

    # Display detected chords
    chords_str = ', '.join(detected_chords)
    messagebox.showinfo("Detected Chords", f"Chords detected:\n{chords_str}")

    # Plot the chroma feature
    plt.figure(figsize=(12, 4))
    librosa.display.specshow(chroma, x_axis='time', y_axis='chroma', hop_length=hop_length, cmap='coolwarm')
    plt.title('Chroma Feature')
    plt.colorbar()
    plt.tight_layout()
    plt.show()

def identify_chord(chroma_vector):
    """
    Identify the chord from the chroma vector using cosine similarity with chord templates.
    """
    # Define chord templates (only major and minor chords)
    chord_templates = {
        'C':    [1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0],  # C, E, G
        'C#':   [0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0],  # C#, F, G#
        'D':    [0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0],  # D, F#, A
        'D#':   [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0],  # D#, G, A#
        'E':    [0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1],  # E, G#, B
        'F':    [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0],  # F, A, C
        'F#':   [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],  # F#, A#, C#
        'G':    [0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1],  # G, B, D
        'G#':   [0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0],  # G#, C, D#
        'A':    [0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0],  # A, C#, E
        'A#':   [0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0],  # A#, D, F
        'B':    [0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1],  # B, D#, F#
        'Cm':   [1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0],  # C, Eb, G
        'C#m':  [0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0],  # C#, E, G#
        'Dm':   [0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0],  # D, F, A
        'D#m':  [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1],  # D#, F#, A#
        'Em':   [0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1],  # E, G, B
        'Fm':   [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0],  # F, Ab, C
        'F#m':  [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],  # F#, A, C#
        'Gm':   [0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1],  # G, Bb, D
        'G#m':  [0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0],  # G#, B, D#
        'Am':   [1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0],  # A, C, E
        'A#m':  [0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0],  # A#, C, F
        'Bm':   [0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1],  # B, D, F#
    }

    # Normalize chord templates
    chord_templates_normalized = {
        chord: np.array(template) / np.linalg.norm(template) if np.linalg.norm(template) != 0 else np.array(template)
        for chord, template in chord_templates.items()
    }

    # Define similarity threshold
    SIMILARITY_THRESHOLD = 0.5  # Adjust as needed (lower if necessary)

    def identify_chord(chroma_vector):
        """
        Identify the chord from the chroma vector using cosine similarity with chord templates.
        """
        # Normalize chroma vector
        if np.linalg.norm(chroma_vector) == 0:
            chroma_norm = chroma_vector
        else:
            chroma_norm = chroma_vector / np.linalg.norm(chroma_vector)

        # Compute cosine similarity with each chord template
        max_similarity = -1
        detected_chord = "Unknown"
        for chord, template in chord_templates_normalized.items():
            similarity = np.dot(chroma_norm, template)
            if similarity > max_similarity:
                max_similarity = similarity
                detected_chord = chord

        # Apply a similarity threshold to reduce false positives
        if max_similarity < SIMILARITY_THRESHOLD:
            detected_chord = "Unknown"

        return detected_chord

    # ============================
    # GUI Application
    # ============================

    def browse_file():
        """
        Open a file dialog to select an audio file for chord detection.
        """
        file_path = filedialog.askopenfilename(
            filetypes=[("WAV files", "*.wav")],
            title="Select Audio File for Chord Detection"
        )
        if file_path:
            detect_chords(file_path)

    def quit_application():
        """
        Quit the application gracefully.
        """
        sys.exit()

    def create_gui():
        """
        Create and run the GUI application.
        """
        root = tk.Tk()
        root.title("Chord Generator and Detector")

        # Set the window size and disable resizing
        root.geometry("500x450")
        root.resizable(False, False)

        # Create Generate Audio button
        generate_button = tk.Button(
            root,
            text="Generate Audio",
            command=save_audio,
            width=25,
            height=2,
            bg='lightblue'
        )
        generate_button.pack(pady=15)

        # Create Play Audio button
        play_button = tk.Button(
            root,
            text="Play Audio",
            command=play_selected_audio,
            width=25,
            height=2,
            bg='lightgreen'
        )
        play_button.pack(pady=10)

        # Create Detect Chords button
        detect_button = tk.Button(
            root,
            text="Detect Chords",
            command=browse_file,
            width=25,
            height=2,
            bg='lightyellow'
        )
        detect_button.pack(pady=15)

        # Instructions Label
        instructions = tk.Label(
            root,
            text="Instructions:\n"
                 "1. Click 'Generate Audio' to create a chord progression.\n"
                 "2. Save the audio as a WAV file.\n"
                 "3. Use 'Play Audio' to listen to the saved file.\n"
                 "4. Use 'Detect Chords' to analyze any WAV file.",
            justify="left",
            padx=10,
            pady=10
        )
        instructions.pack()

        # Add a Quit button
        quit_button = tk.Button(
            root,
            text="Quit",
            command=quit_application,
            width=10,
            bg='red',
            fg='white'
        )
        quit_button.pack(pady=10)

        root.mainloop()

    # ============================
    # Main Execution
    # ============================

    if __name__ == "__main__":
        create_gui()


And the code doesnt execute correclty My previous version worked

import numpy as np
from pydub import AudioSegment
from pydub.generators import Sine
import librosa
import librosa.display
import tkinter as tk
from tkinter import filedialog, messagebox
import matplotlib.pyplot as plt
import threading
import simpleaudio as sa  # For playback
import sys

# ============================
# Configuration and Constants
# ============================

# Define the frequencies for the basic chords (corrected)
CHORD_FREQUENCIES = {
    'G': [196.00, 246.94, 293.66],    # G major chord: G, B, D
    'Em': [164.81, 196.00, 246.94],   # E minor chord: E, G, B
    'Am': [220.00, 261.63, 329.63],   # A minor chord: A, C, E
    'C': [261.63, 329.63, 392.00],    # C major chord: C, E, G
}

# Define the sampling rate and duration
SAMPLE_RATE = 44100  # Hz
DURATION_MS = 1000   # milliseconds per chord

# Define chord progression as a flat list
CHORD_PROGRESSION = [
    'G', 'Am', 'G', 'C', 'G', 'Am', 'G', 'C'
]

# ============================
# Chord Generation Functions
# ============================

def generate_chord_sound(chord_name, duration_ms=DURATION_MS):
    """
    Generate a chord AudioSegment by overlaying sine waves of the constituent frequencies.
    """
    if chord_name not in CHORD_FREQUENCIES:
        raise ValueError(f"Chord '{chord_name}' not recognized.")

    frequencies = CHORD_FREQUENCIES[chord_name]
    chord = AudioSegment.silent(duration=duration_ms)
    for freq in frequencies:
        sine_wave = Sine(freq).to_audio_segment(duration=duration_ms).apply_gain(-5)  # Adjust gain as necessary
        chord = chord.overlay(sine_wave)

    return chord

# ============================
# Audio Sequence Generation
# ============================

def generate_audio_sequence():
    """
    Generate the full audio sequence based on the specified chord progression.
    """
    full_track = AudioSegment.silent(duration=0)
    for chord_name in CHORD_PROGRESSION:
        chord_sound = generate_chord_sound(chord_name).fade_in(50).fade_out(50)  # Apply fade per chord
        full_track += chord_sound
    return full_track

# ============================
# Saving Audio Functionality
# ============================

def save_audio():
    """
    Generate and save the audio sequence to a user-specified file path.
    """
    save_path = filedialog.asksaveasfilename(
        defaultextension=".wav",
        filetypes=[("WAV files", "*.wav")],
        title="Save Audio As"
    )
    if not save_path:
        return  # User canceled

    try:
        audio = generate_audio_sequence()
        audio.export(save_path, format="wav")
        messagebox.showinfo("Success", f"Audio saved to:\n{save_path}")
    except Exception as e:
        messagebox.showerror("Error", f"Failed to save audio.\n{e}")

# ============================
# Playback Functionality
# ============================

def play_audio(file_path):
    """
    Play the specified WAV audio file using simpleaudio.
    """
    try:
        wave_obj = sa.WaveObject.from_wave_file(file_path)
        play_obj = wave_obj.play()
        play_obj.wait_done()
    except Exception as e:
        messagebox.showerror("Error", f"Failed to play audio.\n{e}")

def play_selected_audio():
    """
    Open a file dialog to select and play a WAV audio file.
    """
    file_path = filedialog.askopenfilename(
        filetypes=[("WAV files", "*.wav")],
        title="Select Audio File to Play"
    )
    if file_path:
        threading.Thread(target=play_audio, args=(file_path,), daemon=True).start()

# ============================
# Chord Detection Functions
# ============================

def detect_chords(file_path):
    """
    Detect chords from the specified WAV audio file using librosa's chroma features.
    """
    try:
        y, sr = librosa.load(file_path, sr=SAMPLE_RATE, mono=True)
    except Exception as e:
        messagebox.showerror("Error", f"Failed to load audio file.\n{e}")
        return

    hop_length = 512
    try:
        # Compute chromagram from the audio signal
        chroma = librosa.feature.chroma_stft(y=y, sr=sr, hop_length=hop_length)
    except Exception as e:
        messagebox.showerror("Error", f"Failed to compute chroma features.\n{e}")
        return

    # Define chord duration in seconds
    chord_duration_sec = DURATION_MS / 1000.0
    # Compute number of frames per chord
    frames_per_chord = int(chord_duration_sec * sr / hop_length)

    num_frames = chroma.shape[1]
    num_chords = num_frames // frames_per_chord
    detected_chords = []

    for i in range(num_chords):
        start = i * frames_per_chord
        end = start + frames_per_chord
        chroma_slice = chroma[:, start:end]
        chroma_mean = np.mean(chroma_slice, axis=1)
        # Identify chord
        chord = identify_chord(chroma_mean)
        detected_chords.append(chord)

    # Handle remaining frames
    if num_frames % frames_per_chord != 0:
        chroma_slice = chroma[:, num_chords * frames_per_chord:]
        chroma_mean = np.mean(chroma_slice, axis=1)
        chord = identify_chord(chroma_mean)
        detected_chords.append(chord)

    # Display detected chords
    chords_str = ', '.join(detected_chords)
    messagebox.showinfo("Detected Chords", f"Chords detected:\n{chords_str}")

    # Plot the chroma feature
    plt.figure(figsize=(12, 4))
    librosa.display.specshow(chroma, x_axis='time', y_axis='chroma', hop_length=hop_length, cmap='coolwarm')
    plt.title('Chroma Feature')
    plt.colorbar()
    plt.tight_layout()
    plt.show()

def identify_chord(chroma_vector):
    """
    Identify the chord from the chroma vector using cosine similarity with chord templates.
    """
    # Define chord templates (only major and minor chords)
    chord_templates = {
        'C':    [1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0],
        'C#':   [0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0],
        'D':    [0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0],
        'D#':   [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0],
        'E':    [0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1],
        'F':    [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0],
        'F#':   [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
        'G':    [1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0],
        'G#':   [0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0],
        'A':    [0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0],
        'A#':   [0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0],
        'B':    [0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1],
        'Cm':   [1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0],
        'C#m':  [0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0],
        'Dm':   [0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0],
        'D#m':  [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1],
        'Em':   [0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1],
        'Fm':   [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0],
        'F#m':  [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
        'Gm':   [1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0],
        'G#m':  [0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0],
        'Am':   [0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0],
        'A#m':  [0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0],
        'Bm':   [0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1],
    }

    # Normalize chord templates
    chord_templates_normalized = {
        chord: np.array(template) / np.linalg.norm(template) if np.linalg.norm(template) != 0 else np.array(template)
        for chord, template in chord_templates.items()
    }

    # Normalize chroma vector
    if np.linalg.norm(chroma_vector) == 0:
        chroma_norm = chroma_vector
    else:
        chroma_norm = chroma_vector / np.linalg.norm(chroma_vector)

    # Compute cosine similarity with each chord template
    max_similarity = -1
    detected_chord = "Unknown"
    for chord, template in chord_templates_normalized.items():
        similarity = np.dot(chroma_norm, template)
        if similarity > max_similarity:
            max_similarity = similarity
            detected_chord = chord

    # Apply a similarity threshold to reduce false positives
    similarity_threshold = 0.5  # Adjust as needed (lower if necessary)
    if max_similarity < similarity_threshold:
        detected_chord = "Unknown"

    return detected_chord

# ============================
# GUI Application
# ============================

def browse_file():
    """
    Open a file dialog to select an audio file for chord detection.
    """
    file_path = filedialog.askopenfilename(
        filetypes=[("WAV files", "*.wav")],
        title="Select Audio File for Chord Detection"
    )
    if file_path:
        detect_chords(file_path)

def quit_application():
    """
    Quit the application gracefully.
    """
    sys.exit()

def create_gui():
    """
    Create and run the GUI application.
    """
    root = tk.Tk()
    root.title("Chord Generator and Detector")

    # Set the window size and disable resizing
    root.geometry("500x450")
    root.resizable(False, False)

    # Create Generate Audio button
    generate_button = tk.Button(
        root,
        text="Generate Audio",
        command=save_audio,
        width=25,
        height=2,
        bg='lightblue'
    )
    generate_button.pack(pady=15)

    # Create Play Audio button
    play_button = tk.Button(
        root,
        text="Play Audio",
        command=play_selected_audio,
        width=25,
        height=2,
        bg='lightgreen'
    )
    play_button.pack(pady=10)

    # Create Detect Chords button
    detect_button = tk.Button(
        root,
        text="Detect Chords",
        command=browse_file,
        width=25,
        height=2,
        bg='lightyellow'
    )
    detect_button.pack(pady=15)

    # Instructions Label
    instructions = tk.Label(
        root,
        text="Instructions:\n"
             "1. Click 'Generate Audio' to create a chord progression.\n"
             "2. Save the audio as a WAV file.\n"
             "3. Use 'Play Audio' to listen to the saved file.\n"
             "4. Use 'Detect Chords' to analyze any WAV file.",
        justify="left",
        padx=10,
        pady=10
    )
    instructions.pack()

    # Add a Quit button
    quit_button = tk.Button(
        root,
        text="Quit",
        command=quit_application,
        width=10,
        bg='red',
        fg='white'
    )
    quit_button.pack(pady=10)

    root.mainloop()

# ============================
# Main Execution
# ============================

if __name__ == "__main__":
    create_gui()