LCOV - code coverage report
Current view: top level - src/media/audio/sound - tone.cpp (source / functions) Hit Total Coverage
Test: jami-coverage-filtered.info Lines: 53 59 89.8 %
Date: 2024-04-25 08:05:53 Functions: 4 6 66.7 %

          Line data    Source code
       1             : /*
       2             :  *  Copyright (C) 2004-2024 Savoir-faire Linux Inc.
       3             :  *
       4             :  *  Author: Yan Morin <yan.morin@savoirfairelinux.com>
       5             :  *  Author: Adrien BĂ©raud <adrien.beraud@savoirfairelinux.com>
       6             :  *
       7             :  *  Inspired by tonegenerator of
       8             :  *   Laurielle Lea <laurielle.lea@savoirfairelinux.com> (2004)
       9             :  *  Inspired by ringbuffer of Audacity Project
      10             :  *
      11             :  *  This program is free software; you can redistribute it and/or modify
      12             :  *  it under the terms of the GNU General Public License as published by
      13             :  *  the Free Software Foundation; either version 3 of the License, or
      14             :  *  (at your option) any later version.
      15             :  *
      16             :  *  This program is distributed in the hope that it will be useful,
      17             :  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
      18             :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      19             :  *  GNU General Public License for more details.
      20             :  *
      21             :  *  You should have received a copy of the GNU General Public License
      22             :  *  along with this program; if not, write to the Free Software
      23             :  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
      24             :  */
      25             : #include "tone.h"
      26             : #include "logger.h"
      27             : #include "ring_types.h"
      28             : #include "string_utils.h"
      29             : 
      30             : #include <vector>
      31             : #include <cmath>
      32             : #include <cstdlib>
      33             : 
      34             : namespace jami {
      35             : 
      36         405 : Tone::Tone(std::string_view definition, unsigned int sampleRate, AVSampleFormat sampleFormat)
      37         405 :     : AudioLoop(AudioFormat(sampleRate, 1, sampleFormat))
      38             : {
      39         405 :     genBuffer(definition); // allocate memory with definition parameter
      40         405 : }
      41             : 
      42             : struct ParsedDefinition {
      43             :     unsigned total_samples;
      44             :     std::vector<std::tuple<unsigned, unsigned, unsigned>> frequencies;
      45             : };
      46             : 
      47             : ParsedDefinition
      48         372 : parseDefinition(std::string_view definition, unsigned sampleRate)
      49             : {
      50         372 :     ParsedDefinition parsed;
      51         372 :     parsed.total_samples = 0;
      52             : 
      53         372 :     std::string_view s; // portion of frequencyq
      54        1023 :     while (getline_full(definition, s, ',')) {
      55             :         // Sample string: "350+440" or "350+440/2000,244+655/2000"
      56             :         unsigned low, high, time;
      57             :         size_t count;  // number of int for one sequence
      58             : 
      59             :         // The 1st frequency is before the first + or the /
      60         651 :         size_t pos_plus = s.find('+');
      61         651 :         size_t pos_slash = s.find('/');
      62         651 :         size_t len = s.length();
      63         651 :         size_t endfrequency = 0;
      64             : 
      65         651 :         if (pos_slash == std::string::npos) {
      66          93 :             time = 0;
      67          93 :             endfrequency = len;
      68             :         } else {
      69         558 :             time = to_int<unsigned>(s.substr(pos_slash + 1, len - pos_slash - 1), 0);
      70         558 :             endfrequency = pos_slash;
      71             :         }
      72             : 
      73             :         // without a plus = 1 frequency
      74         651 :         if (pos_plus == std::string::npos) {
      75         279 :             low = to_int<unsigned>(s.substr(0, endfrequency), 0);
      76         279 :             high = 0;
      77             :         } else {
      78         372 :             low = to_int<unsigned>(s.substr(0, pos_plus), 0);
      79         372 :             high = to_int<unsigned>(s.substr(pos_plus + 1, endfrequency - pos_plus - 1), 0);
      80             :         }
      81             : 
      82             :         // If there is time or if it's unlimited
      83         651 :         if (time == 0)
      84          93 :             count = sampleRate;
      85             :         else
      86         558 :             count = (sampleRate * time) / 1000;
      87             : 
      88         651 :         parsed.frequencies.emplace_back(low, high, count);
      89         651 :         parsed.total_samples += count;
      90             :     }
      91         744 :     return parsed;
      92           0 : }
      93             : 
      94             : void
      95         405 : Tone::genBuffer(std::string_view definition)
      96             : {
      97         405 :     if (definition.empty())
      98          33 :         return;
      99             : 
     100         372 :     auto [total_samples, frequencies] = parseDefinition(definition, format_.sample_rate);
     101         372 :     buffer_->nb_samples = total_samples;
     102         372 :     buffer_->format = format_.sampleFormat;
     103         372 :     buffer_->sample_rate = format_.sample_rate;
     104         372 :     av_channel_layout_default(&buffer_->ch_layout, format_.nb_channels);
     105         372 :     av_frame_get_buffer(buffer_.get(), 0);
     106             : 
     107         372 :     size_t outPos = 0;
     108        1023 :     for (auto& [low, high, count] : frequencies) {
     109         651 :         genSin(buffer_.get(), outPos, count, low, high);
     110         651 :         outPos += count;
     111             :     }
     112         372 : }
     113             : 
     114             : void
     115        1179 : Tone::genSin(AVFrame* buffer, size_t outPos, unsigned nb_samples, unsigned lowFrequency, unsigned highFrequency)
     116             : {
     117             :     static constexpr auto PI_2 = 3.141592653589793238462643383279502884L * 2.0L;
     118        1179 :     const double sr = (double) buffer->sample_rate;
     119        1179 :     const double dx_h = sr ? PI_2 * lowFrequency / sr : 0.0;
     120        1179 :     const double dx_l = sr ? PI_2 * highFrequency / sr : 0.0;
     121             :     static constexpr double DATA_AMPLITUDE_S16 = 2048;
     122             :     static constexpr double DATA_AMPLITUDE_FLT = 0.0625;
     123             : 
     124        1179 :     if (buffer->format == AV_SAMPLE_FMT_S16 || buffer->format == AV_SAMPLE_FMT_S16P) {
     125        1179 :         int16_t* ptr = ((int16_t*) buffer->data[0]) + outPos;
     126    21097179 :         for (size_t t = 0; t < nb_samples; t++) {
     127    21096000 :             ptr[t] = DATA_AMPLITUDE_S16 * (sin(t * dx_h) + sin(t * dx_l));
     128             :         }
     129        1179 :     } else if (buffer->format == AV_SAMPLE_FMT_FLT || buffer->format == AV_SAMPLE_FMT_FLTP) {
     130           0 :         float* ptr = ((float*) buffer->data[0]) + outPos;
     131           0 :         for (size_t t = 0; t < nb_samples; t++) {
     132           0 :             ptr[t] = (sin(t * dx_h) + sin(t * dx_l)) * DATA_AMPLITUDE_FLT;
     133             :         }
     134           0 :     } else {
     135           0 :         JAMI_ERROR("Unsupported sample format: {}", av_get_sample_fmt_name((AVSampleFormat)buffer->format));
     136             :     }
     137        1179 : }
     138             : 
     139             : } // namespace jami

Generated by: LCOV version 1.14