kenenet 1.1.1__py3-none-any.whl → 1.1.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.
kenenet/__init__.py CHANGED
@@ -31,7 +31,7 @@ def get_pos(key='f10', kill=False):
31
31
  coord_rgb.append({'coord': (x,y), 'RGB': rgb})
32
32
  coords.append((x,y))
33
33
  pyperclip.copy(f'coords_rgb = {coord_rgb}\ncoords = {coords}')
34
- quick_print(f"Added Coordinates: ({str(x).rjust(4)}, {str(y).rjust(4)}), RGB: {str(rgb).ljust(18)} {color}████████{reset} to clipboard", lineno)
34
+ quick_print(f"Added Coordinates: ({str(x).rjust(3)},{str(y).rjust(3)}), RGB: {str(rgb).ljust(15)} {color}████████{reset} to clipboard", lineno)
35
35
  if kill:
36
36
  quick_print('killing process')
37
37
  zhmiscellany.misc.die()
@@ -198,71 +198,115 @@ def save_img(img, name=' ', reset=True, file='temp_screenshots', mute=False):
198
198
  quick_print(f"Your img is not a fucking numpy array you twat, couldn't save {name}", lineno)
199
199
 
200
200
 
201
- class AudioPlayer:
202
- def __init__(self, file):
203
- self.file = file
204
- self.active_audio = {}
205
-
206
- def _stream_audio(self, sound, stop_event, chunk=1024):
207
- p = pyaudio.PyAudio()
208
- stream = p.open(
209
- format=p.get_format_from_width(sound.sample_width),
210
- channels=sound.channels,
211
- rate=sound.frame_rate,
212
- output=True
213
- )
214
- raw_data = sound.raw_data
215
- for i in range(0, len(raw_data), chunk):
216
- if stop_event.is_set():
217
- break
218
- stream.write(raw_data[i:i + chunk])
201
+ import random
202
+ import threading
203
+ import math
204
+ import pygame
205
+ from pydub import AudioSegment
206
+ import io
207
+ import time
208
+ import zhmiscellany
209
+
210
+
211
+ def sound_engine(sandbox_pygame=True):
212
+ class SoundEngine:
213
+ def __init__(self):
214
+ pygame.mixer.init()
215
+ self.handles = []
216
+ self.cached_audios = {}
219
217
 
220
- stream.stop_stream()
221
- stream.close()
222
- p.terminate()
223
-
224
- class _AudioLooper:
225
- def __init__(self, sound, stop_event, stream_func, loop=True):
226
- self.sound = sound
227
- self.loop = loop
228
- self.stop_event = stop_event
229
- self.stream_func = stream_func
230
- self.thread = threading.Thread(target=self._loop_audio, name="AudioLooperThread", daemon=True)
231
- self.thread.start()
218
+ def change_speed(self, sound, speed=1.0):
219
+ new_frame_rate = int(sound.frame_rate * speed)
220
+ new_sound = sound._spawn(sound.raw_data, overrides={"frame_rate": new_frame_rate})
221
+ # Resample back to the original frame rate for compatibility
222
+ return new_sound.set_frame_rate(sound.frame_rate)
232
223
 
233
- def _loop_audio(self):
234
- while not self.stop_event.is_set():
235
- self.stream_func(self.sound, self.stop_event)
236
- if not self.loop:
237
- break
224
+ class SoundHandle:
225
+ def __init__(self, thread, stop_event, sound_channel=None):
226
+ self.thread = thread
227
+ self.stop_event = stop_event
228
+ self.sound_channel = sound_channel
229
+
230
+ def stop(self):
231
+ self.stop_event.set()
232
+ if self.sound_channel is not None:
233
+ self.sound_channel.stop()
234
+ if hasattr(self.thread, 'kill'):
235
+ self.thread.kill()
236
+ self.thread.join(timeout=1.0)
238
237
 
