cutted 0.3.2__py3-none-any.whl → 0.3.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cutted/__init__.py +1 -1
- cutted/app.py +17 -4
- cutted/core/audio_processor.py +34 -8
- {cutted-0.3.2.dist-info → cutted-0.3.3.dist-info}/METADATA +1 -1
- cutted-0.3.3.dist-info/RECORD +12 -0
- cutted-0.3.2.dist-info/RECORD +0 -12
- {cutted-0.3.2.dist-info → cutted-0.3.3.dist-info}/WHEEL +0 -0
- {cutted-0.3.2.dist-info → cutted-0.3.3.dist-info}/licenses/LICENSE +0 -0
- {cutted-0.3.2.dist-info → cutted-0.3.3.dist-info}/top_level.txt +0 -0
cutted/__init__.py
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
__version__ = "0.3.
|
1
|
+
__version__ = "0.3.3"
|
2
2
|
__author__ = "simon0302010"
|
cutted/app.py
CHANGED
@@ -25,6 +25,8 @@ class CuttedApp:
|
|
25
25
|
self.canvas = None
|
26
26
|
self.cursor_line = None
|
27
27
|
self.last_slider_update = 0
|
28
|
+
self.slider_value = 0
|
29
|
+
self.playback_start_time = 0
|
28
30
|
self.is_playing = False
|
29
31
|
self.last_states = []
|
30
32
|
self.setup_ui()
|
@@ -113,7 +115,7 @@ class CuttedApp:
|
|
113
115
|
self.canvas = FigureCanvasTkAgg(fig, master=self.plot_frame)
|
114
116
|
self.canvas.draw()
|
115
117
|
|
116
|
-
self.audio_lenght = int(round(self.AudioProcessor.
|
118
|
+
self.audio_lenght = int(round(self.AudioProcessor.get_length()))
|
117
119
|
|
118
120
|
slider_width = self.root.winfo_width() - 40
|
119
121
|
self.slider = customtkinter.CTkSlider(
|
@@ -153,11 +155,16 @@ class CuttedApp:
|
|
153
155
|
return
|
154
156
|
|
155
157
|
start_time = self.slider.get() if hasattr(self, 'slider') else 0
|
158
|
+
self.playback_start_time = start_time
|
156
159
|
self.AudioProcessor.play_audio(start_time)
|
157
160
|
|
158
161
|
def stop_audio(self):
|
159
|
-
self.AudioProcessor.stop_audio()
|
162
|
+
rel_pos = self.AudioProcessor.stop_audio()
|
160
163
|
self.is_playing = False
|
164
|
+
abs_pos = self.playback_start_time + rel_pos
|
165
|
+
self.slider.set(abs_pos)
|
166
|
+
self.set_cursor(abs_pos)
|
167
|
+
print_info(f"Absolute position in audio: {abs_pos:.2f}s")
|
161
168
|
|
162
169
|
def export_audio(self):
|
163
170
|
if not hasattr(self.AudioProcessor, "audio") or self.AudioProcessor.audio is None:
|
@@ -184,6 +191,7 @@ class CuttedApp:
|
|
184
191
|
print_success(f"Audio exported to {save_path}")
|
185
192
|
|
186
193
|
def send_prompt(self):
|
194
|
+
print(self.AudioProcessor.get_waveform_summary())
|
187
195
|
self.save_state()
|
188
196
|
|
189
197
|
if not hasattr(self.AudioProcessor, "audio") or self.AudioProcessor.audio is None:
|
@@ -192,14 +200,18 @@ class CuttedApp:
|
|
192
200
|
|
193
201
|
text = self.entry.get()
|
194
202
|
if text.strip():
|
195
|
-
full_prompt = f"You are a audio editing AI. You are controllable via natural language and editing a audio file. The audio file is {round(self.AudioProcessor.
|
203
|
+
full_prompt = f"You are a audio editing AI. You are controllable via natural language and editing a audio file. The audio file is {round(self.AudioProcessor.get_length())}s long. The cursor of the user is currently at {self.slider_value}s."
|
204
|
+
full_prompt += "\nHere is a the waveform samples of the audio. You can use them to determine silent parts, loud parts, silences, beats and much more.\nYou are forced to used these if the user requires you to cut out silent of quiet parts for example."
|
205
|
+
full_prompt += "\nAll of your tools should be enough to fullfill almost every task.\nNEVER ASK FOR CONFIRMATION FROM THE USER. DO EVERYTHING!"
|
206
|
+
full_prompt += f"\n{self.AudioProcessor.get_waveform_summary()}\n"
|
196
207
|
if whisper_support:
|
197
208
|
if self.use_transcript_checkbox.get():
|
198
209
|
if not self.whisper:
|
199
|
-
messagebox.showinfo("Info", "Loading Whisper model. This may take a few minutes depending on your internet connection. See the progress in your command line. If this window appears to be frozen, the transcription is running.")
|
210
|
+
messagebox.showinfo("Info", "Loading Whisper model. This may take a few minutes depending on your internet connection. See the progress in your command line. If this window appears to be frozen, the transcription is running. Press OK to continue.")
|
200
211
|
self.whisper = transcribe.Whisper()
|
201
212
|
transcript = self.whisper.transcribe(self.AudioProcessor.audio_path)
|
202
213
|
full_prompt += f"\nThis is a transcript with per word timestamps of the audio:\n{transcript}"
|
214
|
+
full_prompt += "\nThe transcript likely has issues. If you need infos about some words they might just be misspelled in the audio."
|
203
215
|
full_prompt += f"\n\nUser Prompt: {text}"
|
204
216
|
self.entry.delete(0, "end")
|
205
217
|
|
@@ -220,6 +232,7 @@ class CuttedApp:
|
|
220
232
|
elif text_result:
|
221
233
|
messagebox.showerror("Error", text_result.strip())
|
222
234
|
else:
|
235
|
+
messagebox.showerror("Error", "Gemini returned no data")
|
223
236
|
print_fail("Gemini returned no data")
|
224
237
|
|
225
238
|
def save_state(self):
|
cutted/core/audio_processor.py
CHANGED
@@ -62,7 +62,21 @@ class AudioProcessor:
|
|
62
62
|
|
63
63
|
return fig
|
64
64
|
|
65
|
-
def
|
65
|
+
def get_waveform_summary(self):
|
66
|
+
num_samples = round(self.get_length())
|
67
|
+
if self.audio is None:
|
68
|
+
return "No audio loaded."
|
69
|
+
samples = np.array(self.audio.get_array_of_samples())
|
70
|
+
if self.audio.channels == 2:
|
71
|
+
samples = samples.reshape((-1, 2))
|
72
|
+
samples = samples.mean(axis=1)
|
73
|
+
samples = samples / np.max(np.abs(samples))
|
74
|
+
indices = np.linspace(0, len(samples)-1, num_samples).astype(int)
|
75
|
+
summary = samples[indices]
|
76
|
+
return f"Waveform samples (normalized, {num_samples} points):\n" + \
|
77
|
+
" ".join(f"{x:.2f}" for x in summary)
|
78
|
+
|
79
|
+
def get_length(self):
|
66
80
|
self.duration = self.audio.duration_seconds
|
67
81
|
self.duration = round(self.duration, 2)
|
68
82
|
return self.duration
|
@@ -70,17 +84,25 @@ class AudioProcessor:
|
|
70
84
|
def cut(self, start, end):
|
71
85
|
if len(start) == len(end):
|
72
86
|
if len(start) == 1:
|
73
|
-
|
74
|
-
|
75
|
-
|
87
|
+
single_start = max(0, start[0])
|
88
|
+
single_end = max(0, end[0])
|
89
|
+
if single_end <= single_start:
|
90
|
+
print_fail("End time must be greater than start time.")
|
91
|
+
return False
|
92
|
+
print_info(f"Cutting from {single_start} to {single_end}")
|
93
|
+
start_ms = round(single_start * 1000)
|
94
|
+
end_ms = round(single_end * 1000)
|
76
95
|
self.audio = self.audio[:start_ms] + self.audio[end_ms:]
|
77
96
|
return True
|
78
97
|
else:
|
79
98
|
time_sets = list(zip(start, end))
|
80
99
|
subtract_time = 0
|
81
100
|
for single_start, single_end in time_sets:
|
82
|
-
single_start = single_start - subtract_time
|
83
|
-
single_end = single_end - subtract_time
|
101
|
+
single_start = max(0, single_start - subtract_time)
|
102
|
+
single_end = max(0, single_end - subtract_time)
|
103
|
+
if single_end <= single_start:
|
104
|
+
print_fail("End time must be greater than start time.")
|
105
|
+
continue
|
84
106
|
print_info(f"Cutting from {single_start} to {single_end}")
|
85
107
|
start_ms = round(single_start * 1000)
|
86
108
|
end_ms = round(single_end * 1000)
|
@@ -123,11 +145,15 @@ class AudioProcessor:
|
|
123
145
|
def stop_audio(self):
|
124
146
|
try:
|
125
147
|
if pygame.mixer.get_init():
|
148
|
+
pos_ms = pygame.mixer.music.get_pos()
|
149
|
+
pos_sec = pos_ms / 1000 if pos_ms >= 0 else 0
|
126
150
|
pygame.mixer.music.stop()
|
127
151
|
self.is_playing_var = False
|
128
|
-
print_info("Audio playback stopped")
|
152
|
+
print_info(f"Audio playback stopped at {pos_sec:.2f}s")
|
153
|
+
return pos_sec
|
129
154
|
except Exception as e:
|
130
155
|
print_warn(f"Error stopping audio: {e}")
|
156
|
+
return 0
|
131
157
|
|
132
158
|
def is_playing(self):
|
133
159
|
try:
|
@@ -142,7 +168,7 @@ class AudioProcessor:
|
|
142
168
|
return None
|
143
169
|
|
144
170
|
return {
|
145
|
-
"duration": self.
|
171
|
+
"duration": self.get_length(),
|
146
172
|
"channels": self.audio.channels,
|
147
173
|
"frame_rate": self.audio.frame_rate,
|
148
174
|
"sample_width": self.audio.sample_width
|
@@ -0,0 +1,12 @@
|
|
1
|
+
cutted/__init__.py,sha256=F1mzO6qI2gD6d_DQsjZItLuIfNfa1Te5KwCMThWDQT4,49
|
2
|
+
cutted/__main__.py,sha256=lYGLgtIZ_vGZIJmWG6ZQoqOdyOJnaWEA4NBn5Rc7Q8E,61
|
3
|
+
cutted/app.py,sha256=HaJ3yu8-WVDGKZmFcTVG4CK8q13eHyUQaIyOWMZWV68,10764
|
4
|
+
cutted/core/audio_processor.py,sha256=gKBJ1wpdrX2IozmXDzW7MoFVp9uq0Pb3ezz9R3Ahmnw,6691
|
5
|
+
cutted/core/gemini.py,sha256=yHsQXk4tDHcW5qJBuL2LpPvdChimxlmEbu76BvsoeY4,3108
|
6
|
+
cutted/core/logger.py,sha256=AjqrgW2LV9HdPkPQ8oOmyd9lWzVSIg46r74ILR7mVHo,585
|
7
|
+
cutted/core/transcribe.py,sha256=0e7aCva4y6D-gKe1xw5HT9VoFgbvHGgV6utn12r8wXA,986
|
8
|
+
cutted-0.3.3.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
9
|
+
cutted-0.3.3.dist-info/METADATA,sha256=ehEIEm5qz3wVqBY74Itpwooe4SYOFpXISXUMZO7LVh4,1503
|
10
|
+
cutted-0.3.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
11
|
+
cutted-0.3.3.dist-info/top_level.txt,sha256=PL6glZvzRyKWCDn5aoYI9uH8HlEA5Qd_XFJowJKARYI,7
|
12
|
+
cutted-0.3.3.dist-info/RECORD,,
|
cutted-0.3.2.dist-info/RECORD
DELETED
@@ -1,12 +0,0 @@
|
|
1
|
-
cutted/__init__.py,sha256=ttFLenYuOpXQTaR9nB0dF-3zFB_PeksXf9R4r_TB8S8,49
|
2
|
-
cutted/__main__.py,sha256=lYGLgtIZ_vGZIJmWG6ZQoqOdyOJnaWEA4NBn5Rc7Q8E,61
|
3
|
-
cutted/app.py,sha256=Ay_yVrPt1TQAE3lqmrII88lFoGZb5Mh5cDwediM9ZG8,9592
|
4
|
-
cutted/core/audio_processor.py,sha256=JdPeWO_jAIn_uZFeZYQJX3RC0Vy8GClKrX7xGk4pXR4,5426
|
5
|
-
cutted/core/gemini.py,sha256=yHsQXk4tDHcW5qJBuL2LpPvdChimxlmEbu76BvsoeY4,3108
|
6
|
-
cutted/core/logger.py,sha256=AjqrgW2LV9HdPkPQ8oOmyd9lWzVSIg46r74ILR7mVHo,585
|
7
|
-
cutted/core/transcribe.py,sha256=0e7aCva4y6D-gKe1xw5HT9VoFgbvHGgV6utn12r8wXA,986
|
8
|
-
cutted-0.3.2.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
9
|
-
cutted-0.3.2.dist-info/METADATA,sha256=MPuSW4_LjNch0PXeFrGtRW1C4CuJ7unNv1ZZhvFHmSM,1503
|
10
|
-
cutted-0.3.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
11
|
-
cutted-0.3.2.dist-info/top_level.txt,sha256=PL6glZvzRyKWCDn5aoYI9uH8HlEA5Qd_XFJowJKARYI,7
|
12
|
-
cutted-0.3.2.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|