Ring Daemon 16.0.0
Loading...
Searching...
No Matches
tone.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2004-2025 Savoir-faire Linux Inc.
3 *
4 * Inspired by tonegenerator of
5 * Laurielle Lea <laurielle.lea@savoirfairelinux.com> (2004)
6 * Inspired by ringbuffer of Audacity Project
7 *
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 */
21#include "tone.h"
22#include "logger.h"
23#include "ring_types.h"
24#include "string_utils.h"
25
26#include <vector>
27#include <cmath>
28#include <cstdlib>
29
30namespace jami {
31
32Tone::Tone(std::string_view definition, unsigned int sampleRate, AVSampleFormat sampleFormat)
33 : AudioLoop(AudioFormat(sampleRate, 1, sampleFormat))
34{
35 genBuffer(definition); // allocate memory with definition parameter
36}
37
39 unsigned total_samples;
40 std::vector<std::tuple<unsigned, unsigned, unsigned>> frequencies;
41};
42
44parseDefinition(std::string_view definition, unsigned sampleRate)
45{
48
49 std::string_view s; // portion of frequencyq
50 while (getline_full(definition, s, ',')) {
51 // Sample string: "350+440" or "350+440/2000,244+655/2000"
52 unsigned low, high, time;
53 size_t count; // number of int for one sequence
54
55 // The 1st frequency is before the first + or the /
56 size_t pos_plus = s.find('+');
57 size_t pos_slash = s.find('/');
58 size_t len = s.length();
59 size_t endfrequency = 0;
60
61 if (pos_slash == std::string::npos) {
62 time = 0;
63 endfrequency = len;
64 } else {
65 time = to_int<unsigned>(s.substr(pos_slash + 1, len - pos_slash - 1), 0);
67 }
68
69 // without a plus = 1 frequency
70 if (pos_plus == std::string::npos) {
71 low = to_int<unsigned>(s.substr(0, endfrequency), 0);
72 high = 0;
73 } else {
74 low = to_int<unsigned>(s.substr(0, pos_plus), 0);
75 high = to_int<unsigned>(s.substr(pos_plus + 1, endfrequency - pos_plus - 1), 0);
76 }
77
78 // If there is time or if it's unlimited
79 if (time == 0)
80 count = sampleRate;
81 else
82 count = (sampleRate * time) / 1000;
83
84 parsed.frequencies.emplace_back(low, high, count);
85 parsed.total_samples += count;
86 }
87 return parsed;
88}
89
90void
91Tone::genBuffer(std::string_view definition)
92{
93 if (definition.empty())
94 return;
95
96 auto [total_samples, frequencies] = parseDefinition(definition, format_.sample_rate);
97 buffer_->nb_samples = total_samples;
99 buffer_->sample_rate = format_.sample_rate;
102
103 size_t outPos = 0;
104 for (auto& [low, high, count] : frequencies) {
105 genSin(buffer_.get(), outPos, count, low, high);
106 outPos += count;
107 }
108}
109
110void
112{
113 static constexpr auto PI_2 = 3.141592653589793238462643383279502884L * 2.0L;
114 const double sr = (double) buffer->sample_rate;
115 const double dx_h = sr ? PI_2 * lowFrequency / sr : 0.0;
116 const double dx_l = sr ? PI_2 * highFrequency / sr : 0.0;
117 static constexpr double DATA_AMPLITUDE_S16 = 2048;
118 static constexpr double DATA_AMPLITUDE_FLT = 0.0625;
119
120 if (buffer->format == AV_SAMPLE_FMT_S16 || buffer->format == AV_SAMPLE_FMT_S16P) {
121 int16_t* ptr = ((int16_t*) buffer->data[0]) + outPos;
122 for (size_t t = 0; t < nb_samples; t++) {
123 ptr[t] = DATA_AMPLITUDE_S16 * (sin(t * dx_h) + sin(t * dx_l));
124 }
125 } else if (buffer->format == AV_SAMPLE_FMT_FLT || buffer->format == AV_SAMPLE_FMT_FLTP) {
126 float* ptr = ((float*) buffer->data[0]) + outPos;
127 for (size_t t = 0; t < nb_samples; t++) {
128 ptr[t] = (sin(t * dx_h) + sin(t * dx_l)) * DATA_AMPLITUDE_FLT;
129 }
130 } else {
131 JAMI_ERROR("Unsupported sample format: {}", av_get_sample_fmt_name((AVSampleFormat)buffer->format));
132 }
133}
134
135} // namespace jami
AudioFormat format_
Definition audioloop.h:77
libjami::FrameBuffer buffer_
The data buffer.
Definition audioloop.h:79
static void genSin(AVFrame *buffer, size_t outPos, unsigned nb_samples, unsigned frequency1, unsigned frequency2)
Add a simple or double sin to the buffer, it double the sin in stereo.
Definition tone.cpp:111
Tone(std::string_view definition, unsigned int sampleRate, AVSampleFormat sampleFormat)
Constructor.
Definition tone.cpp:32
#define JAMI_ERROR(formatstr,...)
Definition logger.h:228
void emitSignal(Args... args)
Definition ring_signal.h:64
ParsedDefinition parseDefinition(std::string_view definition, unsigned sampleRate)
Definition tone.cpp:44
bool getline_full(std::string_view &str, std::string_view &line, char delim='\n')
Split a string_view with an API similar to std::getline.
Structure to hold sample rate and channel number associated with audio data.
AVSampleFormat sampleFormat
unsigned total_samples
Definition tone.cpp:39
std::vector< std::tuple< unsigned, unsigned, unsigned > > frequencies
Definition tone.cpp:40
Tone sample (dial, busy, ring, congestion)