mirror of
https://github.com/radio95-rnt/rds95.git
synced 2026-02-27 04:43:52 +01:00
remove unused files and clean up codebase
This commit is contained in:
92
gen_wave.py
Normal file
92
gen_wave.py
Normal file
@@ -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()
|
||||||
@@ -1,5 +1,3 @@
|
|||||||
# This is from kuba's version of MiniRDS
|
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.10)
|
cmake_minimum_required(VERSION 3.10)
|
||||||
|
|
||||||
# Project name and version
|
# Project name and version
|
||||||
@@ -8,10 +6,6 @@ project(minirds VERSION 1.0)
|
|||||||
# Define options
|
# Define options
|
||||||
option(ODA_RTP "Enable ODA (RT+)" ON)
|
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 compiler and flags
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Werror -Wextra -pedantic -O2 -std=c18 -DVERSION=\"${PROJECT_VERSION}\"")
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Werror -Wextra -pedantic -O2 -std=c18 -DVERSION=\"${PROJECT_VERSION}\"")
|
||||||
|
|
||||||
@@ -29,9 +23,7 @@ endif()
|
|||||||
|
|
||||||
set(SOURCES
|
set(SOURCES
|
||||||
${SOURCES}
|
${SOURCES}
|
||||||
fm_mpx.c
|
|
||||||
control_pipe.c
|
control_pipe.c
|
||||||
resampler.c
|
|
||||||
modulator.c
|
modulator.c
|
||||||
lib.c
|
lib.c
|
||||||
ascii_cmd.c
|
ascii_cmd.c
|
||||||
@@ -40,20 +32,8 @@ set(SOURCES
|
|||||||
# Define the executable
|
# Define the executable
|
||||||
add_executable(minirds ${SOURCES})
|
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
|
# Link additional libraries
|
||||||
target_link_libraries(minirds PRIVATE m pthread pulse pulse-simple)
|
target_link_libraries(minirds PRIVATE m pthread pulse pulse-simple)
|
||||||
|
|
||||||
# Install target
|
# Install target
|
||||||
install(TARGETS minirds DESTINATION /usr/local/bin)
|
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")
|
|
||||||
@@ -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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "rds.h"
|
#include "rds.h"
|
||||||
#include "fm_mpx.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) {
|
if(cmd_len == 5) {
|
||||||
cmd = str;
|
cmd = str;
|
||||||
if(CMD_MATCHES("AFCH=")) {
|
if(CMD_MATCHES("AFCH=")) {
|
||||||
@@ -316,25 +274,12 @@ void process_ascii_cmd(unsigned char *str) {
|
|||||||
cmd = str;
|
cmd = str;
|
||||||
cmd[5] = 0;
|
cmd[5] = 0;
|
||||||
arg = str + 6;
|
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] == '=') {
|
if (cmd_len > 7 && str[6] == '=') {
|
||||||
cmd = str;
|
cmd = str;
|
||||||
cmd[6] = 0;
|
cmd[6] = 0;
|
||||||
arg = str + 7;
|
arg = str + 7;
|
||||||
|
|
||||||
if (CMD_MATCHES("RDSGEN")) {
|
|
||||||
arg[1] = 0;
|
|
||||||
set_rdsgen(strtoul((char *)arg, NULL, 10));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CMD_MATCHES("PTYNEN")) {
|
if (CMD_MATCHES("PTYNEN")) {
|
||||||
arg[1] = 0;
|
arg[1] = 0;
|
||||||
set_rds_ptyn_enabled(strtoul((char *)arg, NULL, 10));
|
set_rds_ptyn_enabled(strtoul((char *)arg, NULL, 10));
|
||||||
@@ -353,14 +298,6 @@ void process_ascii_cmd(unsigned char *str) {
|
|||||||
cmd = str;
|
cmd = str;
|
||||||
cmd[5] = 0;
|
cmd[5] = 0;
|
||||||
arg = str + 6;
|
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")) {
|
if (CMD_MATCHES("ECCEN")) {
|
||||||
set_rds_ecclic_toggle(arg[0]);
|
set_rds_ecclic_toggle(arg[0]);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define CMD_BUFFER_SIZE 255
|
#define CMD_BUFFER_SIZE 255
|
||||||
#define CTL_BUFFER_SIZE (CMD_BUFFER_SIZE * 2)
|
#define CTL_BUFFER_SIZE (CMD_BUFFER_SIZE * 2)
|
||||||
#define READ_TIMEOUT_MS 100
|
#define READ_TIMEOUT_MS 100
|
||||||
|
|||||||
20
src/common.h
20
src/common.h
@@ -1,22 +1,4 @@
|
|||||||
/*
|
/* common includes for rds95 */
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* common includes for mpxgen */
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "ascii_cmd.h"
|
#include "ascii_cmd.h"
|
||||||
#include "control_pipe.h"
|
#include "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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
#include <sys/select.h>
|
#include <sys/select.h>
|
||||||
|
|||||||
70
src/fm_mpx.c
70
src/fm_mpx.c
@@ -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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#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;
|
|
||||||
}
|
|
||||||
34
src/fm_mpx.h
34
src/fm_mpx.h
@@ -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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* 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);
|
|
||||||
42
src/lib.c
42
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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "rds.h"
|
#include "rds.h"
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
/*
|
|
||||||
* Stuff for RDS
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* needed workaround implicit declaration (edit: do we need this? ) */
|
|
||||||
extern int nanosleep(const struct timespec *req, struct timespec *rem);
|
|
||||||
|
|
||||||
/* millisecond sleep */
|
/* millisecond sleep */
|
||||||
void msleep(unsigned long ms) {
|
void msleep(unsigned long ms) {
|
||||||
struct timespec ts;
|
struct timespec ts;
|
||||||
@@ -158,22 +132,6 @@ static uint16_t offset_words[] = {
|
|||||||
0x350 /* C' */
|
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 */
|
/* Calculate the checkword for each block and emit the bits */
|
||||||
void add_checkwords(uint16_t *blocks, uint8_t *bits)
|
void add_checkwords(uint16_t *blocks, uint8_t *bits)
|
||||||
{
|
{
|
||||||
|
|||||||
19
src/lib.h
19
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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
extern void msleep(unsigned long ms);
|
extern void msleep(unsigned long ms);
|
||||||
|
|
||||||
extern size_t _strnlen(const char *s, size_t maxlen);
|
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 void add_checkwords(uint16_t *blocks, uint8_t *bits);
|
||||||
extern uint8_t add_rds_af(struct rds_af_t *af_list, float freq);
|
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 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);
|
extern unsigned char *xlat(unsigned char *str);
|
||||||
@@ -29,6 +29,8 @@
|
|||||||
#include "lib.h"
|
#include "lib.h"
|
||||||
#include "ascii_cmd.h"
|
#include "ascii_cmd.h"
|
||||||
|
|
||||||
|
#define NUM_MPX_FRAMES 512
|
||||||
|
|
||||||
static uint8_t stop_rds;
|
static uint8_t stop_rds;
|
||||||
|
|
||||||
static void stop() {
|
static void stop() {
|
||||||
@@ -94,8 +96,6 @@ int main(int argc, char **argv) {
|
|||||||
.ecc = 0xE2,
|
.ecc = 0xE2,
|
||||||
.lps = "radio95 - Radio Nowotomyskie"
|
.lps = "radio95 - Radio Nowotomyskie"
|
||||||
};
|
};
|
||||||
float volume = 100.0f;
|
|
||||||
|
|
||||||
/* buffers */
|
/* buffers */
|
||||||
float *mpx_buffer;
|
float *mpx_buffer;
|
||||||
int8_t r;
|
int8_t r;
|
||||||
@@ -208,23 +208,19 @@ done_parsing_opts:
|
|||||||
pthread_attr_init(&attr);
|
pthread_attr_init(&attr);
|
||||||
|
|
||||||
/* Setup buffers */
|
/* 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 */
|
/* Gracefully stop the encoder on SIGINT or SIGTERM */
|
||||||
signal(SIGINT, stop);
|
signal(SIGINT, stop);
|
||||||
signal(SIGTERM, stop);
|
signal(SIGTERM, stop);
|
||||||
|
|
||||||
/* Initialize the baseband generator */
|
|
||||||
fm_mpx_init(MPX_SAMPLE_RATE);
|
|
||||||
set_output_volume(volume);
|
|
||||||
|
|
||||||
/* Initialize the RDS modulator */
|
/* Initialize the RDS modulator */
|
||||||
init_rds_encoder(rds_params);
|
init_rds_encoder(rds_params);
|
||||||
|
|
||||||
/* PASIMPLE format */
|
/* PASIMPLE format */
|
||||||
format.format = PA_SAMPLE_FLOAT32NE;
|
format.format = PA_SAMPLE_FLOAT32NE;
|
||||||
format.channels = 1;
|
format.channels = 1;
|
||||||
format.rate = OUTPUT_SAMPLE_RATE;
|
format.rate = RDS_SAMPLE_RATE;
|
||||||
|
|
||||||
device = pa_simple_new(
|
device = pa_simple_new(
|
||||||
NULL, // Default PulseAudio server
|
NULL, // Default PulseAudio server
|
||||||
@@ -264,10 +260,12 @@ done_parsing_opts:
|
|||||||
int pulse_error;
|
int pulse_error;
|
||||||
|
|
||||||
for (;;) {
|
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 */
|
/* 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);
|
fprintf(stderr, "Error: could not play audio. (%s : %d)\n", pa_strerror(pulse_error), pulse_error);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -288,7 +286,6 @@ exit:
|
|||||||
|
|
||||||
pthread_attr_destroy(&attr);
|
pthread_attr_destroy(&attr);
|
||||||
pa_simple_free(device);
|
pa_simple_free(device);
|
||||||
fm_mpx_exit();
|
|
||||||
exit_rds_encoder();
|
exit_rds_encoder();
|
||||||
|
|
||||||
free(mpx_buffer);
|
free(mpx_buffer);
|
||||||
|
|||||||
@@ -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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "rds.h"
|
#include "rds.h"
|
||||||
#include "fm_mpx.h"
|
#include "fm_mpx.h"
|
||||||
#include "waveforms.h"
|
#include "waveforms.h"
|
||||||
#include "modulator.h"
|
#include "modulator.h"
|
||||||
|
|
||||||
static struct rds_t **rds_ctx;
|
static struct rds_t *rds;
|
||||||
static float **waveform;
|
static float **waveform;
|
||||||
|
|
||||||
/*
|
|
||||||
* Create the RDS objects
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
void init_rds_objects() {
|
void init_rds_objects() {
|
||||||
rds_ctx = malloc(sizeof(struct rds_t));
|
rds = malloc(sizeof(struct rds_t));
|
||||||
|
rds->bit_buffer = malloc(BITS_PER_GROUP);
|
||||||
rds_ctx[0] = malloc(sizeof(struct rds_t));
|
rds->sample_buffer =
|
||||||
rds_ctx[0]->bit_buffer = malloc(BITS_PER_GROUP);
|
|
||||||
rds_ctx[0]->sample_buffer =
|
|
||||||
malloc(SAMPLE_BUFFER_SIZE * sizeof(float));
|
malloc(SAMPLE_BUFFER_SIZE * sizeof(float));
|
||||||
rds_ctx[0]->symbol_shift_buf_idx = 0;
|
|
||||||
|
|
||||||
waveform = malloc(2 * sizeof(float));
|
waveform = malloc(2 * sizeof(float));
|
||||||
|
|
||||||
for (uint8_t i = 0; i < 2; i++) {
|
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));
|
waveform[i] = malloc(FILTER_SIZE * sizeof(float));
|
||||||
for (uint16_t j = 0; j < FILTER_SIZE; j++) {
|
for (uint16_t j = 0; j < FILTER_SIZE; j++) {
|
||||||
waveform[i][j] = i ?
|
waveform[i][j] = i ?
|
||||||
@@ -50,14 +26,9 @@ void init_rds_objects() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void exit_rds_objects() {
|
void exit_rds_objects() {
|
||||||
int has_symbol_shift = rds_ctx[0]->symbol_shift;
|
free(rds->sample_buffer);
|
||||||
if (has_symbol_shift) {
|
free(rds->bit_buffer);
|
||||||
free(rds_ctx[0]->symbol_shift_buf);
|
free(rds);
|
||||||
}
|
|
||||||
free(rds_ctx[0]->sample_buffer);
|
|
||||||
free(rds_ctx[0]->bit_buffer);
|
|
||||||
free(rds_ctx[0]);
|
|
||||||
free(rds_ctx);
|
|
||||||
|
|
||||||
for (uint8_t i = 0; i < 2; i++) {
|
for (uint8_t i = 0; i < 2; i++) {
|
||||||
free(waveform[i]);
|
free(waveform[i]);
|
||||||
@@ -69,46 +40,33 @@ void exit_rds_objects() {
|
|||||||
/* Get an RDS sample. This generates the envelope of the waveform using
|
/* Get an RDS sample. This generates the envelope of the waveform using
|
||||||
* pre-generated elementary waveform samples.
|
* pre-generated elementary waveform samples.
|
||||||
*/
|
*/
|
||||||
float get_rds_sample(uint8_t stream_num) {
|
float get_rds_sample() {
|
||||||
struct rds_t *rds;
|
|
||||||
uint16_t idx;
|
uint16_t idx;
|
||||||
float *cur_waveform;
|
float *cur_waveform;
|
||||||
float sample;
|
float sample;
|
||||||
|
|
||||||
/* select context */
|
|
||||||
rds = rds_ctx[stream_num];
|
|
||||||
|
|
||||||
if (rds->sample_count == SAMPLES_PER_BIT) {
|
if (rds->sample_count == SAMPLES_PER_BIT) {
|
||||||
|
// New Sample
|
||||||
if (rds->bit_pos == BITS_PER_GROUP) {
|
if (rds->bit_pos == BITS_PER_GROUP) {
|
||||||
|
// New bit stream
|
||||||
get_rds_bits(rds->bit_buffer);
|
get_rds_bits(rds->bit_buffer);
|
||||||
rds->bit_pos = 0;
|
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->cur_bit = rds->bit_buffer[rds->bit_pos++];
|
||||||
rds->prev_output = rds->cur_output;
|
rds->prev_output = rds->cur_output;
|
||||||
rds->cur_output = rds->prev_output ^ rds->cur_bit;
|
rds->cur_output = rds->prev_output ^ rds->cur_bit;
|
||||||
|
|
||||||
idx = rds->in_sample_index;
|
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;
|
rds->in_sample_index += SAMPLES_PER_BIT;
|
||||||
if (rds->in_sample_index == SAMPLE_BUFFER_SIZE)
|
if (rds->in_sample_index == SAMPLE_BUFFER_SIZE)
|
||||||
rds->in_sample_index = 0;
|
rds->in_sample_index = 0;
|
||||||
@@ -117,20 +75,8 @@ float get_rds_sample(uint8_t stream_num) {
|
|||||||
}
|
}
|
||||||
rds->sample_count++;
|
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];
|
sample = rds->sample_buffer[rds->out_sample_index];
|
||||||
done:
|
|
||||||
rds->sample_buffer[rds->out_sample_index++] = 0;
|
rds->sample_buffer[rds->out_sample_index++] = 0;
|
||||||
if (rds->out_sample_index == SAMPLE_BUFFER_SIZE)
|
if (rds->out_sample_index == SAMPLE_BUFFER_SIZE)
|
||||||
rds->out_sample_index = 0;
|
rds->out_sample_index = 0;
|
||||||
|
|||||||
@@ -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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* RDS signal context */
|
/* RDS signal context */
|
||||||
typedef struct rds_t {
|
typedef struct rds_t {
|
||||||
uint8_t *bit_buffer; /* BITS_PER_GROUP */
|
uint8_t *bit_buffer; /* BITS_PER_GROUP */
|
||||||
@@ -27,9 +9,6 @@ typedef struct rds_t {
|
|||||||
uint8_t sample_count;
|
uint8_t sample_count;
|
||||||
uint16_t in_sample_index;
|
uint16_t in_sample_index;
|
||||||
uint16_t out_sample_index;
|
uint16_t out_sample_index;
|
||||||
uint8_t symbol_shift;
|
|
||||||
float *symbol_shift_buf;
|
|
||||||
uint8_t symbol_shift_buf_idx;
|
|
||||||
} rds_t;
|
} rds_t;
|
||||||
|
|
||||||
extern void init_rds_objects();
|
extern void init_rds_objects();
|
||||||
|
|||||||
18
src/rds.c
18
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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "rds.h"
|
#include "rds.h"
|
||||||
#include "modulator.h"
|
#include "modulator.h"
|
||||||
|
|||||||
22
src/rds.h
22
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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef RDS_H
|
#ifndef RDS_H
|
||||||
#define RDS_H
|
#define RDS_H
|
||||||
|
|
||||||
@@ -29,7 +11,7 @@
|
|||||||
#define GROUP_LENGTH 4
|
#define GROUP_LENGTH 4
|
||||||
#define BITS_PER_GROUP (GROUP_LENGTH * (BLOCK_SIZE + POLY_DEG))
|
#define BITS_PER_GROUP (GROUP_LENGTH * (BLOCK_SIZE + POLY_DEG))
|
||||||
#define RDS_SAMPLE_RATE 9500
|
#define RDS_SAMPLE_RATE 9500
|
||||||
#define SAMPLES_PER_BIT 8
|
#define SAMPLES_PER_BIT 8
|
||||||
#define FILTER_SIZE 24
|
#define FILTER_SIZE 24
|
||||||
#define SAMPLE_BUFFER_SIZE (SAMPLES_PER_BIT + FILTER_SIZE)
|
#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_ms(uint8_t ms);
|
||||||
extern void set_rds_ct(uint8_t ct);
|
extern void set_rds_ct(uint8_t ct);
|
||||||
extern void set_rds_di(uint8_t di);
|
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 uint16_t get_rds_pi();
|
||||||
extern void set_rds_cg(uint16_t* blocks);
|
extern void set_rds_cg(uint16_t* blocks);
|
||||||
|
|
||||||
|
|||||||
@@ -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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#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);
|
|
||||||
}
|
|
||||||
@@ -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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <samplerate.h>
|
|
||||||
|
|
||||||
#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);
|
|
||||||
@@ -13,8 +13,6 @@ RT1EN
|
|||||||
TA
|
TA
|
||||||
TP
|
TP
|
||||||
CT
|
CT
|
||||||
LEVEL - Not redecommended, if possible use `MPX`
|
|
||||||
RDSGEN
|
|
||||||
ECC
|
ECC
|
||||||
ECCEN
|
ECCEN
|
||||||
G
|
G
|
||||||
|
|||||||
@@ -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)
|
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
|
|
||||||
/* This file was automatically generated by "gen_wave.py".
|
/* This file was automatically generated by "gen_wave.py".
|
||||||
(C) 2014 Christophe Jacquet.
|
(C) 2014 Christophe Jacquet.
|
||||||
Modified by kuba201
|
(C) 2023 Anthony96922.
|
||||||
|
(C) 2025 kuba201.
|
||||||
Released under the GNU GPL v3 license.
|
Released under the GNU GPL v3 license.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
|
|
||||||
/* This file was automatically generated by "gen_wave.py".
|
/* This file was automatically generated by "gen_wave.py".
|
||||||
(C) 2014 Christophe Jacquet.
|
(C) 2014 Christophe Jacquet.
|
||||||
Modified by kuba201
|
(C) 2023 Anthony96922.
|
||||||
|
(C) 2025 kuba201.
|
||||||
Released under the GNU GPL v3 license.
|
Released under the GNU GPL v3 license.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -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)._
|
|
||||||
@@ -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 <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
# 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()
|
|
||||||
@@ -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]
|
|
||||||
@@ -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
|
|
||||||
@@ -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};
|
|
||||||
|
|
||||||
@@ -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];
|
|
||||||
Reference in New Issue
Block a user