libsstvenc
Asynchronous Analogue SSTV encoder
Loading...
Searching...
No Matches
SSTV modulator

Data Structures

struct  sstvenc_mod
 

Functions

void sstvenc_modulator_init (struct sstvenc_mod *const mod, const struct sstvenc_mode *mode, const char *fsk_id, const uint8_t *framebuffer, double rise_time, double fall_time, uint32_t sample_rate, uint8_t time_unit)
 
void sstvenc_modulator_compute (struct sstvenc_mod *const mod)
 
size_t sstvenc_modulator_fill_buffer (struct sstvenc_mod *const mod, double *buffer, size_t buffer_sz)
 
static void sstvenc_modulator_next_rise_sample (struct sstvenc_mod *const mod)
 
static void sstvenc_modulator_next_tone (struct sstvenc_mod *const mod)
 
static void sstvenc_modulator_next_hold_sample (struct sstvenc_mod *const mod)
 
static void sstvenc_modulator_next_fall_sample (struct sstvenc_mod *const mod)
 

Detailed Description

This uses the SSTV encoder defined in SSTV encoder and combines it with an oscillator from Oscillator implementation and a pulse shaper from Pulse Shaper.

Additional logic is supplied to handle time-quantisation jitter that arises due to the discrete sampling intervals.

Like the SSTV encoder component this is built on, the state machine state is determined by observing sstvenc_mod::ps, in particular, the phase member and comparing that to Pulse Shaper States. When the value matches SSTVENC_PS_PHASE_DONE, no more meaningful samples will be emitted.

The output is returned by the oscillator instance: sstvenc_mod::osc via its output member.


Data Structure Documentation

◆ sstvenc_mod

struct sstvenc_mod

SSTV modulator data structure.

Definition at line 38 of file sstvmod.h.

Collaboration diagram for sstvenc_mod:
Data Fields
struct sstvenc_encoder enc

SSTV encoder state machine

struct sstvenc_oscillator osc

Frequency modulation oscillator

struct sstvenc_pulseshape ps

Pulse shaper

uint32_t remaining

Remaining number of samples needed to correct timing

uint64_t total_ns

Total time period in nanoseconds emitted

uint64_t total_samples

Total audio samples emitted

Function Documentation

◆ sstvenc_modulator_compute()

void sstvenc_modulator_compute ( struct sstvenc_mod *const mod)

Compute the next audio sample to be emitted from the modulator.

Definition at line 125 of file sstvmod.c.

125 {
126 switch (mod->ps.phase) {
129 /* Rising initial pulse */
131 break;
133 /* SSTV encoding state */
135 break;
137 /* Falling final pulse */
139 break;
140 default:
141 /* We're done */
142 mod->osc.output = 0.0;
143 break;
144 }
145}
#define SSTVENC_PS_PHASE_HOLD
Definition pulseshape.h:58
#define SSTVENC_PS_PHASE_FALL
Definition pulseshape.h:67
#define SSTVENC_PS_PHASE_INIT
Definition pulseshape.h:35
#define SSTVENC_PS_PHASE_RISE
Definition pulseshape.h:44
struct sstvenc_oscillator osc
Definition sstvmod.h:42
struct sstvenc_pulseshape ps
Definition sstvmod.h:44
static void sstvenc_modulator_next_rise_sample(struct sstvenc_mod *const mod)
Definition sstvmod.c:37
static void sstvenc_modulator_next_hold_sample(struct sstvenc_mod *const mod)
Definition sstvmod.c:91
static void sstvenc_modulator_next_fall_sample(struct sstvenc_mod *const mod)
Definition sstvmod.c:119

References sstvenc_mod::osc, sstvenc_oscillator::output, sstvenc_pulseshape::phase, sstvenc_mod::ps, sstvenc_modulator_next_fall_sample(), sstvenc_modulator_next_hold_sample(), sstvenc_modulator_next_rise_sample(), SSTVENC_PS_PHASE_FALL, SSTVENC_PS_PHASE_HOLD, SSTVENC_PS_PHASE_INIT, and SSTVENC_PS_PHASE_RISE.

Referenced by main(), sstvenc_modulator_fill_buffer(), and sstvenc_sequencer_compute().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ sstvenc_modulator_fill_buffer()

size_t sstvenc_modulator_fill_buffer ( struct sstvenc_mod *const mod,
double * buffer,
size_t buffer_sz )

Fill the given buffer with audio samples from the SSTV modulator. Stop if we run out of buffer space or if the SSTV state machine finishes. Return the number of samples generated.

Parameters
[in,out]modSSTV modulator state machine to pull samples from.
[out]bufferAudio buffer to write samples to.
[in]buffer_szSize of the audio buffer in samples.
Returns
Number of samples written to buffer

