Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
 help / color / mirror / Atom feed
* [FFmpeg-devel] [PATCH 1/5] avradio/sdrdemux: Factorize synchronous_am_demodulation* functions
@ 2023-07-10  0:01 Michael Niedermayer
  2023-07-10  0:01 ` [FFmpeg-devel] [PATCH 2/5] avradio/sdrdemux: shift 19khz carrier differntly Michael Niedermayer
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: Michael Niedermayer @ 2023-07-10  0:01 UTC (permalink / raw)
  To: FFmpeg development discussions and patches

Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
---
 libavradio/sdrdemux.c | 56 ++++++++++++++++++++-----------------------
 1 file changed, 26 insertions(+), 30 deletions(-)

diff --git a/libavradio/sdrdemux.c b/libavradio/sdrdemux.c
index 7cc71b2cfb..92b218d899 100644
--- a/libavradio/sdrdemux.c
+++ b/libavradio/sdrdemux.c
@@ -616,43 +616,39 @@ static double find_am_carrier(SDRContext *sdr, const AVComplexFloat *data, int d
 }
 
 /**
- * Demodulate with a carrier that is in the middle of the signal like in AM
- * This will normalize the signal based on the carrier amplitude and subtract the carrier
+ * Demodulate with a carrier that is a N-th of the frequency.
+ * If N is one the carrier will be subtracted from the signal too.
+ * N==1 corresponds to classical AM, N>1 are demodulations with suppressed carriers.
+ *
+ * For N==1 and N==3 the signal will be normalized. For N==2 it will not be
+ * This is to avoid a sqrt() and happens to be what we want in the current use cases.
+ *
+ * The output will be scaled by the window.
  */
-static void synchronous_am_demodulation(AVComplexFloat *iblock, AVComplexFloat *icarrier, float *window, int len)
+static av_always_inline void synchronous_am_demodulationN(AVComplexFloat *iblock, AVComplexFloat *icarrier, float *window, int len, int N)
 {
+    av_assert0(N>=1 && N<=3); //currently supported, trivial to add more if needed
+
     for (int i = 0; i<len; i++) {
         AVComplexFloat c = icarrier[i];
         AVComplexFloat s = iblock[i];
         float          w = window[i];
-        float        den = w / (c.re*c.re + c.im*c.im);
-        av_assert0(c.re*c.re + c.im*c.im > 0);
+        AVComplexFloat c2= {c.re*c.re, c.im*c.im};
+        float den        = w/(c2.re + c2.im);
+
+        if (N==2) {
+            c.im *= c.re + c.re;
+            c.re = c2.re - c2.im;
+        } else if (N==3) {
+            den *= den;
+            c.re *=   c2.re - 3*c2.im;
+            c.im *= 3*c2.re -   c2.im;
+        }
 
         iblock[i].re = ( s.im*c.im + s.re*c.re) * den;
         iblock[i].im = ( s.im*c.re - s.re*c.im) * den;
-        iblock[i].re -= w;
-    }
-}
-
-/**
- * Demodulate with a carrier that is half the frequency and reduced amplitude
- * This will not normalize the signal based on the carrier amplitude
- */
-static void synchronous_am_demodulation2(AVComplexFloat *iblock, AVComplexFloat *icarrier, float *window, int len)
-{
-    for (int i = 0; i<len; i++) {
-        AVComplexFloat c = icarrier[i];
-        AVComplexFloat s = iblock[i];
-        AVComplexFloat c2;
-        float          w = window[i];
-        float        den = w / (c.re*c.re + c.im*c.im);
-        av_assert0(c.re*c.re + c.im*c.im > 0);
-
-        c2.re = c.re*c.re - c.im*c.im;
-        c2.im = c.re*c.im + c.im*c.re;
-
-        iblock[i].re = ( s.im*c2.im + s.re*c2.re) * den;
-        iblock[i].im = ( s.im*c2.re - s.re*c2.im) * den;
+        if (N==1)
+            iblock[i].re -= w;
     }
 }
 
@@ -728,7 +724,7 @@ static int demodulate_am(SDRContext *sdr, int stream_index, AVPacket *pkt)
             sst->block[i] = sdr->block[index + i - len];
         sst->ifft(sst->ifft_ctx, sst->icarrier, sst->block, sizeof(AVComplexFloat));
 
-        synchronous_am_demodulation(sst->iblock, sst->icarrier, sst->window, 2*sst->block_size);
+        synchronous_am_demodulationN(sst->iblock, sst->icarrier, sst->window, 2*sst->block_size, 1);
         scale = 0.9;
     } else {
         // Synchronous demodulation using Macleod based systhesized carrier
@@ -997,7 +993,7 @@ static int demodulate_fm(SDRContext *sdr, int stream_index, AVPacket *pkt)
         apply_deemphasis(sdr, sst->block + i + 2*carrier19_i - 2*shift, sst->block_size_p2, sample_rate_p2, + 1);
         apply_deemphasis(sdr, sst->block + i + 2*carrier19_i - 2*shift, sst->block_size_p2, sample_rate_p2, - 1);
         sst->ifft_p2(sst->ifft_p2_ctx, sst->iside   , sst->block + i, sizeof(AVComplexFloat));
-        synchronous_am_demodulation2(sst->iside, sst->icarrier, sst->window_p2, 2*sst->block_size_p2);
+        synchronous_am_demodulationN(sst->iside, sst->icarrier, sst->window_p2, 2*sst->block_size_p2, 2);
     }
     memset(sst->block + len17_i, 0, (2*sst->block_size_p2 - len17_i) * sizeof(AVComplexFloat));
     apply_deemphasis(sdr, sst->block, 2*sst->block_size_p2, sample_rate_p2, + 1);
-- 
2.31.1

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [FFmpeg-devel] [PATCH 2/5] avradio/sdrdemux: shift 19khz carrier differntly
  2023-07-10  0:01 [FFmpeg-devel] [PATCH 1/5] avradio/sdrdemux: Factorize synchronous_am_demodulation* functions Michael Niedermayer
@ 2023-07-10  0:01 ` Michael Niedermayer
  2023-07-10  0:01 ` [FFmpeg-devel] [PATCH 3/5] avradio/sdrdemux: only allocare iside and window_p2 when needed Michael Niedermayer
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Michael Niedermayer @ 2023-07-10  0:01 UTC (permalink / raw)
  To: FFmpeg development discussions and patches

This simplifies the following commits

Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
---
 libavradio/sdrdemux.c | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/libavradio/sdrdemux.c b/libavradio/sdrdemux.c
index 92b218d899..ef8a8a91d3 100644
--- a/libavradio/sdrdemux.c
+++ b/libavradio/sdrdemux.c
@@ -983,15 +983,17 @@ static int demodulate_fm(SDRContext *sdr, int stream_index, AVPacket *pkt)
     carrier19_i = lrint(carrier19_i_exact);
 
     if (carrier19_i >= 0) {
-        int shift = carrier19_i/2;
         i = sst->block_size;
         memset(sst->block + i, 0, 2*sst->block_size_p2 * sizeof(AVComplexFloat));
-        memcpy(sst->block + i + carrier19_i - W - shift , sst->block + carrier19_i - W, sizeof(AVComplexFloat)*(2*W+1));
+        memcpy(sst->block + i, sst->block + carrier19_i, sizeof(AVComplexFloat)*(W+1));
+        memcpy(sst->block + i + 2*sst->block_size_p2 - W, sst->block + carrier19_i - W, sizeof(AVComplexFloat)*W);
         sst->ifft_p2(sst->ifft_p2_ctx, sst->icarrier, sst->block + i, sizeof(AVComplexFloat));
 
-        memcpy(sst->block + i + 2*carrier19_i - 2*shift - len17_i, sst->block + 2*carrier19_i - len17_i, sizeof(AVComplexFloat)*2*len17_i);
-        apply_deemphasis(sdr, sst->block + i + 2*carrier19_i - 2*shift, sst->block_size_p2, sample_rate_p2, + 1);
-        apply_deemphasis(sdr, sst->block + i + 2*carrier19_i - 2*shift, sst->block_size_p2, sample_rate_p2, - 1);
+        memcpy(sst->block + i, sst->block + 2*carrier19_i, sizeof(AVComplexFloat)*len17_i);
+        memcpy(sst->block + i + 2*sst->block_size_p2 - len17_i, sst->block + 2*carrier19_i - len17_i, sizeof(AVComplexFloat)*len17_i);
+
+        apply_deemphasis(sdr, sst->block + i, sst->block_size_p2, sample_rate_p2, + 1);
+        apply_deemphasis(sdr, sst->block + i + 2*sst->block_size_p2, sst->block_size_p2, sample_rate_p2, - 1);
         sst->ifft_p2(sst->ifft_p2_ctx, sst->iside   , sst->block + i, sizeof(AVComplexFloat));
         synchronous_am_demodulationN(sst->iside, sst->icarrier, sst->window_p2, 2*sst->block_size_p2, 2);
     }
-- 
2.31.1

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [FFmpeg-devel] [PATCH 3/5] avradio/sdrdemux: only allocare iside and window_p2 when needed
  2023-07-10  0:01 [FFmpeg-devel] [PATCH 1/5] avradio/sdrdemux: Factorize synchronous_am_demodulation* functions Michael Niedermayer
  2023-07-10  0:01 ` [FFmpeg-devel] [PATCH 2/5] avradio/sdrdemux: shift 19khz carrier differntly Michael Niedermayer
