Simple Sliced audio file creator thats compatible with the M8
import tkinter as tk

win_Main = tk.Tk()

win_Main.geometry("500x500")
win_Main.title("CocatenM8er")

label=tk.Label(win_Main, text="CocatenM8er", font=('Arial',20))
label.pack(padx=20, pady=20)

textbox=tk.Text(win_Main, height=1, font=('Arial',16))
textbox.pack(padx=10, pady=10) 


btn_Exit = tk.Button(win_Main, text="Exit", font=('Arial',20))
btn_Exit.pack(padx=10, pady=10)

btn_Select = tk.Button(win_Main, text="Select Wavs", font=('Arial',20))
btn_Select.pack(padx=10, pady=10)




win_Main.mainloop()


InterfaceTest_01.py
aTanguay/M8_KitCreator
import os
import tkinter as tk
import tkinter.font as tkFont

from tkinter import *
#from PIL import ImageTk, Image
from tkinter import filedialog

import customtkinter as cTK



class App:
    def __init__(self, root):
        #setting title
        root.title("ConcanteM8er")
        #setting window size
        width=500
        height=250
        screenwidth = root.winfo_screenwidth()
        screenheight = root.winfo_screenheight()
        alignstr = '%dx%d+%d+%d' % (width, height, (screenwidth - width) / 2, (screenheight - height) / 2)
        root.geometry(alignstr)
        root.resizable(width=False, height=False)

        GLabel_230=tk.Label(root)
        ft = tkFont.Font(family='Arial',size=22)
        GLabel_230["font"] = ft
        GLabel_230["fg"] = "#333333"
        GLabel_230["justify"] = "center"
        GLabel_230["text"] = "ConcateM8er"
        GLabel_230.place(x=50,y=10,width=155,height=55)

        GButton_334=tk.Button(root)
        GButton_334["bg"] = "#e9e9ed"
        ft = tkFont.Font(family='Arial',size=10)
        GButton_334["font"] = ft
        GButton_334["fg"] = "#000000"
        GButton_334["justify"] = "center"
        GButton_334["text"] = "Exit"
        GButton_334.place(x=420,y=210,width=70,height=25)
        GButton_334["command"] = self.GButton_334_command

        GButton_123=tk.Button(root)
        GButton_123["bg"] = "#e9e9ed"
        ft = tkFont.Font(family='Arial',size=10)
        GButton_123["font"] = ft
        GButton_123["fg"] = "#000000"
        GButton_123["justify"] = "center"
        GButton_123["text"] = "Select Audio Files"
        GButton_123.place(x=120,y=160,width=120,height=25)
        GButton_123["command"] = self.GButton_123_command

        GButton_482=tk.Button(root)
        GButton_482["bg"] = "#e9e9ed"
        ft = tkFont.Font(family='Arial',size=10)
        GButton_482["font"] = ft
        GButton_482["fg"] = "#000000"
        GButton_482["justify"] = "center"
        GButton_482["text"] = "Concetenate"
        GButton_482.place(x=270,y=160,width=100,height=25)
        GButton_482["command"] = self.GButton_482_command

        GMessage_198=tk.Message(root)
        ft = tkFont.Font(family='Arial',size=10)
        GMessage_198["font"] = ft
        GMessage_198["fg"] = "#333333"
        GMessage_198["justify"] = "center"
        GMessage_198["text"] = "Message"
        GMessage_198.place(x=340,y=50,width=80,height=25)

        GLabel_705=tk.Label(root)
        ft = tkFont.Font(family='Arial',size=10)
        GLabel_705["font"] = ft
        GLabel_705["fg"] = "#333333"
        GLabel_705["justify"] = "center"
        GLabel_705["text"] = "Sliced Kit Maker"
        GLabel_705.place(x=20,y=50,width=154,height=30)

    def GButton_334_command(self):
        print("Exit")


    def GButton_123_command(self):
        print("Select_Files")


    def GButton_482_command(self):
        print("Do_it")

if __name__ == "__main__":
    root = tk.Tk()
    app = App(root)
    root.mainloop()

InterfaceTest_02.py
aTanguay/M8_KitCreator
import tkinter as tk
from tkinter import filedialog
import customtkinter as ctk
import os
import wave
import struct
from pydub import AudioSegment
from pydub.silence import split_on_silence

class FileSelectorApp(tk.Tk):
    def __init__(self):
        super().__init__()

        self.title("File Selector App")
        self.geometry("500x500")

        # Lists to store selected file names and their full paths
        self.file_names = []
        self.file_paths = []

        # Frame for buttons
        self.button_frame = tk.Frame(self)
        self.button_frame.pack(pady=20)

        # Button to select files
        self.select_button = ctk.CTkButton(self.button_frame, text="Select Files", command=self.select_files)
        self.select_button.grid(row=0, column=0, padx=5)

        # Button to clear files from the list
        self.clear_button = ctk.CTkButton(self.button_frame, text="Clear Files", command=self.clear_files)
        self.clear_button.grid(row=0, column=1, padx=5)

        # Listbox to display selected file names (not full paths)
        self.file_listbox = tk.Listbox(self, width=50, height=10)
        self.file_listbox.pack(pady=20)

        # Frame for bottom buttons
        self.bottom_button_frame = tk.Frame(self)
        self.bottom_button_frame.pack(pady=20)

        # Button to merge files
        self.merge_button = ctk.CTkButton(self.bottom_button_frame, text="Merge", command=self.merge_files)
        self.merge_button.grid(row=0, column=0, padx=5)

        # Button to close the application
        self.close_button = ctk.CTkButton(self.bottom_button_frame, text="Close", command=self.close_app)
        self.close_button.grid(row=0, column=1, padx=5)

    def select_files(self):
        # Open file dialog to select files
        files = filedialog.askopenfilenames(title="Select Files")

        # Clear the file_names and file_paths lists, and the listbox
        self.file_names.clear()
        self.file_paths.clear()
        self.file_listbox.delete(0, tk.END)

        # Add selected file names (not full paths) to the file_names list and the listbox
        # Also add the full paths to the file_paths list
        for file in files:
            file_name = os.path.basename(file)
            self.file_names.append(file_name)
            self.file_paths.append(file)
            self.file_listbox.insert(tk.END, file_name)

    def clear_files(self):
        # Clear the file_names, file_paths lists, and the listbox
        self.file_names.clear()
        self.file_paths.clear()
        self.file_listbox.delete(0, tk.END)

    def merge_files(self):
        # Prompt the user for the output file location
        output_file = filedialog.asksaveasfilename(title="Select Output File", defaultextension=".wav", filetypes=[("Wav Files", "*.wav"), ("All Files", "*.*")])

        # Check if a valid output file location is provided
        if output_file:
            # For now, just print the selected output location.
            # The actual merging logic can be added here.
            print(f"Merging files into {output_file}...")
            concatenate_audio_files(self.file_paths, output_file)

    def close_app(self):
        self.destroy()



