#!/usr/bin/python3 import sys import time import struct import os.path import subprocess import configparser from collections import defaultdict ################################################## # Config # Decide if the output should go to STDOUT or a fifo buffer PRINT_TO_STDOUT = False # Display no output if all bars are at level 0 HIDE_WHEN_EMPTY = True # Separator Character between bars # Examples: https://www.compart.com/en/unicode/category/Zs SEPARATOR = '' CONFIG_PATH = os.path.join(os.sep, "tmp","cava_polybar.config") RAW_PIPE_OUT = os.path.join(os.sep, "tmp","cava_polybar_output.fifo") # Data from the cava config RAW_PIPE_IN = os.path.join(os.sep, "tmp","cava_polybar_input.fifo") OUTPUT_FILE = os.path.join(os.sep, "tmp","cava_polybar.out") BARS_NUMBER = 8 OUTPUT_BIT_FORMAT = "8bit" # Values range from 0 to 100 # Distribute 9 states over this value range # ▁▂▃▄▅▆▇█ bar_factor = 100 / 10 bar_characters = dict([ (0, '▁'), (bar_factor * 1, '▁'), (bar_factor * 2, '▂'), (bar_factor * 3, '▃'), (bar_factor * 4, '▄'), (bar_factor * 5, '▅'), (bar_factor * 6, '▆'), (bar_factor * 7, '▇'), (bar_factor * 8, '█') ]) ################################################## # Code begins here bytetype, bytesize, bytenorm = ("H", 2, 65535) if (OUTPUT_BIT_FORMAT == "16bit") else ("B", 1, 255) def output(value, fifo): if (PRINT_TO_STDOUT): print(value, end="") else: fifo.write(value) def valToBar(value): for bar_threshold in bar_characters: if(value < bar_threshold): return bar_characters[bar_threshold] return bar_characters[bar_factor * 8] def test(): print("") print("Bar Characters:") for bar_threshold in bar_characters: print('{:02.2f}: {}'.format(bar_threshold,bar_characters[bar_threshold])) print("") print("Value Test:") for i in range(101): print('{:03d}: {}'.format(i,valToBar(i))) def createCavaConfig(): # Exit if file is already there #if (os.path.isfile(CONFIG_PATH)): # return config = configparser.ConfigParser() config.add_section('general') config.set('general', 'bars', str(BARS_NUMBER)) #config.set('general', 'overshoot', str(0)) config.add_section('output') config.set('output', 'method', 'raw') #config.set('output', 'channels', 'mono') #config.set('output', 'mono_option', 'average') config.set('output', 'raw_target', RAW_PIPE_IN) config.set('output', 'bit_format', OUTPUT_BIT_FORMAT) #config.add_section('smoothing') #config.set('smoothing', 'integral', '0') with open(CONFIG_PATH, 'w') as configfile: config.write(configfile) def run(): createCavaConfig() process = subprocess.Popen(["cava", "-p", CONFIG_PATH]) exit_code = 0 fifo_out = None if (not PRINT_TO_STDOUT): if os.path.exists(RAW_PIPE_OUT): os.remove(RAW_PIPE_OUT) os.mkfifo(RAW_PIPE_OUT) print("Output can be found in " + RAW_PIPE_OUT) fifo_out = open(RAW_PIPE_OUT, "w") fifo_in = open(RAW_PIPE_IN, "rb") try: convert(fifo_in, fifo_out) except KeyboardInterrupt: exit_code = 1 finally: if (not PRINT_TO_STDOUT): fifo_out.close() os.remove(RAW_PIPE_OUT) fifo_in.close() sys.exit(exit_code) def convert(fifo_in, fifo_out): chunk = bytesize * BARS_NUMBER fmt = bytetype * BARS_NUMBER emptyOutputs = 0 tstring = "" while True: rawData = fifo_in.read(chunk) if len(rawData) < chunk: break empty = True tstring = "" for i in struct.unpack(fmt, rawData): value = int(i / bytenorm * 100) tstring += valToBar(value) + SEPARATOR if (value != 0): empty = False if (empty and HIDE_WHEN_EMPTY): emptyOutputs += 1 if (emptyOutputs > 5): output(" " + '\n', fifo_out) else: emptyOutputs = 0 output(tstring + '\n', fifo_out) if __name__ == "__main__": for arg in sys.argv: if (arg == "h" or arg == "help"): print("") print("cava polybar parse script") print("Converts cava raw values into characters and outputs to STDOUT or a fifo buffer") print("") print("Adjust thresholds, characters and config directly in the script") print("If the config file at 'CONFIG_PATH' (/tmp/cava_polybar.config) is messed up, simply delet it") print("") print("Arguments:") print(" ... Execute normally") print("t, test ... Run test mode (stdout only)") print("h, help ... Show this help message and exit (stdout only)") print("") sys.exit() if (arg == "t" or arg == "test"): test() sys.exit() run()