miegl / PiFmAdv

Advanced Raspberry Pi FM transmitter with RDS encoding
GNU General Public License v3.0
487 stars 82 forks source link

Feed PiFmAdv with 192kHz MPX signal #58

Open Tratosca opened 5 years ago

Tratosca commented 5 years ago

Hello, Is it possible to use something like Stereotool or Breakaway Broadcast on a Windows computer to feed PiFmAdv with a real MPX signal, over a 192kHz soundcard or Ethernet with MicroMPX (skipping the MPX generation process on the Rasp) ? This would allow to broadcast a processed signal with stereo & RDS directly in it, and use less CPU power I believe.

ItsPops

miegl commented 5 years ago

It's not currently implemented, but it is possible. Not sure about micrompx though as it is proprietary. You could skip all the mpx generation and feed the mpx signal coming off I2S or a usb soundcard directly. If you are having problems with cpu power, there is a bunch of things you can do. The code isn't really optimized and I'm using the double data type in a few places where there's practically no difference. Also you can play with compiler optimizations, the current level of GCC optimizations set in PiFmAdv's Makefile is -O1 for debugging reasons. You can safely push it to -O2 and try some other parameters. But don't compile it with -O3, otherwise the program will have unpredictable results and will malfunction at some point.

rashrf commented 5 years ago

Hi,

I would suspect that even these proprietary things are simply encoding to mono FLAC at 192 kHz sampling, and streamed in an ogg wrapper. ;)

R.

On Fri, 26 Jul 2019 at 12:04, Josef Miegl notifications@github.com wrote:

It's not currently implemented, but it is possible. Not sure about micrompx though as it is proprietary. You could skip all the mpx generation and feed the mpx signal coming off I2S or a usb soundcard directly. If you are having problems with cpu power, there is a bunch of things you can do. The code isn't really optimized and I'm using the double data type in a few places where there's practically no difference. Also you can play with compiler optimizations, the current level of GCC optimizations set in PiFmAdv's Makefile is -O1 for debugging reasons. You can safely push it to -O2 and try some other parameters. But don't compile it with -O3, otherwise the program will have unpredictable results and will malfunction at some point.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/miegl/PiFmAdv/issues/58?email_source=notifications&email_token=ABFIVYVHHSNPKKPVOMKTMX3QBLK4VA5CNFSM4IHB6WY2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD24I3HA#issuecomment-515411356, or mute the thread https://github.com/notifications/unsubscribe-auth/ABFIVYU2MAETK6Y4AF23KR3QBLK4VANCNFSM4IHB6WYQ .

miegl commented 5 years ago

Thanks for the insight! I have also thought about single frequency networks. Would a MPX signal in an ogg container with timestamps and NTP for synchronization be sufficient? DMA synchronization will be needed too of course. So if all the synchronization was done right, would the NTP error be small enough to allow the single frequency network to work?

rashrf commented 5 years ago

There are SFNs and SFNs! With FM, the idea is not to have too much coverage overlapping between transmitters. The more accurate the synchronisation of the audio, the pilot tone phase, the better the outcome will be. One problem never goes away entirely with synchronous FM and that is multipath distortion. Careful placement of the transmitters and choice of tx aerial system can help.

I did wonder about this for PiFM as Logitek open-sourced the squeezebox server (there are 3rd party linux OSS clients) as the system attempts to to play audio synchronously out of multiple clients across a LAN. It might be worth looking at their strategy? The more accurate the sync, the better the experience will be. I think NTP is a few mS to ~100 mS accurate, so it's not ideal. But it is certainly better than nothing!

One could go to extremes and make a hat with a low-cost GPS module to provide 1 PPS into a GPIO pin and use it as a clock source to ensure (timestamped) audio frames are modulated at precisely the right time, and to provide a trigger to ensure the pilot tone phases are 'all going the right way'. As for carrier frequency, I think the Pi uses a 19.2 MHz crystal. This is a fairly standard freq so there room for improving the accuracy and stability of that, but the audio sync is likely to be more important. PPS would be within a few uS between each one! Frequency differences would result in hetrodyne, but it won't be so bad if the modulation is in sync.

All of this said, there is also the FM capture effect to factor in. As long as the overlapping signals are n dB different in strength, it will mask a lot of the interference effects. in the overlapping areas where the difference is not enough, the audio will suffer varying degrees of 'mush'.

A 'poor man' FM SFN using is well worth trying. Years ago I installed two 50 mW FM transmitters to cover a university campus. The audio was fed from an analogue link, so it was synchronous and there was no attempt to synchronise the pilot phase or carrier frequencies. There should therefore have been a large, very noticable mush area but we drove back and forth between them four a couple of hours and we couldn't hear where the overlap was! Strange how the theory predicts a worse outcome than what is found in practice,

From that experience I will say again: the accuracy of synchronising of the modulation will dictate how well it works....

R.

On Sun, 28 Jul 2019 at 11:25, Josef Miegl notifications@github.com wrote:

Thanks for the insight! I have also thought about single frequency networks. Would a MPX signal in a ogg container with timestamps and NTP for synchronization be sufficient? DMA synchronization will be needed too of course. So if all the synchronization was done right, would the NTP error be small enough to allow the single frequency network to work?

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/miegl/PiFmAdv/issues/58?email_source=notifications&email_token=ABFIVYR5JJCGNNT354SQGRTQBVXZBA5CNFSM4IHB6WY2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD263XWI#issuecomment-515750873, or mute the thread https://github.com/notifications/unsubscribe-auth/ABFIVYREYVE43S4K2C6PSQTQBVXZBANCNFSM4IHB6WYQ .

Anthony96922 commented 5 years ago

I'm also looking for a way to feed 192kHz MPX audio into PiFmAdv. The MPX signal will be 1-channel raw PCM data sent over ethernet. Something like this:

On a computer

./mpxgen --out-file /tmp/mpx-out &
nc raspberrypi 1234 < /tmp/mpx-out

and on the Pi

./pi_fm_adv --audio /tmp/mpx-in &
nc -k -l -p 1234 > /tmp/mpx-in

The audio goes through filtering so the processing path would need to be bypassed.

HyperDX commented 4 years ago

That's very good idea! With Stereotool I can easily change RDS/audio settings or insert artist/title in there. Also I can change stereo pilot and RDS level.

miegl commented 4 years ago

@HyperDX you can do all of this with PiFmAdv too, no need for Stereotool ;) Inserting artist/title can be done very easily with a FIFO pipe (--ctl). I've even made a simple script for setting just that from an Icecast server, may post it somewhere. Changing the RDS level is also pretty easy, there's currently no option for it but if you head to https://github.com/miegl/PiFmAdv/blob/master/src/fm_mpx.c#L237, you can just multiply rds_buffer[i]. By default it's on a normal level (that's what most FM stations do anyways).

HyperDX commented 4 years ago

I didn't know about that, thanks! For me Stereotool is/was the easiest way to provide artist and title info to transmitter. Could you share this script if you can? :D

miegl commented 4 years ago

@HyperDX here it is: (didn't test it and made some adjustments, hopefully it will work :)

#!/bin/bash

fifo="rds_ctl";
[ -p $fifo ] || mkfifo $fifo;

old_content_file="old_rds.txt";
[ -f $old_content_file ] || touch $old_content_file;

echo "PS Radio" > $fifo;

while true
do
        content=$(curl -s <icecat server>/rds.xsl);
        content_old=$(cat "$old_content_file");

        prefix="* - "
        suffix=" - * - *"
        song=${content#$prefix}
        song2=$song
        show=${content%$suffix}
        name="$song / $show"

        if [ "$content" != "$content_old" ]; then
                echo "$content" > $old_content_file;
                if [ ${#name} -lt 49 ]; then
                        echo "RT $name / Radio" > $fifo;
                        echo "RadioText has been set to: $name / Radio";
                elif [ ${#name} -gt 62 ]; then
                        echo "RT $song" > $fifo;
                        echo "RadioText has been set to: $song";
                else
                        echo "RT $name" > $fifo;
                        echo "RadioText has been set to: $name";
                fi

                sleep 5;

                while [[ -n $song ]]; do                # loop until $song is empty
                        if [[ ${#song} -gt 8 ]]; then
                                b="${song:0:8}"         # get first 8 characters of $song
                                c="${b% *}"             # crop all from right incl. first whitespace
                        else
                                c="$song"
                        fi
                        echo "PS $c" > "$fifo"
                        d="${song#$c}"                  # crop $c left from string $song
                        song="${d# *}"                  # remove a leading whitespace
                        sleep 2.5
                done

                echo "PS  " > $fifo;
                sleep 2.5;

                while [[ -n $song2 ]]; do               # loop until $song2 is empty
                        if [[ ${#song2} -gt 8 ]]; then
                                b="${song2:0:8}"        # get first 8 characters of $song2
                                c="${b% *}"             # crop all from right incl. first whitespace
                        else
                                c="$song2"
                        fi
                        echo "PS $c" > "$fifo"
                        d="${song2#$c}"                 # crop $c left from string $song2
                        song2="${d# *}"                 # remove a leading whitespace
                        sleep 2.5
                done

                echo "PS Radio" > $fifo;
        fi

        echo "$content" > $old_content_file;
        sleep 2.5;
done

The script expects rds.xsl to contain pure text of format: <show name> - <artist> - <song name>