@ 2023-07-10  0:01 ` Michael Niedermayer
  2023-07-10  0:01 ` [FFmpeg-devel] [PATCH 4/5] avradio/sdrdemux: factor block_time out Michael Niedermayer
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Michael Niedermayer @ 2023-07-10  0:01 UTC (permalink / raw)
  To: FFmpeg development discussions and patches

Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
---
 libavradio/sdrdemux.c | 17 ++++++++++-------
 1 file changed, 10 insertions(+), 7 deletions(-)

diff --git a/libavradio/sdrdemux.c b/libavradio/sdrdemux.c
index ef8a8a91d3..36b8aac2fb 100644
--- a/libavradio/sdrdemux.c
+++ b/libavradio/sdrdemux.c
@@ -1136,16 +1136,23 @@ static int setup_stream(SDRContext *sdr, int stream_index, Station *station)
             if (ret < 0)
                 return ret;
 
+            sst->window_p2 = av_malloc(sizeof(*sst->window_p2)* 2 * sst->block_size_p2);
+            sst->iside     = av_malloc(sizeof(*sst->iside)    * 2 * sst->block_size_p2);
+            if (!sst->iside || !sst->window_p2)
+                return AVERROR(ENOMEM);
+
+            avpriv_kbd_window_init(sst->window_p2, sdr->kbd_alpha, sst->block_size_p2);
+            for(int i = sst->block_size_p2; i < 2 * sst->block_size_p2; i++) {
+                sst->window_p2[i] = sst->window_p2[2*sst->block_size_p2 - i - 1];
+            }
         }
 
         sst->out_buf   = av_malloc(sizeof(*sst->out_buf)  * 2 * sst->block_size);
         sst->block     = av_malloc(sizeof(*sst-> block)   * 2 * sst->block_size);
         sst->iblock    = av_malloc(sizeof(*sst->iblock)   * 2 * sst->block_size);
         sst->icarrier  = av_malloc(sizeof(*sst->icarrier) * 2 * sst->block_size);
