updated repos to latest versions

This commit is contained in:
stan 2024-06-29 13:29:48 -05:00
parent 18ca545440
commit d78288b614
12 changed files with 621 additions and 198 deletions

BIN
Fbroswer.tar.gz Normal file

Binary file not shown.

View File

@ -4,18 +4,30 @@
# Importing Libraries
import sys
import os
from ScanOrg import organizer, file_scanner, DirectoryFilterProxyModel, FileFilterProxyModel
from stanzip import Extractor as extractor
from stanzip import Compressor as compressor
from stanzip import zipfile, py7zr, rarfile
from PyQt5.QtGui import QStandardItem , QStandardItemModel, QContextMenuEvent
from PyQt5.QtWidgets import QApplication, QLabel, QPushButton, QVBoxLayout, QMenu, QTreeView, QMessageBox, QSlider, QWidget, QFileSystemModel, QSplitter, QHBoxLayout, QFileDialog
from PyQt5.QtMultimedia import QMediaPlaylist, QMediaPlayer, QMediaContent, QAudioFormat, QAudioDeviceInfo, QAudio
from PyQt5.QtCore import QDir, QSortFilterProxyModel, Qt, QUrl
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as MPLCanvas
from matplotlib.figure import Figure
from PyQt5.QtGui import QStandardItem , QStandardItemModel
from PyQt5.QtWidgets import QApplication, QLabel, QPushButton, QTreeView, QMessageBox, QSlider, QWidget, QFileSystemModel, QSplitter, QHBoxLayout, QFileDialog
from PyQt5.QtMultimedia import QMediaPlaylist, QMediaPlayer, QMediaContent, QAudioFormat, QAudioDeviceInfo, QAudio
from PyQt5.QtCore import QDir, QSortFilterProxyModel, Qt, QUrl #QAbstractItemModel, QAbstractProxyModel, QModelIndex, QItemSelectionModel, QItemSelection, QItemSelectionRange, QItemSelectionModel, QItemSelection, QItemSelectionRange
"""
# Audio Format
audio_format = QAudioFormat()
audio_format.setSampleRate(44100)
audio_format.setChannelCount(2)
audio_format.setSampleSize(16)
audio_format.setCodec('audio/pcm')
audio_format.setByteOrder(QAudioFormat.LittleEndian)
audio_format.setSampleType(QAudioFormat.SignedInt)
# Audio Device Info
device_info = QAudioDeviceInfo.defaultOutputDevice()
if not device_info.isFormatSupported(audio_format):
print('Raw audio format not supported by backend, cannot play audio.')
audio_format = device_info.nearestFormat(audio_format)
"""
# Sample Music Browser Main Class
@ -23,7 +35,6 @@ class SampleMusicBrowser(QWidget):
def __init__(self):
super().__init__()
self.organizer = organizer()
self.extractor = extractor()
self.file_model = QStandardItemModel()
self.player = QMediaPlayer()
self.playlist = QMediaPlaylist()
@ -31,102 +42,68 @@ class SampleMusicBrowser(QWidget):
self.tree_model = QFileSystemModel()
self.init_ui()
#self.midi_player = MidPlay()
self.folder_contents_view.setEditTriggers(QTreeView.NoEditTriggers)
self.player.error.connect(self.player_error)
self.player.mediaStatusChanged.connect(self.player_media_status_changed)
self.player.setAudioRole(QAudio.MusicRole)
self.layout = QHBoxLayout()
self.canvas = MPLCanvas()
self.layout.addWidget(self.canvas)
self.setLayout(self.layout)
# Player Error Debugging
def player_error(self, error):
try:
if error == QMediaPlayer.NoError:
return
print(f"An error occurred: Code:{error} {self.player.errorString()}")
except Exception as e:
print(f"Error: {e}")
print('Error: ' + self.player.errorString())
# Media Status Changed Debugging
def player_media_status_changed(self, status):
if status == QMediaPlayer.NoMedia:
return
print('Media Status: ' + str(status))
def on_extract_button_clicked(self):
extraction_directory = QFileDialog.getExistingDirectory(self, "Select Extraction Directory")
if extraction_directory:
index = self.folder_contents_view.currentIndex()
if index.isValid():
self.extractor.zipviewer(index, self.file_filter_model, self.list_model, extraction_directory)
def show_context_menu(self, position):
menu = QMenu(self)
extract_action = menu.addAction('Extract')
extract_action.triggered.connect(self.on_extract_button_clicked) # Connect to the extraction function
menu.exec(self.folder_contents_view.mapToGlobal(position))
def init_ui(self):
layout = QVBoxLayout()
layout = QHBoxLayout()
label = QLabel('Sample Music Browser')
buttons_layout = QHBoxLayout()
layout.addWidget(label)
#self.midi_player = MidPlay()
button = QPushButton('Exit')
button.clicked.connect(self.show_exit_popup)
layout.addWidget(button)
self.file_tree = QTreeView()
self.file_tree.setHeaderHidden(True)
self.file_tree.clicked.connect(self.change_directory)
play_button = QPushButton('Play')
play_button.clicked.connect(self.player.play)
#play_button.clicked.connect(self.midi_player.play_midi)
buttons_layout.addWidget(play_button)
stop_button = QPushButton('Stop')
stop_button.clicked.connect(self.player.stop)
# stop_button.clicked.connect(self.midi_player.stop)
buttons_layout.addWidget(stop_button)
self.player.stateChanged.connect(self.player_state_changed)
self.player.positionChanged.connect(self.player_position_changed)
self.player.durationChanged.connect(self.player_duration_changed)
layout.addLayout(buttons_layout)
self.folder_contents_view = QTreeView()
self.folder_contents_view.setHeaderHidden(False)
self.folder_contents_view.setRootIsDecorated(False)
self.folder_contents_view.setSortingEnabled(True)
splitter = QSplitter()
splitter.addWidget(self.file_tree)
splitter.addWidget(self.folder_contents_view)
layout.addWidget(splitter)
self.current_dir_label = QLabel()
layout.addWidget(self.current_dir_label)
up_dir_button = QPushButton('Up Directory')
up_dir_button.clicked.connect(self.go_up_directory)
layout.addWidget(up_dir_button)
back_button = QPushButton('Back')
back_button.clicked.connect(self.go_back_directory)
layout.addWidget(back_button)
forward_button = QPushButton('Forward')
forward_button.clicked.connect(self.go_forward_directory)
layout.addWidget(forward_button)
self.setLayout(layout)
self.setWindowTitle('Samples are life!')
path = QFileDialog.getExistingDirectory(self, 'Select Directory')
if path:
self.populate_file_tree(path)
play_button = QPushButton('Play')
play_button.clicked.connect(self.player.play)
layout.addWidget(play_button)
pause_button = QPushButton('Pause')
pause_button.clicked.connect(self.player.pause)
layout.addWidget(pause_button)
stop_button = QPushButton('Stop')
stop_button.clicked.connect(self.player.stop)
layout.addWidget(stop_button)
self.player.stateChanged.connect(self.player_state_changed)
self.player.positionChanged.connect(self.player_position_changed)
self.player.durationChanged.connect(self.player_duration_changed)
self.player.setVolume(50)
volume_slider = QSlider(Qt.Horizontal)
volume_slider.setRange(0, 100)
@ -139,9 +116,6 @@ class SampleMusicBrowser(QWidget):
self.playlist.mediaRemoved.connect(self.playlist_media_removed)
self.playlist.setPlaybackMode(QMediaPlaylist.Loop)
self.folder_contents_view.doubleClicked.connect(self.play_file)
self.folder_contents_view.setContextMenuPolicy(Qt.CustomContextMenu)
self.folder_contents_view.customContextMenuRequested.connect(self.show_context_menu)
def directory_loaded(self, path):
self.file_tree.setRootIndex(self.directory_model.mapFromSource(self.model.index(path)))
@ -165,45 +139,19 @@ class SampleMusicBrowser(QWidget):
except Exception as e:
print(f"Error Populating File Tree: {e}")
def closeEvent(self, event):
def show_exit_popup(self):
reply = QMessageBox.question(self, 'Exit', 'Are you sure you want to exit?',
QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
if reply == QMessageBox.Yes:
event.accept()
else:
event.ignore()
sys.exit()
def play_file(self, index):
try:
index = self.file_filter_model.mapToSource(index)
file_path = self.list_model.filePath(index)
if file_path.endswith(('.zip', '.rar', '.7z')):
with zipfile.ZipFile(file_path, 'r') as zip_ref:
for filename in zip_ref.namelist():
if filename.lower().endswith(('mp3', 'wav', 'ogg', 'flac',
'm4a', 'wma', 'aac', 'aiff', 'alac',
'mid', 'midi', 'mp4', 'm4a')):
audo_file = zip_ref.extract(filename)
media = QMediaContent(QUrl.fromLocalFile(audo_file))
self.playlist.clear()
self.playlist.addMedia(media)
self.player.play()
break
if os.path.exists(audo_file):
os.remove(audo_file)
elif file_path.endswith(('.mid', '.midi')):
#self.midi_player = MidPlay()
#fig = self.midi_player.play_midi(file_path)
self.canvas.draw()
else:
media = QMediaContent(QUrl.fromLocalFile(file_path))
self.playlist.clear()
self.playlist.addMedia(media)
self.player.play()
except Exception as e:
print(f"Error Playing File: {e}")
def player_state_changed(self, state):
if state == QMediaPlayer.StoppedState:
@ -235,39 +183,34 @@ class SampleMusicBrowser(QWidget):
def go_up_directory(self):
index = self.folder_contents_view.rootIndex()
index = self.file_filter_model.mapToSource(index)
parent_index = index.parent()
if parent_index.isValid(): # Check if the parent index is valid
self.folder_contents_view.setRootIndex(self.file_filter_model.mapFromSource(parent_index))
self.current_dir_label.setText(self.list_model.filePath(parent_index))
index = self.file_model.index(index)
index = index.parent()
index = self.file_filter_model.mapFromSource(index)
self.folder_contents_view.setRootIndex(index)
self.current_dir_label.setText(self.model.filePath(index))
def go_back_directory(self):
index = self.folder_contents_view.rootIndex()
index = self.file_filter_model.mapToSource(index)
index = self.file_model.index(index)
index = index.parent()
index = self.file_filter_model.mapFromSource(index)
self.folder_contents_view.setRootIndex(index)
self.current_dir_label.setText(self.model.filePath(index))
def go_forward_directory(self):
index = self.folder_contents_view.rootIndex()
index = self.file_filter_model.mapToSource(index)
parent_index = index.parent()
if parent_index.isValid():
self.folder_contents_view.setRootIndex(self.file_filter_model.mapFromSource(parent_index))
self.current_dir_label.setText(self.list_model.filePath(parent_index))
index = self.file_model.index(index)
index = index.parent()
index = self.file_filter_model.mapFromSource(index)
self.folder_contents_view.setRootIndex(index)
self.current_dir_label.setText(self.model.filePath(index))
if __name__ == '__main__':
# player = MidPlay()
# file_path = list(player.select_file()) # Get the selected file path
# viewer = MidViewer()
# viewer.read_midi(file_path)
# viewer.view_midi()
#viewer.show()
# viewer.save('test.png')
# viewer.clear()
# viewer.close()
# print(viewer.get_midi_info(file_path)) # Use the file path
# print(viewer.get_piano_roll(file_path)) # Use the file path
# print(viewer.get_tempo(file_path)) # Use the file path
# print(viewer.get_notes(file_path)) # Use the file path
app = QApplication(sys.argv)
sampleMusicBrowser = SampleMusicBrowser()
sampleMusicBrowser.show()
sys.exit(app.exec_())

BIN
Fbrowser.zip Executable file

Binary file not shown.

View File

@ -1,25 +1,10 @@
#Path: MidPlay.py
# Description: A class to play MIDI files and a class to view MIDI files
# probably switching to a different library for midi handling
# pretty_midi is not very good for this purpose or real-time playback of midi files
"""Pretty Midi module type stubs are included but incomplete.
Pretty Midi comes with a statement to cite the following paper
when used in a research project:
Colin Raffel and Daniel P. W. Ellis. Intuitive Analysis,
Creation and Manipulation of MIDI Data with pretty_midi.
In Proceedings of the 15th International Conference on Music
Information Retrieval Late Breaking and Demo Papers, 2014.
colinraffel.com/publications/ismir2014intuitive.pdf
"""
import pygame
# Imports
import pretty_midi
import mido
import fluidsynth
import sys
import os
from PyQt5.QtWidgets import (QApplication, QLabel, QListWidget, QFileDialog, QMessageBox, QWidget, QPushButton, QHBoxLayout,
QVBoxLayout,
@ -29,6 +14,18 @@ from PyQt5.QtCore import QTimer, Qt
import threading
import cProfile # profiler remove for production
#profiler remove for production
def start_profiling():
global pr
pr = cProfile.Profile()
pr.enable()
def stop_profiling():
pr.disable()
pr.dump_stats('midi_profile.out')
# The pygame.mixer.init() call is necessary to initialize the mixer module
# before any sound can be played. The pygame.init() call is necessary maybe.
pygame.mixer.init()
pygame.init()
@ -51,10 +48,17 @@ class MidPlayGUI(QWidget):
def update_progress(self):
if self.player.current_midi:
current_time = pygame.mixer.music.get_pos() / 1000 # get_pos returns time in milliseconds NOT SECONDS!
total_time = self.player.current_midi.get_end_time()
total_time = self.calculate_midi_duration(self.player.current_midi)
progress = current_time / total_time * 100
self.progress_bar.setValue(int(progress))
def calculate_midi_duration(self, midi_file):
total_duration = 0
for track in midi_file.tracks:
track_duration = max([msg.time for msg in track]) if track else 0
total_duration = max(total_duration, track_duration)
return total_duration
def handle_song_end(self):
if self.player.playing and not pygame.mixer.music.get_busy():
self.player.next_song()
@ -194,7 +198,7 @@ class MidPlay:
def load_midi(self, filepath: str) -> None:
def load():
try:
self.current_midi = pretty_midi.PrettyMIDI(filepath)
self.current_midi = mido.MidiFile(filepath)
pygame.mixer.music.load(filepath)
except Exception as e:
print(f"Error loading MIDI: {e}")
@ -240,6 +244,7 @@ class MidPlay:
# print("Debug: Filepath:", filepath) # debug line
# print("Debug: Current MIDI:", self.current_midi) # debug line
"""
if __name__ == '__main__':
app = QApplication([])
player_gui = MidPlayGUI()
@ -253,3 +258,4 @@ if __name__ == '__main__':
running = False
break
app.exec_()
"""

View File

@ -9,13 +9,13 @@ import py7zr
import rarfile
import os
import mutagen
from PyQt5.QtCore import Qt, QSortFilterProxyModel, QAbstractTableModel, QModelIndex, QVariant, QAbstractItemModel, QFileInfo, QDir, QMimeDatabase, QMimeData, QUrl, QItemSelectionModel, QItemSelection, QItemSelectionRange, QObject, QThread, QTimer, QEventLoop, QCoreApplication, QUrl, pyqtSignal
from PyQt6.QtCore import Qt, QSortFilterProxyModel, pyqtSignal
# Directory Filter Proxy Model
class DirectoryFilterProxyModel(QSortFilterProxyModel):
def __init__(self):
super().__init__()
self.setFilterCaseSensitivity(Qt.CaseInsensitive)
self.setFilterCaseSensitivity(Qt.CaseSensitivity.CaseInsensitive)
self.setFilterKeyColumn(0)
def filterAcceptsRow(self, source_row, source_parent):
index = self.sourceModel().index(source_row, 0, source_parent)
@ -25,7 +25,7 @@ class DirectoryFilterProxyModel(QSortFilterProxyModel):
class FileFilterProxyModel(QSortFilterProxyModel):
def __init__(self):
super().__init__()
self.setFilterCaseSensitivity(Qt.CaseInsensitive)
self.setFilterCaseSensitivity(Qt.CaseSensitivity.CaseInsensitive)
self.setFilterKeyColumn(0)
self.allowed_extensions = ['.zip', '.mp3', '.wav', '.flac', '.mid', '.midi', '.aiff', '.aif', '.aifc', '.au', '.snd', '.wv', '.wma', '.m4a']
@ -77,44 +77,21 @@ class file_scanner:
def clear_file_list(self):
self.file_list = []
class Extractor:
class extractor:
def zipviewer(self, index, file_filter_model, list_model, extraction_directory):
if index.isValid() and extraction_directory is not None:
index = file_filter_model.mapToSource(index)
file_path = list_model.filePath(index)
try:
if file_path.endswith(".zip"):
if file_path.endswith(('.zip', '.rar', '.7z')):
with zipfile.ZipFile(file_path, 'r') as zip_ref:
self._extract_files(zip_ref, extraction_directory)
elif file_path.endswith(".rar"):
with rarfile.RarFile(file_path, 'r') as rar_ref:
self._extract_files(rar_ref, extraction_directory)
elif file_path.endswith(".7z"):
with py7zr.SevenZipFile(file_path, 'r') as sevenzip_ref:
self._extract_files(sevenzip_ref, extraction_directory)
else:
print(f"Unsupported file format: {file_path}")
except (zipfile.BadZipFile, zipfile.LargeZipFile) as e:
print(f"ZIP Extraction Error: {e}")
except (rarfile.RarFileException, rarfile.NotRARFile) as e:
print(f"RAR Extraction Error: {e}")
except py7zr.exceptions.SevenZipException as e:
print(f"7z Extraction Error: {e}")
except OSError as e:
print(f"Extraction Error: {e}")
def _extract_files(self, archive_ref, extraction_directory):
for filename in archive_ref.namelist():
for filename in zip_ref.namelist():
destination = os.path.join(extraction_directory, filename)
if os.path.isfile(destination):
print(f"File already exists: {destination}")
else:
os.makedirs(os.path.dirname(destination), exist_ok=True)
with open(destination, 'wb') as file:
file.write(archive_ref.read(filename))
print(f"Extracted: {filename}")
zip_ref.extract(filename, extraction_directory)
except (zipfile.BadZipFile, OSError, zipfile.LargeZipFile, zipfile.LargeZipFile) as e:
print(f"Extraction Error: {e}")
return
class organizer:
global metadata_queue
@ -208,6 +185,3 @@ class organizer:
if os.path.splitext(file)[1] == ('.mp3', '.wav', '.flac', '.m4a', '.wma', 'mid', '.midi'):
self.organize_audio()
audio = mutagen.File(file)

69
ScanOrg100.py Normal file
View File

@ -0,0 +1,69 @@
import os
from PyQt6.QtCore import QThread, pyqtSignal
class FileScanner(QThread):
items_found = pyqtSignal(list)
scan_complete = pyqtSignal()
def __init__(self, path):
super().__init__()
self.path = path
self.stop_requested = False
self.allowed_extensions = {
'.mid', '.midi', '.mp3', '.wav', '.ogg', '.flac', '.aac', '.m4a', '.wma',
'.flp', '.als', '.logic', '.logicx', '.ptx', '.pts', '.cpr', '.rpp',
'.reason', '.sng', '.ardour', '.bwproject'
}
def run(self):
self.scan_directory(self.path)
self.scan_complete.emit()
def scan_directory(self, path):
try:
items = []
with os.scandir(path) as entries:
for entry in entries:
if self.stop_requested:
return
if entry.is_dir():
items.append((entry.path, True))
elif entry.is_file() and entry.name.lower().endswith(tuple(self.allowed_extensions)):
items.append((entry.path, False))
self.items_found.emit(items)
except PermissionError:
print(f"Permission denied: {path}")
except OSError as e:
print(f"Error accessing {path}: {e}")
def stop(self):
self.stop_requested = True
class Organizer:
def __init__(self):
self.file_list = []
self.dir_list = []
self.scanner = None
def start_scan(self, path):
self.file_list.clear()
self.dir_list.clear()
self.scanner = FileScanner(path)
self.scanner.items_found.connect(self.add_items)
self.scanner.scan_complete.connect(self.scan_finished)
self.scanner.start()
def add_items(self, items):
for path, is_dir in items:
if is_dir:
self.dir_list.append(path)
else:
self.file_list.append(path)
def scan_finished(self):
print(f"Scan complete. Found {len(self.dir_list)} directories and {len(self.file_list)} files.")
def stop_scan(self):
if self.scanner:
self.scanner.stop()
self.scanner.wait()

147
maintest.py Normal file
View File

@ -0,0 +1,147 @@
import warnings
warnings.filterwarnings("ignore", category=DeprecationWarning)
import sys
import os
from PyQt6.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QPushButton,
QTreeView, QLabel, QStyle, QFileDialog, QHBoxLayout, QLineEdit, QProgressBar)
from PyQt6.QtCore import Qt, QDir, QTimer
from PyQt6.QtGui import QStandardItemModel, QStandardItem
from testmid import MidPlay
from ScanOrg100 import Organizer
from timer_m import Timer_Ui
class Fbrowser(QMainWindow):
def __init__(self):
super().__init__()
self.midplay = None
self.current_path = QDir.homePath()
self.organizer = Organizer()
self.init_ui()
self.timer = Timer_Ui()
def init_ui(self):
self.setWindowTitle('File Browser')
central_widget = QWidget()
layout = QVBoxLayout(central_widget)
# Address bar
address_layout = QHBoxLayout()
self.address_bar = QLineEdit(self.current_path)
self.address_bar.returnPressed.connect(self.navigate_to_address)
address_layout.addWidget(self.address_bar)
# Navigation buttons
back_button = QPushButton('Back')
back_button.clicked.connect(self.go_back)
address_layout.addWidget(back_button)
layout.addLayout(address_layout)
# Add a progress bar
self.progress_bar = QProgressBar()
layout.addWidget(self.progress_bar)
# File view
self.file_model = QStandardItemModel()
self.file_tree = QTreeView()
self.file_tree.setModel(self.file_model)
self.file_tree.doubleClicked.connect(self.on_item_double_clicked)
layout.addWidget(self.file_tree)
# MidPlay button
open_midplay_button = QPushButton('Open MidPlay')
open_midplay_button.clicked.connect(self.open_midplay)
layout.addWidget(open_midplay_button)
self.setCentralWidget(central_widget)
self.resize(800, 600)
# Timer Button
self.timer_button = QPushButton('Start Timer')
self.timer_button.clicked.connect(self.open_timer)
layout.addWidget(self.timer_button)
self.scan_current_directory()
def scan_current_directory(self):
self.organizer.start_scan(self.current_path)
self.progress_bar.setRange(0, 0) # Indeterminate progress
self.organizer.scanner.scan_complete.connect(self.scan_finished)
def scan_finished(self):
self.progress_bar.setRange(0, 100)
self.progress_bar.setValue(100)
self.update_file_tree()
def navigate_to_address(self):
new_path = self.address_bar.text()
if os.path.isdir(new_path):
self.current_path = new_path
self.scan_current_directory()
else:
self.address_bar.setText(self.current_path)
def update_file_tree(self):
self.file_model.clear()
self.file_model.setHorizontalHeaderLabels(['Name'])
root = self.file_model.invisibleRootItem()
# Add directories
for path in self.organizer.dir_list:
name = os.path.basename(path)
item = QStandardItem(name)
item.setData(path, Qt.ItemDataRole.UserRole)
item.setIcon(self.style().standardIcon(QStyle.StandardPixmap.SP_DirIcon))
root.appendRow(item)
# Add files
for path in self.organizer.file_list:
name = os.path.basename(path)
item = QStandardItem(name)
item.setData(path, Qt.ItemDataRole.UserRole)
item.setIcon(self.style().standardIcon(QStyle.StandardPixmap.SP_FileIcon))
root.appendRow(item)
self.file_tree.sortByColumn(0, Qt.SortOrder.AscendingOrder)
def on_item_double_clicked(self, index):
item = self.file_model.itemFromIndex(index)
path = item.data(Qt.ItemDataRole.UserRole)
if os.path.isdir(path):
self.current_path = path
self.address_bar.setText(path)
self.scan_current_directory()
else:
self.play_file(path)
def playingcheck_and_stop(self):
if self.midplay.is_playing():
self.midplay.stop()
def play_file(self, file_path):
if not self.midplay:
self.midplay = MidPlay()
#self.midplay.showUI()
self.midplay.add_to_playlist(file_path)
def go_back(self):
parent_dir = os.path.dirname(self.current_path)
if parent_dir != self.current_path:
self.current_path = parent_dir
self.address_bar.setText(parent_dir)
self.scan_current_directory()
def open_midplay(self):
if not self.midplay:
self.midplay = MidPlay()
self.midplay.showUI()
def open_timer(self):
self.timer.showUI()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Fbrowser()
ex.show()
sys.exit(app.exec())

17
requirements.txt Executable file → Normal file
View File

@ -1,6 +1,13 @@
# To ensure app dependencies are ported from your virtual environment/host machine into your container, run 'pip freeze > requirements.txt' in the terminal to overwrite this file
py7zr
PyQT5
PyQt5-tools
PyQt6
PyQt6-tools
matplotlib
rarfile
tqdm
PyQt5
mutagen
py7zr
pygame
mido
numpy
crypto
django
pyFluidSynth

View File

@ -1,4 +1,4 @@
import pretty_midi
import mido as pretty_midi
import random
import tkinter as tk
from tkinter import ttk, filedialog

View File

@ -1,7 +1,7 @@
import unittest
from unittest.mock import MagicMock
from PyQt5.QtWidgets import QApplication
from fbrowser import SampleMusicBrowser
from Fbrowser import SampleMusicBrowser
class TestSampleMusicBrowser(unittest.TestCase):
def setUp(self):

136
testmid.py Normal file
View File

@ -0,0 +1,136 @@
import os
import subprocess
from PyQt6.QtWidgets import QWidget, QVBoxLayout, QPushButton, QLabel, QFileDialog, QSlider, QListWidget
from PyQt6.QtCore import Qt, QUrl
from PyQt6.QtMultimedia import QMediaPlayer, QAudioOutput
DEFAULT_SOUNDFONT = '/home/stan/Documents/Dev/Tests/MidPlay/SoundFonts/FinalFantasyVI.sf2'
class MidPlay(QWidget):
def __init__(self):
super().__init__()
self.current_file = None
self.current_soundfont = DEFAULT_SOUNDFONT
self.process = None
self.media_player = QMediaPlayer()
self.audio_output = QAudioOutput()
self.media_player.setAudioOutput(self.audio_output)
self.playlist = []
self.current_index = 0
self.current_volume = 50
self.init_ui()
def init_ui(self):
layout = QVBoxLayout()
self.playlist_widget = QListWidget()
self.playlist_widget.itemDoubleClicked.connect(self.play_selected)
layout.addWidget(self.playlist_widget)
self.play_button = QPushButton("Play")
self.play_button.clicked.connect(self.play)
layout.addWidget(self.play_button)
self.stop_button = QPushButton("Stop")
self.stop_button.clicked.connect(self.stop)
layout.addWidget(self.stop_button)
self.next_button = QPushButton("Next")
self.next_button.clicked.connect(self.play_next)
layout.addWidget(self.next_button)
self.volume_slider = QSlider(Qt.Orientation.Horizontal)
self.volume_slider.setRange(0, 100)
self.volume_slider.setValue(self.current_volume)
self.volume_slider.valueChanged.connect(self.set_volume)
layout.addWidget(self.volume_slider)
self.status_label = QLabel("No file loaded")
layout.addWidget(self.status_label)
self.setLayout(layout)
def add_to_playlist(self, file_path):
self.playlist.append(file_path)
self.playlist_widget.addItem(os.path.basename(file_path))
if not self.current_file:
self.current_file = file_path
self.play()
def play_selected(self, item):
index = self.playlist_widget.row(item)
self.current_index = index
self.current_file = self.playlist[index]
self.play()
def play(self):
if not self.current_file:
self.status_label.setText("No file selected")
return
self.stop() # Stop any current playback
if self.current_file.lower().endswith(('.mid', '.midi')):
self.play_midi()
else:
self.play_audio()
def play_midi(self):
self.media_player.stop()
command = [
"fluidsynth",
"-a", "pulseaudio",
"-g", str(self.current_volume / 50),
self.current_soundfont,
self.current_file
]
self.process = subprocess.Popen(command)
self.status_label.setText(f"Playing MIDI: {os.path.basename(self.current_file)}")
def play_audio(self):
if self.process:
self.process.terminate()
self.process = None
self.media_player.setSource(QUrl.fromLocalFile(self.current_file))
self.media_player.play()
self.status_label.setText(f"Playing Audio: {os.path.basename(self.current_file)}")
self.media_player.mediaStatusChanged.connect(self.handle_media_status_change)
def stop(self):
if self.process:
self.process.terminate()
self.process = None
self.media_player.stop()
self.status_label.setText("Playback stopped")
def set_volume(self, value):
self.current_volume = value
self.audio_output.setVolume(value / 50)
if self.process and self.current_file.lower().endswith(('.mid', '.midi')):
self.update_midi_volume()
def update_midi_volume(self):
pass
def play_next(self):
if self.playlist:
self.current_index = (self.current_index + 1) % len(self.playlist)
self.current_file = self.playlist[self.current_index]
self.play()
def handle_media_status_change(self, status):
if status == QMediaPlayer.MediaStatus.EndOfMedia:
self.play_next()
def closeEvent(self, event):
self.stop()
super().closeEvent(event)
def showUI(self):
self.setWindowTitle("MidPlay")
super().show()
def close(self):
self.stop()
super().close()

141
timer_m.py Normal file
View File

@ -0,0 +1,141 @@
import time
import threading
import subprocess
from PyQt6.QtWidgets import QWidget, QVBoxLayout, QPushButton, QLabel, QHBoxLayout, QLineEdit
from PyQt6.QtCore import QTimer, QUrl
from PyQt6.QtMultimedia import QSoundEffect
class Timer:
def __init__(self):
self.remaining = 0
self.running = False
self.timer_thread = None
def set(self, hours, minutes, seconds):
self.remaining = hours * 3600 + minutes * 60 + seconds
def start(self):
if self.remaining > 0:
self.running = True
self.timer_thread = threading.Thread(target=self._run_timer)
self.timer_thread.start()
def _run_timer(self):
while self.running and self.remaining > 0:
time.sleep(1)
self.remaining -= 1
if self.running:
self._alarm()
def stop(self):
self.running = False
if self.timer_thread:
self.timer_thread.join()
def get_remaining_time(self):
return self.remaining
def _alarm(self):
print("Time's up!")
try:
for _ in range(3):
subprocess.run(["aplay", "/usr/share/sounds/sound-icons/glass.wav"],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
check=True)
except subprocess.CalledProcessError:
print("Error playing alarm sound")
self._fallback_alarm()
def _fallback_alarm(self):
sound = QSoundEffect()
sound.setSource(QUrl.fromLocalFile("/usr/share/sounds/sound-icons/glass.wav"))
sound.play()
class Timer_Ui(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Timer")
self.width = 400
self.height = 200
self.timer = Timer()
self.init_ui()
def init_ui(self):
layout = QVBoxLayout()
self.setLayout(layout)
self.timer_label = QLabel('Timer: Not Set')
layout.addWidget(self.timer_label)
timer_input_layout = QHBoxLayout()
self.hours_input = QLineEdit()
self.minutes_input = QLineEdit()
self.seconds_input = QLineEdit()
timer_input_layout.addWidget(QLabel('Hours:'))
timer_input_layout.addWidget(self.hours_input)
timer_input_layout.addWidget(QLabel('Minutes:'))
timer_input_layout.addWidget(self.minutes_input)
timer_input_layout.addWidget(QLabel('Seconds:'))
timer_input_layout.addWidget(self.seconds_input)
layout.addLayout(timer_input_layout)
self.set_timer_button = QPushButton('Set Timer')
self.set_timer_button.clicked.connect(self.set_timer)
layout.addWidget(self.set_timer_button)
self.start_timer_button = QPushButton('Start Timer')
self.start_timer_button.clicked.connect(self.start_timer)
layout.addWidget(self.start_timer_button)
self.stop_timer_button = QPushButton('Stop Timer')
self.stop_timer_button.clicked.connect(self.stop_timer)
layout.addWidget(self.stop_timer_button)
self.update_timer = QTimer()
self.update_timer.timeout.connect(self.update_timer_display)
self.update_timer.start(1000)
def set_timer(self):
try:
hours = int(self.hours_input.text() or 0)
minutes = int(self.minutes_input.text() or 0)
seconds = int(self.seconds_input.text() or 0)
self.timer.set(hours, minutes, seconds)
self.timer_label.setText(f'Timer: Set to {hours:02d}:{minutes:02d}:{seconds:02d}')
except ValueError:
self.timer_label.setText('Timer: Invalid input')
def start_timer(self):
if self.timer.get_remaining_time() > 0:
self.timer.start()
else:
self.timer_label.setText('Timer: Not set')
def stop_timer(self):
self.timer.stop()
self.timer_label.setText('Timer: Stopped')
def update_timer_display(self):
if self.timer.running:
remaining = self.timer.get_remaining_time()
hours, remainder = divmod(remaining, 3600)
minutes, seconds = divmod(remainder, 60)
self.timer_label.setText(f'Timer: {hours:02d}:{minutes:02d}:{seconds:02d}')
elif self.timer.get_remaining_time() == 0 and self.timer_label.text() != 'Timer: Not Set':
self.timer_label.setText('Timer: Time\'s up!')
def showUI(self):
self.setWindowTitle("Timer")
self.setGeometry(100, 100, self.width, self.height)
super().show()
if __name__ == "__main__":
import sys
from PyQt6.QtWidgets import QApplication
app = QApplication(sys.argv)
Timerui = Timer_Ui()
Timerui.showUI()
sys.exit(app.exec())