PeppyMeter

Hi,


Thank you very much! Digging into the code deeper I had nearly the same hypothesis of the threads “racing” I tried to fix myself by significantly (ten times) decreasing ui.refresh.period in meters.txt for the used indicator with noticeably higher CPU usage.
Your solution is obviously much better, thanks once more!


However, using your solution I noticed that the needle behavior is visually equal on
[data.source]
type = saw
and
type = sine


Not a big deal though, it’s just a test.
Actually the real signal measurements are more critical for me.


Might I ask you, if you don’t mind, for an advice.
I’m planning to use PeppyMeter with mpd directly, without peppyalsa.
My first result was negative, maybe because of the “thread racing”, maybe because of something else.
I saw sporadic the needle movements, so started with test signals.
Now with the fixed “sporadic” movements, should I expect the correct behavior if the signal comes from mpd’s fifo?
Mpd sends 16 bit signed big endian data. Correct?
But looks like datasource.py/get_pipe_value/(data[length - 4] + (data[length - 3] << 8) gets them unsigned.


Today (a bit later) I will continue “fighting” with mpd, but your gracious suggestion would be very helpful.
So should I expect the correct signed/unsigned (and big/little endian) correctness.
And, probably the more stupid question.
In the case of test signal, the test generator gives the prepared signal (slowly varied) amplitude, i.e. rounded/enveloped signal. Mpd oppositely sends momentary samples.
Should I expect PeppyMeter to produce rounding itself (by the python’s statistics module for instance)?
Or the signal should be already rounded in the pipe or by an additional python code (what peppyalsa could do, for instance)?


Thank you very much,
Serge
 
Hi Serge,

There was the issue with the sine data source - it was working too fast. I fixed that. It's really hard to notice the difference between the saw and sine data sources as the waveform is very similar.

The peppyalsa plugin was created to support players other than mpd. That was done mainly to support VLC player which is used as a default audio player for the Peppy player. Before that Peppy player was using mpd as the audio player and its' fifo output for the meter.

After making peppyalsa plugin I tested it only with VLC player. I didn't test it with mpd or any other player hoping that meter and peppyalsa plugins will make it player independent. Therefore you are in a gray area. If you are going to use the meter solely with mpd I would recommend to use the previous version of the meter which doesn't use peppyalsa:
PeppyMeter
But if you could help me to make the mpd and peppyalsa working together it would be great.

I fixed only testing signals. I didn't touch pipe functionality. Therefore if there was any issue it's still there.

PeppyMeter assumes that the signal is unassigned 16 bit. The only conversion it does - it scales the signal down if you define value volume.max.in.pipe which is 100% by default.

I hope you can assume signed/unsigned (and big/little endian) correctness. If possible I would recommend to use some testing files with a known signal parameters. To debug the player you can set property in the config.txt file:
use.logging = True
after that you can add logging statements this way:
logging.debug(.....)

By default the meter doesn't make any signal rounding. I don't think peppyalsa does that either. I think only 'meter' ALSA plugin can change the shape of the signal by making it 16 bit from 24 bit for example. The meter does the averaging for the mono signal if you select mono.algorithm = average. Also you can select the algorithm for the stereo signal from:
- new (default), no signal processing, shows whatever comes from the pipe
- logarithm, makes logarithmic calculation between the previous signal and new one
- average, calculates the average between the previous and new signals

Please let me know if you need any other help.
Best regards
 
Hi Rpi,

I've made a progress with PeppyMeter and MPD.
Unfortunately I've faced python for the first time, so not sure my language constructions are good enough.

What I did in brief (in the implementations order)


- polished thread synchronization in datasource.py/ get_value. Self.data must be under the lock

- created conversion from mpd's 16 bit signed to peppy's 16 bit unsigned with full scale volume.max.in.pipe = 32768.0

- polished datasource.py/ get_pipe_value. it must read all the data (I believe, just not to miss peaks, now get_pipe_value accumulates peaks for every polling.interval (100ms seems good for me)

- datasource.py/ get_pipe_value now finds peaks every polling.interval

- removed needle softening in circular.py, because of the softening should me equal in circular.py and linear.py (initially linears was not soften). Also the previous implementation was not perfect as number of steps in circular.py/run depended on the needle swing. In the worst case there was a lot redrawings, taking CPU and preventing from receiving new values to indicate.

- put softening into datasource.py/smooth to be equal for all indicators in get_value

My patches include a lot of (commented) debug prints so far, sorry for that.

All in all it works with mpd fine at the moment, but I've just started the testing

I would be happy if you take a look and comment my efforts (attached).
Also test signal is attached (click.wav)


Thank you,
Serge
 

Attachments

  • click.wav.zip
    998.3 KB · Views: 52
  • PeppyMeter-patch.zip
    42.5 KB · Views: 52
Hi Serge,

Thank you, this is great job! I'll check your changes during the weekend. If it looks/works fine I'll include them to the new release and I'll mention you as a contributor.
Do you use the latest PeppyMeter code and peppyalsa plugin?

Thank you!
 
If you use peppyalsa plugin you need to disable fifo output in mpd.conf and rely on the pipe created by the plugin. I believe in this case there is no need to make conversion from signed to unsigned value as that will be done in the plugin.

Best regards!
 
Hi,


At the moment I didn’t even touch the ALSA plugin and honestly have no plans to use it.
It’s just senseless for me. If mpd generates data to pipe, the plugin is rather redundant for my PI configuration.


While I was trying to understand what’s wrong with mpd, I reviewed (tried to review) the plugin code in the hope it could get better understanding of why PeppyMeter+mpd doesn’t work.
Once I realized the (signed/unsigned) problem the plugin became totally redundant for my “workflow”


To be honest, after the main mpd related problem was understood and solved, I was very surprised of my conclusion. Mpd support, that is declared working, can’t work at all.


The indicator’s needle will obviously swing somehow (rather arbitrary), but it can't indicate anything similar to the sound volume because of (a) signed values are treated as unsigned by default and (b) Peppy meter takes just momentary samples at arbitrary points in time (just takes 4 bytes of 16bits/2 channels when the sleep exits). It’s not the sound volume at all.



Thank you,
Serge
 
Hi Serge,

The current PeppyMeter code should be used only with peppyalsa plugin. That's because the reasons which you mentioned - the meter doesn't do any RMS calculations etc. All that stuff was offloaded from PeppyMeter's Python code to the C code in the native ALSA meter and custom peppyalsa plugins.

As I mentioned earlier if you want to use the meter with mpd's fifo output you can get older meter version - Vermeer Edition. It does all calculations in the Python code.

Best Regards
 
Hi,

Thank you for the clarification!
Probably I just wasted the time trying to patch the latest edition
Actually you mentioned a previous edition once before but I was just perplexed with the rich choice of the previous variants.
Now, and thank you for that, you pointed to Vermeer,
so I will I have a chance to verify my patches against the Edition

Thank you,
Serge
 
Hi again,


How could I get Vermeer Edition, unfortunately I could not find any branches beyond the master
in GitHub - project-owner/PeppyMeter: PeppyMeter Repository


And, just out of curiosity, if you don’t mind.
Could you point me to the alsa plugin part that makes RMS/etc, just to avoid learning alsa general specifics and extract the pure RMS experience.


IMHO, if you would like to support mdp directly and concurrently you may want to use
[data.source]
type = pipe-mdp
and a separrate
type = pipe-alsa
to support the both


Thank you,
Serge
 
Hi Serge,

I hope that your changes will be very helpful even for the current version of the meter.

You can create new branch for Vermeer Edition this way (assuming you are in the PeppyMeter folder):
git checkout -b Vermeer c07c742f6eeed4cf6796dc3f15f7cda933c0028f

The ALSA plugin chain for the new meter code is like this:
audio player PCM signal -> Official ALSA 'meter' plugin (normalized signal) -> Custom 'peppyalsa' plugin -> volume signal in the named pipe

You can find the source file for the 'meter' plugin here:
alsa-lib/pcm_meter.c at master * michaelwu/alsa-lib * GitHub
The source for the 'peppyalsa' plugin is here:
peppyalsa/peppyalsa.c at master * project-owner/peppyalsa * GitHub

You are right the meter could support both - 'raw' PCM signal in the named pipe and processed signal in the pipe from the meter/peppyalsa plugins. This is just more code to test/support ;)

If you will find any issues please let me know.

Best regards
 
I have tested PeppyMeter with meter/peppyalsa plugins using mpd, mpv and vlc players. It works fine. There is a delay at the very beginning which I think is because of the signal buffering (?). After that it works as expected.

You can get the best result using linear meters (bar, dash and gas). The circular meters are slow especially on slow video systems (SPI etc). The circular meters simulate real meters. That means the meter's hand cannot sharply jump from one position to another. It should travel through all intermediate steps. The current logic should be probably changed and that traveling should be shortened whenever the signal starts going in the opposite direction.

You can specify the linear meter in the configuration file config.txt for example:
[current]
meter = bar

The volume level in the PeppyMeter depends on the current player's volume level.
 
>git checkout -b Vermeer c07c742f6eeed4cf6796dc3f15f7cda933c0028f

Thank you! It was hard to me to guess in advance ;-)

