project-owner / PeppyMeter

PeppyMeter Repository
GNU General Public License v3.0
62 stars 13 forks source link

Question about use for recording with Raspberry Pi #7

Closed nls-GitHub closed 1 year ago

nls-GitHub commented 1 year ago

My application is for recording with the Raspberry Pi, I am using the Audio Injector Stereo board. There is a Python program which uses the 'arecord' command to generate wav files, convert them to MP3 files and upload them to a shared network drive. It is mostly an unattended setup, with cron starting the recordings at scheduled times for specific time durations, remotely monitored to a certain extent. Can PeppyMeter be used to check the recording levels remotely, and perhaps even sent to a local display for the times when the recordings are done manually? How would I integrate this with my Python program and the 'arecord'? All other sound devices are disabled, so the Audio Injector board is the only ALSA device for sound, as a default. Thanks.

project-owner commented 1 year ago

If you don't have touchscreen functionality you should not have this device: https://github.com/project-owner/PeppyMeter/blob/c9056bd7e798e0d07bc77587c25f75dda0c80018/config.txt#L20 try to set /dev/input/event0 instead (if you have that device). It's used here: https://github.com/project-owner/PeppyMeter/blob/c9056bd7e798e0d07bc77587c25f75dda0c80018/peppymeter.py#L128 Here is the thread about similar issue: https://www.diyaudio.com/community/threads/peppymeter.291010/post-6427315

nls-GitHub commented 1 year ago

image I used /dev/input/mouse0, and while that seemed to get rid of the error, the screen just goes blank after displaying image, it does not display the meters. The config.txt file also has /dev/fb0 and double,buffer = False, per previous suggestions. image I also tried event0 instead of mouse0 with the same results.

project-owner commented 1 year ago

I've created a disk image with PeppyMeter. Just install it on SD card and observe the meters in the HDMI display. https://github.com/project-owner/PeppyMeter/releases/download/2023.01.21/signac-peppymeter-hdmi.img.xz It starts from /etc/rc.local. User/pass: pi/Signac

nls-GitHub commented 1 year ago

Many thanks for this, greatly appreciated. I am now able to see the meters and also get them showing the audio levels for playback with the Fe-Pi audio card, will test recording next. I did notice that the /boot/config.txt file was substantially different from the default file, with a lot of HDMI related lines, perhaps those are mandatory for a proper display?

project-owner commented 1 year ago

I took the existing Peppy player disk image for this display: https://github.com/project-owner/PeppyPlayers.doc/wiki/Waveshare-5.0 , removed Peppy player and installed PeppyMeter on top of it. During configuration of that display you need to specify some HDMI properties: https://github.com/project-owner/PeppyPlayers.doc/wiki/Waveshare-5.0#configure-the-touchscreen-functionality The most important parameter is the display resolution: 800x480

nls-GitHub commented 1 year ago

Thanks, I will keep experimenting more now that I have a good starting point. One question about the meter display - If there is no information coming from the pipe, does the display freeze at the very last value? I am testing with recording now, and when the arecord command terminates after the specified interval, the meter values stay fixed at those levels.

project-owner commented 1 year ago

Yes, it will stop at the last value. But it will be set to 0 when the meter will be shown next time in case of 'random' meter type when all meters are are displayed periodically.

nls-GitHub commented 1 year ago

With a single meter display, is there a way to distinguish between an active pipe with zero audio level values versus a disconnected pipe? The boot messages display seems to be disabled in this image, is that only via cmdline.txt, or are there other things I need to change to enable them? With the two HDMI ports on the Pi4, I assume that one port can be used for the command line and the other for the meter display. If I wanted to add more indicators and controls to the display, I assume that it would be via peppymeter.py? What is a good learning reference for that? Many thanks for your help, the VU meter indication during recording has been a shortcoming in our preset setup.

project-owner commented 1 year ago