Definition at line 147 of file sstvmod.c.

148 {
149 size_t written_sz = 0;
150
151 while ((buffer_sz > 0) && (mod->ps.phase < SSTVENC_PS_PHASE_DONE)) {
153
154 buffer[0] = mod->osc.output;
155 buffer++;
156 buffer_sz--;
157
158 written_sz++;
159 }
160
161 return written_sz;
162}
#define SSTVENC_PS_PHASE_DONE
Definition pulseshape.h:75
void sstvenc_modulator_compute(struct sstvenc_mod *const mod)
Definition sstvmod.c:125

References sstvenc_mod::osc, sstvenc_oscillator::output, sstvenc_pulseshape::phase, sstvenc_mod::ps, sstvenc_modulator_compute(), and SSTVENC_PS_PHASE_DONE.

Here is the call graph for this function:

◆ sstvenc_modulator_init()

void sstvenc_modulator_init ( struct sstvenc_mod *const mod,
const struct sstvenc_mode * mode,
const char * fsk_id,
const uint8_t * framebuffer,
double rise_time,
double fall_time,
uint32_t sample_rate,
uint8_t time_unit )

Initialise the SSTV modulator with the given parameters.

Parameters
[in,out]modSSTV modulator context to initialise
[in]modeSSTV mode to encode
[in]fsk_idFSK ID to send at the end, NULL to disable.
[in]framebufferFramebuffer data representing the image.
[in]rise_timeCarrier rise time, set to 0 to disable.
[in]fall_timeCarrier fall time, set to 0 to disable.
[in]sample_rateSample rate in Hz
[in]time_unitTime unit used to measure rise_time and fall_time.

Definition at line 14 of file sstvmod.c.

18 {
19 /* Initialise the data structures */
20 sstvenc_encoder_init(&(mod->enc), mode, fsk_id, framebuffer);
21 sstvenc_osc_init(&(mod->osc), 1.0, SSTVENC_FREQ_SYNC, 0.0,
22 sample_rate);
23 sstvenc_ps_init(&(mod->ps), 1.0, rise_time, INFINITY, fall_time,
24 sample_rate, time_unit);
25
26 /* Clear the state machine */
27 mod->total_samples = 0;
28 mod->total_ns = 0;
29 mod->remaining = 0;
30}
void sstvenc_osc_init(struct sstvenc_oscillator *const osc, double amplitude, double frequency, double offset, uint32_t sample_rate)
Definition oscillator.c:42
void sstvenc_ps_init(struct sstvenc_pulseshape *const ps, double amplitude, double rise_time, double hold_time, double fall_time, uint32_t sample_rate, uint8_t time_unit)
Definition pulseshape.c:28
uint64_t total_ns
Definition sstvmod.h:48
uint32_t remaining
Definition sstvmod.h:50
struct sstvenc_encoder enc
Definition sstvmod.h:40
uint64_t total_samples
Definition sstvmod.h:46
void sstvenc_encoder_init(struct sstvenc_encoder *const enc, const struct sstvenc_mode *mode, const char *fsk_id, const uint8_t *framebuffer)
Definition sstv.c:392
#define SSTVENC_FREQ_SYNC
Definition sstvfreq.h:19

References sstvenc_mod::enc, sstvenc_mod::osc, sstvenc_mod::ps, sstvenc_mod::remaining, sstvenc_encoder_init(), SSTVENC_FREQ_SYNC, sstvenc_osc_init(), sstvenc_ps_init(), sstvenc_mod::total_ns, and sstvenc_mod::total_samples.

Referenced by main(), and sstvenc_sequencer_begin_image().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ sstvenc_modulator_next_fall_sample()

static void sstvenc_modulator_next_fall_sample ( struct sstvenc_mod *const mod)
static

Compute the next sample whilst in the FALL phase of the pulse shaper state machine.

Definition at line 119 of file sstvmod.c.

119 {
120 sstvenc_ps_compute(&(mod->ps));
121 mod->osc.amplitude = mod->ps.output;
122 sstvenc_osc_compute(&(mod->osc));
123}
void sstvenc_osc_compute(struct sstvenc_oscillator *const osc)
Definition oscillator.c:52
void sstvenc_ps_compute(struct sstvenc_pulseshape *const ps)
Definition pulseshape.c:63

References sstvenc_oscillator::amplitude, sstvenc_mod::osc, sstvenc_pulseshape::output, sstvenc_mod::ps, sstvenc_osc_compute(), and sstvenc_ps_compute().

Referenced by sstvenc_modulator_compute().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ sstvenc_modulator_next_hold_sample()

static void sstvenc_modulator_next_hold_sample ( struct sstvenc_mod *const mod)
static

Compute the next sample whilst in the HOLD phase of the pulse shaper state machine.

