Skip to content

Commit 669756b

Browse files
committed
update to Qt 6 and Pillow 12
and yeah, I accidentally ran black on the codebase. I don't want to spend more free time fixing that. All of these changes are simple renames or removals, nothing too major.
1 parent 9d45f7f commit 669756b

30 files changed

+2558
-2240
lines changed

README.md

Lines changed: 58 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,89 +1,102 @@
11
# Audio Visualizer Python
2+
23
**We need a good name that is not as generic as "audio-visualizer-python"!**
34

45
This is a little GUI tool which creates an audio visualization video from an input audio file. Different components can be added and layered to change the resulting video and add images, videos, gradients, text, etc. Encoding options can be changed with a variety of different output containers.
56

67
The program works on **Linux**, **macOS**, and **Windows**. If you encounter problems running it or have other bug reports or features that you wish to see implemented, please fork the project and submit a pull request and/or file an [issue](https://github.com/djfun/audio-visualizer-python/issues) on this project.
78

8-
99
# Screenshots & Videos
10+
1011
[<img title="AVP running on Windows" alt="Screenshot of program on Windows" src="screenshot.png" width="707">](/screenshot.png?raw=true)
1112

1213
## A video created by this app
13-
* **[YouTube: A day in spring](https://www.youtube.com/watch?v=-M3jR1NuJHM)** 🎥
14+
15+
- **[YouTube: A day in spring](https://www.youtube.com/watch?v=-M3jR1NuJHM)** 🎥
1416

1517
## Video demonstration of the app features
16-
* [YouTube: Audio Visualizer Python v2.0.0 demonstration](https://www.youtube.com/watch?v=EVt2ckQs1Yg) 🎥
1718

19+
- [YouTube: Audio Visualizer Python v2.0.0 demonstration](https://www.youtube.com/watch?v=EVt2ckQs1Yg) 🎥
1820

1921
# Installation
22+
2023
## Installation on Ubuntu 24.04
21-
* Install dependencies: `sudo apt install ffmpeg pipx python3-pyqt5`
22-
* Download this repo and run `pipx install .` in this directory
23-
* Run the program with `avp` from terminal
2424

25+
- Install system dependencies: `sudo apt install ffmpeg`
26+
- Make a virtual environment: `python -m venv env`
27+
- Activate it: `source env/bin/activate`
28+
- Install Python dependencies: `pip install pyqt6 pillow numpy`
29+
- Install this program: `pip install .` in this directory
30+
- Run the program with `avp` from terminal
2531

2632
## Installation on Windows
27-
* Install Python from the Windows Store
28-
* Add Python to your system PATH (it should ask during the installation process)
29-
* Download this repo (extract from zip if needed)
30-
* Download and install [FFmpeg](https://www.ffmpeg.org/download.html). Use the GPL-licensed static builds.
31-
* Add FFmpeg to the system PATH as well (program will then work anywhere)
32-
* Alternatively, copy ffmpeg.exe into the folder that you want to run the program within
33-
* Open command prompt, `cd` into the repo directory, and run: `pip install .`
34-
* Now run `avp` or `python -m avp` from a command prompt window to start the app
33+
34+
- Install Python from the Windows Store
35+
- Add Python to your system PATH (it should ask during the installation process)
36+
- Download this repo (extract from zip if needed)
37+
- Download and install [FFmpeg](https://www.ffmpeg.org/download.html). Use the GPL-licensed static builds.
38+
- Add FFmpeg to the system PATH as well (program will then work anywhere)
39+
- Alternatively, copy ffmpeg.exe into the folder that you want to run the program within
40+
- Open command prompt, `cd` into the repo directory, and run: `pip install pyqt6 pillow numpy .`
41+
- Now run `avp` or `python -m avp` from a command prompt window to start the app
3542

3643
## Installation on macOS
37-
* We need help writing instructions for macOS, but the program should work in theory.
44+
45+
- We need help writing instructions for macOS, but the program should work in theory.
3846

3947
# [Keyboard Shortcuts](https://github.com/djfun/audio-visualizer-python/wiki/Keyboard-Shortcuts)
40-
| Key Combo | Effect |
41-
| ------------------------- | -------------------------------------------------- |
42-
| Ctrl+S | Save Current Project |
43-
| Ctrl+A | Save Project As... |
44-
| Ctrl+O | Open Project |
45-
| Ctrl+N | New Project (prompts to save current project) |
46-
| Ctrl+Z | Undo |
47-
| Ctrl+Shift+Z _or_ Ctrl+Y | Redo |
48-
| Ctrl+T _or_ Insert | Add Component |
49-
| Ctrl+R _or_ Delete | Remove Component |
50-
| Ctrl+Space | Focus Component List |
51-
| Ctrl+Shift+S | Save Component Preset |
52-
| Ctrl+Shift+C | Remove Preset from Component |
53-
| Ctrl+Up | Move Selected Component Up |
54-
| Ctrl+Down | Move Selected Component Down |
55-
| Ctrl+Home | Move Selected Component to Top |
56-
| Ctrl+End | Move Selected Component to Bottom |
57-
| Ctrl+Shift+U | Open Undo History |
58-
| Ctrl+Shift+F | Show FFmpeg Command |
5948

49+
| Key Combo | Effect |
50+
| ------------------------ | --------------------------------------------- |
51+
| Ctrl+S | Save Current Project |
52+
| Ctrl+A | Save Project As... |
53+
| Ctrl+O | Open Project |
54+
| Ctrl+N | New Project (prompts to save current project) |
55+
| Ctrl+Z | Undo |
56+
| Ctrl+Shift+Z _or_ Ctrl+Y | Redo |
57+
| Ctrl+T _or_ Insert | Add Component |
58+
| Ctrl+R _or_ Delete | Remove Component |
59+
| Ctrl+Space | Focus Component List |
60+
| Ctrl+Shift+S | Save Component Preset |
61+
| Ctrl+Shift+C | Remove Preset from Component |
62+
| Ctrl+Up | Move Selected Component Up |
63+
| Ctrl+Down | Move Selected Component Down |
64+
| Ctrl+Home | Move Selected Component to Top |
65+
| Ctrl+End | Move Selected Component to Bottom |
66+
| Ctrl+Shift+U | Open Undo History |
67+
| Ctrl+Shift+F | Show FFmpeg Command |
6068

6169
# Commandline Mode
70+
6271
Projects can be created with the GUI then loaded from the commandline for easy automation of video production. Some components have commandline options for extra customization, and you can save "presets" with settings to load if the commandline option doesn't exist.
6372

6473
## Example/test command
65-
* Create a video with a grey "classic visualizer", background image, and text:
66-
* `avp -c 0 image path=src/tests/data/test.jpg -c 1 classic color=180,180,180 -c 2 text "title=Episode 371" -i src/tests/data/test.ogg -o output.mp4`
67-
* [See more about commandline mode in the wiki!](https://github.com/djfun/audio-visualizer-python/wiki/Commandline-Mode)
6874

75+
- Create a video with a grey "classic visualizer", background image, and text:
76+
- `avp -c 0 image path=src/tests/data/test.jpg -c 1 classic color=180,180,180 -c 2 text "title=Episode 371" -i src/tests/data/test.ogg -o output.mp4`
77+
- [See more about commandline mode in the wiki!](https://github.com/djfun/audio-visualizer-python/wiki/Commandline-Mode)
6978

7079
# Developer Information
80+
7181
## Known Working Versions of Dependencies
72-
* Python 3.10
73-
* FFmpeg 4.4.1
74-
* PyQt5 (Qt v5.15.3)
75-
* Pillow 9.1.0
76-
* NumPy 1.22.3
82+
83+
- Python 3.13
84+
- FFmpeg 8.0.1
85+
- PyQt6 v6.10.2 (Qt v6.10.1)
86+
- Pillow 12.1.0
87+
- NumPy 2.4.1
7788

7889
## Getting Faster Export Times
79-
* [Pillow-SIMD](https://github.com/uploadcare/pillow-simd) may be used as a drop-in replacement for Pillow if you desire faster video export times, but it must be compiled from source. For help installing dependencies to compile Pillow-SIMD, see the [Pillow installation guide](https://pillow.readthedocs.io/en/stable/installation.html). Then add the `-SIMD` suffix into `setup.py` and install as usual.
90+
91+
- [Pillow-SIMD](https://github.com/uploadcare/pillow-simd) may be used as a drop-in replacement for Pillow if you desire faster video export times, but it must be compiled from source. For help installing dependencies to compile Pillow-SIMD, see the [Pillow installation guide](https://pillow.readthedocs.io/en/stable/installation.html).
8092

8193
## Developing a New Component
82-
* Information for developing a component is in our wiki: [How a Component Works](https://github.com/djfun/audio-visualizer-python/wiki/How-a-Component-Works)
83-
* File an issue on GitHub if you need help fitting your visualizer into our component system; we would be happy to collaborate
8494

95+
- Information for developing a component is in our wiki: [How a Component Works](https://github.com/djfun/audio-visualizer-python/wiki/How-a-Component-Works)
96+
- File an issue on GitHub if you need help fitting your visualizer into our component system; we would be happy to collaborate
8597

8698
# License
99+
87100
Source code of audio-visualizer-python is licensed under the MIT license.
88101

89102
Some dependencies of this application are under the GPL license. When packaged with these dependencies, audio-visualizer-python may also be under the terms of this GPL license.

setup.py

Lines changed: 31 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -15,49 +15,53 @@ def getTextFromFile(filename, fallback):
1515
return output
1616

1717

18-
PACKAGE_NAME = 'avp'
19-
SOURCE_DIRECTORY = 'src'
20-
SOURCE_PACKAGE_REGEX = re.compile(rf'^{SOURCE_DIRECTORY}')
21-
PACKAGE_DESCRIPTION = 'Create audio visualization videos from a GUI or commandline'
18+
PACKAGE_NAME = "avp"
19+
SOURCE_DIRECTORY = "src"
20+
SOURCE_PACKAGE_REGEX = re.compile(rf"^{SOURCE_DIRECTORY}")
21+
PACKAGE_DESCRIPTION = "Create audio visualization videos from a GUI or commandline"
2222

2323

2424
avp = import_module(SOURCE_DIRECTORY)
25-
source_packages = find_packages(include=[SOURCE_DIRECTORY, f'{SOURCE_DIRECTORY}.*'])
26-
proj_packages = [SOURCE_PACKAGE_REGEX.sub(PACKAGE_NAME, name) for name in source_packages]
25+
source_packages = find_packages(include=[SOURCE_DIRECTORY, f"{SOURCE_DIRECTORY}.*"])
26+
proj_packages = [
27+
SOURCE_PACKAGE_REGEX.sub(PACKAGE_NAME, name) for name in source_packages
28+
]
2729

2830

2931
setup(
30-
name='audio_visualizer_python',
32+
name="audio_visualizer_python",
3133
version=avp.__version__,
32-
url='https://github.com/djfun/audio-visualizer-python',
33-
license='MIT',
34+
url="https://github.com/djfun/audio-visualizer-python",
35+
license="MIT",
3436
description=PACKAGE_DESCRIPTION,
35-
author=getTextFromFile('AUTHORS', 'djfun, tassaron'),
36-
long_description=getTextFromFile('README.md', PACKAGE_DESCRIPTION),
37+
author=getTextFromFile("AUTHORS", "djfun, tassaron"),
38+
long_description=getTextFromFile("README.md", PACKAGE_DESCRIPTION),
3739
classifiers=[
38-
'Development Status :: 4 - Beta',
39-
'License :: OSI Approved :: MIT License',
40-
'Programming Language :: Python :: 3 :: Only',
41-
'Intended Audience :: End Users/Desktop',
42-
'Topic :: Multimedia :: Video :: Non-Linear Editor',
40+
"Development Status :: 4 - Beta",
41+
"License :: OSI Approved :: MIT License",
42+
"Programming Language :: Python :: 3 :: Only",
43+
"Intended Audience :: End Users/Desktop",
44+
"Topic :: Multimedia :: Video :: Non-Linear Editor",
4345
],
4446
keywords=[
45-
'visualizer', 'visualization', 'commandline video',
46-
'video editor', 'ffmpeg', 'podcast'
47+
"visualizer",
48+
"visualization",
49+
"commandline video",
50+
"video editor",
51+
"ffmpeg",
52+
"podcast",
4753
],
4854
packages=proj_packages,
4955
package_dir={PACKAGE_NAME: SOURCE_DIRECTORY},
5056
include_package_data=True,
5157
install_requires=[
52-
'Pillow==9.1.1',
53-
'PyQt5',
54-
'numpy',
55-
'pytest',
56-
'pytest-qt',
58+
"Pillow",
59+
"PyQt6",
60+
"numpy",
61+
"pytest",
62+
"pytest-qt",
5763
],
5864
entry_points={
59-
'console_scripts': [
60-
f'avp = {PACKAGE_NAME}.__main__:main'
61-
],
62-
}
65+
"console_scripts": [f"avp = {PACKAGE_NAME}.__main__:main"],
66+
},
6367
)

src/__init__.py

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,32 +3,35 @@
33
import logging
44

55

6-
__version__ = '2.0.0'
6+
__version__ = "2.1.0"
77

88

99
class Logger(logging.getLoggerClass()):
10-
'''
11-
Custom Logger class to handle custom VERBOSE log level.
12-
Levels used in this program are as follows:
13-
VERBOSE Annoyingly frequent debug messages (e.g, in loops)
14-
DEBUG Ordinary debug information
15-
INFO Expected events that are expensive or irreversible
16-
WARNING A non-fatal error or suspicious behaviour
17-
ERROR Any error that would interrupt the user
18-
CRITICAL Things that really shouldn't happen at all
19-
'''
10+
"""
11+
Custom Logger class to handle custom VERBOSE log level.
12+
Levels used in this program are as follows:
13+
VERBOSE Annoyingly frequent debug messages (e.g, in loops)
14+
DEBUG Ordinary debug information
15+
INFO Expected events that are expensive or irreversible
16+
WARNING A non-fatal error or suspicious behaviour
17+
ERROR Any error that would interrupt the user
18+
CRITICAL Things that really shouldn't happen at all
19+
"""
20+
2021
def __init__(self, name, level=logging.NOTSET):
2122
super().__init__(name, level)
2223
logging.addLevelName(5, "VERBOSE")
2324

2425
def verbose(self, msg, *args, **kwargs):
2526
if self.isEnabledFor(5):
2627
self._log(5, msg, args, **kwargs)
28+
29+
2730
logging.setLoggerClass(Logger)
2831
logging.VERBOSE = 5
2932

3033

31-
if getattr(sys, 'frozen', False):
34+
if getattr(sys, "frozen", False):
3235
# frozen
3336
wd = os.path.dirname(sys.executable)
3437
else:

src/__main__.py

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,47 @@
1-
from PyQt5.QtWidgets import QApplication
1+
from PyQt6.QtWidgets import QApplication
22
import sys
33
import logging
44
import re
55
import string
66

77

8-
log = logging.getLogger('AVP.Main')
8+
log = logging.getLogger("AVP.Main")
99

1010

1111
def main() -> int:
1212
"""Returns an exit code (0 for success)"""
1313
proj = None
14-
mode = 'GUI'
14+
mode = "GUI"
1515

1616
# Determine whether we're in GUI or commandline mode
1717
if len(sys.argv) > 2:
18-
mode = 'commandline'
18+
mode = "commandline"
1919
elif len(sys.argv) == 2:
20-
if sys.argv[1].startswith('-'):
21-
mode = 'commandline'
20+
if sys.argv[1].startswith("-"):
21+
mode = "commandline"
2222
else:
2323
# remove unsafe punctuation characters such as \/?*&^%$#
24-
if sys.argv[1].endswith('.avp'):
24+
if sys.argv[1].endswith(".avp"):
2525
# remove file extension
2626
sys.argv[1] = sys.argv[1][:-4]
27-
sys.argv[1] = re.sub(f'[{re.escape(string.punctuation)}]', '', sys.argv[1])
27+
sys.argv[1] = re.sub(f"[{re.escape(string.punctuation)}]", "", sys.argv[1])
2828
# opening a project file with gui
2929
proj = sys.argv[1]
3030

3131
# Create Qt Application
3232
app = QApplication(sys.argv)
3333
app.setApplicationName("audio-visualizer")
3434

35+
screen = app.primaryScreen()
36+
if screen is None:
37+
dpi = None
38+
log.error("Could not detect DPI")
39+
else:
40+
dpi = screen.physicalDotsPerInchX()
41+
log.info("Detected screen DPI: %s", dpi)
42+
3543
# Launch program
36-
if mode == 'commandline':
44+
if mode == "commandline":
3745
from .command import Command
3846

3947
main = Command()
@@ -42,14 +50,15 @@ def main() -> int:
4250

4351
# Both branches here may occur in one execution:
4452
# Commandline parsing could change mode back to GUI
45-
if mode == 'GUI':
53+
if mode == "GUI":
4654
from .gui.mainwindow import MainWindow
4755

48-
mainWindow = MainWindow(proj)
56+
mainWindow = MainWindow(proj, dpi)
4957
log.debug("Finished creating MainWindow")
5058
mainWindow.raise_()
5159

52-
return app.exec_()
60+
return app.exec()
61+
5362

54-
if __name__ == '__main__':
55-
sys.exit(main())
63+
if __name__ == "__main__":
64+
sys.exit(main())

0 commit comments

Comments
 (0)