Initial commit
This commit is contained in:
commit
262601edb8
2025 files changed
+218754
No files matched your search
@@ -0,0 +1 @@
|
||||
{"notes": [[38.636584, "up"], [56.136472000000005, "up"], [72.95220799999998, "up"], [95.20515200000001, "up"], [120.26671999999999, "up"], [143.419864, "up"], [159.191368, "up"], [173.990656, "up"], [189.870184, "up"], [208.23426399999997, "up"], [223.32161599999998, "up"], [242.33383999999998, "right"], [259.005544, "right"], [283.77904800000005, "down"], [303.511432, "down"], [316.654352, "down"], [331.99376000000007, "down"], [350.393848, "down"], [367.67768799999993, "down"], [382.33294399999994, "down"], [398.21247199999993, "down"], [414.9922, "down"], [432.52809600000006, "down"], [447.1833519999999, "down"], [464.25114399999995, "down"], [480.4187360000001, "down"], [496.0102, "down"], [512.5018640000001, "down"], [527.589216, "down"], [543.108664, "down"], [560.680568, "down"], [576.5961040000001, "down"], [592.799704, "down"], [608.247136, "down"], [623.9466239999999, "down"], [650.340488, "down"], [669.820816, "down"], [686.024416, "down"], [703.020192, "down"], [717.351376, "down"], [732.0066320000001, "down"], [746.373824, "down"], [760.2729119999998, "down"], [776.584536, "down"], [792.1039840000001, "down"], [806.5431920000001, "down"], [822.3146959999999, "down"], [831.9288319999999, "down"], [846.404048, "down"], [861.779464, "down"], [875.930608, "down"], [893.610536, "down"], [909.3460320000002, "down"], [925.0815279999999, "down"], [941.6812160000001, "down"], [958.388928, "down"], [974.592528, "down"], [990.2199999999999, "down"], [1008.8721439999999, "down"], [1016.8659200000001, "down"], [1023.851472, "down"], [1030.8730320000002, "down"], [1038.4707199999998, "down"], [1045.31224, "down"], [1055.682544, "down"], [1069.293568, "down"], [1085.3891440000002, "down"], [1101.952824, "down"], [1117.7603360000003, "down"], [1134.43204, "down"], [1150.9237039999998, "down"], [1159.169536, "down"], [1169.863912, "down"], [1177.173536, "down"], [1186.5716240000002, "down"], [1198.238216, "down"], [1210.769, "down"], [1222.183536, "down"], [1234.9663759999999, "down"], [1246.4169200000001, "down"], [1261.4322559999998, "down"], [1277.455816, "down"], [1290.16664, "down"], [1312.4916, "down"], [1327.8670160000001, "down"], [1342.162192, "down"], [1356.78144, "down"], [1373.16508, "down"], [1390.2688799999999, "down"], [1404.420024, "down"], [1419.7234239999998, "down"], [1436.755208, "up"], [1453.3188879999998, "up"], [1469.0183759999998, "up"], [1485.0419359999999, "up"], [1500.3453359999999, "up"], [1515.0366000000001, "up"], [1533.40068, "up"], [1542.8707840000002, "up"], [1550.4324640000002, "up"], [1556.7698719999999, "up"], [1565.98792, "up"], [1581.075272, "up"], [1595.6945199999996, "up"], [1613.1223919999998, "up"], [1627.777648, "up"], [1643.117056, "up"], [1661.3371039999997, "up"], [1669.51092, "up"], [1677.216632, "up"], [1685.1743999999999, "up"], [1694.680512, "up"], [1706.5631519999997, "up"], [1719.1659519999998, "up"], [1730.8685520000004, "up"], [1742.535144, "up"], [1748.944568, "up"], [1755.4260079999997, "up"], [1768.965016, "up"], [1781.6398319999998, "up"], [1794.9267839999995, "up"], [1806.305312, "up"], [1821.6807279999996, "up"], [1832.303088, "up"], [1837.2361840000003, "up"], [1851.963456, "up"], [1865.7905280000002, "up"], [1882.9303360000001, "up"], [1895.46112, "up"], [1914.4733439999998, "up"], [1932.045248, "up"], [1948.1768320000003, "up"], [1964.9205519999998, "up"], [1980.764072, "up"], [1996.6436000000006, "up"], [2012.7391759999998, "up"], [2027.5384640000002, "up"], [2044.2461759999999, "up"], [2059.8376399999997, "up"], [2073.52068, "up"], [2082.198608, "up"], [2094.40532, "up"], [2099.9865600000003, "up"], [2112.7694, "up"], [2122.2755119999997, "up"], [2127.784736, "up"], [2135.346416, "up"], [2149.2455039999995, "up"], [2159.687824, "up"], [2170.418208, "up"], [2178.051904, "up"], [2184.641368, "up"], [2189.718496, "up"], [2203.0054479999994, "up"], [2213.4837760000005, "up"], [2220.325296, "up"], [2233.432208, "up"], [2243.730496, "up"], [2249.5277840000003, "up"], [2259.2859519999997, "up"], [2275.4175359999995, "up"], [2286.0398959999998, "up"], [2299.7589439999997, "up"], [2310.8854160000005, "up"], [2324.7484959999997, "left"], [2335.3348479999995, "left"], [2342.8605199999997, "left"], [2348.369744, "left"], [2362.592904, "up"], [2376.0238879999997, "up"], [2392.479544, "up"], [2406.6666960000002, "up"], [2423.914528, "up"], [2443.50288, "up"], [2459.598456, "up"], [2475.4419759999996, "up"], [2491.57356, "up"], [2506.444864, "up"], [2522.0363279999997, "up"], [2539.932304, "up"], [2555.4877599999995, "up"], [2570.935192, "up"], [2586.5266559999995, "up"], [2602.9463039999996, "up"], [2618.8258319999995, "up"], [2634.7413680000004, "up"], [2647.66824, "up"], [2662.0714400000006, "up"], [2680.9756399999997, "up"], [2697.755368, "up"], [2714.427072, "up"], [2730.8827279999996, "up"], [2747.806488, "up"], [2763.217912, "up"], [2780.753808, "up"], [2796.9574079999998, "up"], [2814.1692319999997, "up"], [2829.2205759999997, "up"], [2845.568207999999Line truncated
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f81ca634437ee39668bcf03074ac7e0e
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,488 @@
|
||||
import tkinter as tk
|
||||
from tkinter import filedialog, messagebox, simpledialog
|
||||
from mutagen.mp3 import MP3, EasyMP3
|
||||
import base64
|
||||
import tempfile
|
||||
import json
|
||||
import os
|
||||
import pygame
|
||||
|
||||
from mutagen.id3 import ID3, APIC
|
||||
|
||||
|
||||
class LevelDesigner:
|
||||
def __init__(self, root):
|
||||
self.root = root
|
||||
self.root.title("Level Designer")
|
||||
initial_width = 600
|
||||
initial_height = 400
|
||||
|
||||
self.root.geometry(
|
||||
f"{initial_width}x{initial_height}"
|
||||
) # Set initial window size
|
||||
self.root.minsize(width=initial_width, height=initial_height)
|
||||
self.song_path = ""
|
||||
self.notes = []
|
||||
|
||||
self.select_button = tk.Button(
|
||||
root, text="Select Song", command=self.select_song
|
||||
)
|
||||
self.select_button.pack()
|
||||
|
||||
self.canvas_frame = tk.Frame(root)
|
||||
self.canvas_frame.pack(fill="both", expand=True)
|
||||
|
||||
self.canvas = tk.Canvas(self.canvas_frame, bg="white")
|
||||
self.canvas.pack(side="top", fill="both", expand=True)
|
||||
|
||||
self.h_scrollbar = tk.Scrollbar(
|
||||
self.canvas_frame, orient="horizontal", command=self.canvas.xview
|
||||
)
|
||||
self.h_scrollbar.pack(side="bottom", fill="x")
|
||||
self.canvas.configure(xscrollcommand=self.h_scrollbar.set)
|
||||
|
||||
self.canvas.bind("<Button-1>", self.add_note)
|
||||
self.canvas.bind("<Button-3>", self.delete_note)
|
||||
|
||||
self.root.bind("<space>", self.auto_add_note)
|
||||
|
||||
self.save_button_visible = False
|
||||
self.save_button_height = 0
|
||||
|
||||
self.arrows_visible = False
|
||||
|
||||
self.save_button = tk.Button(root, text="Save Level", command=self.save_level)
|
||||
self.save_button.pack()
|
||||
self.save_button_height = self.save_button.winfo_height()
|
||||
self.save_button.pack_forget()
|
||||
|
||||
self.arrow_buttons_frame = tk.Frame(root)
|
||||
self.arrow_buttons_frame.pack()
|
||||
|
||||
self.song = None
|
||||
self.meta = None
|
||||
|
||||
self.left_button = tk.Button(
|
||||
self.arrow_buttons_frame,
|
||||
text="←",
|
||||
command=lambda: self.select_arrow("left"),
|
||||
bg="red",
|
||||
)
|
||||
self.left_button.pack(side="left")
|
||||
|
||||
self.up_button = tk.Button(
|
||||
self.arrow_buttons_frame,
|
||||
text="↑",
|
||||
command=lambda: self.select_arrow("up"),
|
||||
bg="green",
|
||||
)
|
||||
self.up_button.pack(side="left")
|
||||
|
||||
self.down_button = tk.Button(
|
||||
self.arrow_buttons_frame,
|
||||
text="↓",
|
||||
command=lambda: self.select_arrow("down"),
|
||||
bg="blue",
|
||||
)
|
||||
self.down_button.pack(side="left")
|
||||
|
||||
self.right_button = tk.Button(
|
||||
self.arrow_buttons_frame,
|
||||
text="→",
|
||||
command=lambda: self.select_arrow("right"),
|
||||
bg="yellow",
|
||||
)
|
||||
self.right_button.pack(side="left")
|
||||
|
||||
self.canvas_frame.bind("<Configure>", self.update_canvas_height)
|
||||
self.canvas.bind("<Configure>", self.redraw_notes)
|
||||
|
||||
self.add_controls()
|
||||
self.current_pos: float = 0.0
|
||||
|
||||
pygame.mixer.init()
|
||||
self.song_playing = False
|
||||
|
||||
def init_song(self):
|
||||
if self.song_path:
|
||||
pygame.mixer.music.load(self.song_path)
|
||||
self.song_playing = False
|
||||
self.cursor = None
|
||||
|
||||
def update_cursor(self):
|
||||
self.canvas.delete("cursor")
|
||||
if self.song_playing:
|
||||
current_time = self.current_pos + pygame.mixer.music.get_pos() / 1000.0
|
||||
else:
|
||||
current_time = self.current_pos
|
||||
|
||||
x = current_time / self.song_length * self.canvas_width
|
||||
|
||||
canvas_width = self.canvas.winfo_width() # Get current canvas width
|
||||
visible_x1 = self.canvas.canvasx(0) # Get the leftmost visible x coordinate
|
||||
visible_x2 = visible_x1 + canvas_width # Get the rightmost visible x coordinate
|
||||
|
||||
# # Calculate the new scroll region based on the cursor's position
|
||||
if x < visible_x1 + 50: # If cursor is about to leave from the left
|
||||
new_x1 = max(0, x - canvas_width / 2)
|
||||
self.canvas.xview_moveto(new_x1 / self.canvas_width)
|
||||
elif x > visible_x2 - 50: # If cursor is about to leave from the right
|
||||
new_x1 = max(0, x - canvas_width / 2)
|
||||
self.canvas.xview_moveto(new_x1 / self.canvas_width)
|
||||
|
||||
# Draw the cursor
|
||||
self.cursor = self.canvas.create_line(
|
||||
x, 0, x, self.canvas.winfo_height(), fill="red", tags="cursor"
|
||||
)
|
||||
|
||||
if self.song_playing:
|
||||
self.root.after(100, self.update_cursor)
|
||||
|
||||
def play_pause_song(self):
|
||||
if self.song_playing:
|
||||
print("Paused")
|
||||
pygame.mixer.music.pause()
|
||||
self.current_pos += pygame.mixer.music.get_pos() / 1000.0
|
||||
self.song_playing = False
|
||||
else:
|
||||
print("Unpaused")
|
||||
pygame.mixer.music.play(start=self.current_pos)
|
||||
self.song_playing = True
|
||||
self.update_cursor()
|
||||
|
||||
def move_cursor(self, amount):
|
||||
if self.song_playing:
|
||||
self.current_pos += pygame.mixer.music.get_pos() / 1000.0
|
||||
self.current_pos = max(0, min(self.current_pos + amount, self.song_length))
|
||||
pygame.mixer.music.play(start=self.current_pos)
|
||||
else:
|
||||
self.current_pos = max(0, min(self.current_pos + amount, self.song_length))
|
||||
self.update_cursor()
|
||||
|
||||
def backward_1_second(self):
|
||||
self.move_cursor(-1)
|
||||
|
||||
def backward_half_second(self):
|
||||
self.move_cursor(-0.5)
|
||||
|
||||
def forward_1_second(self):
|
||||
self.move_cursor(1)
|
||||
|
||||
def forward_half_second(self):
|
||||
self.move_cursor(0.5)
|
||||
|
||||
def backward_5_seconds(self):
|
||||
self.move_cursor(-5)
|
||||
|
||||
def forward_5_seconds(self):
|
||||
self.move_cursor(5)
|
||||
|
||||
def add_controls(self):
|
||||
control_frame = tk.Frame(self.root)
|
||||
control_frame.pack()
|
||||
|
||||
backward_half_second_button = tk.Button(
|
||||
control_frame, text="<< 0.5s", command=self.backward_half_second
|
||||
)
|
||||
backward_half_second_button.pack(side="left")
|
||||
|
||||
backward_1_second_button = tk.Button(
|
||||
control_frame, text="<< 1s", command=self.backward_1_second
|
||||
)
|
||||
backward_1_second_button.pack(side="left")
|
||||
|
||||
backward_button = tk.Button(
|
||||
control_frame, text="<< 5s", command=self.backward_5_seconds
|
||||
)
|
||||
backward_button.pack(side="left")
|
||||
|
||||
play_pause_button = tk.Button(
|
||||
control_frame, text="PP", command=self.play_pause_song
|
||||
)
|
||||
play_pause_button.pack(side="left")
|
||||
|
||||
forward_button = tk.Button(
|
||||
control_frame, text=">> 5s", command=self.forward_5_seconds
|
||||
)
|
||||
forward_button.pack(side="left")
|
||||
|
||||
forward_1_second_button = tk.Button(
|
||||
control_frame, text=">> 1s", command=self.forward_1_second
|
||||
)
|
||||
forward_1_second_button.pack(side="left")
|
||||
|
||||
forward_half_second_button = tk.Button(
|
||||
control_frame, text=">> 0.5s", command=self.forward_half_second
|
||||
)
|
||||
forward_half_second_button.pack(side="left")
|
||||
|
||||
def get_canvas_width(self):
|
||||
canvas_width = self.canvas.winfo_width()
|
||||
return canvas_width
|
||||
|
||||
def redraw_notes(self, event):
|
||||
self.canvas.delete("notes")
|
||||
canvas_height = (
|
||||
self.canvas_frame.winfo_height() - self.arrow_buttons_frame.winfo_height()
|
||||
)
|
||||
self.canvas_height = canvas_height # Store canvas height for future use
|
||||
for note_time, arrow in self.notes:
|
||||
x = (
|
||||
note_time
|
||||
/ float(MP3(self.song_path).info.length)
|
||||
* self.get_canvas_width()
|
||||
)
|
||||
color = self.get_arrow_color(arrow)
|
||||
self.canvas.create_rectangle(
|
||||
x - 2, 0, x + 2, self.canvas_height, fill=color, tags="notes"
|
||||
)
|
||||
|
||||
def update_canvas_height(self, event):
|
||||
canvas_height = (
|
||||
self.canvas_frame.winfo_height()
|
||||
- self.arrow_buttons_frame.winfo_height()
|
||||
- self.save_button_height
|
||||
)
|
||||
self.canvas.config(height=canvas_height)
|
||||
self.generate_visualizations()
|
||||
|
||||
def select_song(self):
|
||||
file_path = filedialog.askopenfilename(
|
||||
filetypes=[("MP3 files", "*.mp3"), ("RHYS files", "*.rhys")]
|
||||
)
|
||||
if file_path:
|
||||
self.song_path = file_path # Assign the song path here
|
||||
if file_path.endswith(".rhys"):
|
||||
self.load_rhys_file(file_path)
|
||||
self.init_song()
|
||||
self.generate_visualizations()
|
||||
self.save_button.pack()
|
||||
self.arrow_buttons_frame.pack()
|
||||
|
||||
def generate_visualizations(self):
|
||||
audio = MP3(self.song_path)
|
||||
meta = EasyMP3(self.song_path)
|
||||
song_length = audio.info.length
|
||||
song_name = meta["title"][0]
|
||||
song_artist = meta["artist"][0]
|
||||
self.song_length = song_length
|
||||
|
||||
self.canvas.delete("all")
|
||||
|
||||
mins = int(song_length / 60)
|
||||
secs = song_length % 60
|
||||
self.canvas.create_text(
|
||||
20, 10, text=f"{song_name}", anchor="nw", font=("Arial", 12)
|
||||
)
|
||||
self.canvas.create_text(
|
||||
20, 25, text=f"By: {song_artist}", anchor="nw", font=("Arial", 12)
|
||||
)
|
||||
self.canvas.create_text(
|
||||
20,
|
||||
40,
|
||||
text=f"Song Length: {mins}m:{secs}:s",
|
||||
anchor="nw",
|
||||
font=("Arial", 12),
|
||||
)
|
||||
|
||||
canvas_height = (
|
||||
self.canvas_frame.winfo_height() - self.arrow_buttons_frame.winfo_height()
|
||||
)
|
||||
self.canvas.config(height=canvas_height)
|
||||
|
||||
self.canvas_width = song_length * 100
|
||||
self.canvas.config(scrollregion=(0, 0, self.canvas_width, canvas_height))
|
||||
|
||||
for sec in range(int(song_length) + 1):
|
||||
x = sec * 100
|
||||
self.canvas.create_line(x, 0, x, canvas_height, fill="gray")
|
||||
if sec % 5 == 0:
|
||||
self.canvas.create_text(
|
||||
x + 10,
|
||||
canvas_height - 20,
|
||||
text=f"{sec}s",
|
||||
font=("Arial", 10),
|
||||
anchor="nw",
|
||||
)
|
||||
elif sec % 1 == 0:
|
||||
self.canvas.create_line(x, 0, x, canvas_height, fill="lightgray")
|
||||
|
||||
self.update_cursor()
|
||||
|
||||
def load_rhys_file(self, file_path):
|
||||
with open(file_path, "r") as f:
|
||||
data = json.load(f)
|
||||
encoded_audio = data["audio"]
|
||||
self.notes = data["notes"]
|
||||
|
||||
# Decode the base64 audio and save it temporarily
|
||||
decoded_audio = base64.b64decode(encoded_audio)
|
||||
temp_audio_file = tempfile.NamedTemporaryFile(delete=False, suffix=".mp3")
|
||||
temp_audio_file.write(decoded_audio)
|
||||
temp_audio_file.close()
|
||||
|
||||
self.song_path = (
|
||||
temp_audio_file.name
|
||||
) # Update the song_path to the temporary file
|
||||
|
||||
self.generate_visualizations()
|
||||
for note_time, arrow in self.notes:
|
||||
x = note_time * 100
|
||||
color = self.get_arrow_color(arrow)
|
||||
self.canvas.create_rectangle(x - 2, 0, x + 2, 200, fill=color)
|
||||
|
||||
def auto_add_note(self, event):
|
||||
print("Auto add")
|
||||
|
||||
if self.song_playing:
|
||||
current_time = self.current_pos + pygame.mixer.music.get_pos() / 1000.0
|
||||
else:
|
||||
current_time = self.current_pos
|
||||
|
||||
x = current_time / self.song_length * self.canvas_width
|
||||
|
||||
time = x / self.get_canvas_width() * float(MP3(self.song_path).info.length)
|
||||
self.notes.append((time, self.selected_arrow))
|
||||
color = self.get_arrow_color(self.selected_arrow)
|
||||
self.canvas.create_rectangle(
|
||||
x - 2,
|
||||
0,
|
||||
x + 2,
|
||||
self.canvas_frame.winfo_height(),
|
||||
fill=color,
|
||||
tags=f"{time}",
|
||||
)
|
||||
|
||||
def add_note(self, event):
|
||||
x = self.canvas.canvasx(
|
||||
event.x
|
||||
) # Adjust x coordinate based on canvas scroll position
|
||||
time = x / self.get_canvas_width() * float(MP3(self.song_path).info.length)
|
||||
self.notes.append((time, self.selected_arrow))
|
||||
color = self.get_arrow_color(self.selected_arrow)
|
||||
self.canvas.create_rectangle(
|
||||
x - 2,
|
||||
0,
|
||||
x + 2,
|
||||
self.canvas_frame.winfo_height(),
|
||||
fill=color,
|
||||
tags=f"{time}",
|
||||
)
|
||||
|
||||
def delete_note(self, event):
|
||||
x = self.canvas.canvasx(
|
||||
event.x
|
||||
) # Adjust x coordinate based on canvas scroll position
|
||||
canvas_width = self.get_canvas_width()
|
||||
closest_note = None
|
||||
closest_distance = float("inf")
|
||||
|
||||
delta = 4
|
||||
|
||||
# Find the closest note to the mouse click
|
||||
for note_time, _ in self.notes:
|
||||
note_x = note_time / float(MP3(self.song_path).info.length) * canvas_width
|
||||
distance = abs(note_x - x)
|
||||
if distance < closest_distance and distance <= delta:
|
||||
closest_note = (note_time, _)
|
||||
self.canvas.delete(f"{note_time}")
|
||||
closest_distance = distance
|
||||
|
||||
if closest_note:
|
||||
self.notes.remove(closest_note)
|
||||
self.redraw_notes(event)
|
||||
|
||||
def select_arrow(self, direction):
|
||||
self.selected_arrow = direction
|
||||
|
||||
def get_arrow_color(self, direction):
|
||||
if direction == "up":
|
||||
return "green"
|
||||
elif direction == "down":
|
||||
return "blue"
|
||||
elif direction == "left":
|
||||
return "red"
|
||||
elif direction == "right":
|
||||
return "yellow"
|
||||
|
||||
def save_from_mp3(self):
|
||||
encoded_audio = ""
|
||||
with open(self.song_path, "rb") as f:
|
||||
encoded_audio = base64.b64encode(f.read()).decode("utf-8")
|
||||
|
||||
# Get metadata information
|
||||
audio = EasyMP3(self.song_path)
|
||||
artist = audio.get("artist", [""])[0]
|
||||
album = audio.get("album", [""])[0]
|
||||
title = audio.get("title", [""])[0]
|
||||
track_time = int(audio.info.length)
|
||||
|
||||
# Fallback to MP3 and ID3 to get cover art
|
||||
mp3_audio = MP3(self.song_path, ID3=ID3)
|
||||
cover_art_data = ""
|
||||
cover_art_filename = ""
|
||||
|
||||
# Extract cover art
|
||||
for tag in mp3_audio.tags.values():
|
||||
if isinstance(tag, APIC):
|
||||
cover_art_data = base64.b64encode(tag.data).decode("utf-8")
|
||||
cover_art_filename = (
|
||||
f"{os.path.splitext(os.path.basename(self.song_path))[0]}_cover.jpg"
|
||||
)
|
||||
|
||||
|
||||
formatted_notes = [{"t": note[0], "a": note[1]} for note in self.notes]
|
||||
|
||||
# Fail-safe for missing metadata
|
||||
if not artist:
|
||||
artist = "Unknown Artist"
|
||||
if not album:
|
||||
album = "Unknown Album"
|
||||
if not title:
|
||||
title = "Unknown Track"
|
||||
|
||||
song_data = {
|
||||
"notes": formatted_notes,
|
||||
"artist": artist,
|
||||
"album": album,
|
||||
"title": title,
|
||||
"track_time": track_time,
|
||||
"audio": encoded_audio,
|
||||
"cover_art": cover_art_data,
|
||||
}
|
||||
|
||||
file_name = filedialog.asksaveasfilename(
|
||||
parent=root, title="Save as rhys:", filetypes=[("RHYS files", "*.rhys")]
|
||||
)
|
||||
|
||||
if file_name:
|
||||
with open(f"{file_name}", "w", encoding="utf-8") as f:
|
||||
json.dump(song_data, f)
|
||||
print(f"Level saved to {file_name}")
|
||||
|
||||
messagebox.showinfo("Success", f"Level saved to {file_name}")
|
||||
else:
|
||||
messagebox.showerror("Error", "You must provide a filename")
|
||||
|
||||
def update_rhys(self):
|
||||
with open(self.song_path, "r+", encoding="utf-8") as f:
|
||||
data = json.load(f)
|
||||
data["notes"] = self.notes
|
||||
f.seek(0)
|
||||
json.dump(data, f)
|
||||
f.truncate()
|
||||
print("Notes added to rhys file")
|
||||
|
||||
def save_level(self):
|
||||
if self.song_path:
|
||||
file_extension = os.path.splitext(self.song_path)[1]
|
||||
if file_extension == ".mp3":
|
||||
self.save_from_mp3()
|
||||
elif file_extension == ".rhys":
|
||||
self.update_rhys()
|
||||
|
||||
|
||||
root = tk.Tk()
|
||||
app = LevelDesigner(root)
|
||||
|
||||
root.mainloop()
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b4c76466f83d805ee91bfe213b94f444
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
@@ -0,0 +1,23 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 551ceb1164cf982b88ec38ddad60fb3e
|
||||
AudioImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 7
|
||||
defaultSettings:
|
||||
serializedVersion: 2
|
||||
loadType: 0
|
||||
sampleRateSetting: 0
|
||||
sampleRateOverride: 44100
|
||||
compressionFormat: 1
|
||||
quality: 1
|
||||
conversionMode: 0
|
||||
preloadAudioData: 0
|
||||
platformSettingOverrides: {}
|
||||
forceToMono: 0
|
||||
normalize: 1
|
||||
loadInBackground: 0
|
||||
ambisonic: 0
|
||||
3D: 1
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1 @@
|
||||
{"notes": [], "artist": "meganeko", "album": "Violent Purple", "title": "Violent Purple", "track_time": 216, "audio": "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 truncated
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 197cce406806a79ffa20a4a3a6a58d12
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in new issue
Block a user