-        sst->iside     = av_malloc(sizeof(*sst->iside)    * 2 * sst->block_size_p2);
         sst->window    = av_malloc(sizeof(*sst->window)   * 2 * sst->block_size);
-        sst->window_p2 = av_malloc(sizeof(*sst->window_p2)* 2 * sst->block_size_p2);
-        if (!sst->out_buf || !sst->block || !sst->iblock || !sst->icarrier || !sst->iside || !sst->window || !sst->window_p2)
+        if (!sst->out_buf || !sst->block || !sst->iblock || !sst->icarrier || !sst->window)
             return AVERROR(ENOMEM);
 
         avpriv_kbd_window_init(sst->window, sdr->kbd_alpha, sst->block_size);
@@ -1153,10 +1160,6 @@ static int setup_stream(SDRContext *sdr, int stream_index, Station *station)
             sst->window[i] = sst->window[2*sst->block_size - i - 1];
         }
 
-        avpriv_kbd_window_init(sst->window_p2, sdr->kbd_alpha, sst->block_size_p2);
-        for(int i = sst->block_size_p2; i < 2 * sst->block_size_p2; i++) {
-            sst->window_p2[i] = sst->window_p2[2*sst->block_size_p2 - i - 1];
-        }
         sst->am_amplitude = 0;
     }
 
-- 
2.31.1

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [FFmpeg-devel] [PATCH 4/5] avradio/sdrdemux: factor block_time out
  2023-07-10  0:01 [FFmpeg-devel] [PATCH 1/5] avradio/sdrdemux: Factorize synchronous_am_demodulation* functions Michael Niedermayer
  2023-07-10  0:01 ` [FFmpeg-devel] [PATCH 2/5] avradio/sdrdemux: shift 19khz carrier differntly Michael Niedermayer
  2023-07-10  0:01 ` [FFmpeg-devel] [PATCH 3/5] avradio/sdrdemux: only allocare iside and window_p2 when needed Michael Niedermayer
