TinyModem
Header-only software audio modem library
Loading...
Searching...
No Matches
DTMFEncoder.h
Go to the documentation of this file.
1#pragma once
2
3#include <math.h>
4
5#include "AudioTools.h"
6#include "DTMF.h"
7#include "ModemBase.h"
8
9namespace tinymodem {
10
19class DTMFEncoder : public ModemEncoder {
20 public:
21 DTMFEncoder() = default;
22 DTMFEncoder(Print& out) { setOutput(out); }
23
26
27 void setOutput(Print& out) override {
28 samples.setOutput(out);
29 ModemEncoder::setOutput(out); // writeSilence(), writeTone()
30 }
31
33 void setAudioInfo(audio_tools::AudioInfo info) override {
34 cfg.sample_rate = info.sample_rate;
35 cfg.channels = info.channels;
36 cfg.bits_per_sample = info.bits_per_sample;
37 if (is_active) begin();
38 }
39
40 audio_tools::AudioInfo audioInfo() override { return cfg; }
41
42 using audio_tools::AudioEncoder::begin;
43
46 cfg = config;
47 return begin();
48 }
49
50 bool begin() override {
51 is_active = false;
52 if (!cfg.isValid()) return false;
53 if (cfg.bits_per_sample != 16) {
54 LOGE("DTMFEncoder: bits_per_sample must be 16, not %d",
55 (int)cfg.bits_per_sample);
56 return false;
57 }
58 if (cfg.channels < 1) {
59 LOGE("DTMFEncoder: invalid number of channels: %d", (int)cfg.channels);
60 return false;
61 }
62 samples.begin(cfg.channels, cfg.volume);
63 if (!tones.begin(cfg, cfg.volume)) return false;
64 transmitting = false;
65 is_active = true;
66 return true;
67 }
68
69 void end() override {
71 is_active = false;
72 }
73
75 size_t write(const uint8_t* data, size_t len) override {
76 if (!is_active) return 0;
77 for (size_t j = 0; j < len; j++) {
78 int row, column;
79 if (DTMFKeys::find(data[j], row, column)) {
80 transmitting = true;
81 sendKey(row, column);
82 } else if (data[j] == ',') {
83 transmitting = true;
84 silence(cfg.comma_ms);
85 }
86 }
87 samples.flush();
88 return len;
89 }
90
93 bool writeKey(char key) {
94 int row, column;
95 if (!is_active || !DTMFKeys::find(key, row, column)) return false;
96 transmitting = true;
97 sendKey(row, column);
98 samples.flush();
99 return true;
100 }
101
104 bool endTransmission(size_t silence_samples = 0) override {
105 if (!is_active || !transmitting) return false;
106 for (size_t j = 0; j < silence_samples; j++) samples.write(0.0f);
107 samples.flush();
108 transmitting = false;
109 return true;
110 }
111
113 bool writeIdle(size_t nsamples) override {
114 if (!is_active) return false;
115 for (size_t j = 0; j < nsamples; j++) samples.write(0.0f);
116 samples.flush();
117 return true;
118 }
119
121 bool isTransmitting() override { return transmitting; }
122
124 float symbolRate() override {
125 return 1000.0f / (cfg.tone_ms + cfg.pause_ms);
126 }
127
129 DTMFConfig& config() { return cfg; }
130
131 operator bool() override { return is_active; }
132
133 protected:
134 static constexpr float RAMP_MS = 2.0f;
137 bool is_active = false;
138 bool transmitting = false;
139
140 void sendKey(int row, int column) {
141 size_t n = (size_t)cfg.tone_ms * cfg.sample_rate / 1000;
142 size_t ramp = RAMP_MS * cfg.sample_rate / 1000;
143 if (2 * ramp > n) ramp = n / 2;
144 float w1 = 2.0f * (float)M_PI * DTMFKeys::rows()[row] / cfg.sample_rate;
145 float w2 = 2.0f * (float)M_PI * DTMFKeys::columns()[column] / cfg.sample_rate;
146 for (size_t j = 0; j < n; j++) {
147 float gain = 0.5f;
148 if (j < ramp) gain *= 0.5f - 0.5f * cosf((float)M_PI * j / ramp);
149 if (n - j <= ramp)
150 gain *= 0.5f - 0.5f * cosf((float)M_PI * (n - j) / ramp);
151 samples.write(gain * (sinf(w1 * j) + sinf(w2 * j)));
152 }
153 silence(cfg.pause_ms);
154 }
155
156 void silence(int ms) {
157 size_t n = (size_t)ms * cfg.sample_rate / 1000;
158 for (size_t j = 0; j < n; j++) samples.write(0.0f);
159 }
160};
161
162} // namespace tinymodem
bool begin(DTMFConfig config)
Starts the processing with the indicated configuration.
Definition DTMFEncoder.h:45
DTMFConfig defaultConfig()
Provides a default configuration.
Definition DTMFEncoder.h:25
bool endTransmission(size_t silence_samples=0) override
Definition DTMFEncoder.h:104
bool transmitting
Definition DTMFEncoder.h:138
SampleOutput samples
Definition DTMFEncoder.h:136
DTMFEncoder(Print &out)
Definition DTMFEncoder.h:22
void silence(int ms)
Definition DTMFEncoder.h:156
void setAudioInfo(audio_tools::AudioInfo info) override
Defines the sample rate and number of channels of the generated audio.
Definition DTMFEncoder.h:33
bool is_active
Definition DTMFEncoder.h:137
DTMFConfig cfg
Definition DTMFEncoder.h:135
bool isTransmitting() override
true between the first key and endTransmission()
Definition DTMFEncoder.h:121
static constexpr float RAMP_MS
Definition DTMFEncoder.h:134
DTMFConfig & config()
The configuration which was provided in begin().
Definition DTMFEncoder.h:129
void end() override
Definition DTMFEncoder.h:69
bool writeKey(char key)
Definition DTMFEncoder.h:93
void setOutput(Print &out) override
Definition DTMFEncoder.h:27
size_t write(const uint8_t *data, size_t len) override
Sends the keys.
Definition DTMFEncoder.h:75
float symbolRate() override
Keys per second.
Definition DTMFEncoder.h:124
bool begin() override
Definition DTMFEncoder.h:50
bool writeIdle(size_t nsamples) override
Sends silence for the indicated number of samples.
Definition DTMFEncoder.h:113
void sendKey(int row, int column)
Definition DTMFEncoder.h:140
audio_tools::AudioInfo audioInfo() override
Definition DTMFEncoder.h:40
static const float * rows()
row frequencies in Hz
Definition DTMF.h:87
static const float * columns()
column frequencies in Hz
Definition DTMF.h:93
static bool find(char ch, int &row, int &column)
Definition DTMF.h:103
Common API of the modulators (FSKEncoder, MFSKEncoder): the written data is converted to 16 bit PCM a...
Definition ModemBase.h:286
void setOutput(Print &out) override
Definition ModemBase.h:288
ToneOutput tones
Definition ModemBase.h:334
Writes float samples (-1.0 to 1.0) as 16 bit PCM with the requested number of channels and volume to ...
Definition ModemBase.h:118
TinyModem: software audio modems and packets with error correction.
Definition AX25.h:11
Configuration of the DTMF (touch tone) modem (DTMFEncoder, DTMFDecoder): each of the characters 0-9,...
Definition DTMF.h:20