diff options
Diffstat (limited to 'src/avp/components/classic.py')
| -rw-r--r-- | src/avp/components/classic.py | 210 |
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") |