def concatenate_audio_files(file_names, output_file, marker_duration_ms=1, silence_thresh=-50.0, min_silence_len=10, retained_silence=1):
    marker = AudioSegment.silent(duration=marker_duration_ms)
    retain_silence = AudioSegment.silent(duration=retained_silence)

    concatenated_audio = AudioSegment.empty()
    cue_positions = [len(marker.get_array_of_samples())]  # Add initial marker position

    concatenated_audio += marker  # Add marker at 00 position

    for file in file_names:
        audio = AudioSegment.from_wav(file)

        # Convert to mono
        audio = audio.set_channels(1)

        chunks = split_on_silence(audio, silence_thresh=silence_thresh, min_silence_len=min_silence_len)
        processed_audio = sum([chunk + retain_silence for chunk in chunks], AudioSegment.empty())[:-retained_silence]

        concatenated_audio += processed_audio
        cue_positions.append(len(concatenated_audio.get_array_of_samples()))
        concatenated_audio += marker

    concatenated_audio.export(output_file, format="wav")

    # Add cue points
    with wave.open(output_file, 'rb') as wf:
        params = wf.getparams()
        num_frames = params.nframes
        data = wf.readframes(num_frames)

    cue_chunk_data = struct.pack('<L', len(cue_positions))
    for i, position in enumerate(cue_positions):
        cue_id = i + 1
        cue_chunk_data += struct.pack('<LL4sLLL', cue_id, position, b'data', 0, 0, position)

    cue_chunk = b'cue ' + struct.pack('<L', len(cue_chunk_data)) + cue_chunk_data

    with wave.open(output_file, 'wb') as wf:
        wf.setparams(params)
        wf.writeframes(data)
        wf._file.write(cue_chunk)

    print(f"Concatenated audio saved as {output_file}")
    

if __name__ == "__main__":
    app = FileSelectorApp()
    app.mainloop()

InterfaceTest_03.py
aTanguay/M8_KitCreator
import os
from pydub import AudioSegment
from pydub.generators import Sine
import tkinter as tk
from tkinter import filedialog, messagebox

# This script works, but it only puts a bleep at the start of the files.
# If it added markers instead, it would be great

def concatenate_audio_files(files, output_file, marker_duration_ms=1, marker_frequency=440, silence_thresh=-40.0, silence_len=1000):
    # Generate the audio marker
    marker = Sine(marker_frequency).to_audio_segment(duration=marker_duration_ms)

    # Concatenate audio files with a marker in between and remove long silences
    concatenated_audio = AudioSegment.empty()
    for file in files:
        audio = AudioSegment.from_wav(file)

        # Remove silences longer than silence_len
        audio = strip_long_silence(audio, silence_thresh, silence_len)

        concatenated_audio += audio + marker

    # Remove the last marker
    concatenated_audio = concatenated_audio[:-marker_duration_ms]

    # Export the concatenated audio
    concatenated_audio.export(output_file, format="wav")
def strip_long_silence(audio, silence_thresh=-40.0, silence_len=500):
    """Remove silences longer than silence_len from the audio."""
    return audio.strip_silence(silence_thresh=silence_thresh, silence_len=silence_len)

def gui_select_files():
    root = tk.Tk()
    root.withdraw()  # Hide the main window

    # Let the user select multiple .wav files
    files = filedialog.askopenfilenames(title="Select WAV Files", filetypes=[("WAV files", "*.wav")])
    if not files:
        return

    # Let the user select an output file location
    output_file = filedialog.asksaveasfilename(title="Save Concatenated WAV as", defaultextension=".wav", filetypes=[("WAV files", "*.wav")])
    if not output_file:
        return

    concatenate_audio_files(files, output_file)

    messagebox.showinfo("Success", f"Concatenated audio saved as {output_file}")

if __name__ == "__main__":
    gui_select_files()

M8_KitBasher.py
aTanguay/M8_KitCreator
import os
import wave
import struct
import tkinter as tk
from tkinter import filedialog
from pydub import AudioSegment
from pydub.silence import split_on_silence

# This seems to work just right.
# I think the main code is a little wonky, but it's pretty good
# Seems to be trimming fat off the files, which is great
# Written against python 3 on 2023_10_04


#def concatenate_audio_files(audio_files, output_file, marker_duration_ms=1000, silence_thresh=-40.0, min_silence_len=1000, retained_silence=100):

def concatenate_audio_files(audio_files, output_file, marker_duration_ms=1, silence_thresh=-60.0, min_silence_len=10, retained_silence=1):
    marker = AudioSegment.silent(duration=marker_duration_ms)
    retain_silence = AudioSegment.silent(duration=retained_silence)

    concatenated_audio = AudioSegment.empty()
    cue_positions = [len(marker.get_array_of_samples())]  # Add initial marker position

    concatenated_audio += marker  # Add marker at 00 position

    for file in audio_files:
        audio = AudioSegment.from_wav(file)
        chunks = split_on_silence(audio, silence_thresh=silence_thresh, min_silence_len=min_silence_len)
        processed_audio = sum([chunk + retain_silence for chunk in chunks], AudioSegment.empty())[:-retained_silence]

        concatenated_audio += processed_audio
        cue_positions.append(len(concatenated_audio.get_array_of_samples()))
        concatenated_audio += marker

    concatenated_audio.export(output_file, format="wav")

    # Add cue points
    with wave.open(output_file, 'rb') as wf:
        params = wf.getparams()
        num_frames = params.nframes
        data = wf.readframes(num_frames)

    cue_chunk_data = struct.pack('<L', len(cue_positions))
    for i, position in enumerate(cue_positions):
        cue_id = i + 1
        cue_chunk_data += struct.pack('<LL4sLLL', cue_id, position, b'data', 0, 0, position)

    cue_chunk = b'cue ' + struct.pack('<L', len(cue_chunk_data)) + cue_chunk_data

    with wave.open(output_file, 'wb') as wf:
        wf.setparams(params)
        wf.writeframes(data)
        wf._file.write(cue_chunk)

    print(f"Concatenated audio saved as {output_file}")