The meter implementation assumes that there is always data coming from the named pipe. There is currently no way to detect that the "pipeline" was broken. Boot messages have been disabled in the /boot/cmdline.txt: https://github.com/project-owner/PeppyPlayers.doc/wiki/Waveshare-5.0#remove-console-messages-during-booting I've never tried to use two HDMI displays. I usually use one display and one SSH session. For custom meters just read the PeppyMeter wiki pages: https://github.com/project-owner/PeppyMeter.doc/wiki/Adding-Your-Own-Meter

nls-GitHub commented 1 year ago

Will the image work with a Pi 4B, or is it meant only for the Pi 3B series?

project-owner commented 1 year ago

It should work with any Pi model. It was created on Pi 4B.

nls-GitHub commented 1 year ago

Thanks. Perhaps you could see if the PyMeter could use the first HDMI port while the second one would be the regular terminal. The I2C interface - does it work only with LED arrays, or will it also work with a 2x16 or 4x20 display to show bar graphs? Is there a commercial product with two LED arrays and I2C driver, or does it have to be custom built? Is the DSI port display supported?

project-owner commented 1 year ago

I don't have plans to use two HDMI displays for any project. Feel free to try it. The I2C interface will work only with dummy LED arrays. You just need to adjust the code according to the number of LEDs. Any display which assumes the usage of specific protocol will need a custom implementation of the I2C interface. Yes, DSI displays are supported. You can use the Peppy player disk image for the official Raspberry 7" Display as a base, replace the player and install PeppyMeter: https://github.com/project-owner/PeppyPlayers.doc/wiki/Official-7.0

nls-GitHub commented 1 year ago

Did you ever consider https://learn.adafruit.com/adafruit-led-backpack/bi-color-24-bargraph for the I2C LED bar-graph display? The website is not very clear about whether the two LED arrays can be used independently. The colors are also not fixed, but have to be programmed. Regarding adding custom controls or indicators along with the meters, most of the PyGame tutorials seem to be geared towards a desktop environment, I am a novice in this arena.

project-owner commented 1 year ago

I think it's not a good display for VU Meter purposes. It changes the brightness (16 levels) for all LEDs at once which is unusual for VU Meter. It's much easier to use a desktop environment for developing PyGame programs. I usually use my Windows desktop for development and then just deploy on Lite OS Linux (w/o desktop). But you can also use Desktop OS Linux.

nls-GitHub commented 1 year ago

I was referring to the fact that the PyGame tutorials are all for applications with X11, but PyMeter perhaps doesn't use it and writes directly to the frame buffers? I am not a Linux/Python expert, so am basically trying to reuse already developed open-source code as much as possible.

project-owner commented 1 year ago

PeppyMeter can work in both types of OSs - w/ desktop and w/o desktop without any changes in the code.

nls-GitHub commented 1 year ago

Yes, but I need to add additional controls along with the meters and my programming proficiency is not at that level! Should I be able to get the actual processed volume levels via the function calls in datasource.py?

project-owner commented 1 year ago

The easiest way is to use the existing meters and add your own stuff on top of it. If you need to create your own VU Meter there is no need to touch the code. You need to create images and configuration files: https://github.com/project-owner/PeppyMeter.doc/wiki/Adding-Your-Own-Meter Adding additional components to UI is a generic programming question.

project-owner commented 1 year ago

Hopefully I answered all questions. Feel free to open another issue if you will have additional questions.

nls-GitHub commented 1 year ago

I think that I have finally managed to adapt these programs to my application of VU meter display on a 4x20 LCD panel for recording audio, but it has not been a scientific approach, it has mostly been a trial and error exercise because of my lack of knowledge of advanced Python concepts. I have now got it down to just three Python programs - peppymeter, datasource and i2cinterface, removing all the Pygame dependencies and the configuration parsing. But even with that, I don't quite understand the program flow well, especially some of the threading aspects. If at all you would be willing to help me with that, I can ask a few specific questions that will enlighten me. I could also send the files to you for review.

Thanks!

On Thu, Feb 9, 2023 at 10:03 PM project-owner @.***> wrote:

Hopefully I answered all questions. Feel free to open another issue if you will have additional questions.

— Reply to this email directly, view it on GitHub https://github.com/project-owner/PeppyMeter/issues/7#issuecomment-1425144282, or unsubscribe https://github.com/notifications/unsubscribe-auth/ANJASF4YHSMCD6IU2TOSEO3WWW42LANCNFSM6AAAAAATVO47Z4 . You are receiving this because you authored the thread.Message ID: @.***>

project-owner commented 1 year ago

Hi, sure, go ahead with your questions. I would recommend to open another issue as this one becomes too long.

nls-GitHub commented 1 year ago

Opening an issue might not be proper, because this is a highly stripped version of the original concept, specific to the application and hardware. It might be extremely confusing to others. I have attached the files that I ended up with which work to show the volume levels (either for playback or for recording). My questions might appear silly to programmers who are very conversant with Python, and my terminology might not be proper!

From what I can see, peppymeter.py runs continuously, and starts the datasource and i2cinterface programs. Datasource is looking at the fifo, converting the data stream to the three volume levels - left, right and mono. I2cinterface can then use that information for display. The programs don't really exit/stop unless aborted. The start_data_source call seems to start the get_data thread, which leads to get_pipe_value and then get_mono, get_channel, etc. The values get put in v[0], v[1] and v[2], which are then used by the i2c program. Perhaps all this can be simplified much more in my application, not sure. There is also some reference to RLock, I didn't quite understand the reason, is that because of the fifo? Where does the lock get released?

What state is the datasource program in when there no alsa activity which puts data in the fifo? I was interested in using the 4 line display for other messages during the recording process and thought that the i2cinterface program could be used, but it looks like the start_writing routine is not even running when there is no alsa activity. Perhaps I need to have another background program exclusively for the i2c display, with some type of shared memory so that other routines could send the display data to it.

Thanks in advance for your review and advice.

On Sat, Jul 29, 2023 at 9:45 AM project-owner @.***> wrote:

Hi, sure, go ahead with your questions. I would recommend to open another issue as this one becomes too long.

— Reply to this email directly, view it on GitHub https://github.com/project-owner/PeppyMeter/issues/7#issuecomment-1656745822, or unsubscribe https://github.com/notifications/unsubscribe-auth/ANJASFZ6Y2IKI77JVRBPCCTXSUOXBANCNFSM6AAAAAATVO47Z4 . You are receiving this because you authored the thread.Message ID: @.***>

project-owner commented 1 year ago

Hi,

You correctly described the logic. The lock is required because several threads (data source and animation) have access to the same data. The lock will be released automatically when you leave the scope of the 'with self.lock' opertaion. You can google for more info on Python locks.

The data source thread is constantly checking the data in the pipe no matter if there is data or not: https://github.com/project-owner/PeppyMeter/blob/fc5bfd7ac82045ef31d5ada334114aee627953a3/datasource.py#L73 The I2C interface checks if data is empty it doesn't send data to a device: https://github.com/project-owner/PeppyMeter/blob/fc5bfd7ac82045ef31d5ada334114aee627953a3/i2cinterface.py#L105 You can either modify that logic or write additional thread for your needs. It's up to you.

Best regards

nls-GitHub commented 1 year ago

Many thanks for the feedback. Since I only have one destination for the output of the datasource, perhaps the lock is not necessary? I will read up.

My version of the write_data is very simple, I am not checking for zero values. When I uncomment the debug line and look at the peppymeter.log file, it stops when there is no alsa activity, either with playback or with record. That is what I am confused about and am wondering what is preventing the data_string to be printed out three times a second. I will try to run some more tests.

def write_data(self):
    """ Method of the writing thread """

    while self.running:
        v = self.data_source.get_value()
        data_string = "Left %03i Right %03i" % (v[0], v[1])

logging.debug(data_string)

        self.lcd.printline(1, "L:" + self.data_to_string(v[0]))
        self.lcd.printline(2, "R:" + self.data_to_string(v[1]))

        time.sleep(self.update_period)

On Sun, Jul 30, 2023 at 10:18 AM project-owner @.***> wrote:

Hi,

You correctly described the logic. The lock is required because several threads (data source and animation) have access to the same data. The lock will be released automatically when you leave the scope of the 'with self.lock' opertaion. You can google for more info on Python locks.

The data source thread is constantly checking the data in the pipe no matter if there is data or not:

https://github.com/project-owner/PeppyMeter/blob/fc5bfd7ac82045ef31d5ada334114aee627953a3/datasource.py#L73 The I2C interface checks if data is empty it doesn't send data to a device:

https://github.com/project-owner/PeppyMeter/blob/fc5bfd7ac82045ef31d5ada334114aee627953a3/i2cinterface.py#L105 You can either modify that logic or write additional thread for your needs. It's up to you.

Best regards

— Reply to this email directly, view it on GitHub https://github.com/project-owner/PeppyMeter/issues/7#issuecomment-1657199122, or unsubscribe https://github.com/notifications/unsubscribe-auth/ANJASF5PH7MSYLJBA7554QLXSZ3N3ANCNFSM6AAAAAATVO47Z4 . You are receiving this because you authored the thread.Message ID: @.***>

project-owner commented 1 year ago

You still need a lock as one thread read data from the pipe and updates the value. The other thread reads that value and sends to I2C device. Anyway, you can experiment. Though the thread deadlock issue can be intermittent.

If you don't check for empty value then more likely the thread was stopped somehow. Add a log output to the 'stop_writing' function.

nls-GitHub commented 1 year ago

That debug message is already there for the stop_writing function, and that doesn't show up. In fact I wanted to show zero values on the VUmeter when the recording ended, but adding those commands in this function did nothing. If I enable the log message for the start_writing, I will get the R & L values of the audio signal, and they stop when the signal ends. If I replay the audio, the R & L values will show up again in the log. So for whatever reason, the fact that there is nothing in the pipe seems to pause the writing, even though I am not checking for zero values.

I will try adding debug messages in datasource.py, perhaps that will give some clue.

def stop_writing(self):
    """ Stop writing thread and nullify values in I2C """

    self.running = False
    time.sleep(self.update_period)
    logging.debug("Writing stopped")

[2023-08-01 18:40:04,052] {i2cinterface.py:38} DEBUG - Left 056 Right 049 [2023-08-01 18:40:04,357] {i2cinterface.py:38} DEBUG - Left 053 Right 047

[2023-08-01 18:40:04,654] {i2cinterface.py:38} DEBUG - Left 047 Right 042[2023-08-01 18:40:04,962] {i2cinterface.py:38} DEBUG - Left 058 Right 051[2023-08-01 18:44:13,077] {i2cinterface.py:38} DEBUG - Left 053 Right 048[2023-08-01 18:44:13,369] {i2cinterface.py:38} DEBUG - Left 031 Right 028 [2023-08-01 18:44:13,678] {i2cinterface.py:38} DEBUG - Left 029 Right 026 [2023-08-01 18:44:13,992] {i2cinterface.py:38} DEBUG - Left 037 Right 033 [2023-08-01 18:44:14,304] {i2cinterface.py:38} DEBUG - Left 040 Right 036 [2023-08-01 18:44:14,616] {i2cinterface.py:38} DEBUG - Left 055 Right 049

On Mon, Jul 31, 2023 at 11:40 AM project-owner @.***> wrote:

You still need a lock as one thread read data from the pipe and updates the value. The other thread reads that value and sends to I2C device. Anyway, you can experiment. Though the thread deadlock issue can be intermittent.

If you don't check for empty value then more likely the thread was stopped somehow. Add a log output to the 'stop_writing' function.

— Reply to this email directly, view it on GitHub https://github.com/project-owner/PeppyMeter/issues/7#issuecomment-1658747724, or unsubscribe https://github.com/notifications/unsubscribe-auth/ANJASFZRNR2VJUECMCJN4GTXS7NWFANCNFSM6AAAAAATVO47Z4 . You are receiving this because you authored the thread.Message ID: @.***>

nls-GitHub commented 1 year ago

I had one more question if you will have the time to answer it. I thought that peppyalsa was a standalone add-on, and would display the audio levels in the bar-graph format on the command line when meter_show is set to 1 in .asoundrc, and music is played. But it looks like that happens only when peppymeter.py is running, and not otherwise. What is the dependency on peppyalsa from peppymeter.py? Of course peppymeter.py needs peppyalsa, but I am confused why the latter would need the former.

pcm_scope.peppyalsa { type peppyalsa decay_ms 400 meter "/home/pi/myfifo" meter_max 100 meter_show 0 }

Thanks!

On Tue, Aug 1, 2023 at 6:48 PM Sriram N.L. @.***> wrote:

That debug message is already there for the stop_writing function, and that doesn't show up. In fact I wanted to show zero values on the VUmeter when the recording ended, but adding those commands in this function did nothing. If I enable the log message for the start_writing, I will get the R & L values of the audio signal, and they stop when the signal ends. If I replay the audio, the R & L values will show up again in the log. So for whatever reason, the fact that there is nothing in the pipe seems to pause the writing, even though I am not checking for zero values.

I will try adding debug messages in datasource.py, perhaps that will give some clue.

def stop_writing(self):
    """ Stop writing thread and nullify values in I2C """

    self.running = False
    time.sleep(self.update_period)
    logging.debug("Writing stopped")

[2023-08-01 18:40:04,052] {i2cinterface.py:38} DEBUG - Left 056 Right 049 [2023-08-01 18:40:04,357] {i2cinterface.py:38} DEBUG - Left 053 Right 047

[2023-08-01 18:40:04,654] {i2cinterface.py:38} DEBUG - Left 047 Right 042[2023-08-01 18:40:04,962] {i2cinterface.py:38} DEBUG - Left 058 Right 051[2023-08-01 18:44:13,077] {i2cinterface.py:38} DEBUG - Left 053 Right 048[2023-08-01 18:44:13,369] {i2cinterface.py:38} DEBUG - Left 031 Right 028 [2023-08-01 18:44:13,678] {i2cinterface.py:38} DEBUG - Left 029 Right 026 [2023-08-01 18:44:13,992] {i2cinterface.py:38} DEBUG - Left 037 Right 033 [2023-08-01 18:44:14,304] {i2cinterface.py:38} DEBUG - Left 040 Right 036 [2023-08-01 18:44:14,616] {i2cinterface.py:38} DEBUG - Left 055 Right 049

On Mon, Jul 31, 2023 at 11:40 AM project-owner @.***> wrote:

You still need a lock as one thread read data from the pipe and updates the value. The other thread reads that value and sends to I2C device. Anyway, you can experiment. Though the thread deadlock issue can be intermittent.

If you don't check for empty value then more likely the thread was stopped somehow. Add a log output to the 'stop_writing' function.

— Reply to this email directly, view it on GitHub https://github.com/project-owner/PeppyMeter/issues/7#issuecomment-1658747724, or unsubscribe https://github.com/notifications/unsubscribe-auth/ANJASFZRNR2VJUECMCJN4GTXS7NWFANCNFSM6AAAAAATVO47Z4 . You are receiving this because you authored the thread.Message ID: @.***>

project-owner commented 1 year ago

Hi,

There is no dependency of peppyalsa on PeppyMeter. The peppyalsa will show ASCII meter in the termianl if you set the property 'meter_show 1' and if any player starts playback. Here is the example screenshot for 'aplay': https://github.com/project-owner/peppyalsa.doc/wiki/VU-Meter And here is that code in the peppyalsa: https://github.com/project-owner/peppyalsa/blob/0544ed6f7bbc4a02049ab538636a8a5f587ca30e/src/meter.c#L71

Best regards

nls-GitHub commented 1 year ago

Thanks for the feedback. The very last sentence in the first link is as follows, doesn't it mean that Peppymeter has to be running as a "reader" for the ASCII bar-graph to be visible?

The VU Meter will be visible only when there is a reader available on the other end of the named pipe.

On Sat, Aug 5, 2023 at 2:36 PM project-owner @.***> wrote:

Hi,

There is no dependency of peppyalsa on PeppyMeter. The peppyalsa will show ASCII meter in the termianl if you set the property 'meter_show 1' and if any player starts playback. Here is the example screenshot for 'aplay': https://github.com/project-owner/peppyalsa.doc/wiki/VU-Meter And here is that code in the peppyalsa:

https://github.com/project-owner/peppyalsa/blob/0544ed6f7bbc4a02049ab538636a8a5f587ca30e/src/meter.c#L71

Best regards

— Reply to this email directly, view it on GitHub https://github.com/project-owner/PeppyMeter/issues/7#issuecomment-1666588382, or unsubscribe https://github.com/notifications/unsubscribe-auth/ANJASF62KLKATKNCKHDP333XT2OEFANCNFSM6AAAAAATVO47Z4 . You are receiving this because you authored the thread.Message ID: @.***>

project-owner commented 1 year ago

If you have 'meter_show 1' it's enough just to run a player in the same terminal. No need for PeppyMeter.

nls-GitHub commented 1 year ago

[image: image.png]

I see the meter with aplay only when peppymeter.py is running in the background. If I terminate it, aplay does not show the meter.

On Sat, Aug 5, 2023 at 5:54 PM project-owner @.***> wrote:

There should be a reader if you have 'meter_show 0'. If you have 'meter_show 1' it's enough just to run a player in the same terminal.

— Reply to this email directly, view it on GitHub https://github.com/project-owner/PeppyMeter/issues/7#issuecomment-1666631699, or unsubscribe https://github.com/notifications/unsubscribe-auth/ANJASF7RGN75EM53SEIECATXT3FLZANCNFSM6AAAAAATVO47Z4 . You are receiving this because you authored the thread.Message ID: @.***>

project-owner commented 1 year ago

That's right, I forgot that already :( That can be any reader from the pipe. You can for example just run the command: cat myfifo

nls-GitHub commented 1 year ago

I tried the debug command in various functions of datasource.py to figure out which was in a continuous loop mode, of course with sleep, but drew a blank. This is almost like an interrupt routine, with the functions getting called when there is some new alsa data in the fifo queue, and not otherwise! I am stumped.

On Sat, Aug 5, 2023 at 7:07 PM project-owner @.***> wrote:

That's right, I forgot that already :( That can be any reader from the pipe. You can for example just run the command: cat myfifo

— Reply to this email directly, view it on GitHub https://github.com/project-owner/PeppyMeter/issues/7#issuecomment-1666647642, or unsubscribe https://github.com/notifications/unsubscribe-auth/ANJASF5VDAPRLU7LNLBNTUDXT3N2XANCNFSM6AAAAAATVO47Z4 . You are receiving this because you authored the thread.Message ID: @.***>

project-owner commented 1 year ago

This function starts the thread to get data: https://github.com/project-owner/PeppyMeter/blob/master/datasource.py#L121

This thread: https://github.com/project-owner/PeppyMeter/blob/master/datasource.py#L130 runs this function: https://github.com/project-owner/PeppyMeter/blob/master/datasource.py#L173 which is infinite loop (not interrupt function): https://github.com/project-owner/PeppyMeter/blob/master/datasource.py#L176 with this delay: https://github.com/project-owner/PeppyMeter/blob/master/datasource.py#L179

get_value called in that infinite loop which in turn calls get_pipe_value: https://github.com/project-owner/PeppyMeter/blob/master/datasource.py#L272

that calls another function get_latest_pipe_value with infinite loop to get all data from the pipe so that it's always the latest data: https://github.com/project-owner/PeppyMeter/blob/master/datasource.py#L257

It will exit that loop only when it reads all data from the pipe. In this case (pipe is empty) os.read causes exception which breaks the loop: https://github.com/project-owner/PeppyMeter/blob/master/datasource.py#L262