@ 2023-07-10  0:01 ` Michael Niedermayer
  2023-07-10  0:01 ` [FFmpeg-devel] [PATCH 5/5] avradio: RDS support Michael Niedermayer
  2023-07-11 20:10 ` [FFmpeg-devel] [PATCH 1/5] avradio/sdrdemux: Factorize synchronous_am_demodulation* functions Michael Niedermayer
  4 siblings, 0 replies; 6+ messages in thread
From: Michael Niedermayer @ 2023-07-10  0:01 UTC (permalink / raw)
  To: FFmpeg development discussions and patches

Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
---
 libavradio/sdrdemux.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/libavradio/sdrdemux.c b/libavradio/sdrdemux.c
index 36b8aac2fb..0cad9a2d3a 100644
--- a/libavradio/sdrdemux.c
+++ b/libavradio/sdrdemux.c
@@ -1099,6 +1099,7 @@ static int setup_stream(SDRContext *sdr, int stream_index, Station *station)
     AVFormatContext *s = sdr->avfmt;
     AVStream *st = s->streams[stream_index];
     SDRStream *sst = st->priv_data;
+    double block_time = sdr->block_size / (double)sdr->sdr_sample_rate;
     int ret;
 
     //For now we expect each station to be only demodulated once, nothing should break though if its done more often
@@ -1116,7 +1117,7 @@ static int setup_stream(SDRContext *sdr, int stream_index, Station *station)
     if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
         free_stream(sdr, stream_index);
 
-        for (sst->block_size = 4; 2ll *sst->station->bandwidth * sdr->block_size / sdr->sdr_sample_rate > sst->block_size; sst->block_size <<= 1)
+        for (sst->block_size = 4; 2ll *sst->station->bandwidth * block_time > sst->block_size; sst->block_size <<= 1)
             ;
         sst->block_size = FFMIN(sdr->block_size,  sst->block_size);
 
@@ -1130,7 +1131,7 @@ static int setup_stream(SDRContext *sdr, int stream_index, Station *station)
             if (ret < 0)
                 return ret;
 
-            for (sst->block_size_p2 = 4; 2ll *sst->station->bandwidth_p2 * sdr->block_size / sdr->sdr_sample_rate > sst->block_size_p2; sst->block_size_p2 <<= 1)
+            for (sst->block_size_p2 = 4; 2ll *sst->station->bandwidth_p2 * block_time > sst->block_size_p2; sst->block_size_p2 <<= 1)
                 ;
             ret = av_tx_init(&sst->ifft_p2_ctx, &sst->ifft_p2, AV_TX_FLOAT_FFT, 1, 2*sst->block_size_p2, NULL, 0);
             if (ret < 0)
-- 
2.31.1

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [FFmpeg-devel] [PATCH 5/5] avradio: RDS support
  2023-07-10  0:01 [FFmpeg-devel] [PATCH 1/5] avradio/sdrdemux: Factorize synchronous_am_demodulation* functions Michael Niedermayer
                   ` (2 preceding siblings ...)
  2023-07-10  0:01 ` [FFmpeg-devel] [PATCH 4/5] avradio/sdrdemux: factor block_time out Michael Niedermayer
@ 2023-07-10  0:01 ` Michael Niedermayer
  2023-07-11 20:10 ` [FFmpeg-devel] [PATCH 1/5] avradio/sdrdemux: Factorize synchronous_am_demodulation* functions Michael Niedermayer
  4 siblings, 0 replies; 6+ messages in thread
From: Michael Niedermayer @ 2023-07-10  0:01 UTC (permalink / raw)
  To: FFmpeg development discussions and patches

Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
---
 libavradio/Makefile     |   4 +-
 libavradio/rds.c        | 203 ++++++++++++++++++++++++++++++++++++++++
 libavradio/sdr.h        |  13 ++-
 libavradio/sdrdemux.c   |  18 +++-
 libavradio/vissualize.c |  13 ++-
 5 files changed, 240 insertions(+), 11 deletions(-)
 create mode 100644 libavradio/rds.c

diff --git a/libavradio/Makefile b/libavradio/Makefile
index 40b38f798e..5efc2588c3 100644
--- a/libavradio/Makefile
+++ b/libavradio/Makefile
@@ -11,5 +11,5 @@ OBJS    = allradios.o                                                   \
 
 
 # input/output radios
-OBJS-$(CONFIG_SDR_INRADIO)            		+= sdrinradio.o vissualize.o
-OBJS-$(CONFIG_SDRFILE_INRADIO)                  += sdrdemux.o vissualize.o
+OBJS-$(CONFIG_SDR_INRADIO)            		+= sdrinradio.o vissualize.o rds.o
+OBJS-$(CONFIG_SDRFILE_INRADIO)                  += sdrdemux.o vissualize.o rds.o
diff --git a/libavradio/rds.c b/libavradio/rds.c
new file mode 100644
index 0000000000..dd9a934c3c
--- /dev/null
+++ b/libavradio/rds.c
@@ -0,0 +1,203 @@
+/*
+ * RDS
+ * Copyright (c) 2023 Michael Niedermayer
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ *
+ *
+ */
+
+#include "sdr.h"
+
+#include <float.h>
+#include "libavutil/avassert.h"
+#include "libavutil/ffmath.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/opt.h"
+#include "libavformat/avformat.h"
+#include "libavformat/demux.h"
+
+/**
+ * Check and correct RDS block
+ * @param[out] group the data bits are returned here
+ * @param block block nu,ber (0 to 3)
+ * @return 1 if correctable single bit error, 0 if no error, >99 if non correctable errors
+ */
+static int check_rds_block(uint16_t group[4], const float diff[104], int block)
+{
+#define RDS_G 0x5B9 //101 1011 1001
+    static const uint16_t offset[4] = {0x0FC, 0x198, 0x168, 0x1B4};
+    unsigned codeword = 0;
+    unsigned syndrom = 0;
+    //we carry floats through to here so we can do a soft decission decoder
+    //ATM lets just do hard decission decoding that should be more than good enough
+
+    //FIXME we could do this more efficiently but does it matter?
+    for(int i=0; i<26; i++) {
+        int bit = (diff[i + block*26]<0);
+        codeword += codeword + bit;
+        syndrom += syndrom + bit;
+        if (syndrom & (1<<10))
+            syndrom ^= RDS_G;
+    }
+    if (block==2 && (group[1]&0x800)) {
+        syndrom ^= 0x350;
+    }else
+        syndrom ^= offset[block];
+    //FIXME the spec talks about a special case of a 0 offset used in the USA
+
+    group[block] = codeword >> 10;
+
+    // try correcting some basic errors
+    if (syndrom) {
+        for (unsigned e = 1; e <= 2; e ++) {
+            unsigned mask = 255 >> (8-e);
+            unsigned syndrom1 = mask;
+            for(int i=0; i<27-e; i++) {
+                if (syndrom == syndrom1) {
+                    group[block] ^= (mask<<i) >> 10;
+                    return e;
+                }
+                syndrom1 += syndrom1;
+                if (syndrom1 & (1<<10))
+                    syndrom1 ^= RDS_G;
+            }
+        }
+        return 100; // this is a good place do a 2nd pass with a soft decssion multi bit decoder
+    }
+
+    return 0;
+}
+
+static int decode_rds_group(SDRContext *sdr, SDRStream *sst, uint16_t group[4])
+{
+    Station *station = sst->station;
+    int pi = group[0];
+    int a  = group[1] >> 12;
+    int b  = group[1] & 0x800;
+    int tp = group[1] & 0x400;
+    int pty= (group[1] >> 5) & 0x1F;
+
+    switch(a) {
+    case 0:
+        AV_WB16(station->name + 2*(group[1]&3), group[3]);
+    break;
+    case 2:
+        if (b) {
+            AV_WB16(station->radiotext + 2*(group[1]&15)    , group[3]);
+        } else {
+            AV_WB16(station->radiotext + 4*(group[1]&15)    , group[2]);
+            AV_WB16(station->radiotext + 4*(group[1]&15) + 2, group[3]);
+        }
+    break;
+    case 10:
+        if (b==0) {
+            AV_WB16(station->programm_type_name + 4*(group[1]&1)    , group[2]);
+            AV_WB16(station->programm_type_name + 4*(group[1]&1) + 2, group[3]);
+        }
+    break;
+//     case 14:
+//     break;
+    default:
+        av_log(sdr->avfmt, AV_LOG_DEBUG, "RDS: PI %X, A %X B %X PTY %X\n", pi,a,b,pty);
+    }
+
+    return 0;
+}
+
+int ff_sdr_decode_rds(SDRContext *sdr, SDRStream *sst, AVComplexFloat *signal)
+{
+    int i, phase;
+    float (*ring)[2] = sst->rds_ring;
+    float diff[2*104 - 1];
+    uint16_t group[4];
+    int64_t num_step_in_p2 = sdr->sdr_sample_rate * (int64_t)sst->block_size_p2;
+    int64_t den_step_on_p2 = sdr->block_size * 2375LL;
+#define IDX(I) ((I)*num_step_in_p2/den_step_on_p2)
+
+    av_assert0(sst->rds_ring_pos <= sst->rds_ring_size - 2*sst->block_size_p2);
+
+    //For reasons that are beyond me, RDS spec allows inphase and quadrature so we have to compute and check both
+    for (int i=0; i < sst->block_size_p2; i++) {
+        ring[ sst->rds_ring_pos + i                      ][0] += signal[i].re * sst->window_p2[i];
+        ring[ sst->rds_ring_pos + i + sst->block_size_p2 ][0]  = signal[i + sst->block_size_p2].re * sst->window_p2[i + sst->block_size_p2];
+        ring[ sst->rds_ring_pos + i                      ][1] += signal[i].im * sst->window_p2[i];
+        ring[ sst->rds_ring_pos + i + sst->block_size_p2 ][1]  = signal[i + sst->block_size_p2].im * sst->window_p2[i + sst->block_size_p2];
+    }
+    sst->rds_ring_pos += sst->block_size_p2;
+
+    while (sst->rds_ring_pos > IDX(2) + IDX(4*104-1)) {
+        int best_phase;
+        float best_amplitude = -1;
+        for (phase = 0; phase < 2*IDX(2); phase++) {
+            double a = 0;
+            for (i = 0; i<2*104; i++) {
+                a += fabs(ring[IDX(2*i+1)][phase] - ring[IDX(2*i)][phase]);
+            }
+            if (a > best_amplitude) {
+                best_amplitude = a;
+                best_phase = phase;
+            }
+        }
+
+        phase = best_phase;
+        float last_bpsk = 0;
+        for (i = 0; i<2*104; i++) {
+            float bpsk = ring[IDX(2*i+1)][phase] - ring[IDX(2*i)][phase];
+            if (i)
+                diff[i-1] = bpsk * last_bpsk;
+            last_bpsk = bpsk;
+        }
+
+        int best_errors = INT_MAX;
+        for (phase = 0; phase < 104; phase++) {
+            int error = 0;
+            for (int block = 0; block < 4; block++) {
+                error += check_rds_block(group, diff + phase, block);
+            }
+            if (error < best_errors) {
+                best_errors = error;
+                best_phase = phase;
+            }
+        }
+        av_log(sdr->avfmt, AV_LOG_DEBUG, "RDS ERR:%d\n", best_errors);
+
+        // are we having no errors or correctable errors
+        if (best_errors < 10) {
+            int error = 0;
+            for (int block = 0; block < 4; block++) {
+                error += check_rds_block(group, diff + best_phase, block);
+            }
+            //have to recheck because of floats
+            if (error < 10) {
+                decode_rds_group(sdr, sst, group);
+            }
+        }
+        int step = IDX(2*(best_phase + 103));
+
+        av_assert0(sst->rds_ring_pos >= step);
+        memmove(ring, ring + step, (sst->rds_ring_pos + sst->block_size_p2 - step) * sizeof(*sst->rds_ring));
+        sst->rds_ring_pos -= step;
+    }
+    av_assert0 (sst->rds_ring_pos + 2*sst->block_size_p2 <= sst->rds_ring_size);
+
+    return 0;
+}
diff --git a/libavradio/sdr.h b/libavradio/sdr.h
index 1582f70d86..212358fad9 100644
--- a/libavradio/sdr.h
+++ b/libavradio/sdr.h
@@ -71,7 +71,9 @@ typedef enum Modulation {
 #define HISTOGRAMM_SIZE 9
 
 typedef struct Station {
-    char *name;
+    char name[9];
+    char radiotext[65];
+    char programm_type_name[9];
     enum Modulation modulation;
     double frequency;
     int nb_frequency;       ///< number of detections which are used to compute the frequency
@@ -110,6 +112,9 @@ typedef struct SDRStream {
     AVComplexFloat *iside;
     float *window;
     float *window_p2;
+    float (*rds_ring)[2];
+    int rds_ring_size;
+    int rds_ring_pos;
     Station *station;
     float am_amplitude;
 
@@ -266,6 +271,12 @@ int ff_sdr_find_stations(SDRContext *sdr, double freq, double range, Station **s
 
 int ff_sdr_histogram_score(Station *s);
 
+/**
+ * Decode RDS
+ * @param signal the time domain RDS signal
+ */
+int ff_sdr_decode_rds(SDRContext *sdr, SDRStream *sst, AVComplexFloat *signal);
+
 static inline float len2(AVComplexFloat c)
 {
     return c.re*c.re + c.im*c.im;
diff --git a/libavradio/sdrdemux.c b/libavradio/sdrdemux.c
index 0cad9a2d3a..a34f784e63 100644
--- a/libavradio/sdrdemux.c
+++ b/libavradio/sdrdemux.c
@@ -99,7 +99,6 @@ static void apply_deemphasis(SDRContext *sdr, AVComplexFloat *data, int len, int
 
 static void free_station(Station *station)
 {
-    av_freep(&station->name);
     if (station->stream)
         station->stream->station = NULL;
     av_free(station);
@@ -937,7 +936,8 @@ static int demodulate_fm(SDRContext *sdr, int stream_index, AVPacket *pkt)
     int ret, i;
     float clip = 1.0;
     int carrier19_i = 2L*sst->block_size*19000 / sample_rate;
-    int len17_i     = 2L*sst->block_size*17000 / sample_rate;
+    int len17_i     = 2L*sst->block_size*16500 / sample_rate;
+    int len2_4_i    = 2L*sst->block_size* 2400 / sample_rate;
     double carrier19_i_exact;
     int W= 5;
 
@@ -989,9 +989,14 @@ static int demodulate_fm(SDRContext *sdr, int stream_index, AVPacket *pkt)
         memcpy(sst->block + i + 2*sst->block_size_p2 - W, sst->block + carrier19_i - W, sizeof(AVComplexFloat)*W);
         sst->ifft_p2(sst->ifft_p2_ctx, sst->icarrier, sst->block + i, sizeof(AVComplexFloat));
 
+        memcpy(sst->block + i, sst->block + 3*carrier19_i, sizeof(AVComplexFloat)*len2_4_i);
+        memcpy(sst->block + i + 2*sst->block_size_p2 - len2_4_i, sst->block + 3*carrier19_i - len2_4_i, sizeof(AVComplexFloat)*len2_4_i);
+        sst->ifft_p2(sst->ifft_p2_ctx, sst->iside   , sst->block + i, sizeof(AVComplexFloat));
+        synchronous_am_demodulationN(sst->iside, sst->icarrier, sst->window_p2, 2*sst->block_size_p2, 3);
+        ff_sdr_decode_rds(sdr, sst, sst->iside);
+
         memcpy(sst->block + i, sst->block + 2*carrier19_i, sizeof(AVComplexFloat)*len17_i);
         memcpy(sst->block + i + 2*sst->block_size_p2 - len17_i, sst->block + 2*carrier19_i - len17_i, sizeof(AVComplexFloat)*len17_i);
-
         apply_deemphasis(sdr, sst->block + i, sst->block_size_p2, sample_rate_p2, + 1);
         apply_deemphasis(sdr, sst->block + i + 2*sst->block_size_p2, sst->block_size_p2, sample_rate_p2, - 1);
         sst->ifft_p2(sst->ifft_p2_ctx, sst->iside   , sst->block + i, sizeof(AVComplexFloat));
@@ -1091,7 +1096,7 @@ static void free_stream(SDRContext *sdr, int stream_index)
     av_freep(&sst->iside);
     av_freep(&sst->window);
     av_freep(&sst->window_p2);
-
+    av_freep(&sst->rds_ring);
 }
 
 static int setup_stream(SDRContext *sdr, int stream_index, Station *station)
@@ -1137,9 +1142,12 @@ static int setup_stream(SDRContext *sdr, int stream_index, Station *station)
             if (ret < 0)
                 return ret;
 
+            sst->rds_ring_size = ceil((2*105 / 1187.5 + 2.0*block_time) * sst->block_size_p2 / block_time);
+
+            sst->rds_ring  = av_malloc(sizeof(*sst->rds_ring ) * sst->rds_ring_size);
             sst->window_p2 = av_malloc(sizeof(*sst->window_p2)* 2 * sst->block_size_p2);
             sst->iside     = av_malloc(sizeof(*sst->iside)    * 2 * sst->block_size_p2);
-            if (!sst->iside || !sst->window_p2)
+            if (!sst->iside || !sst->window_p2 || !sst->rds_ring)
                 return AVERROR(ENOMEM);
 
             avpriv_kbd_window_init(sst->window_p2, sdr->kbd_alpha, sst->block_size_p2);
diff --git a/libavradio/vissualize.c b/libavradio/vissualize.c
index b27f78f171..d87ca167de 100644
--- a/libavradio/vissualize.c
+++ b/libavradio/vissualize.c
@@ -202,7 +202,7 @@ int ff_sdr_vissualization(SDRContext *sdr, AVStream *st, AVPacket *pkt)
             Station *s = station_list[station_index];
             double f = s->frequency;
             int xmid  = 256*( f     - sdr->block_center_freq + sdr->sdr_sample_rate/2) * w / sdr->sdr_sample_rate;
-            char text[80];
+            char text[100];
             int color = s->stream ? 64 : 32;
             int size = s->stream ? 181 : 128;
             int xd = size, yd = size;
@@ -210,10 +210,17 @@ int ff_sdr_vissualization(SDRContext *sdr, AVStream *st, AVPacket *pkt)
             if (!s->in_station_list)
                 continue;
 
-            snprintf(text, sizeof(text), "%s %f Mhz %d %d %d",
-                     ff_sdr_modulation_descs[s->modulation].shortname,
+            if (s->name[0]) {
+                snprintf(text, sizeof(text), "%s ", s->name);
+            } else {
+                snprintf(text, sizeof(text), "%s ", ff_sdr_modulation_descs[s->modulation].shortname);
+            }
+            av_strlcatf(text, sizeof(text), "%f Mhz %d %d %d",
                      f/1000000, (int)s->score, ff_sdr_histogram_score(s), s->timeout);
             draw_string(pkt->data, 4*w, text, xmid + 8*yd, 320*h2, xd, yd, color, color, color, w, h);
+            if (s->radiotext[0]) {
+                draw_string(pkt->data, 4*w, s->radiotext, xmid + 8*yd, 320*h2 + 24*yd, xd, yd, color, color, color, w, h);
+            }
         }
     }
 
-- 
2.31.1

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [FFmpeg-devel] [PATCH 1/5] avradio/sdrdemux: Factorize synchronous_am_demodulation* functions
  2023-07-10  0:01 [FFmpeg-devel] [PATCH 1/5] avradio/sdrdemux: Factorize synchronous_am_demodulation* functions Michael Niedermayer
                   ` (3 preceding siblings ...)
  2023-07-10  0:01 ` [FFmpeg-devel] [PATCH 5/5] avradio: RDS support Michael Niedermayer
@ 2023-07-11 20:10 ` Michael Niedermayer
  4 siblings, 0 replies; 6+ messages in thread
