-
Notifications
You must be signed in to change notification settings - Fork 233
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Raw output not going STDOUT? #123
Comments
@DejitaruJin first of all I'm sorry for causing you so much frustration with my program 😟 You probably know more about the STDOUT and redirecting then I do, the raw output module is actually not really tested that well. It was kind of a feature request and when I had it ready for testing the people that came with the request went sort of quiet. You are right about cava printing to the file /dev/stdout, which might be why it can't be redirected in any ordinary sense. If you do want to output it to a different file you can always specify a different file in the config:
I'm sure if you create a fifo for output, you can pipe that fifo into whatever. |
The issue with using a file is the way some programs or languages treat it. For example, a Python script (useful for the LED strips people like to use this for) will gobble up the file's current contents, reach the end, and then say "Okay, done!" Which you'd swear is some kind of bug when dealing with a FIFO file, but oh no, Python is "supposed to do that." And then I died a little inside :P But when dealing with redirectable STDIO, things are generally geared toward streaming; a program will usually just block until it has input to consume, and a lot of the time the source will block until it has something to consume the output. I'll mess around with a few work-arounds, and may even tinker with the CAVA code; it is written very clearly, and as best I can tell the actual raw output is working fine beside that. |
ok cool, I think it's possbile to rewrite it so that it uses a normal printf when writing to STDOUT. As a work around maybe you can use a FIFO and then |
Many thanks for adding the raw output - I will soon be doing something similar to DejitaruJin by way of using Cava to drive LED strips. Quick question - is the output range of raw (either binary or ascii) a linear bar height, or a logarithmic audio intensity? I ask so as to use the right variation of the driver chip. |
Not sure if I understand the question, but the raw output values are the same values that are normally used to draw the bar height in the "spectrum mode". Just linearly scaled up or down to whatever range specified in the config file. Does that answer your question? |
It does, thank you for the reply :) To add more context - I plan to use a driver chip that takes an input voltage - up to a certain reference/maximum - and convert that into how many bars are lit. There are a couple of versions of the chip that differ in how they map the input voltage to bars - one does it linearly, ie 0.5 the voltage lights up half the bars. The other responds on a log scale, I think making the bottom end more sensitive to provide more useful feedback. If I were feeding the audio level straight into the chip, I'd want the log version; but I'm figuring that Cava is already doing whatever log conversion is needed to convert the audio level into a more responsive bar - so the raw output value is a linear value of the bar height. Solved! Many thanks :) |
cool, good luck with your project! Don't hesitate to raise an issue if you find anything strange. I don't know how well tested the raw output module actually is. |
I want to speak in defense of binary output as it is for today. Seems like using FIFO pretty flexible way for third party extensions. Here is my simple GUI app built over CAVA and I would personally prefer that the output way remained unchanged. By the way @karlstav thanks a lot for your work. |
this workaround works to redirect the /dev/stdout output. this captures 1 second worth of data:
(unbuffer is in the 'expect' package. Or on some systems expect-dev) |
Trying to capture the output here is killing me, 2 days I've been on. Pretty noobish with python I admit, but what is going on? |
@chrisg-waymark #!/usr/bin/python3
import struct
"""
cava config for testing
[general]
bars = 30
[output]
method = raw
raw_target = /tmp/cava.fifo
bit_format = 16bit
"""
# this is data from cava config
RAW_TARGERT = "/tmp/cava.fifo"
BARS_NUMBER = 30
OUTPUT_BIT_FORMAT = "16bit"
bytetype, bytesize, bytenorm = ("H", 2, 65535) if OUTPUT_BIT_FORMAT == "16bit" else ("B", 1, 255)
def run():
fifo = open(RAW_TARGERT, "rb")
chunk = bytesize * BARS_NUMBER
fmt = bytetype * BARS_NUMBER
while True:
data = fifo.read(chunk)
if len(data) < chunk:
break
sample = [i / bytenorm for i in struct.unpack(fmt, data)]
print(sample)
fifo.close()
if __name__ == "__main__":
run() |
Thanks Worron, I managed to change the output from Cava to printf statements like Karl mentioned, then I can pickup the stdout straight away. I'll have a look at this though as it might solve some of the lag I'm experiencing. I'm currently just outputting Ascii to 256, and I'm also voice controlling the LEDs and this introduces bad lag. I'm killing and restarting the process but its only a temporary fix. I think tonight I'll try and read through the whole buffer doing nothing until I get to the last line, which should allow it to catch up! Much appreciated code sample though, hopefully this helps others to work more easily with CAVA. FYI : I'm running on a raspberry pi 3, and framerate = 30 seems very unresponsive. I've tested and it seems 120-240 is the best option. I didn't want to use the FIFO option as I wasn't sure if it used a physical file, and I dont want to excessively write to the SD card |
Sorry, seems like i messed up with file extension in description. Anyway the only important thing is using |
turns out the raw target was never opened if the target was /dev/stdout the file descriptor was opened within an if (target != /dev/stdout) statement
@worron do you want to test the redirect /dev/stdout output now? With the latest commit, without the work around? It turns out that the whole "opening of the file descriptor" was within an |
@karlstav, sorry for delay I was absent for a while. Not sure what "work around" was mentioned, but I check last commit and can confirm that now raw binary output works ok with May be interesting for someone - dirty example how to grab cava output data in python: #!/usr/bin/python3
import os
import struct
import subprocess
import tempfile
BARS_NUMBER = 30
# OUTPUT_BIT_FORMAT = "8bit"
OUTPUT_BIT_FORMAT = "16bit"
# RAW_TARGET = "/tmp/cava.fifo"
RAW_TARGET = "/dev/stdout"
conpat = """
[general]
bars = %d
[output]
method = raw
raw_target = %s
bit_format = %s
"""
config = conpat % (BARS_NUMBER, RAW_TARGET, OUTPUT_BIT_FORMAT)
bytetype, bytesize, bytenorm = ("H", 2, 65535) if OUTPUT_BIT_FORMAT == "16bit" else ("B", 1, 255)
def run():
with tempfile.NamedTemporaryFile() as config_file:
config_file.write(config.encode())
config_file.flush()
process = subprocess.Popen(["cava", "-p", config_file.name], stdout=subprocess.PIPE)
chunk = bytesize * BARS_NUMBER
fmt = bytetype * BARS_NUMBER
if RAW_TARGET != "/dev/stdout":
if not os.path.exists(RAW_TARGET):
os.mkfifo(RAW_TARGET)
source = open(RAW_TARGET, "rb")
else:
source = process.stdout
while True:
data = source.read(chunk)
if len(data) < chunk:
break
# sample = [i for i in struct.unpack(fmt, data)] # raw values without norming
sample = [i / bytenorm for i in struct.unpack(fmt, data)]
print(sample)
if __name__ == "__main__":
run() |
this workaround was necessary before to make redirecting work:
it should not be necessary anymore. I will close this issue. |
@worron just wanted to say thanks for the code, integrated/works perfectly with my controller. Gonna put in a pr adding a link for others to find this more easily. |
I just made a deno library for bindings to cava too. |
I have the latest version of CAVA, set to raw output method. And indeed, if the nonsense in the terminal is to be believed, it is spitting out 8-bit raw data. (The way they all seem to be boxes is kind of odd, but I can't verify what I can't parse.)
The problem is, while it's printing in the terminal, it is not technically STDOUT - it can not be piped nor redirected. I've tried piping it to a Python script, dd, and hexdump, and even tried redirecting it (along with STDERR) to /dev/null... but those boxes just keep printing! Testing in ASCII mode, it also produces unconsumable output. Myself and my coworkers can't even figure out how it's doing that, nothing should be that resistant to redirection.
Looking at the code, it seems almost like it's trying to output to a file, /dev/stdout? Which technically is file descriptor 1 for the current process (that being the Bash window), but it can't be piped, so it's a ways away from actual "STDOUT".
Currently running on a Raspberry Pi B+, all updates applied. Got so frustrated with this I reformatted, so all's clean.
The text was updated successfully, but these errors were encountered: