aboutsummaryrefslogtreecommitdiff
path: root/src/avp/components/classic.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/avp/components/classic.py')
-rw-r--r--src/avp/components/classic.py210
1 files changed, 210 insertions, 0 deletions
diff --git a/src/avp/components/classic.py b/src/avp/components/classic.py
new file mode 100644
index 0000000..72089af
--- /dev/null
+++ b/src/avp/components/classic.py
@@ -0,0 +1,210 @@
+import numpy
+from PIL import Image, ImageDraw
+
+from ..libcomponent import BaseComponent
+from ..toolkit.frame import BlankFrame, FloodFrame
+from ..toolkit.visualizer import createSpectrumArray
+
+
+class Component(BaseComponent):
+ name = "Classic Visualizer"
+ version = "1.2.0"
+
+ def names(*args):
+ return ["Original"]
+
+ def properties(self):
+ props = ["pcm"]
+ if self.invert:
+ props.append("composite")
+ return props
+
+ def widget(self, *args):
+ self.scale = 20
+ self.bars = 63
+ self.y = 0
+ super().widget(*args)
+
+ self.page.comboBox_visLayout.addItem("Classic")
+ self.page.comboBox_visLayout.addItem("Split")
+ self.page.comboBox_visLayout.addItem("Bottom")
+ self.page.comboBox_visLayout.addItem("Top")
+ self.page.comboBox_visLayout.setCurrentIndex(0)
+
+ self.trackWidgets(
+ {
+ "visColor": self.page.lineEdit_visColor,
+ "layout": self.page.comboBox_visLayout,
+ "scale": self.page.spinBox_scale,
+ "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,
+ },
+ relativeWidgets=[
+ "y",
+ ],
+ )
+
+ 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,
+ frame,
+ )
+
+ def preFrameRender(self, **kwargs):
+ super().preFrameRender(**kwargs)
+ smoothConstantDown = 0.08 if not self.smooth else self.smooth / 15
+ smoothConstantUp = 0.8 if not self.smooth else self.smooth / 15
+ self.spectrumArray = createSpectrumArray(
+ self,
+ self.completeAudioArray,
+ self.sampleSize,
+ smoothConstantDown,
+ smoothConstantUp,
+ self.scale,
+ self.progressBarUpdate,
+ self.progressBarSetText,
+ )
+
+ def frameRender(self, frameNo, frame=None):
+ arrayNo = frameNo * self.sampleSize
+ return self.drawBars(
+ self.width,
+ self.height,
+ self.spectrumArray[arrayNo],
+ self.visColor,
+ self.layout,
+ frame,
+ )
+
+ def drawBars(self, width, height, spectrum, color, layout, frame):
+ bigYCoord = height - height / 8
+ smallYCoord = height / 1200
+ bigXCoord = width / (self.bars + 1)
+ middleXCoord = bigXCoord / 2
+ smallXCoord = bigXCoord / 4
+
+ imTop = BlankFrame(width, height)
+ draw = ImageDraw.Draw(imTop)
+ r, g, b = color
+ color2 = (r, g, b, 125)
+
+ for i in range(self.bars):
+ # 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,
+ )
+ 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(
+ 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)
+
+ im = BlankFrame(width, height)
+
+ if layout == 0: # Classic
+ y = self.y - int(height / 100 * 43)
+ im.paste(imTop, (0, y), mask=imTop)
+ y = self.y + int(height / 100 * 43)
+ im.paste(imBottom, (0, y), mask=imBottom)
+
+ if layout == 1: # Split
+ y = self.y + int(height / 100 * 10)
+ im.paste(imTop, (0, y), mask=imTop)
+ y = self.y - int(height / 100 * 10)
+ im.paste(imBottom, (0, y), mask=imBottom)
+
+ if layout == 2: # Bottom
+ y = self.y + int(height / 100 * 10)
+ im.paste(imTop, (0, y), mask=imTop)
+
+ if layout == 3: # Top
+ y = self.y - int(height / 100 * 10)
+ im.paste(imBottom, (0, y), mask=imBottom)
+
+ 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:
+ key, arg = arg.split("=", 1)
+ try:
+ if key == "color":
+ self.page.lineEdit_visColor.setText(arg)
+ return
+ elif key == "layout":
+ if arg == "classic":
+ self.page.comboBox_visLayout.setCurrentIndex(0)
+ elif arg == "split":
+ self.page.comboBox_visLayout.setCurrentIndex(1)
+ elif arg == "bottom":
+ self.page.comboBox_visLayout.setCurrentIndex(2)
+ elif arg == "top":
+ self.page.comboBox_visLayout.setCurrentIndex(3)
+ return
+ elif key == "scale":
+ arg = int(arg)
+ self.page.spinBox_scale.setValue(arg)
+ return
+ elif key == "y":
+ arg = int(arg)
+ self.page.spinBox_y.setValue(arg)
+ return
+ except ValueError:
+ print("You must enter a number.")
+ quit(1)
+ super().command(arg)
+
+ def commandHelp(self):
+ print("Give a layout name:\n layout=[classic/split/bottom/top]")
+ print("Specify a color:\n color=255,255,255")
+ print("Visualizer scale (20 is default):\n scale=number")
+ print("Y position:\n y=number")