Definition at line 91 of file sstvmod.c.

91 {
92 sstvenc_ps_compute(&(mod->ps));
93 mod->osc.amplitude = mod->ps.output;
94
96 /* We're done */
97 if (mod->ps.phase != SSTVENC_PS_PHASE_FALL) {
98 sstvenc_ps_advance(&(mod->ps));
99 }
100 return;
101 }
102
103 if (mod->remaining == 0) {
105 }
106
107 if (mod->remaining > 0) {
108 /* Compute the next oscillator output sample */
109 sstvenc_osc_compute(&(mod->osc));
110 mod->remaining--;
111 }
112}
void sstvenc_ps_advance(struct sstvenc_pulseshape *const ps)
Definition pulseshape.c:56
static void sstvenc_modulator_next_tone(struct sstvenc_mod *const mod)
Definition sstvmod.c:46
#define SSTVENC_ENCODER_PHASE_DONE
Definition sstv.h:80
uint8_t phase
Definition sstv.h:180

References sstvenc_oscillator::amplitude, sstvenc_mod::enc, sstvenc_mod::osc, sstvenc_pulseshape::output, sstvenc_encoder::phase, sstvenc_pulseshape::phase, sstvenc_mod::ps, sstvenc_mod::remaining, SSTVENC_ENCODER_PHASE_DONE, sstvenc_modulator_next_tone(), sstvenc_osc_compute(), sstvenc_ps_advance(), sstvenc_ps_compute(), and SSTVENC_PS_PHASE_FALL.

Referenced by sstvenc_modulator_compute().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ sstvenc_modulator_next_rise_sample()

static void sstvenc_modulator_next_rise_sample ( struct sstvenc_mod *const mod)
static

Compute the next sample whilst in the RISE phase of the pulse shaper state machine.

Definition at line 37 of file sstvmod.c.

37 {
38 sstvenc_ps_compute(&(mod->ps));
39 mod->osc.amplitude = mod->ps.output;
40 sstvenc_osc_compute(&(mod->osc));
41}

References sstvenc_oscillator::amplitude, sstvenc_mod::osc, sstvenc_pulseshape::output, sstvenc_mod::ps, sstvenc_osc_compute(), and sstvenc_ps_compute().

Referenced by sstvenc_modulator_compute().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ sstvenc_modulator_next_tone()

static void sstvenc_modulator_next_tone ( struct sstvenc_mod *const mod)
static

Compute the next tone.

Definition at line 46 of file sstvmod.c.

46 {
47 while (mod->enc.phase != SSTVENC_ENCODER_PHASE_DONE) {
48 const struct sstvenc_encoder_pulse* pulse
50
51 if (pulse) {
52 /* Update the oscillator frequency */
54 pulse->frequency);
55
56 /* Figure out time duration in samples */
58 pulse->duration_ns, mod->osc.sample_rate,
60
61 /* Total up time and sample count */
62 mod->total_samples += mod->remaining;
63 mod->total_ns += pulse->duration_ns;
64
65 /* Sanity check timing, adjust for any
66 * slippage */
67 uint64_t expected_total_samples
69 mod->total_ns, mod->osc.sample_rate,
71 if (expected_total_samples > mod->total_samples) {
72 /*
73 * Rounding error has caused a slip,
74 * add samples to catch up.
75 */
76 uint64_t diff = expected_total_samples
77 - mod->total_samples;
78 mod->remaining += diff;
79 mod->total_samples += diff;
80 }
81 return;
82 }
83 }
84}
uint32_t sample_rate
Definition oscillator.h:55
void sstvenc_osc_set_frequency(struct sstvenc_oscillator *const osc, double frequency)
Definition oscillator.c:33
const struct sstvenc_encoder_pulse * sstvenc_encoder_next_pulse(struct sstvenc_encoder *const enc)
Definition sstv.c:1032
#define SSTVENC_TS_UNIT_NANOSECONDS
Definition timescale.h:39
uint32_t sstvenc_ts_unit_to_samples(double time, uint32_t sample_rate, uint8_t unit)
Definition timescale.c:46

References sstvenc_encoder_pulse::duration_ns, sstvenc_mod::enc, sstvenc_encoder_pulse::frequency, sstvenc_mod::osc, sstvenc_encoder::phase, sstvenc_mod::remaining, sstvenc_oscillator::sample_rate, sstvenc_encoder_next_pulse(), SSTVENC_ENCODER_PHASE_DONE, sstvenc_osc_set_frequency(), SSTVENC_TS_UNIT_NANOSECONDS, sstvenc_ts_unit_to_samples(), sstvenc_mod::total_ns, and sstvenc_mod::total_samples.

Referenced by sstvenc_modulator_next_hold_sample().

Here is the call graph for this function:
Here is the caller graph for this function: