diff --git a/gen_wave.py b/gen_wave.py
new file mode 100644
index 0000000..b1ca6bb
--- /dev/null
+++ b/gen_wave.py
@@ -0,0 +1,92 @@
+import math
+import io, os
+import matplotlib.pyplot as plt
+
+sample_rate = 9500
+
+# next 2 funcs are modified from ChristopheJacquet's pydemod
+def rrcosfilter(NumSamples):
+ T_delta = 1/float(sample_rate)
+ sample_num = list(range(NumSamples))
+ h_rrc = [0.0] * NumSamples
+ SymbolPeriod = 1/(2*1187.5)
+
+ for x in sample_num:
+ t = (x-NumSamples/2)*T_delta
+ if t == 0.0:
+ h_rrc[x] = 1.0 - 1 + (4/math.pi)
+ elif t == SymbolPeriod/4:
+ h_rrc[x] = (1/math.sqrt(2))*(((1+2/math.pi)* \
+ (math.sin(math.pi/4))) + ((1-2/math.pi)*(math.cos(math.pi/4))))
+ elif t == -SymbolPeriod/4:
+ h_rrc[x] = (1/math.sqrt(2))*(((1+2/math.pi)* \
+ (math.sin(math.pi/4))) + ((1-2/math.pi)*(math.cos(math.pi/4))))
+ else:
+ h_rrc[x] = (4*(t/SymbolPeriod)*math.cos(math.pi*t*2/SymbolPeriod))/ \
+ (math.pi*t*(1-(4*t/SymbolPeriod)*(4*t/SymbolPeriod))/SymbolPeriod)
+
+ return h_rrc
+
+def convolve(a, b):
+ out = [0] * (len(a) + len(b) - 1)
+ for i in range(len(a)):
+ for j in range(len(b)):
+ out[i+j] += a[i] * b[j]
+ return out
+
+PATH = os.path.dirname(os.path.abspath(__file__))
+
+outc = io.open(f"{PATH}/src/waveforms.c", mode="w", encoding="utf8")
+outh = io.open(f"{PATH}/src/waveforms.h", mode="w", encoding="utf8")
+
+header = u"""
+/* This file was automatically generated by "gen_wave.py".
+ (C) 2014 Christophe Jacquet.
+ (C) 2023 Anthony96922.
+ (C) 2025 kuba201.
+ Released under the GNU GPL v3 license.
+*/
+
+"""
+
+outc.write(header)
+outh.write(header)
+
+def generate():
+ offset = int(sample_rate*0.004) # 190 khz = 760
+ count = int(offset / 10**(len(str(offset)) - 1)) # 760 / 100 = 7
+ l = int(sample_rate / 1187.5) // 2 # 16/2 = 8
+ if l == 1: raise Exception("Sample rate too small")
+ print(f"{offset=} {count=} {l=}")
+
+ sample = [0.0] * (count*l)
+ sample[l] = 1
+ sample[2*l] = -1
+
+ # Apply the data-shaping filter
+ sf = rrcosfilter(l*16)
+ shapedSamples = convolve(sample, sf)
+
+ # Slice the array like numpy would
+ out = shapedSamples[offset-l*count:offset+l*count]
+
+ plt.plot(sf, label="sf")
+ plt.plot(shapedSamples, label="shapedSamples")
+ plt.plot(out, label="out")
+ plt.legend()
+ plt.grid(True)
+ plt.show()
+
+ outc.write(u"float waveform_biphase[{size}] = {{{values}}};\n\n".format(
+ values = u", ".join(map(str, [val / 2.5 for val in out])),
+ size = len(out)))
+ # note: need to limit the amplitude so as not to saturate when the biphase
+ # waveforms are summed
+
+ outh.write(u"extern float waveform_biphase[{size}];\n".format(size=len(out)))
+
+
+generate()
+
+outc.close()
+outh.close()
\ No newline at end of file
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index c425064..d4a85c8 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,5 +1,3 @@
-# This is from kuba's version of MiniRDS
-
cmake_minimum_required(VERSION 3.10)
# Project name and version
@@ -8,10 +6,6 @@ project(minirds VERSION 1.0)
# Define options
option(ODA_RTP "Enable ODA (RT+)" ON)
-option(STATIC_LIBSAMPLERATE "Use a static libsamplerate library (.a)" OFF)
-
-set(LIBSAMPLERATE_DIR "./libsamplerate" CACHE STRING "Directory for static libsamplerate")
-
# Set compiler and flags
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Werror -Wextra -pedantic -O2 -std=c18 -DVERSION=\"${PROJECT_VERSION}\"")
@@ -29,9 +23,7 @@ endif()
set(SOURCES
${SOURCES}
- fm_mpx.c
control_pipe.c
- resampler.c
modulator.c
lib.c
ascii_cmd.c
@@ -40,20 +32,8 @@ set(SOURCES
# Define the executable
add_executable(minirds ${SOURCES})
-# Handle libsamplerate linkage
-if(STATIC_LIBSAMPLERATE)
- target_include_directories(minirds PRIVATE ${LIBSAMPLERATE_DIR}/include)
- target_link_libraries(minirds PRIVATE ${LIBSAMPLERATE_DIR}/lib/libsamplerate.a)
-else()
- find_library(SAMPLERATE_LIBRARY samplerate)
- target_link_libraries(minirds PRIVATE ${SAMPLERATE_LIBRARY})
-endif()
-
# Link additional libraries
target_link_libraries(minirds PRIVATE m pthread pulse pulse-simple)
# Install target
-install(TARGETS minirds DESTINATION /usr/local/bin)
-# Add profiling flags globally
-set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2")
-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2")
+install(TARGETS minirds DESTINATION /usr/local/bin)
\ No newline at end of file
diff --git a/src/ascii_cmd.c b/src/ascii_cmd.c
index 11da238..b235145 100644
--- a/src/ascii_cmd.c
+++ b/src/ascii_cmd.c
@@ -1,23 +1,3 @@
-/*
- * MiniRDS - FM RDS Encoder
- * contains code from:
- * mpxgen - FM multiplex encoder with Stereo and RDS
- * Copyright (C) 2019 Anthony96922
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
#include "common.h"
#include "rds.h"
#include "fm_mpx.h"
@@ -50,28 +30,6 @@ void process_ascii_cmd(unsigned char *str) {
}
}
- if (cmd_len > 4 && str[3] == ' ') {
- cmd = str;
- cmd[3] = 0;
- arg = str + 4;
-
- if (CMD_MATCHES("MPX")) {
- float gains[2];
- if (sscanf((char *)arg, "%f,%f",
- &gains[0], &gains[1]) == 2)
- {
- set_carrier_volume(0, gains[0]);
- set_carrier_volume(1, gains[1]);
- }
- return;
- }
- if (CMD_MATCHES("VOL")) {
- arg[4] = 0;
- set_output_volume(strtof((char *)arg, NULL));
- return;
- }
- }
-
if(cmd_len == 5) {
cmd = str;
if(CMD_MATCHES("AFCH=")) {
@@ -316,25 +274,12 @@ void process_ascii_cmd(unsigned char *str) {
cmd = str;
cmd[5] = 0;
arg = str + 6;
- if (CMD_MATCHES("LEVEL")) {
- uint8_t val = strtoul((char *)arg, NULL, 10);
- val /= 255;
- val *= 15; /* max value*/
- set_carrier_volume(1, val);
- return;
- }
}
if (cmd_len > 7 && str[6] == '=') {
cmd = str;
cmd[6] = 0;
arg = str + 7;
- if (CMD_MATCHES("RDSGEN")) {
- arg[1] = 0;
- set_rdsgen(strtoul((char *)arg, NULL, 10));
- return;
- }
-
if (CMD_MATCHES("PTYNEN")) {
arg[1] = 0;
set_rds_ptyn_enabled(strtoul((char *)arg, NULL, 10));
@@ -353,14 +298,6 @@ void process_ascii_cmd(unsigned char *str) {
cmd = str;
cmd[5] = 0;
arg = str + 6;
- if (CMD_MATCHES("LEVEL")) {
- uint8_t val = strtoul((char *)arg, NULL, 10);
- val /= 255;
- val *= 15; /* max value*/
- set_carrier_volume(1, val);
- return;
- }
-
if (CMD_MATCHES("ECCEN")) {
set_rds_ecclic_toggle(arg[0]);
return;
diff --git a/src/ascii_cmd.h b/src/ascii_cmd.h
index fbcf2a6..d999aef 100644
--- a/src/ascii_cmd.h
+++ b/src/ascii_cmd.h
@@ -1,21 +1,3 @@
-/*
- * mpxgen - FM multiplex encoder with Stereo and RDS
- * Copyright (C) 2019 Anthony96922
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
#define CMD_BUFFER_SIZE 255
#define CTL_BUFFER_SIZE (CMD_BUFFER_SIZE * 2)
#define READ_TIMEOUT_MS 100
diff --git a/src/common.h b/src/common.h
index f6ec959..01734b8 100644
--- a/src/common.h
+++ b/src/common.h
@@ -1,22 +1,4 @@
-/*
- * mpxgen - FM multiplex encoder with Stereo and RDS
- * Copyright (C) 2019-2021 Anthony96922
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-/* common includes for mpxgen */
+/* common includes for rds95 */
#include
#include
#include
diff --git a/src/control_pipe.c b/src/control_pipe.c
index babfad5..5bd07cf 100644
--- a/src/control_pipe.c
+++ b/src/control_pipe.c
@@ -1,21 +1,3 @@
-/*
- * mpxgen - FM multiplex encoder with Stereo and RDS
- * Copyright (C) 2019 Anthony96922
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
#include "common.h"
#include "ascii_cmd.h"
#include "control_pipe.h"
diff --git a/src/control_pipe.h b/src/control_pipe.h
index 7f6b2d6..2fec9c9 100644
--- a/src/control_pipe.h
+++ b/src/control_pipe.h
@@ -1,21 +1,3 @@
-/*
- * mpxgen - FM multiplex encoder with Stereo and RDS
- * Copyright (C) 2019 Anthony96922
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
#include
#include
#include
diff --git a/src/fm_mpx.c b/src/fm_mpx.c
deleted file mode 100644
index ec14da4..0000000
--- a/src/fm_mpx.c
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * mpxgen - FM multiplex encoder with Stereo and RDS
- * Copyright (C) 2019 Anthony96922
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-#include "common.h"
-
-#include "rds.h"
-#include "fm_mpx.h"
-
-static float mpx_vol;
-
-static uint8_t rdsgen;
-
-void set_output_volume(float vol) {
- if (vol > 100.0f) vol = 100.0f;
- mpx_vol = vol / 100.0f;
-}
-
-void set_rdsgen(uint8_t gen) {
- if (gen > 1) gen = 1;
- rdsgen = gen;
-}
-
-void set_carrier_volume(uint8_t carrier, float new_volume) {
- (void)carrier;
- mpx_vol = new_volume / 100.0f;
-}
-
-void fm_mpx_init(uint32_t sample_rate) {
- (void)sample_rate;
- rdsgen = 1;
-}
-
-void fm_rds_get_frames(float *outbuf, size_t num_frames) {
- size_t j = 0;
- float out;
-
- for (size_t i = 0; i < num_frames; i++) {
- out = 0.0f;
-
- out += get_rds_sample(0);
-
- /* clipper */
- out = fminf(+1.0f, out);
- out = fmaxf(-1.0f, out);
-
- /* adjust volume and put into channel */
- if(rdsgen != 0) outbuf[j] = out * mpx_vol;
- j++;
-
- }
-}
-
-void fm_mpx_exit() {
- return;
-}
diff --git a/src/fm_mpx.h b/src/fm_mpx.h
deleted file mode 100644
index 61180be..0000000
--- a/src/fm_mpx.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * mpxgen - FM multiplex encoder with Stereo and RDS
- * Copyright (C) 2019 Anthony96922
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-/* MPX */
-#define NUM_MPX_FRAMES_IN 512
-#define NUM_MPX_FRAMES_OUT (NUM_MPX_FRAMES_IN * 2)
-/*
- * The sample rate at which the MPX generation runs at
- */
-#define MPX_SAMPLE_RATE RDS_SAMPLE_RATE
-
-#define OUTPUT_SAMPLE_RATE MPX_SAMPLE_RATE
-
-extern void fm_mpx_init(uint32_t sample_rate);
-extern void fm_rds_get_frames(float *outbuf, size_t num_frames);
-extern void fm_mpx_exit();
-extern void set_output_volume(float vol);
-extern void set_rdsgen(uint8_t gen);
-extern void set_carrier_volume(uint8_t carrier, float new_volume);
diff --git a/src/lib.c b/src/lib.c
index 966af57..6a07d1d 100644
--- a/src/lib.c
+++ b/src/lib.c
@@ -1,33 +1,7 @@
-/*
- * mpxgen - FM multiplex encoder with Stereo and RDS
- * Copyright (C) 2021 Anthony96922
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
#include "common.h"
#include "rds.h"
#include
-/*
- * Stuff for RDS
- *
- */
-
-/* needed workaround implicit declaration (edit: do we need this? ) */
-extern int nanosleep(const struct timespec *req, struct timespec *rem);
-
/* millisecond sleep */
void msleep(unsigned long ms) {
struct timespec ts;
@@ -158,22 +132,6 @@ static uint16_t offset_words[] = {
0x350 /* C' */
};
-/* CRC-16 ITU-T/CCITT checkword calculation */
-/* wanna ask where is this used */
-uint16_t crc16(uint8_t *data, size_t len) {
- uint16_t crc = 0xffff;
-
- for (size_t i = 0; i < len; i++) {
- crc = (crc >> 8) | (crc << 8);
- crc ^= data[i];
- crc ^= (crc & 0xff) >> 4;
- crc ^= (crc << 8) << 4;
- crc ^= ((crc & 0xff) << 4) << 1;
- }
-
- return crc ^ 0xffff;
-}
-
/* Calculate the checkword for each block and emit the bits */
void add_checkwords(uint16_t *blocks, uint8_t *bits)
{
diff --git a/src/lib.h b/src/lib.h
index cafbba4..c7008bf 100644
--- a/src/lib.h
+++ b/src/lib.h
@@ -1,21 +1,3 @@
-/*
- * mpxgen - FM multiplex encoder with Stereo and RDS
- * Copyright (C) 2021 Anthony96922
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
extern void msleep(unsigned long ms);
extern size_t _strnlen(const char *s, size_t maxlen);
@@ -26,5 +8,4 @@ extern char *get_rtp_tag_name(uint8_t rtp_tag);
extern void add_checkwords(uint16_t *blocks, uint8_t *bits);
extern uint8_t add_rds_af(struct rds_af_t *af_list, float freq);
extern char *show_af_list(struct rds_af_t af_list);
-extern uint16_t crc16(uint8_t *data, size_t len);
extern unsigned char *xlat(unsigned char *str);
\ No newline at end of file
diff --git a/src/minirds.c b/src/minirds.c
index d441c6f..822015b 100644
--- a/src/minirds.c
+++ b/src/minirds.c
@@ -29,6 +29,8 @@
#include "lib.h"
#include "ascii_cmd.h"
+#define NUM_MPX_FRAMES 512
+
static uint8_t stop_rds;
static void stop() {
@@ -94,8 +96,6 @@ int main(int argc, char **argv) {
.ecc = 0xE2,
.lps = "radio95 - Radio Nowotomyskie"
};
- float volume = 100.0f;
-
/* buffers */
float *mpx_buffer;
int8_t r;
@@ -208,23 +208,19 @@ done_parsing_opts:
pthread_attr_init(&attr);
/* Setup buffers */
- mpx_buffer = malloc(NUM_MPX_FRAMES_IN * 2 * sizeof(float));
+ mpx_buffer = malloc(NUM_MPX_FRAMES * 2 * sizeof(float));
/* Gracefully stop the encoder on SIGINT or SIGTERM */
signal(SIGINT, stop);
signal(SIGTERM, stop);
- /* Initialize the baseband generator */
- fm_mpx_init(MPX_SAMPLE_RATE);
- set_output_volume(volume);
-
/* Initialize the RDS modulator */
init_rds_encoder(rds_params);
/* PASIMPLE format */
format.format = PA_SAMPLE_FLOAT32NE;
format.channels = 1;
- format.rate = OUTPUT_SAMPLE_RATE;
+ format.rate = RDS_SAMPLE_RATE;
device = pa_simple_new(
NULL, // Default PulseAudio server
@@ -264,10 +260,12 @@ done_parsing_opts:
int pulse_error;
for (;;) {
- fm_rds_get_frames(mpx_buffer, NUM_MPX_FRAMES_IN);
+ for (size_t i = 0; i < NUM_MPX_FRAMES; i++) {
+ mpx_buffer[i] = fminf(1.0f, fmaxf(-1.0f, get_rds_sample()));
+ }
/* num_bytes = audio frames( * channels) * bytes per sample */
- if (pa_simple_write(device, mpx_buffer, NUM_MPX_FRAMES_IN * sizeof(float), &pulse_error) != 0) {
+ if (pa_simple_write(device, mpx_buffer, NUM_MPX_FRAMES * sizeof(float), &pulse_error) != 0) {
fprintf(stderr, "Error: could not play audio. (%s : %d)\n", pa_strerror(pulse_error), pulse_error);
break;
}
@@ -288,7 +286,6 @@ exit:
pthread_attr_destroy(&attr);
pa_simple_free(device);
- fm_mpx_exit();
exit_rds_encoder();
free(mpx_buffer);
diff --git a/src/modulator.c b/src/modulator.c
index cb30b46..7ceb9e1 100644
--- a/src/modulator.c
+++ b/src/modulator.c
@@ -1,46 +1,22 @@
-/*
- * mpxgen - FM multiplex encoder with Stereo and RDS
- * Copyright (C) 2021 Anthony96922
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
#include "common.h"
#include "rds.h"
#include "fm_mpx.h"
#include "waveforms.h"
#include "modulator.h"
-static struct rds_t **rds_ctx;
+static struct rds_t *rds;
static float **waveform;
-/*
- * Create the RDS objects
- *
- */
void init_rds_objects() {
- rds_ctx = malloc(sizeof(struct rds_t));
-
- rds_ctx[0] = malloc(sizeof(struct rds_t));
- rds_ctx[0]->bit_buffer = malloc(BITS_PER_GROUP);
- rds_ctx[0]->sample_buffer =
+ rds = malloc(sizeof(struct rds_t));
+ rds->bit_buffer = malloc(BITS_PER_GROUP);
+ rds->sample_buffer =
malloc(SAMPLE_BUFFER_SIZE * sizeof(float));
- rds_ctx[0]->symbol_shift_buf_idx = 0;
waveform = malloc(2 * sizeof(float));
for (uint8_t i = 0; i < 2; i++) {
+ // This is the bpsk, so waveform[0] is 0 degrees out of phase but waveform[1] is 180 degrees, bpsk
waveform[i] = malloc(FILTER_SIZE * sizeof(float));
for (uint16_t j = 0; j < FILTER_SIZE; j++) {
waveform[i][j] = i ?
@@ -50,14 +26,9 @@ void init_rds_objects() {
}
void exit_rds_objects() {
- int has_symbol_shift = rds_ctx[0]->symbol_shift;
- if (has_symbol_shift) {
- free(rds_ctx[0]->symbol_shift_buf);
- }
- free(rds_ctx[0]->sample_buffer);
- free(rds_ctx[0]->bit_buffer);
- free(rds_ctx[0]);
- free(rds_ctx);
+ free(rds->sample_buffer);
+ free(rds->bit_buffer);
+ free(rds);
for (uint8_t i = 0; i < 2; i++) {
free(waveform[i]);
@@ -69,46 +40,33 @@ void exit_rds_objects() {
/* Get an RDS sample. This generates the envelope of the waveform using
* pre-generated elementary waveform samples.
*/
-float get_rds_sample(uint8_t stream_num) {
- struct rds_t *rds;
+float get_rds_sample() {
uint16_t idx;
float *cur_waveform;
float sample;
- /* select context */
- rds = rds_ctx[stream_num];
-
if (rds->sample_count == SAMPLES_PER_BIT) {
+ // New Sample
if (rds->bit_pos == BITS_PER_GROUP) {
+ // New bit stream
get_rds_bits(rds->bit_buffer);
rds->bit_pos = 0;
}
- /* do differential encoding */
+ // Differentially encode, so 1111 becomes 1000 and 0001 becomes 0001
rds->cur_bit = rds->bit_buffer[rds->bit_pos++];
rds->prev_output = rds->cur_output;
rds->cur_output = rds->prev_output ^ rds->cur_bit;
idx = rds->in_sample_index;
- cur_waveform = waveform[rds->cur_output];
+ cur_waveform = waveform[rds->cur_output]; // get the waveform, this is the biphase in a 0/180 degree phase shift
+
+ // Copy over the biphase to the sample buffer, every SAMPLES_PER_BIT
+ for (uint16_t i = 0; i < FILTER_SIZE; i++) {
+ rds->sample_buffer[idx++] += *cur_waveform++;
+ if (idx == SAMPLE_BUFFER_SIZE) idx = 0;
+ }
- uint16_t buffer_remaining = SAMPLE_BUFFER_SIZE - idx;
- if (buffer_remaining >= FILTER_SIZE) {
- // Process continuous chunk
- for (uint16_t i = 0; i < FILTER_SIZE; i++) {
- rds->sample_buffer[idx + i] += cur_waveform[i];
- }
- idx += FILTER_SIZE;
- } else {
- // Process in two parts to handle wrapping
- for (uint16_t i = 0; i < buffer_remaining; i++) {
- rds->sample_buffer[idx + i] += cur_waveform[i];
- }
- for (uint16_t i = 0; i < FILTER_SIZE - buffer_remaining; i++) {
- rds->sample_buffer[i] += cur_waveform[buffer_remaining + i];
- }
- idx = FILTER_SIZE - buffer_remaining;
- }
rds->in_sample_index += SAMPLES_PER_BIT;
if (rds->in_sample_index == SAMPLE_BUFFER_SIZE)
rds->in_sample_index = 0;
@@ -117,20 +75,8 @@ float get_rds_sample(uint8_t stream_num) {
}
rds->sample_count++;
- if (rds->symbol_shift) {
- rds->symbol_shift_buf[rds->symbol_shift_buf_idx++] =
- rds->sample_buffer[rds->out_sample_index];
-
- if (rds->symbol_shift_buf_idx == rds->symbol_shift)
- rds->symbol_shift_buf_idx = 0;
-
- sample = rds->symbol_shift_buf[rds->symbol_shift_buf_idx];
-
- goto done;
- }
-
sample = rds->sample_buffer[rds->out_sample_index];
-done:
+
rds->sample_buffer[rds->out_sample_index++] = 0;
if (rds->out_sample_index == SAMPLE_BUFFER_SIZE)
rds->out_sample_index = 0;
diff --git a/src/modulator.h b/src/modulator.h
index db34124..fa2d395 100644
--- a/src/modulator.h
+++ b/src/modulator.h
@@ -1,21 +1,3 @@
-/*
- * mpxgen - FM multiplex encoder with Stereo and RDS
- * Copyright (C) 2021 Anthony96922
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
/* RDS signal context */
typedef struct rds_t {
uint8_t *bit_buffer; /* BITS_PER_GROUP */
@@ -27,9 +9,6 @@ typedef struct rds_t {
uint8_t sample_count;
uint16_t in_sample_index;
uint16_t out_sample_index;
- uint8_t symbol_shift;
- float *symbol_shift_buf;
- uint8_t symbol_shift_buf_idx;
} rds_t;
extern void init_rds_objects();
diff --git a/src/rds.c b/src/rds.c
index a031c9d..1621a50 100644
--- a/src/rds.c
+++ b/src/rds.c
@@ -1,21 +1,3 @@
-/*
- * mpxgen - FM multiplex encoder with Stereo and RDS
- * Copyright (C) 2019 Anthony96922
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
#include "common.h"
#include "rds.h"
#include "modulator.h"
diff --git a/src/rds.h b/src/rds.h
index 39b1f54..fe3d099 100644
--- a/src/rds.h
+++ b/src/rds.h
@@ -1,21 +1,3 @@
-/*
- * mpxgen - FM multiplex encoder with Stereo and RDS
- * Copyright (C) 2019 Anthony96922
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
#ifndef RDS_H
#define RDS_H
@@ -29,7 +11,7 @@
#define GROUP_LENGTH 4
#define BITS_PER_GROUP (GROUP_LENGTH * (BLOCK_SIZE + POLY_DEG))
#define RDS_SAMPLE_RATE 9500
-#define SAMPLES_PER_BIT 8
+#define SAMPLES_PER_BIT 8
#define FILTER_SIZE 24
#define SAMPLE_BUFFER_SIZE (SAMPLES_PER_BIT + FILTER_SIZE)
@@ -310,7 +292,7 @@ extern void set_rds_tp(uint8_t tp);
extern void set_rds_ms(uint8_t ms);
extern void set_rds_ct(uint8_t ct);
extern void set_rds_di(uint8_t di);
-extern float get_rds_sample(uint8_t stream_num);
+extern float get_rds_sample();
extern uint16_t get_rds_pi();
extern void set_rds_cg(uint16_t* blocks);
diff --git a/src/resampler.c b/src/resampler.c
deleted file mode 100644
index 668a7cd..0000000
--- a/src/resampler.c
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * mpxgen - FM multiplex encoder with Stereo and RDS
- * Copyright (C) 2019 Anthony96922
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-#include "common.h"
-#include "resampler.h"
-
-int8_t resampler_init(SRC_STATE **src_state, uint8_t channels) {
- int src_error;
-
- *src_state = src_new(CONVERTER_TYPE, channels, &src_error);
-
- if (*src_state == NULL) {
- fprintf(stderr, "Error: src_new failed: %s\n", src_strerror(src_error));
- return -1;
- }
-
- return 0;
-}
-
-int8_t resample(SRC_STATE *src_state, SRC_DATA src_data, size_t *frames_generated) {
- int src_error;
-
- src_error = src_process(src_state, &src_data);
-
- if (src_error) {
- fprintf(stderr, "Error: src_process failed: %s\n", src_strerror(src_error));
- return -1;
- }
-
- *frames_generated = src_data.output_frames_gen;
-
- return 0;
-}
-
-void resampler_exit(SRC_STATE *src_state) {
- src_delete(src_state);
-}
diff --git a/src/resampler.h b/src/resampler.h
deleted file mode 100644
index 3be9c47..0000000
--- a/src/resampler.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * mpxgen - FM multiplex encoder with Stereo and RDS
- * Copyright (C) 2019 Anthony96922
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-#include
-
-#define CONVERTER_TYPE SRC_SINC_MEDIUM_QUALITY
-
-extern int8_t resampler_init(SRC_STATE **src_state, uint8_t channels);
-extern int8_t resample(SRC_STATE *src_state, SRC_DATA src_data, size_t *frames_generated);
-extern void resampler_exit(SRC_STATE *src_state);
diff --git a/src/supported_cmds.txt b/src/supported_cmds.txt
index 4251376..6f3cf56 100644
--- a/src/supported_cmds.txt
+++ b/src/supported_cmds.txt
@@ -13,8 +13,6 @@ RT1EN
TA
TP
CT
-LEVEL - Not redecommended, if possible use `MPX`
-RDSGEN
ECC
ECCEN
G
diff --git a/src/uecp_rds_todo.txt b/src/uecp_rds_todo.txt
deleted file mode 100644
index fcfc7d4..0000000
--- a/src/uecp_rds_todo.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-This aims to have the around the same options as UECP should have, this is what is not yet implemented:
-- PIN (low priority, how do i decode that?)
-- EON AF (very low priority)
-- Linkage information (very low priority)
-- (ODA skipped)
-- TDC (low priority)
-- EWS (how do i even implement that? can someone give docs?)
-- IH (low priority)
-- (Paging skipped)
-- (No CT time adjustments)
-- RDS on/off (low priority)
-- RDS phase (might be medium, 9.5 degree steps)
-- (ARI skipped)
-
-Others:
-- Encoder identification (site and encoder address)
-- (PSN skipped)
-- (EON skipped)
-- Data set select
-- Group sequence
-- (other sequence related comamnds skipped)
diff --git a/src/waveforms.c b/src/waveforms.c
index d615df6..78e2b96 100644
--- a/src/waveforms.c
+++ b/src/waveforms.c
@@ -1,7 +1,8 @@
/* This file was automatically generated by "gen_wave.py".
(C) 2014 Christophe Jacquet.
- Modified by kuba201
+ (C) 2023 Anthony96922.
+ (C) 2025 kuba201.
Released under the GNU GPL v3 license.
*/
diff --git a/src/waveforms.h b/src/waveforms.h
index 67bab7e..c657cad 100644
--- a/src/waveforms.h
+++ b/src/waveforms.h
@@ -1,7 +1,8 @@
/* This file was automatically generated by "gen_wave.py".
(C) 2014 Christophe Jacquet.
- Modified by kuba201
+ (C) 2023 Anthony96922.
+ (C) 2025 kuba201.
Released under the GNU GPL v3 license.
*/
diff --git a/waveform/Pydemod/README.md b/waveform/Pydemod/README.md
deleted file mode 100644
index 73ccf90..0000000
--- a/waveform/Pydemod/README.md
+++ /dev/null
@@ -1,11 +0,0 @@
-Pydemod
--------
-
-Pydemod is a set of Python libraries and tools for demodulating radio signals. It does not intend to compete with full-featured packages such as GNU Radio. Instead, it strives to allow radio enthusiasts to gain hands-on experience with modulation schemes.
-
-Pydemod relies on [NumPy](http://numpy.scipy.org/)/[SciPy](http://www.scipy.org/).
-
-Pydemod is licensed under the terms of the [GNU GPL v3](https://www.gnu.org/copyleft/gpl.html).
-
-----
-_Pydemod is developed by [Christophe Jacquet](http://www.jacquet80.eu/), [F8FTK](http://f8ftk.tk)._
diff --git a/waveform/Pydemod/src/gen_wave.py b/waveform/Pydemod/src/gen_wave.py
deleted file mode 100644
index ff10395..0000000
--- a/waveform/Pydemod/src/gen_wave.py
+++ /dev/null
@@ -1,81 +0,0 @@
-#!/usr/bin/python
-
-
-# PiFmRds - FM/RDS transmitter for the Raspberry Pi
-# Copyright (C) 2014 Christophe Jacquet, F8FTK
-#
-# See https://github.com/ChristopheJacquet/PiFmRds
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program 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 General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-
-# This program generates the waveform of a single biphase symbol
-#
-# This program uses Pydemod, see https://github.com/ChristopheJacquet/Pydemod
-
-import pydemod.app.rds as rds
-import numpy
-import io
-import matplotlib.pyplot as plt
-
-sample_rate = 9500
-
-outc = io.open("waveforms.c", mode="w", encoding="utf8")
-outh = io.open("waveforms.h", mode="w", encoding="utf8")
-
-header = u"""
-/* This file was automatically generated by "gen_wave.py".
- (C) 2014 Christophe Jacquet.
- Modified by kuba201
- Released under the GNU GPL v3 license.
-*/
-
-"""
-
-outc.write(header)
-outh.write(header)
-
-def generate_bit(name):
- offset = int(sample_rate*0.004) # 190 khz = 760
- count = int(offset / 10**(len(str(offset)) - 1)) # 760 / 100 = 7
- l = int(sample_rate / 1187.5) // 2 # 16/2 = 8
- if l == 1: raise Exception("Sample rate too small")
-
- sample = numpy.zeros(count*l)
- sample[l] = 1
- sample[2*l] = -1
-
- # Apply the data-shaping filter
- sf = rds.pulse_shaping_filter(l*16, sample_rate-1)
- shapedSamples = numpy.convolve(sample, sf)
-
- out = shapedSamples[offset-l*count:offset+l*count] #[offset:offset+l*count]
- #plt.plot(sf)
- #plt.plot(shapedSamples)
- plt.plot(out)
- plt.show()
-
- outc.write(u"float waveform_{name}[{size}] = {{{values}}};\n\n".format(
- name = name,
- values = u", ".join(map(str, out / 2.5)),
- size = len(out)))
- # note: need to limit the amplitude so as not to saturate when the biphase
- # waveforms are summed
-
- outh.write(u"extern float waveform_{name}[{size}];\n".format(name=name, size=len(out)))
-
-
-generate_bit("biphase")
-
-outc.close()
-outh.close()
\ No newline at end of file
diff --git a/waveform/Pydemod/src/pydemod/__init__.py b/waveform/Pydemod/src/pydemod/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/waveform/Pydemod/src/pydemod/app/__init__.py b/waveform/Pydemod/src/pydemod/app/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/waveform/Pydemod/src/pydemod/app/rds.py b/waveform/Pydemod/src/pydemod/app/rds.py
deleted file mode 100644
index 2d45dd9..0000000
--- a/waveform/Pydemod/src/pydemod/app/rds.py
+++ /dev/null
@@ -1,11 +0,0 @@
-# This file is part of Pydemod
-# Copyright Christophe Jacquet (F8FTK), 2014
-# Licence: GNU GPL v3
-# See: https://github.com/ChristopheJacquet/Pydemod
-
-import numpy
-
-import pydemod.filters.shaping as shaping
-
-def pulse_shaping_filter(length, sample_rate):
- return shaping.rrcosfilter(length, 1, 1/(2*1187.5), sample_rate+1) [1]
\ No newline at end of file
diff --git a/waveform/Pydemod/src/pydemod/filters/__init__.py b/waveform/Pydemod/src/pydemod/filters/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/waveform/Pydemod/src/pydemod/filters/shaping.py b/waveform/Pydemod/src/pydemod/filters/shaping.py
deleted file mode 100644
index 29766d6..0000000
--- a/waveform/Pydemod/src/pydemod/filters/shaping.py
+++ /dev/null
@@ -1,64 +0,0 @@
-# This file is part of Pydemod
-# Copyright Christophe Jacquet (F8FTK), 2014
-# Licence: GNU GPL v3
-# See: https://github.com/ChristopheJacquet/Pydemod
-#
-# Contains code from CommPy, used under the terms of the GPL
-# https://github.com/veeresht/CommPy/blob/master/commpy/filters.py
-# (c) 2012 Veeresh Taranalli
-
-import numpy
-
-# The following function is from:
-# https://github.com/veeresht/CommPy/blob/master/commpy/filters.py
-# See also: https://en.wikipedia.org/wiki/Root-raised-cosine_filter
-def rrcosfilter(N, alpha, Ts, Fs):
- """
- Generates a root raised cosine (RRC) filter (FIR) impulse response.
-
- Parameters
- ----------
- N : int
- Length of the filter in samples.
-
- alpha: float
- Roll off factor (Valid values are [0, 1]).
-
- Ts : float
- Symbol period in seconds.
-
- Fs : float
- Sampling Rate in Hz.
-
- Returns
- ---------
-
- h_rrc : 1-D ndarray of floats
- Impulse response of the root raised cosine filter.
-
- time_idx : 1-D ndarray of floats
- Array containing the time indices, in seconds, for
- the impulse response.
- """
-
- T_delta = 1/float(Fs)
- time_idx = ((numpy.arange(N)-N/2))*T_delta
- sample_num = numpy.arange(N)
- h_rrc = numpy.zeros(N, dtype=float)
-
- for x in sample_num:
- t = (x-N/2)*T_delta
- if t == 0.0:
- h_rrc[x] = 1.0 - alpha + (4*alpha/numpy.pi)
- elif alpha != 0 and t == Ts/(4*alpha):
- h_rrc[x] = (alpha/numpy.sqrt(2))*(((1+2/numpy.pi)* \
- (numpy.sin(numpy.pi/(4*alpha)))) + ((1-2/numpy.pi)*(numpy.cos(numpy.pi/(4*alpha)))))
- elif alpha != 0 and t == -Ts/(4*alpha):
- h_rrc[x] = (alpha/numpy.sqrt(2))*(((1+2/numpy.pi)* \
- (numpy.sin(numpy.pi/(4*alpha)))) + ((1-2/numpy.pi)*(numpy.cos(numpy.pi/(4*alpha)))))
- else:
- h_rrc[x] = (numpy.sin(numpy.pi*t*(1-alpha)/Ts) + \
- 4*alpha*(t/Ts)*numpy.cos(numpy.pi*t*(1+alpha)/Ts))/ \
- (numpy.pi*t*(1-(4*alpha*t/Ts)*(4*alpha*t/Ts))/Ts)
-
- return time_idx, h_rrc
diff --git a/waveform/Pydemod/src/waveforms.c b/waveform/Pydemod/src/waveforms.c
deleted file mode 100644
index f91b354..0000000
--- a/waveform/Pydemod/src/waveforms.c
+++ /dev/null
@@ -1,8 +0,0 @@
-
-/* This file was automatically generated by "generate_waveforms.py".
- (C) 2014 Christophe Jacquet.
- Released under the GNU GPL v3 license.
-*/
-
-float waveform_biphase[24] = {0.002532628775852384, -6.480266785053461e-18, -0.004522551385450683, 2.807603181808536e-17, 0.00940690688173742, -2.1836329850641248e-17, -0.025868993924777907, -1.1701083086090883e-17, 0.1552139635486674, 0.4, 0.5432488724203361, 0.4, 0.0, -0.4, -0.5432488724203361, -0.4, -0.1552139635486674, 1.1701083086090883e-17, 0.025868993924777907, 2.1836329850641248e-17, -0.00940690688173742, -2.807603181808536e-17, 0.004522551385450683, 6.480266785053461e-18};
-
diff --git a/waveform/Pydemod/src/waveforms.h b/waveform/Pydemod/src/waveforms.h
deleted file mode 100644
index 17eae23..0000000
--- a/waveform/Pydemod/src/waveforms.h
+++ /dev/null
@@ -1,7 +0,0 @@
-
-/* This file was automatically generated by "generate_waveforms.py".
- (C) 2014 Christophe Jacquet.
- Released under the GNU GPL v3 license.
-*/
-
-extern float waveform_biphase[24];