diff options
| author | Brianna Rainey | 2026-02-12 15:38:54 -0500 |
|---|---|---|
| committer | GitHub | 2026-02-12 15:38:54 -0500 |
| commit | f03a3a686c7304588dd434322c73506531e53595 (patch) | |
| tree | ee41d920873e9a77c41f4a65857af019e71a4754 /src/avp/components | |
| parent | 48a9105eab94e64101470402427564203e1d8970 (diff) | |
v2.2.4 - Quiet FFmpeg; add "invert" option to Classic Vis; fix CLI parsing for Image component (#96)
* change noisiness of terminal output
ffmpeg no longer prints everything into the terminal unless we're in `--verbose` mode. percentage progress text stays on one line while not in verbose mode.
* Added hint to run `avp --verbose` if `avp --log` is run with no avp_debug.log file present
* Classic Visualizer: add invert option
* Image component: fix path commandline option
* Image component: restrict file formats in CLI to match GUI
* Color component: add tooltip to color2 picker (second color of gradients)
* change tests to work with pytest-xdist
avp core stores its config (location of `settings.ini`) in temp directories if using multiple workers to run tests, so they don't interfere with each other. when using a single worker, the `tests/data/config` directory is still used
* check alt comp names when parsing cmdline
* rename `original.py` to `classic.py`
* move `component.py` into subpackage
* rename comp_original to comp_classic
* show traceback if renderFrame() raises exception
* do not try to insert non-existent components from project files
* add "composite" property for components
if a component returns "composite" then it will receive a frame to draw on during calls to previewRender and frameRender
* more tests of projects, actions, waveform, spectrum, image, color, classic
* do not change presetDir to "projects" within PresetManager
Diffstat (limited to 'src/avp/components')
| -rw-r--r-- | src/avp/components/classic.py (renamed from src/avp/components/original.py) | 81 | ||||
| -rw-r--r-- | src/avp/components/classic.ui (renamed from src/avp/components/original.ui) | 9 | ||||
| -rw-r--r-- | src/avp/components/color.py | 4 | ||||
| -rw-r--r-- | src/avp/components/color.ui | 3 | ||||
| -rw-r--r-- | src/avp/components/image.py | 16 | ||||
| -rw-r--r-- | src/avp/components/life.py | 7 | ||||
| -rw-r--r-- | src/avp/components/sound.py | 6 | ||||
| -rw-r--r-- | src/avp/components/spectrum.py | 9 | ||||
| -rw-r--r-- | src/avp/components/text.py | 10 | ||||
| -rw-r--r-- | src/avp/components/video.py | 8 | ||||
| -rw-r--r-- | src/avp/components/waveform.py | 8 |
11 files changed, 95 insertions, 66 deletions
diff --git a/src/avp/components/original.py b/src/avp/components/classic.py index 0da78dc..72089af 100644 --- a/src/avp/components/original.py +++ b/src/avp/components/classic.py @@ -1,21 +1,23 @@ import numpy from PIL import Image, ImageDraw -from copy import copy -from ..component import Component -from ..toolkit.frame import BlankFrame +from ..libcomponent import BaseComponent +from ..toolkit.frame import BlankFrame, FloodFrame from ..toolkit.visualizer import createSpectrumArray -class Component(Component): +class Component(BaseComponent): name = "Classic Visualizer" - version = "1.1.0" + version = "1.2.0" def names(*args): - return ["Original Audio Visualization"] + return ["Original"] def properties(self): - return ["pcm"] + props = ["pcm"] + if self.invert: + props.append("composite") + return props def widget(self, *args): self.scale = 20 @@ -37,6 +39,7 @@ class Component(Component): "y": self.page.spinBox_y, "smooth": self.page.spinBox_sensitivity, "bars": self.page.spinBox_bars, + "invert": self.page.checkBox_invert, }, colorWidgets={ "visColor": self.page.pushButton_visColor, @@ -46,14 +49,19 @@ class Component(Component): ], ) - def previewRender(self): + def previewRender(self, frame=None): spectrum = numpy.fromfunction( lambda x: float(self.scale) / 2500 * (x - 128) ** 2, (255,), dtype="int16", ) return self.drawBars( - self.width, self.height, spectrum, self.visColor, self.layout + self.width, + self.height, + spectrum, + self.visColor, + self.layout, + frame, ) def preFrameRender(self, **kwargs): @@ -71,7 +79,7 @@ class Component(Component): self.progressBarSetText, ) - def frameRender(self, frameNo): + def frameRender(self, frameNo, frame=None): arrayNo = frameNo * self.sampleSize return self.drawBars( self.width, @@ -79,9 +87,10 @@ class Component(Component): self.spectrumArray[arrayNo], self.visColor, self.layout, + frame, ) - def drawBars(self, width, height, spectrum, color, layout): + def drawBars(self, width, height, spectrum, color, layout, frame): bigYCoord = height - height / 8 smallYCoord = height / 1200 bigXCoord = width / (self.bars + 1) @@ -94,32 +103,44 @@ class Component(Component): color2 = (r, g, b, 125) for i in range(self.bars): - x0 = middleXCoord + i * bigXCoord - y0 = bigYCoord + smallXCoord - y1 = bigYCoord + smallXCoord - spectrum[i * 4] * smallYCoord - middleXCoord - x1 = middleXCoord + i * bigXCoord + bigXCoord - draw.rectangle( - ( + # draw outline behind rectangles if not inverted + if frame is None: + x0 = middleXCoord + i * bigXCoord + y0 = bigYCoord + smallXCoord + x1 = middleXCoord + i * bigXCoord + bigXCoord + y1 = ( + bigYCoord + + smallXCoord + - spectrum[i * 4] * smallYCoord + - middleXCoord + ) + selection = ( x0, y0 if y0 < y1 else y1, x1 if x1 > x0 else x0, y1 if y0 < y1 else y0, - ), - fill=color2, - ) + ) + draw.rectangle( + selection, + fill=color2, + ) x0 = middleXCoord + smallXCoord + i * bigXCoord y0 = bigYCoord x1 = middleXCoord + smallXCoord + i * bigXCoord + middleXCoord y1 = bigYCoord - spectrum[i * 4] * smallYCoord + selection = ( + x0, + y0 if y0 < y1 else y1, + x1 if x1 > x0 else x0, + y1 if y0 < y1 else y0, + ) + # fill rectangle if not inverted draw.rectangle( - ( - x0, - y0 if y0 < y1 else y1, - x1 if x1 > x0 else x0, - y1 if y0 < y1 else y0, - ), - fill=color, + selection, + fill=color if frame is None else (0, 0, 0, 0), + outline=color, + width=int(x1 - x0), ) imBottom = imTop.transpose(Image.Transpose.FLIP_TOP_BOTTOM) @@ -146,7 +167,11 @@ class Component(Component): y = self.y - int(height / 100 * 10) im.paste(imBottom, (0, y), mask=imBottom) - return im + if frame is None: + return im + f = FloodFrame(width, height, color) + f.paste(frame, (0, 0), mask=im) + return f def command(self, arg): if "=" in arg: diff --git a/src/avp/components/original.ui b/src/avp/components/classic.ui index 8dbdaa2..1ae7faa 100644 --- a/src/avp/components/original.ui +++ b/src/avp/components/classic.ui @@ -86,7 +86,7 @@ <item> <widget class="QLineEdit" name="lineEdit_visColor"> <property name="text"> - <string></string> + <string/> </property> </widget> </item> @@ -233,6 +233,13 @@ </widget> </item> <item> + <widget class="QCheckBox" name="checkBox_invert"> + <property name="text"> + <string>Invert</string> + </property> + </widget> + </item> + <item> <spacer name="horizontalSpacer"> <property name="orientation"> <enum>Qt::Orientation::Horizontal</enum> diff --git a/src/avp/components/color.py b/src/avp/components/color.py index cb0960a..826f37f 100644 --- a/src/avp/components/color.py +++ b/src/avp/components/color.py @@ -1,14 +1,14 @@ from PyQt6 import QtGui import logging -from ..component import Component +from ..libcomponent import BaseComponent from ..toolkit.frame import BlankFrame, FloodFrame, FramePainter log = logging.getLogger("AVP.Components.Color") -class Component(Component): +class Component(BaseComponent): name = "Color" version = "1.0.0" diff --git a/src/avp/components/color.ui b/src/avp/components/color.ui index c36bdd8..788adb9 100644 --- a/src/avp/components/color.ui +++ b/src/avp/components/color.ui @@ -124,6 +124,9 @@ <height>32</height> </size> </property> + <property name="toolTip"> + <string>End color of gradient. Disabled if fill is solid.</string> + </property> <property name="text"> <string/> </property> diff --git a/src/avp/components/image.py b/src/avp/components/image.py index e012cec..a082092 100644 --- a/src/avp/components/image.py +++ b/src/avp/components/image.py @@ -1,14 +1,13 @@ from PIL import Image, ImageOps, ImageEnhance from PyQt6 import QtWidgets import os -from copy import copy -from ..component import Component +from ..libcomponent import BaseComponent from ..toolkit.frame import BlankFrame, addShadow from ..toolkit.visualizer import createSpectrumArray -class Component(Component): +class Component(BaseComponent): name = "Image" version = "2.1.0" @@ -177,17 +176,22 @@ class Component(Component): self.mergeUndo = True def command(self, arg): + def fail(): + print("Not a supported image format") + quit(1) + if "=" in arg: key, arg = arg.split("=", 1) if key == "path" and os.path.exists(arg): + if f"*{os.path.splitext(arg)[1]}" not in self.core.imageFormats: + fail() try: Image.open(arg) self.page.lineEdit_image.setText(arg) - self.page.checkBox_stretch.setChecked(True) + self.page.comboBox_resizeMode.setCurrentIndex(2) return except OSError as e: - print("Not a supported image format") - quit(1) + fail() super().command(arg) def commandHelp(self): diff --git a/src/avp/components/life.py b/src/avp/components/life.py index a062617..374b299 100644 --- a/src/avp/components/life.py +++ b/src/avp/components/life.py @@ -1,13 +1,12 @@ from PyQt6 import QtCore, QtWidgets from PyQt6.QtGui import QUndoCommand -from PIL import Image, ImageDraw, ImageEnhance, ImageChops, ImageFilter, ImageOps +from PIL import Image, ImageDraw import os -from copy import copy import math import logging -from ..component import Component +from ..libcomponent import BaseComponent from ..toolkit.frame import BlankFrame, scale, addShadow from ..toolkit.visualizer import createSpectrumArray @@ -15,7 +14,7 @@ from ..toolkit.visualizer import createSpectrumArray log = logging.getLogger("AVP.Component.Life") -class Component(Component): +class Component(BaseComponent): name = "Conway's Game of Life" version = "2.0.1" diff --git a/src/avp/components/sound.py b/src/avp/components/sound.py index 2df8e38..c212870 100644 --- a/src/avp/components/sound.py +++ b/src/avp/components/sound.py @@ -1,11 +1,11 @@ -from PyQt6 import QtGui, QtCore, QtWidgets +from PyQt6 import QtWidgets import os -from ..component import Component +from ..libcomponent import BaseComponent from ..toolkit.frame import BlankFrame -class Component(Component): +class Component(BaseComponent): name = "Sound" version = "1.0.0" diff --git a/src/avp/components/spectrum.py b/src/avp/components/spectrum.py index 062ebc7..0446865 100644 --- a/src/avp/components/spectrum.py +++ b/src/avp/components/spectrum.py @@ -1,14 +1,11 @@ from PIL import Image -from PyQt6 import QtGui, QtCore, QtWidgets import os -import math import subprocess -import time import logging -from ..component import Component +from ..libcomponent import BaseComponent from ..toolkit.frame import BlankFrame, scale -from ..toolkit import checkOutput, connectWidget +from ..toolkit import connectWidget from ..toolkit.ffmpeg import ( openPipe, closePipe, @@ -21,7 +18,7 @@ from ..toolkit.ffmpeg import ( log = logging.getLogger("AVP.Components.Spectrum") -class Component(Component): +class Component(BaseComponent): name = "Spectrum" version = "1.0.1" diff --git a/src/avp/components/text.py b/src/avp/components/text.py index bee117e..d248772 100644 --- a/src/avp/components/text.py +++ b/src/avp/components/text.py @@ -1,16 +1,14 @@ -from PIL import ImageEnhance, ImageFilter, ImageChops -from PyQt6.QtGui import QColor, QFont -from PyQt6 import QtGui, QtCore, QtWidgets -import os +from PyQt6.QtGui import QFont +from PyQt6 import QtGui, QtCore import logging -from ..component import Component +from ..libcomponent import BaseComponent from ..toolkit.frame import FramePainter, addShadow log = logging.getLogger("AVP.Components.Text") -class Component(Component): +class Component(BaseComponent): name = "Title Text" version = "1.0.1" diff --git a/src/avp/components/video.py b/src/avp/components/video.py index 65a05af..1e9b788 100644 --- a/src/avp/components/video.py +++ b/src/avp/components/video.py @@ -1,20 +1,18 @@ from PIL import Image -from PyQt6 import QtGui, QtCore, QtWidgets +from PyQt6 import QtWidgets import os -import math import subprocess import logging -from ..component import Component +from ..libcomponent import BaseComponent from ..toolkit.frame import BlankFrame, scale from ..toolkit.ffmpeg import openPipe, closePipe, testAudioStream, FfmpegVideo -from ..toolkit import checkOutput log = logging.getLogger("AVP.Components.Video") -class Component(Component): +class Component(BaseComponent): name = "Video" version = "1.0.0" diff --git a/src/avp/components/waveform.py b/src/avp/components/waveform.py index e10dec2..bfebc30 100644 --- a/src/avp/components/waveform.py +++ b/src/avp/components/waveform.py @@ -3,12 +3,10 @@ from PyQt6.QtGui import QColor import os import subprocess import logging -from copy import copy -from ..component import Component -from ..toolkit.visualizer import transformData, createSpectrumArray +from ..libcomponent import BaseComponent +from ..toolkit.visualizer import createSpectrumArray from ..toolkit.frame import BlankFrame, scale -from ..toolkit import checkOutput from ..toolkit.ffmpeg import ( openPipe, closePipe, @@ -21,7 +19,7 @@ from ..toolkit.ffmpeg import ( log = logging.getLogger("AVP.Components.Waveform") -class Component(Component): +class Component(BaseComponent): name = "Waveform" version = "2.0.0" |