if __name__ == "__main__":
    root = tk.Tk()
    root.withdraw()  # Hide the main window

    audio_files = filedialog.askopenfilenames(title="Select WAV files", filetypes=[("WAV files", "*.wav")])
    if not audio_files:
        print("No files selected. Exiting.")
        exit()

    output_file = filedialog.asksaveasfilename(title="Select the output file", defaultextension=".wav", filetypes=[("WAV files", "*.wav")])
    if not output_file:
        print("No output file selected. Exiting.")
        exit()
    concatenate_audio_files(audio_files, output_file)



M8_KitBasher_0.13.py
aTanguay/M8_KitCreator
import os
import wave
import struct
import tkinter as tk
from tkinter import filedialog
from pydub import AudioSegment
from pydub.silence import split_on_silence

# This seems to work just right. The only issue is that it converts it to mono
# I think the main code is a little wonky, but it's pretty good
# Seems to be trimming fat off the files, which is great
# Written against python 3 on 2023_10_04


def concatenate_audio_files(audio_files, output_file, marker_duration_ms=1, silence_thresh=-50.0, min_silence_len=10, retained_silence=1):
    marker = AudioSegment.silent(duration=marker_duration_ms)
    retain_silence = AudioSegment.silent(duration=retained_silence)

    concatenated_audio = AudioSegment.empty()
    cue_positions = [len(marker.get_array_of_samples())]  # Add initial marker position

    concatenated_audio += marker  # Add marker at 00 position

    for file in audio_files:
        audio = AudioSegment.from_wav(file)

        # Convert to mono
        audio = audio.set_channels(1)

        chunks = split_on_silence(audio, silence_thresh=silence_thresh, min_silence_len=min_silence_len)
        processed_audio = sum([chunk + retain_silence for chunk in chunks], AudioSegment.empty())[:-retained_silence]

        concatenated_audio += processed_audio
        cue_positions.append(len(concatenated_audio.get_array_of_samples()))
        concatenated_audio += marker

    concatenated_audio.export(output_file, format="wav")

    # Add cue points
    with wave.open(output_file, 'rb') as wf:
        params = wf.getparams()
        num_frames = params.nframes
        data = wf.readframes(num_frames)

    cue_chunk_data = struct.pack('<L', len(cue_positions))
    for i, position in enumerate(cue_positions):
        cue_id = i + 1
        cue_chunk_data += struct.pack('<LL4sLLL', cue_id, position, b'data', 0, 0, position)

    cue_chunk = b'cue ' + struct.pack('<L', len(cue_chunk_data)) + cue_chunk_data

    with wave.open(output_file, 'wb') as wf:
        wf.setparams(params)
        wf.writeframes(data)
        wf._file.write(cue_chunk)

    print(f"Concatenated audio saved as {output_file}")


if __name__ == "__main__":
    root = tk.Tk()
    root.withdraw()  # Hide the main window

    audio_files = filedialog.askopenfilenames(title="Select WAV files", filetypes=[("WAV files", "*.wav")])
    if not audio_files:
        print("No files selected. Exiting.")
        exit()

    output_file = filedialog.asksaveasfilename(title="Select the output file", defaultextension=".wav", filetypes=[("WAV files", "*.wav")])
    if not output_file:
        print("No output file selected. Exiting.")
        exit()
    concatenate_audio_files(audio_files, output_file)



M8_KitBasher_0.14.py
aTanguay/M8_KitCreator
import tkinter as tk
from tkinter import filedialog, messagebox
import customtkinter as ctk
import os
import wave
import struct
from pydub import AudioSegment
from pydub.silence import split_on_silence

class FileSelectorApp(tk.Tk):
    def __init__(self):
        super().__init__()

        self.title("ConcateM8")
        self.geometry("400x400")

        # Lists to store selected file names and their full paths
        self.file_names = []
        self.file_paths = []

        # Frame for buttons
        self.button_frame = tk.Frame(self)
        self.button_frame.pack(pady=20)

        # Button to select files
        self.select_button = ctk.CTkButton(self.button_frame, text="Select Files", command=self.select_files)
        self.select_button.grid(row=0, column=0, padx=5)

        # Button to clear files from the list
        self.clear_button = ctk.CTkButton(self.button_frame, text="Clear Files", command=self.clear_files)
        self.clear_button.grid(row=0, column=1, padx=5)

        # Listbox to display selected file names (not full paths)
        self.file_listbox = tk.Listbox(self, width=30, height=10)
        self.file_listbox.pack(pady=20)

        # Frame for bottom buttons
        self.bottom_button_frame = tk.Frame(self)
        self.bottom_button_frame.pack(pady=20)

        # Button to merge files
        self.merge_button = ctk.CTkButton(self.bottom_button_frame, text="Merge", command=self.merge_files)
        self.merge_button.grid(row=0, column=0, padx=5)

        # Button to close the application
        self.close_button = ctk.CTkButton(self.bottom_button_frame, text="Close", command=self.close_app)
        self.close_button.grid(row=0, column=1, padx=5)

    def select_files(self):
        # Open file dialog to select files
        files = filedialog.askopenfilenames(title="Select Files")

        # Clear the file_names and file_paths lists, and the listbox
        self.file_names.clear()
        self.file_paths.clear()
        self.file_listbox.delete(0, tk.END)

        # Add selected file names (not full paths) to the file_names list and the listbox
        # Also add the full paths to the file_paths list
        for file in files:
            file_name = os.path.basename(file)
            self.file_names.append(file_name)
            self.file_paths.append(file)
            self.file_listbox.insert(tk.END, file_name)

    def clear_files(self):
        # Clear the file_names, file_paths lists, and the listbox
        self.file_names.clear()
        self.file_paths.clear()
        self.file_listbox.delete(0, tk.END)

    def merge_files(self):
        # Prompt the user for the output file location
        output_file = filedialog.asksaveasfilename(title="Select Output File", defaultextension=".wav", filetypes=[("Wav Files", "*.wav"), ("All Files", "*.*")])

        # Check if a valid output file location is provided
        if output_file:
            # For now, just print the selected output location.
            # The actual merging logic can be added here.
            print(f"Merging files into {output_file}...")
            concatenate_audio_files(self.file_paths, output_file)

            self.clear_files()

    def close_app(self):
        self.destroy()