From: Michael Niedermayer @ 2023-07-11 20:10 UTC (permalink / raw)
  To: FFmpeg development discussions and patches


[-- Attachment #1.1: Type: text/plain, Size: 629 bytes --]

On Mon, Jul 10, 2023 at 02:01:00AM +0200, Michael Niedermayer wrote:
> Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
> ---
>  libavradio/sdrdemux.c | 56 ++++++++++++++++++++-----------------------
>  1 file changed, 26 insertions(+), 30 deletions(-)

will apply patchset

[...]
-- 
Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB

The real ebay dictionary, page 1
"Used only once"    - "Some unspecified defect prevented a second use"
"In good condition" - "Can be repaird by experienced expert"
"As is" - "You wouldnt want it even if you were payed for it, if you knew ..."

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 195 bytes --]

[-- Attachment #2: Type: text/plain, Size: 251 bytes --]

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2023-07-11 20:10 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-07-10  0:01 [FFmpeg-devel] [PATCH 1/5] avradio/sdrdemux: Factorize synchronous_am_demodulation* functions Michael Niedermayer
2023-07-10  0:01 ` [FFmpeg-devel] [PATCH 2/5] avradio/sdrdemux: shift 19khz carrier differntly Michael Niedermayer
2023-07-10  0:01 ` [FFmpeg-devel] [PATCH 3/5] avradio/sdrdemux: only allocare iside and window_p2 when needed Michael Niedermayer
2023-07-10  0:01 ` [FFmpeg-devel] [PATCH 4/5] avradio/sdrdemux: factor block_time out Michael Niedermayer
2023-07-10  0:01 ` [FFmpeg-devel] [PATCH 5/5] avradio: RDS support Michael Niedermayer
2023-07-11 20:10 ` [FFmpeg-devel] [PATCH 1/5] avradio/sdrdemux: Factorize synchronous_am_demodulation* functions Michael Niedermayer

Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
		ffmpegdev@gitmailbox.com
	public-inbox-index ffmpegdev

Example config snippet for mirrors.


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git