239
- def stop(self):
240
- self.stop_event.set()
241
- self.thread.join()
242
-
243
- def play(self, loop=False, range=(0.9, 1.1)):
244
- file_sound = AudioSegment.from_mp3(self.file)._spawn(
245
- AudioSegment.from_mp3(self.file).raw_data,
246
- overrides={'frame_rate': int(AudioSegment.from_mp3(self.file).frame_rate * random.uniform(*range))}
247
- )
248
- stop_event = threading.Event()
249
- looper = self._AudioLooper(file_sound, stop_event, self._stream_audio, loop=loop)
250
- self.active_audio[id(file_sound)] = looper
238
+ def play(self, file_path, volume=1.0, speed=1, loop=False):
239
+ # Handle random speed selection
240
+ if isinstance(speed, tuple):
241
+ speed = random.uniform(speed[0], speed[1])
242
+
243
+ # Load or use cached audio
244
+ if file_path not in self.cached_audios:
245
+ sound = AudioSegment.from_file(file_path)
246
+ self.cached_audios[file_path] = sound
247
+ else:
248
+ sound = self.cached_audios[file_path]
249
+
250
+ # Adjust volume: pydub uses decibels.
251
+ # To convert a multiplier to dB change, use: gain = 20 * log10(volume)
252
+ if volume <= 0:
253
+ gain = -120
254
+ else:
255
+ gain = 20 * math.log10(volume)
256
+ sound = sound.apply_gain(gain)
257
+
258
+ # Apply speed change if needed
259
+ if speed != 1.0:
260
+ sound = self.change_speed(sound, speed)
261
+
262
+ # Convert to in-memory file object that pygame can read
263
+ buffer = io.BytesIO()
264
+ sound.export(buffer, format="wav")
265
+ buffer.seek(0)
266
+
267
+ # Create a pygame Sound object
268
+ pygame_sound = pygame.mixer.Sound(buffer)
269
+
270
+ # Set volume (pygame uses 0.0 to 1.0)
271
+ pygame_sound.set_volume(min(1.0, max(0.0, volume)))
272
+
273
+ stop_event = threading.Event()
274
+ channel = None
275
+
276
+ def play_sound():
277
+ nonlocal channel
278
+ try:
279
+ # Find an available channel
280
+ channel = pygame.mixer.find_channel()
281
+ if channel is None:
282
+ # If no channel is available, create a new one
283
+ current_channels = pygame.mixer.get_num_channels()
284
+ pygame.mixer.set_num_channels(current_channels + 1)
285
+ channel = pygame.mixer.Channel(current_channels)
286
+
287
+ # Start playing
288
+ channel.play(pygame_sound, loops=-1 if loop else 0)
289
+
290
+ # Wait until sound is done or stopped
291
+ while channel.get_busy() and not stop_event.is_set():
292
+ time.sleep(0.1)
293
+ except Exception as e:
294
+ print(f"Error playing sound: {e}")
295
+ if channel:
296
+ channel.stop()
297
+
298
+ # Start playback in a separate thread so it's nonblocking
299
+ thread = threading.Thread(target=play_sound, daemon=True)
300
+ thread.start()
301
+
302
+ handle = self.SoundHandle(thread, stop_event, channel)
303
+ self.handles.append(handle)
304
+ return handle
251
305
 
252
- def stop(self, file_sound=None):
253
- if file_sound:
254
- file_sound_id = id(file_sound)
255
- if file_sound_id in self.active_audio:
256
- self.active_audio[file_sound_id].stop()
257
- del self.active_audio[file_sound_id]
258
- else:
259
- for looper in self.active_audio.values():
260
- looper.stop()
261
- self.active_audio.clear()
262
-
263
- def load_audio(mp3_path):
264
- _ray_init_thread.join()
265
- return zhmiscellany.processing.synchronous_class_multiprocess(AudioPlayer, mp3_path)
306
+ if sandbox_pygame:
307
+ return zhmiscellany.processing.synchronous_class_multiprocess(SoundEngine)
308
+ else:
309
+ return SoundEngine()
266
310
 
267
311
  def time_func(func, loop=10000, *args, **kwargs):
268
312
  func_name = getattr(func, '__name__', repr(func))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: kenenet
3
- Version: 1.1.1
3
+ Version: 1.1.3
4
4
  Summary: dude what the fuck even is this package
5
5
  Home-page: https://www.youtube.com/@KiddyKene
6
6
  Author: kiddykene
@@ -0,0 +1,5 @@
1
+ kenenet/__init__.py,sha256=gRg62hDZd49s-OwmwTPnCrcZ9Ww2OrJTa5GdVP9eTj0,21730
2
+ kenenet-1.1.3.dist-info/METADATA,sha256=rbBX7ov2MHlVbz4hcTIDQK4sy8Gi2fH1d0EU2J1hfdA,1693
3
+ kenenet-1.1.3.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
4
+ kenenet-1.1.3.dist-info/top_level.txt,sha256=gUsWXLrM0jF4b4nbYJZdksdFewIx_F3xOF-zER8fMuQ,8
5
+ kenenet-1.1.3.dist-info/RECORD,,
@@ -1,5 +0,0 @@
1
- kenenet/__init__.py,sha256=VQ4e0H5Fj6CRmCYrOgY8uzNLSug9b_EuEadGLYiiIUw,19878
2
- kenenet-1.1.1.dist-info/METADATA,sha256=f1GztdOi4S_3_NLfunc_Hn4PJQE1pK3hJtzgU9AngKk,1693
3
- kenenet-1.1.1.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
4
- kenenet-1.1.1.dist-info/top_level.txt,sha256=gUsWXLrM0jF4b4nbYJZdksdFewIx_F3xOF-zER8fMuQ,8
5
- kenenet-1.1.1.dist-info/RECORD,,