def concatenate_audio_files(file_names, output_file, marker_duration_ms=1, silence_thresh=-50.0, min_silence_len=10, retained_silence=1):
    marker = AudioSegment.silent(duration=marker_duration_ms)
    retain_silence = AudioSegment.silent(duration=retained_silence)

    concatenated_audio = AudioSegment.empty()
    cue_positions = [len(marker.get_array_of_samples())]  # Add initial marker position

    concatenated_audio += marker  # Add marker at 00 position

    for file in file_names:
        audio = AudioSegment.from_wav(file)

        # Convert to mono
        audio = audio.set_channels(1)

        chunks = split_on_silence(audio, silence_thresh=silence_thresh, min_silence_len=min_silence_len)
        processed_audio = sum([chunk + retain_silence for chunk in chunks], AudioSegment.empty())[:-retained_silence]

        concatenated_audio += processed_audio
        cue_positions.append(len(concatenated_audio.get_array_of_samples()))
        concatenated_audio += marker

    concatenated_audio.export(output_file, format="wav")

    # Add cue points
    with wave.open(output_file, 'rb') as wf:
        params = wf.getparams()
        num_frames = params.nframes
        data = wf.readframes(num_frames)

    cue_chunk_data = struct.pack('<L', len(cue_positions))
    for i, position in enumerate(cue_positions):
        cue_id = i + 1
        cue_chunk_data += struct.pack('<LL4sLLL', cue_id, position, b'data', 0, 0, position)

    cue_chunk = b'cue ' + struct.pack('<L', len(cue_chunk_data)) + cue_chunk_data

    with wave.open(output_file, 'wb') as wf:
        wf.setparams(params)
        wf.writeframes(data)
        wf._file.write(cue_chunk)

    print(f"Concatenated audio saved as {output_file}")
    #clear_files(self)
    #messagebox.showinfo("Success", f"Files have been merged successfully into {saved_file_name}!")
    messagebox.showinfo("Success", "Files have been merged successfully.")
    

if __name__ == "__main__":
    app = FileSelectorApp()
    app.mainloop()

M8_KitBasher_0.20.py
aTanguay/M8_KitCreator
import tkinter as tk
from tkinter import filedialog, messagebox
import customtkinter as ctk
import os
import wave
import struct
from pydub import AudioSegment
from pydub.silence import split_on_silence


#----------------------------------------------------------------

# Seemingly working version with a GUI.
# You'll need tkinter, customtkinter, pydub, wave, and os.

#----------------------------------------------------------------

class FileSelectorApp(tk.Tk):
    def __init__(self):
        super().__init__()

        self.title("ConcateM8")
        self.geometry("400x400")

        # Lists to store selected file names and their full paths
        self.file_names = []
        self.file_paths = []

        # Frame for buttons
        self.button_frame = tk.Frame(self)
        self.button_frame.pack(pady=20)

        # Button to select files
        self.select_button = ctk.CTkButton(self.button_frame, text="Select Files", command=self.select_files)
        self.select_button.grid(row=0, column=0, padx=5)

        # Button to clear files from the list
        self.clear_button = ctk.CTkButton(self.button_frame, text="Clear Files", command=self.clear_files)
        self.clear_button.grid(row=0, column=1, padx=5)

        # Listbox to display selected file names (not full paths)
        self.file_listbox = tk.Listbox(self, width=30, height=10)
        self.file_listbox.pack(pady=20)

        # Frame for bottom buttons
        self.bottom_button_frame = tk.Frame(self)
        self.bottom_button_frame.pack(pady=20)

        # Button to merge files
        self.merge_button = ctk.CTkButton(self.bottom_button_frame, text="Merge", command=self.merge_files)
        self.merge_button.grid(row=0, column=0, padx=5)

        # Button to close the application
        self.close_button = ctk.CTkButton(self.bottom_button_frame, text="Close", command=self.close_app)
        self.close_button.grid(row=0, column=1, padx=5)

    def select_files(self):
        # Open file dialog to select files
        files = filedialog.askopenfilenames(title="Select Files")

        # Clear the file_names and file_paths lists, and the listbox
        self.file_names.clear()
        self.file_paths.clear()
        self.file_listbox.delete(0, tk.END)

        # Add selected file names (not full paths) to the file_names list and the listbox
        # Also add the full paths to the file_paths list
        for file in files:
            file_name = os.path.basename(file)
            self.file_names.append(file_name)
            self.file_paths.append(file)
            self.file_listbox.insert(tk.END, file_name)

    def clear_files(self):
        # Clear the file_names, file_paths lists, and the listbox
        self.file_names.clear()
        self.file_paths.clear()
        self.file_listbox.delete(0, tk.END)

    def merge_files(self):
        # Prompt the user for the output file location
        output_file = filedialog.asksaveasfilename(title="Select Output File", defaultextension=".wav", filetypes=[("Wav Files", "*.wav"), ("All Files", "*.*")])

        # Check if a valid output file location is provided
        if output_file:
            # For now, just print the selected output location.
            # The actual merging logic can be added here.
            print(f"Merging files into {output_file}...")
            concatenate_audio_files(self.file_paths, output_file)

            self.clear_files()

    def close_app(self):
        self.destroy()



