The following code please add the full cords to the window in addition to displaying the current code. also make sure you find the right cords you can use the average over multiple predictions for each takt. the takt should be 4 nodes per takt in most cases.

import tkinter as tk
from tkinter import filedialog, messagebox
import pygame
import librosa
import numpy as np
import threading
import time

# Define chord templates (Major and Minor)
CHORD_TEMPLATES = {
    'C':    [1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1],
    'C#':   [1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0],
    'D':    [0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0],
    'D#':   [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0],
    'E':    [0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1],
    'F':    [1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0],
    'F#':   [0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0],
    'G':    [0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0],
    'G#':   [0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0],
    'A':    [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0],
    'A#':   [0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1],
    'B':    [0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0],
    'Cm':   [1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1],
    'C#m':  [0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0],
    'Dm':   [0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0],
    'D#m':  [0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0],
    'Em':   [0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1],
    'Fm':   [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1],
    'F#m':  [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
    'Gm':   [0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0],
    'G#m':  [0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0],
    'Am':   [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0],
    'A#m':  [0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0],
    'Bm':   [0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0],
}

# Normalize chord templates
for chord in CHORD_TEMPLATES:
    template = np.array(CHORD_TEMPLATES[chord], dtype=float)
    CHORD_TEMPLATES[chord] = template / np.linalg.norm(template) if np.linalg.norm(template) != 0 else template

def transpose_chord(chord, semitones):
    # Define the order of chords
    base_chords = ['C', 'C#', 'D', 'D#', 'E', 'F',
                  'F#', 'G', 'G#', 'A', 'A#', 'B']

    # Handle minor chords
    is_minor = False
    if chord.endswith('m'):
        is_minor = True
        base = chord[:-1]
    else:
        base = chord

    if base not in base_chords:
        return chord  # Return original if chord not recognized

    idx = base_chords.index(base)
    transposed_idx = (idx + semitones) % 12
    transposed_base = base_chords[transposed_idx]

    transposed_chord = transposed_base + ('m' if is_minor else '')
    return transposed_chord

class ChordLyricsPlayer:
    def __init__(self, root):
        self.root = root
        self.root.title("Chord and Lyrics Player")

        # Initialize pygame mixer
        pygame.mixer.init()

        # Variables
        self.mp3_path = ""
        self.y = None
        self.sr = None
        self.chords = []
        self.playing = False
        self.start_time = 0
        self.transposition = 0
        self.current_chord = ""
        self.processed = False

        # UI Elements
        self.load_button = tk.Button(root, text="Load MP3", command=self.load_mp3)
        self.load_button.pack(pady=10)

        self.play_button = tk.Button(root, text="Play", command=self.play_pause, state=tk.DISABLED)
        self.play_button.pack(pady=5)

        transpose_frame = tk.Frame(root)
        transpose_frame.pack(pady=5)

        self.transpose_up = tk.Button(transpose_frame, text="Transpose +1", command=lambda: self.transpose(1), state=tk.DISABLED)
        self.transpose_up.pack(side=tk.LEFT, padx=5)

        self.transpose_down = tk.Button(transpose_frame, text="Transpose -1", command=lambda: self.transpose(-1), state=tk.DISABLED)
        self.transpose_down.pack(side=tk.LEFT, padx=5)

        self.display = tk.Label(root, text="", font=("Helvetica", 48))
        self.display.pack(pady=20)

        self.status = tk.Label(root, text="Load an MP3 to start.", relief=tk.SUNKEN, anchor='w')
        self.status.pack(fill=tk.X, side=tk.BOTTOM, ipady=2)

    def load_mp3(self):
        filepath = filedialog.askopenfilename(filetypes=[("MP3 Files", "*.mp3")])
        if not filepath:
            return
        self.mp3_path = filepath
        self.status.config(text="Processing audio for chord detection...")
        self.play_button.config(state=tk.DISABLED)
        self.transpose_up.config(state=tk.DISABLED)
        self.transpose_down.config(state=tk.DISABLED)
        self.display.config(text="")
        self.chords = []
        self.processed = False

        # Start a new thread for processing to keep GUI responsive
        threading.Thread(target=self.process_audio, daemon=True).start()

    def process_audio(self):
        try:
            # Load audio using librosa
            y, sr = librosa.load(self.mp3_path, sr=None, mono=True)
            self.y = y
            self.sr = sr

            # Tempo and beat tracking
            tempo, beat_frames = librosa.beat.beat_track(y=y, sr=sr)
            beat_times = librosa.frames_to_time(beat_frames, sr=sr)
            self.status.config(text=f"Detected Tempo: {int(tempo)} BPM. Extracting chords...")

            # Determine the number of beats per measure (assuming 4/4 time)
            beats_per_measure = 4
            measures = []
            for i in range(0, len(beat_times), beats_per_measure):
                start = beat_times[i]
                if i + beats_per_measure < len(beat_times):
                    end = beat_times[i + beats_per_measure]
                else:
                    end = librosa.get_duration(y=y, sr=sr)
                measures.append((start, end))

            # Extract chroma features
            chroma = librosa.feature.chroma_cqt(y=y, sr=sr)

            # Get timing for each chroma frame
            chroma_times = librosa.frames_to_time(np.arange(chroma.shape[1]), sr=sr)

            # For each measure, determine the dominant chord
            for measure in measures:
                start, end = measure
                # Find chroma frames within the measure
                indices = np.where((chroma_times >= start) & (chroma_times < end))[0]
                if len(indices) == 0:
                    continue
                # Average chroma features within the measure
                mean_chroma = np.mean(chroma[:, indices], axis=1)
                # Normalize
                mean_chroma = mean_chroma / np.linalg.norm(mean_chroma) if np.linalg.norm(mean_chroma) != 0 else mean_chroma
                # Compare with chord templates
                similarity = {}
                for chord, template in CHORD_TEMPLATES.items():
                    similarity[chord] = np.dot(mean_chroma, template)
                # Select the chord with the highest similarity
                detected_chord = max(similarity, key=similarity.get)
                self.chords.append({'time': start, 'chord': detected_chord})

            self.processed = True
            self.status.config(text="Chord detection complete. Ready to play.")
            self.play_button.config(state=tk.NORMAL)
            self.transpose_up.config(state=tk.NORMAL)
            self.transpose_down.config(state=tk.NORMAL)

            # Load the mp3 into pygame
            pygame.mixer.music.load(self.mp3_path)

        except Exception as e:
            messagebox.showerror("Error", f"Failed to process audio: {e}")
            self.status.config(text="Error processing audio.")

    def play_pause(self):
        if not self.playing:
            pygame.mixer.music.play()
            self.start_time = time.time()
            self.playing = True
            self.play_button.config(text="Pause")
            self.status.config(text="Playing...")
            # Start a new thread to update chords
            threading.Thread(target=self.update_chords, daemon=True).start()
        else:
            pygame.mixer.music.pause()
            self.playing = False
            self.play_button.config(text="Play")
            self.status.config(text="Paused.")

    def transpose(self, semitones):
        self.transposition += semitones
        # Update current chord if exists
        if self.current_chord:
            transposed = transpose_chord(self.current_chord, semitones)
            self.display.config(text=transposed)

    def update_chords(self):
        while self.playing and pygame.mixer.music.get_busy():
            elapsed_time = time.time() - self.start_time
            current_chord = ""
            for chord_entry in self.chords:
                if elapsed_time >= chord_entry['time']:
                    current_chord = chord_entry['chord']
                else:
                    break
            if current_chord != self.current_chord:
                self.current_chord = current_chord
                transposed = transpose_chord(current_chord, self.transposition)
                self.display.config(text=transposed)
            time.sleep(0.1)
        if self.playing:
            # Song ended
            self.playing = False
            self.play_button.config(text="Play")
            self.status.config(text="Finished.")

def main():
    root = tk.Tk()
    app = ChordLyricsPlayer(root)
    root.mainloop()

if __name__ == "__main__":
    main()