>.......l -> Official ALSA 'meter' plugin (normalized signal) .......

That's why I was not able to find a normalization in PeppyALSA plugin ;-)

I would be happy to get a feedback from you on my patches when/if you could find a time for that
 
Hi Serge,

Here are some comments regarding your patch code:

- I agree that the current circular meter is very slow. The code should be modified. But I don't think the hand should jump from one position to another without going through the intermediate steps. In the linear meters it looks more or less natural but in the circular meter such behavior is not so natural.

- In the datasource.py in the open_pipe function you have interesting code which flushes the pipe's buffer. I'm just not sure what's the default named pipe buffer size? Probably 64K (?)

- I'm not sure that there is the need in extra locking in the get_value function.

- The signal in the named pipe is ready to be used as is in case when the meter and peppyalsa plugins are in use. There is no need to smooth it or apply any other processing on it. That would be required if the whole PCM processing would be done in the Python code like in the Vermeer Edition.

How is your progress with Vermeer Edition code? Does it work for you or not?

Best regards
 
Hi,

Thank you for the feedback!

> I agree that the current circular meter is very slow. The code should be modified. But I don't think the hand should jump from one position to another without going through the intermediate steps. In the linear meters it looks more or less natural but in the circular meter such behavior is not so natural.

I think if the VU meter is expected to be rather a volume unit than "virtually useless", it should be rather strict than nice. As far as I could understand it means

- equal smoothing for all the meters with rounding at datasource level.
- if you would like to add more/dedicated smoothing to circle based meters, it should be done with fixed quantity of steps, not with fixed steps level.
For instance the circle meter makes about 60+ steps while moving through the full scale, It takes time (being too slow) and takes CPU.
The decision is obviously up to you, it's just my humble point.


>- In the datasource.py in the open_pipe function you have interesting code which flushes the pipe's buffer. I'm just not sure what's the default named pipe buffer size? Probably 64K (?)

Just the experience, I've found a couple of times that the indicator was late for about 700-800 ms to follow the real level. After flushing the buffer that didn't happen anymore. It's not a buffer size related, I guess the buffer should be cleared completely on the start. The default buffer size (1M) just should be enough to clear everything.


>- I'm not sure that there is the need in extra locking in the get_value function.

I'm not too familiar with Python, maybe it inserts a synchronization implicitly. Who knows. But being experienced c++ programmer I put some print(threading.currentThread().native_id) and saw the races to synchronize.
Maybe such lack of synchronization couldn't cause a crash in Python, but it would be the problem with c++ for sure.
All in all I saw non-equal stereo needle/bar movement on test (mono by definition) signals before the synchronization was inserted.


>How is your progress with Vermeer Edition code? Does it work for you or not?

Haven't checked so far. I will check and report if you would like me to.



Actually genuinely I needed PeppyMeter for mpd solely, read the documentation that declared the support, tried and detected mpd was not actually supported and so made some patches.
Would be happy if my patches appear useful for you.


I see you are not focused on mpd only as me. I just think if a support is declared unconditionally, it should work unconditionally with all the editions.
Having about 5mln users on my (completely different of course) product I do understand that.
It's obviously not a must for you, just my experience.

BTW, I'm finishing development using PeppyMeter as a general screensaver for Raspberry Pi.
Could you be interested for the details?


Yours,
Serge
 
Hi Serge,

Thank you for the detailed feedback to the feedback :) I’m open for any recommendations which can improve the app.

The smoothing for the circular meters was added after some experiments. It’s unusual to see when the hand suddenly jumps from 0% to 50%. So probably the right implementation would be - start moving to 50% and continue polling during this process. If the current hand position (e.g. 30%) is greater than the current volume (e.g. 20%) then change direction - stop moving to the right and start moving to the left and so on. More complicated but more natural would be also to take into account hand weight/ballistics/inertia. What do you think?

I agree that the linear meters should probably use the same logic as the circular ones. I just found by experimenting that just setting the current volume level was acceptable.

The places which can be accessed concurrently should be synchronized. I’ll check that.

Maybe I need to emphasize in the documentation that PeppyMeter supports any audio/video player BUT only if you use meter and peppyalsa plugins. If you use mpd there is no need to configure file output in mpd.conf. Instead you need to configure meter and peppyalsa in .asoundrc file. peppyalsa also applies FFT and outputs spectrum data into separate pipe.

Sure I’m interested to see any usage of the PeppyMeter. What is your main use case? Do you run it on Desktop OS? Is it Raspbian? Do you use mpd as a stand alone player?

Again, I’m open for any feedback which can help to improve the code. You provided very valuable input which I hope to use in the next release. I will be glad to mention you as the contributor. Please send me PM how you would prefer to be mentioned - full name or just first name or nickname, e-mail or link to your web site, blog, GitHub etc.

Best regards
 
Hi Rpi,

>Vermeer

If I knew of audioop existence before, I would use it. :-( Will redo my code with audioop, it looks more efficient.


> It’s unusual to see when the hand suddenly jumps from 0% to 50%.

I've made nearly the same via the signal smoothing, not the needle smoothing
smooth_val(self, data, prev) (with my initial smoothing "percentages")

Needle based smoothing, if you prefer that, swallows CPU if it's made by varying quantity of fixed steps.
There should be fixed quantity of steps with varied steps sizes.
Anyway if human eye can't distinguish changes made faster than "a millisecond"
there is no need to draw intermediate "microseconds" momentary position. Right?

>I agree that the linear meters should probably use the same logic as the circular ones. I just found by experimenting that just setting the current volume level was acceptable.

For me the level measurements is not just a nice "toy" making something jumps.
After that (pi based) mpd I have a parametric EQ connected for room equalization.
The PEQ has some filters with +5-7 db, so I need to do the best to avoid clipping.
My PEQ is smart enough to make clipping gentle, but it can't avoid clipping on the maximum scale input. So monitoring the player output (with PeppyMeter) is the most desired

> in the documentation ............... If you use mpd there is no need to configure file output in mpd.conf.

Mot probably.
But not just to configure, but to install the plugin itself first.
For me any mpd.conf's audio_output beyond "hw:" is not too welcomed as it may cause resampling at the ALSA level. I already have a lot of digital post processing after the (pi based) player output and wouldn't like to have another one (directly in player)


>Sure I’m interested to see any usage of the PeppyMeter. What is your main use case? Do you run it on Desktop OS? Is it Raspbian? Do you use mpd as a stand alone player?

The common target is a Pi based hi-res touchscreen audio player.
After trying a set of players and "volumino"s (integral solutions) I have chosen mpd+sonata as the basis (with LIRC/etc).
All the preparations are made on a VM with Raspbian x86.
After a problem solution is found and tested I move the code to the Pi.
Now I'm at the final step, I would like to show PeppyMeter on the top of Pi-native desktop as a screensaver. Sorry I tried to be descriptive, if you need more details/reasoning/logic - welcome.


A questions, if you don't mind.
The Pygame caption looks redundant. Is there a way to get rid of it?

Thank you,
Serge
 
Hi Serge,

You are right, moving through the intermediate steps consumes CPU for redrawing. But that provides the visual smoothness. I think that logic should take into account the display frame rate. That should make it smooth and avoid jumping.

Actually the meter was originally created as a toy :) It was not intended as a scientific measurement tool. Though I believe it can be “tuned” to make more or less precise measurements.

ALSA allows to split the signal and redirect one “stream” to the hardware and the other to meter. This way you can avoid resampling etc.

Do you connect touchscreen through HDMI? What is the screen resolution? The meter supports 800*480 maximum.

You can remove the window frame by adding parameter in this line:
PeppyMeter/peppymeter.py at ad4915870dd5433cb67f6ca0c4ed80072cddb9bc * project-owner/PeppyMeter * GitHub
change to
pygame.DOUBLEBUF | pygame.NOFRAME

Best regards
 
Hi,


>But that provides the visual smoothness.


I meant the smoothness better than human ability to distinguish is senseless.
Your initial variant imho was extremely smooth and generally “swallowed” all the peaks.
There should be a compromise


>I think that logic should take into account the display frame rate.


Maybe frame rate is good point to start from, I’m afraid it’s just too CPU consumptive.
Maybe 10Hz could be fast enough, and it could hardly be >24-25Hz (as in traditional movies, that was smooth enough). What do you think?

>ALSA allows to split the signal and redirect one “stream” to the hardware and the other to meter. This way you can avoid resampling etc.


Hmm, Probably so. Sounds logically, but how could I check that to be sure. I have no an idea...
If there is an option to resample, resampling is possible for internal reasons, for universality or so. With mpd’s “hw:” there is just no chance to resample.


I do understand why you recommend ALSA (everything is ready, right?)
But I have everything ready for mpd as well and just don’t need any externals.
Maybe later, when I’ll be trying PEQs/FFTs on the Pi side.

>Do you connect touchscreen through HDMI? What is the screen resolution? The meter supports 800*480 maximum.


7" official DSI display with 800*480


>pygame.DOUBLEBUF | pygame.NOFRAME


Thank a lot!


Also, using the Vermeer as a sample, I’ve patched datasource.py to use audioop, the CPU consumption dropped twice, now it’s 1-2 %. If I only knew about audioop before ;-)


All in all the Pi based player integration v1 (say so) has been finished.
I’ll have to make the SD backup and that’s all


For v2 I’ve planned
- Android MPD clients connected via (peer-to-peer) bluetooth
- APTx for transmitting to “kitchen” and receiving from there…. maybe
-PEQ for Room Equalization (actually the room is already equalized, just out of curiosity)
-FFT (maybe, if I invent “what’s for” ;-) )


Thank you,
Serge
 
Hi,

I'll check if linking redrawing/updating to the frame rate can improve the animation and reduce CPU consumption.

The ALSA plugins (meter, peppyalsa) are used for PeppyMeter to make it universal for any player not only mpd. That's the main reason. If I would use only mpd then the Vermeer Edition would be enough.

2% consumption, is it for linear meters? If possible it would be great to see the video with meter animation.

BTW, peppyalsa plugin also makes FFT for spectrum analizer:
Spectrum Analyzer Usage * project-owner/peppyalsa.doc Wiki * GitHub
It outputs the signal to the other named pipe.

Best regards