def concatenate_audio_files(file_names, output_file, marker_duration_ms=1, silence_thresh=-50.0, min_silence_len=10, retained_silence=1):
    marker = AudioSegment.silent(duration=marker_duration_ms)
    retain_silence = AudioSegment.silent(duration=retained_silence)

    concatenated_audio = AudioSegment.empty()
    cue_positions = [len(marker.get_array_of_samples())]  # Add initial marker position

    concatenated_audio += marker  # Add marker at 00 position

    for file in file_names:
        audio = AudioSegment.from_wav(file)

        # Convert to mono
        audio = audio.set_channels(1)

        chunks = split_on_silence(audio, silence_thresh=silence_thresh, min_silence_len=min_silence_len)
        processed_audio = sum([chunk + retain_silence for chunk in chunks], AudioSegment.empty())[:-retained_silence]

        concatenated_audio += processed_audio
        cue_positions.append(len(concatenated_audio.get_array_of_samples()))
        concatenated_audio += marker

    try:
        concatenated_audio.export(output_file, format="wav")
        # If no errors, you can notify the user or log a success message if desired
        print("Audio exported successfully!")
    except Exception as e:
        # Handle the error
        print(f"Error exporting audio: {e}")
        # Optionally, you can use tkinter's messagebox to show the error in a popup
        messagebox.showerror("Error", f"Failed to export audio: {e}")

    ### OLD CODE   concatenated_audio.export(output_file, format="wav")

    # Add cue points
    with wave.open(output_file, 'rb') as wf:
        params = wf.getparams()
        num_frames = params.nframes
        data = wf.readframes(num_frames)

    cue_chunk_data = struct.pack('<L', len(cue_positions))
    for i, position in enumerate(cue_positions):
        cue_id = i + 1
        cue_chunk_data += struct.pack('<LL4sLLL', cue_id, position, b'data', 0, 0, position)

    cue_chunk = b'cue ' + struct.pack('<L', len(cue_chunk_data)) + cue_chunk_data

    with wave.open(output_file, 'wb') as wf:
        wf.setparams(params)
        wf.writeframes(data)
        wf._file.write(cue_chunk)

    print(f"Concatenated audio saved as {output_file}")
    messagebox.showinfo("Success", "Files have been merged successfully.")
    

if __name__ == "__main__":
    app = FileSelectorApp()
    app.mainloop()

M8_KitBasher_0.21.py
aTanguay/M8_KitCreator
import os
import struct
import tkinter as tk
import customtkinter as ctk
import wave
from tkinter import filedialog, messagebox
from pydub import AudioSegment
from pydub.silence import split_on_silence

#----------------------------------------------------------------
# ConcateM8 - A Dirtywave M8 Sliced Wav Kit Maker
# Seemingly working version with a GUI.
# You'll need tkinter, customtkinter, pydub, wave, and os.
# Written on OCtober 2023 - Andy Tanguay.
# Note: Files are merged in mono. Can't seem to figure this one out.

#----------------------------------------------------------------


class FileSelectorApp(tk.Tk):
    def __init__(self):
        super().__init__()

        self.title("ConcateM8")
        self.geometry("350x510")

        # Lists to store selected file names and their full paths
        self.file_names = []
        self.file_paths = []

        self.title_label = ctk.CTkLabel(self, text="Dirtywave M8 Sliced Wav Kit Maker", font=("Arial", 16))
        self.title_label.pack(pady=2, padx=1)
        self.title_label = ctk.CTkLabel(self, text="Select WAV files, Press Merge, Select Output Wav", font=("Arial", 11))
        self.title_label.pack(pady=2, padx=1)


        # Frame for buttons
        # Assuming customtkinter has a CTkFrame (this might not be the case)
        self.button_frame = ctk.CTkFrame(self)
        self.button_frame.pack(pady=5, padx=5)

        # Button to select files
        self.select_button = ctk.CTkButton(self.button_frame, text="Select Files", command=self.select_files)
        self.select_button.grid(row=0, column=0, padx=5, pady=5)

        # Button to clear files from the list
        self.clear_button = ctk.CTkButton(self.button_frame, text="Clear Files", command=self.clear_files)
        self.clear_button.grid(row=0, column=1, padx=5, pady=5)


        # Frame for file selection
        # Again, assuming customtkinter has a CTkFrame
        self.filelist_frame = ctk.CTkFrame(self)
        self.filelist_frame.pack(pady=5,padx=5)

        self.title_label = ctk.CTkLabel(self.filelist_frame, text="Current WAV files to process:", font=("Arial", 11))
        self.title_label.pack(pady=1, padx=1)

        # Listbox to display selected file names (not full paths)
        # customtkinter might not have an alternative for Listbox
        self.file_listbox = tk.Listbox(self.filelist_frame, width=30, height=16)
        self.file_listbox.pack(pady=10, padx=10)



        # Frame for bottom buttons
        # Again, assuming customtkinter has a CTkFrame
        self.bottom_button_frame = ctk.CTkFrame(self)
        self.bottom_button_frame.pack(pady=5,padx=5)

        # Button to merge files
        self.merge_button = ctk.CTkButton(self.bottom_button_frame, text="Merge", command=self.merge_files)
        self.merge_button.grid(row=0, column=0, padx=5, pady=5)

        # Button to close the application
        self.close_button = ctk.CTkButton(self.bottom_button_frame, text="Exit", command=self.close_app)
        self.close_button.grid(row=0, column=1, padx=5, pady=5)

# ... [rest of the code remains unchanged] ...


    def select_files(self):
        # Open file dialog to select files
        files = filedialog.askopenfilenames(title="Select Files")

        # Clear the file_names and file_paths lists, and the listbox
        self.file_names.clear()
        self.file_paths.clear()
        self.file_listbox.delete(0, tk.END)

        # Add selected file names (not full paths) to the file_names list and the listbox
        # Also add the full paths to the file_paths list
        for file in files:
            file_name = os.path.basename(file)
            self.file_names.append(file_name)
            self.file_paths.append(file)
            self.file_listbox.insert(tk.END, file_name)

    def clear_files(self):
        # Clear the file_names, file_paths lists, and the listbox
        self.file_names.clear()
        self.file_paths.clear()
        self.file_listbox.delete(0, tk.END)

    def merge_files(self):
        # Prompt the user for the output file location
        output_file = filedialog.asksaveasfilename(title="Select Output File", defaultextension=".wav", filetypes=[("Wav Files", "*.wav"), ("All Files", "*.*")])

        # Check if a valid output file location is provided
        if output_file:
            # For now, just print the selected output location.
            # The actual merging logic can be added here.
            print(f"Merging files into {output_file}...")
            concatenate_audio_files(self.file_paths, output_file)

            self.clear_files()

    def close_app(self):
        self.destroy()



def concatenate_audio_files(file_names, output_file, marker_duration_ms=1, silence_thresh=-50.0, min_silence_len=10, retained_silence=1):
    marker = AudioSegment.silent(duration=marker_duration_ms)
    retain_silence = AudioSegment.silent(duration=retained_silence)

    concatenated_audio = AudioSegment.empty()
    cue_positions = [len(marker.get_array_of_samples())]  # Add initial marker position

    concatenated_audio += marker  # Add marker at 00 position

    for file in file_names:
        audio = AudioSegment.from_wav(file)

        # Convert to mono
        audio = audio.set_channels(1)

        chunks = split_on_silence(audio, silence_thresh=silence_thresh, min_silence_len=min_silence_len)
        processed_audio = sum([chunk + retain_silence for chunk in chunks], AudioSegment.empty())[:-retained_silence]

        concatenated_audio += processed_audio
        cue_positions.append(len(concatenated_audio.get_array_of_samples()))
        concatenated_audio += marker

    try:
        concatenated_audio.export(output_file, format="wav")
        # If no errors, you can notify the user or log a success message if desired
        print("Audio exported successfully!")
    except Exception as e:
        # Handle the error
        print(f"Error exporting audio: {e}")
        # Optionally, you can use tkinter's messagebox to show the error in a popup
        messagebox.showerror("Error", f"Failed to export audio: {e}")

    ### OLD CODE   concatenated_audio.export(output_file, format="wav")

    # Add cue points
    with wave.open(output_file, 'rb') as wf:
        params = wf.getparams()
        num_frames = params.nframes
        data = wf.readframes(num_frames)

    cue_chunk_data = struct.pack('<L', len(cue_positions))
    for i, position in enumerate(cue_positions):
        cue_id = i + 1
        cue_chunk_data += struct.pack('<LL4sLLL', cue_id, position, b'data', 0, 0, position)

    cue_chunk = b'cue ' + struct.pack('<L', len(cue_chunk_data)) + cue_chunk_data

    with wave.open(output_file, 'wb') as wf:
        wf.setparams(params)
        wf.writeframes(data)
        wf._file.write(cue_chunk)

    print(f"Concatenated audio saved as {output_file}")
    messagebox.showinfo("Success", "Files have been merged successfully.")
    

if __name__ == "__main__":
    app = FileSelectorApp()
    app.mainloop()

M8_KitBasher_0.22.py
aTanguay/M8_KitCreator
"""
This is a setup.py script generated by py2applet

Usage:
    python3 setup.py py2app
"""

from setuptools import setup

APP = ['M8_KitBasher_0.22.py']
DATA_FILES = []
OPTIONS = {
	'argv_emulation': True,
	'packages':['pydub','customtkinter']
	}

setup(
    app=APP,
    data_files=DATA_FILES,
    options={'py2app': OPTIONS},
    setup_requires=['py2app'],
)

setup.py
aTanguay/M8_KitCreator
import os
from pydub import AudioSegment
from pydub.generators import Sine
import tkinter as tk
from tkinter import filedialog, messagebox

# This script works, but it only puts a bleep at the start of the files.
# If it added markers instead, it would be great

def concatenate_audio_files(files, output_file, marker_duration_ms=1, marker_frequency=440, silence_thresh=-40.0, silence_len=1000):
    # Generate the audio marker
    marker = Sine(marker_frequency).to_audio_segment(duration=marker_duration_ms)

    # Concatenate audio files with a marker in between and remove long silences
    concatenated_audio = AudioSegment.empty()
    for file in files:
        audio = AudioSegment.from_wav(file)

        # Remove silences longer than silence_len
        audio = strip_long_silence(audio, silence_thresh, silence_len)

        concatenated_audio += audio + marker

    # Remove the last marker
    concatenated_audio = concatenated_audio[:-marker_duration_ms]

    # Export the concatenated audio
    concatenated_audio.export(output_file, format="wav")
def strip_long_silence(audio, silence_thresh=-40.0, silence_len=500):
    """Remove silences longer than silence_len from the audio."""
    return audio.strip_silence(silence_thresh=silence_thresh, silence_len=silence_len)

def gui_select_files():
    root = tk.Tk()
    root.withdraw()  # Hide the main window

    # Let the user select multiple .wav files
    files = filedialog.askopenfilenames(title="Select WAV Files", filetypes=[("WAV files", "*.wav")])
    if not files:
        return

    # Let the user select an output file location
    output_file = filedialog.asksaveasfilename(title="Save Concatenated WAV as", defaultextension=".wav", filetypes=[("WAV files", "*.wav")])
    if not output_file:
        return

    concatenate_audio_files(files, output_file)

    messagebox.showinfo("Success", f"Concatenated audio saved as {output_file}")

if __name__ == "__main__":
    gui_select_files()

versions/M8_KitBasher_0.01.py
aTanguay/M8_KitCreator
import os
import wave
import struct
from pydub.silence import split_on_silence
from pydub import AudioSegment
from pydub.generators import Sine
import tkinter as tk
from tkinter import filedialog, messagebox



# This script works, but it only puts a bleep at the start of the files.
# If it added markers instead, it would be great




def concatenate_audio_files(files, output_file, marker_duration_ms=1, marker_frequency=440, silence_thresh=-40.0, silence_len=1000):
    # Generate the audio marker
    marker = Sine(marker_frequency).to_audio_segment(duration=marker_duration_ms)

    # Concatenate audio files with a marker in between and remove long silences
    concatenated_audio = AudioSegment.empty()
    for file in files:
        audio = AudioSegment.from_wav(file)

        # Remove silences longer than silence_len
        audio = strip_long_silence(audio, silence_thresh, silence_len)

        concatenated_audio += audio + marker

    # Remove the last marker
    concatenated_audio = concatenated_audio[:-marker_duration_ms]

    # Export the concatenated audio
    concatenated_audio.export(output_file, format="wav")



def strip_long_silence(audio, silence_thresh=-40.0, silence_len=500):
    """Remove silences longer than silence_len from the audio."""
    return audio.strip_silence(silence_thresh=silence_thresh, silence_len=silence_len)




def gui_select_files():
    root = tk.Tk()
    root.withdraw()  # Hide the main window

    # Let the user select multiple .wav files
    files = filedialog.askopenfilenames(title="Select WAV Files", filetypes=[("WAV files", "*.wav")])
    if not files:
        return

    # Let the user select an output file location
    output_file = filedialog.asksaveasfilename(title="Save Concatenated WAV as", defaultextension=".wav", filetypes=[("WAV files", "*.wav")])
    if not output_file:
        return

    concatenate_audio_files(files, output_file)

    messagebox.showinfo("Success", f"Concatenated audio saved as {output_file}")





if __name__ == "__main__":
    gui_select_files()
versions/M8_KitBasher_0.07.py
aTanguay/M8_KitCreator
import os
import wave
import struct
from pydub import AudioSegment
from pydub.silence import split_on_silence

#this version comes real close to working. It adds some markes

def concatenate_audio_files(directory, output_file, marker_duration_ms=1000, silence_thresh=-40.0, min_silence_len=1000, retained_silence=100):
    marker = AudioSegment.silent(duration=marker_duration_ms)
    retain_silence = AudioSegment.silent(duration=retained_silence)

    audio_files = [f for f in os.listdir(directory) if f.endswith('.wav')]
    audio_files.sort()

    concatenated_audio = AudioSegment.empty()
    cue_positions = []
    current_frame = 0

    for file in audio_files:
        audio_path = os.path.join(directory, file)
        audio = AudioSegment.from_wav(audio_path)

        chunks = split_on_silence(audio, silence_thresh=silence_thresh, min_silence_len=min_silence_len)
        processed_audio = sum([chunk + retain_silence for chunk in chunks], AudioSegment.empty())[:-retained_silence]

        concatenated_audio += processed_audio
        cue_positions.append(len(concatenated_audio.get_array_of_samples()))

        concatenated_audio += marker


    concatenated_audio.export(output_file, format="wav")







    # Add cue points
    with wave.open(output_file, 'rb') as wf:
        params = wf.getparams()
        num_frames = params.nframes
        data = wf.readframes(num_frames)

    cue_chunk_data = struct.pack('<L', len(cue_positions))
    for i, position in enumerate(cue_positions):
        cue_id = i + 1
        cue_chunk_data += struct.pack('<LL4sLLL', cue_id, position, b'data', 0, 0, position)

    cue_chunk = b'cue ' + struct.pack('<L', len(cue_chunk_data)) + cue_chunk_data

    with wave.open(output_file, 'wb') as wf:
        wf.setparams(params)
        wf.writeframes(data)
        wf._file.write(cue_chunk)

    print(f"Concatenated audio saved as {output_file}")

if __name__ == "__main__":
    directory = input("Enter the directory containing the wav files: ").strip("'").strip('"')
    output_file = input("Enter the name of the output file (e.g., output.wav): ").strip("'").strip('"')
    concatenate_audio_files(directory, output_file)

versions/M8_KitBasher_0.08.py
aTanguay/M8_KitCreator
import wave
import struct
import tkinter as tk
from tkinter import filedialog
from pydub import AudioSegment

def concatenate_audio_files(output_file, marker_duration_ms=1000):
    marker = AudioSegment.silent(duration=marker_duration_ms)

    root = tk.Tk()
    root.withdraw()  # Hide the main window

    audio_files = filedialog.askopenfilenames(title="Select WAV files", filetypes=[("WAV files", "*.wav")])

    if not audio_files:
        print("No files selected. Exiting.")
        return

    concatenated_audio = AudioSegment.empty()
    cue_positions = []

    for idx, file in enumerate(audio_files):
        audio = AudioSegment.from_wav(file)

        cue_positions.append(len(concatenated_audio.get_array_of_samples()))  # this is where the new audio will start

        concatenated_audio += audio

        # Add marker only if it's not the last file
        if idx != len(audio_files) - 1:
            concatenated_audio += marker

    concatenated_audio.export(output_file, format="wav")

    # Add cue points
    with wave.open(output_file, 'rb') as wf:
        params = wf.getparams()
        num_frames = params.nframes
        data = wf.readframes(num_frames)

    cue_chunk_data = struct.pack('<L', len(cue_positions))
    for i, position in enumerate(cue_positions):
        cue_id = i + 1
        cue_chunk_data += struct.pack('<LL4sLLL', cue_id, position, b'data', 0, 0, position)

    cue_chunk = b'cue ' + struct.pack('<L', len(cue_chunk_data)) + cue_chunk_data

    with wave.open(output_file, 'wb') as wf:
        wf.setparams(params)
        wf.writeframes(data)
        wf._file.write(cue_chunk)

    print(f"Concatenated audio saved as {output_file}")

if __name__ == "__main__":
    output_file = input("Enter the name of the output file (e.g., output.wav): ").strip("'").strip('"')
    concatenate_audio_files(output_file)

versions/M8_KitBasher_0.09.py
aTanguay/M8_KitCreator
import wave
import struct
import tkinter as tk
from tkinter import filedialog
from pydub import AudioSegment

def concatenate_audio_files(output_file, marker_duration_ms=1000):
    marker = AudioSegment.silent(duration=marker_duration_ms)

    root = tk.Tk()
    root.withdraw()  # Hide the main window

    audio_files = filedialog.askopenfilenames(title="Select WAV files", filetypes=[("WAV files", "*.wav")])

    if not audio_files:
        print("No files selected. Exiting.")
        return

    concatenated_audio = AudioSegment.empty()
    cue_positions = []

    for idx, file in enumerate(audio_files):
        audio = AudioSegment.from_wav(file)

        cue_positions.append(len(concatenated_audio.get_array_of_samples()))  # this is where the new audio will start

        concatenated_audio += audio

        # Add marker only if it's not the last file
        if idx != len(audio_files) - 1:
            concatenated_audio += marker

    concatenated_audio.export(output_file, format="wav")

    # Add cue points
    with wave.open(output_file, 'rb') as wf:
        params = wf.getparams()
        num_frames = params.nframes
        data = wf.readframes(num_frames)

    cue_chunk_data = struct.pack('<L', len(cue_positions))
    for i, position in enumerate(cue_positions):
        cue_id = i + 1
        cue_chunk_data += struct.pack('<LL4sLLL', cue_id, position, b'data', 0, 0, position)

    cue_chunk = b'cue ' + struct.pack('<L', len(cue_chunk_data)) + cue_chunk_data

    with wave.open(output_file, 'wb') as wf:
        wf.setparams(params)
        wf.writeframes(data)
        wf._file.write(cue_chunk)

    print(f"Concatenated audio saved as {output_file}")

if __name__ == "__main__":
    output_file = input("Enter the name of the output file (e.g., output.wav): ").strip("'").strip('"')
    concatenate_audio_files(output_file)

versions/M8_KitBasher_0.10.py
aTanguay/M8_KitCreator
import os
import wave
import struct
import tkinter as tk
from tkinter import filedialog
from pydub import AudioSegment
from pydub.silence import split_on_silence

# This works for the most part. for some reason, the markers are wrong ,but damn it's close


#def concatenate_audio_files(audio_files, output_file, marker_duration_ms=1000, silence_thresh=-40.0, min_silence_len=1000, retained_silence=100):

def concatenate_audio_files(audio_files, output_file, marker_duration_ms=1, silence_thresh=-40.0, min_silence_len=10, retained_silence=1):
    marker = AudioSegment.silent(duration=marker_duration_ms)
    retain_silence = AudioSegment.silent(duration=retained_silence)

    concatenated_audio = AudioSegment.empty()
    cue_positions = []
    current_frame = 0

    for file in audio_files:
        audio = AudioSegment.from_wav(file)
        chunks = split_on_silence(audio, silence_thresh=silence_thresh, min_silence_len=min_silence_len)
        processed_audio = sum([chunk + retain_silence for chunk in chunks], AudioSegment.empty())[:-retained_silence]

        concatenated_audio += processed_audio
        cue_positions.append(len(concatenated_audio.get_array_of_samples()))
        concatenated_audio += marker

    concatenated_audio.export(output_file, format="wav")

    # Add cue points
    with wave.open(output_file, 'rb') as wf:
        params = wf.getparams()
        num_frames = params.nframes
        data = wf.readframes(num_frames)

    cue_chunk_data = struct.pack('<L', len(cue_positions))
    for i, position in enumerate(cue_positions):
        cue_id = i + 1
        cue_chunk_data += struct.pack('<LL4sLLL', cue_id, position, b'data', 0, 0, position)

    cue_chunk = b'cue ' + struct.pack('<L', len(cue_chunk_data)) + cue_chunk_data

    with wave.open(output_file, 'wb') as wf:
        wf.setparams(params)
        wf.writeframes(data)
        wf._file.write(cue_chunk)

    print(f"Concatenated audio saved as {output_file}")




if __name__ == "__main__":
    root = tk.Tk()
    root.withdraw()  # Hide the main window

    audio_files = filedialog.askopenfilenames(title="Select WAV files", filetypes=[("WAV files", "*.wav")])
    if not audio_files:
        print("No files selected. Exiting.")
        exit()

    output_file = filedialog.asksaveasfilename(title="Select the output file", defaultextension=".wav", filetypes=[("WAV files", "*.wav")])
    if not output_file:
        print("No output file selected. Exiting.")
        exit()
    concatenate_audio_files(audio_files, output_file)



versions/M8_KitBasher_0.11.py
aTanguay/M8_KitCreator
import os
import wave
import struct
import tkinter as tk
from tkinter import filedialog
from pydub import AudioSegment
from pydub.silence import split_on_silence

# This works for the most part. for some reason, the markers are wrong ,but damn it's close


#def concatenate_audio_files(audio_files, output_file, marker_duration_ms=1000, silence_thresh=-40.0, min_silence_len=1000, retained_silence=100):

def concatenate_audio_files(audio_files, output_file, marker_duration_ms=1, silence_thresh=-60.0, min_silence_len=10, retained_silence=1):
    marker = AudioSegment.silent(duration=marker_duration_ms)
    retain_silence = AudioSegment.silent(duration=retained_silence)

    concatenated_audio = AudioSegment.empty()
    cue_positions = []
    current_frame = 0

    for file in audio_files:
        audio = AudioSegment.from_wav(file)
        chunks = split_on_silence(audio, silence_thresh=silence_thresh, min_silence_len=min_silence_len)
        processed_audio = sum([chunk + retain_silence for chunk in chunks], AudioSegment.empty())[:-retained_silence]

        concatenated_audio += processed_audio
        cue_positions.append(len(concatenated_audio.get_array_of_samples()))
        concatenated_audio += marker

    concatenated_audio.export(output_file, format="wav")

    # Add cue points
    with wave.open(output_file, 'rb') as wf:
        params = wf.getparams()
        num_frames = params.nframes
        data = wf.readframes(num_frames)

    cue_chunk_data = struct.pack('<L', len(cue_positions))
    for i, position in enumerate(cue_positions):
        cue_id = i + 1
        cue_chunk_data += struct.pack('<LL4sLLL', cue_id, position, b'data', 0, 0, position)

    cue_chunk = b'cue ' + struct.pack('<L', len(cue_chunk_data)) + cue_chunk_data

    with wave.open(output_file, 'wb') as wf:
        wf.setparams(params)
        wf.writeframes(data)
        wf._file.write(cue_chunk)

    print(f"Concatenated audio saved as {output_file}")




if __name__ == "__main__":
    root = tk.Tk()
    root.withdraw()  # Hide the main window

    audio_files = filedialog.askopenfilenames(title="Select WAV files", filetypes=[("WAV files", "*.wav")])
    if not audio_files:
        print("No files selected. Exiting.")
        exit()

    output_file = filedialog.asksaveasfilename(title="Select the output file", defaultextension=".wav", filetypes=[("WAV files", "*.wav")])
    if not output_file:
        print("No output file selected. Exiting.")
        exit()
    concatenate_audio_files(audio_files, output_file)



versions/M8_KitBasher_0.12.py
aTanguay/M8_KitCreator