util.cpp 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. /*
  2. * util.cpp
  3. * Miscellaneous routines
  4. *
  5. * Copyright (c) 2015-2021 Tomasz Lemiech <szpajder@gmail.com>
  6. *
  7. * This program is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation, either version 3 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. #include <lame/lame.h>
  21. #include <shout/shout.h>
  22. #include <stdint.h> // uint32_t
  23. #include <unistd.h>
  24. #include <cerrno>
  25. #include <cmath>
  26. #include <cstdarg>
  27. #include <cstdlib>
  28. #include <cstring>
  29. #include <iostream>
  30. #include "config.h"
  31. #include "logging.h"
  32. #include "rtl_airband.h"
  33. int atomic_inc(volatile int* pv) {
  34. return __sync_fetch_and_add(pv, 1);
  35. }
  36. int atomic_dec(volatile int* pv) {
  37. return __sync_fetch_and_sub(pv, 1);
  38. }
  39. int atomic_get(volatile int* pv) {
  40. return __sync_fetch_and_add(pv, 0);
  41. }
  42. void tag_queue_put(device_t* dev, int freq, struct timeval tv) {
  43. pthread_mutex_lock(&dev->tag_queue_lock);
  44. dev->tq_head++;
  45. dev->tq_head %= TAG_QUEUE_LEN;
  46. if (dev->tq_head == dev->tq_tail) {
  47. log(LOG_WARNING, "tag_queue_put: queue overrun\n");
  48. dev->tq_tail++;
  49. }
  50. dev->tag_queue[dev->tq_head].freq = freq;
  51. memcpy(&dev->tag_queue[dev->tq_head].tv, &tv, sizeof(struct timeval));
  52. pthread_mutex_unlock(&dev->tag_queue_lock);
  53. }
  54. void tag_queue_get(device_t* dev, struct freq_tag* tag) {
  55. int i;
  56. if (!tag)
  57. return;
  58. pthread_mutex_lock(&dev->tag_queue_lock);
  59. if (dev->tq_head == dev->tq_tail) { /* empty queue */
  60. tag->freq = -1;
  61. } else {
  62. // read queue entry at pos tq_tail+1 without dequeueing it
  63. i = dev->tq_tail + 1;
  64. i %= TAG_QUEUE_LEN;
  65. tag->freq = dev->tag_queue[i].freq;
  66. memcpy(&tag->tv, &dev->tag_queue[i].tv, sizeof(struct timeval));
  67. }
  68. pthread_mutex_unlock(&dev->tag_queue_lock);
  69. }
  70. void tag_queue_advance(device_t* dev) {
  71. pthread_mutex_lock(&dev->tag_queue_lock);
  72. dev->tq_tail++;
  73. dev->tq_tail %= TAG_QUEUE_LEN;
  74. pthread_mutex_unlock(&dev->tag_queue_lock);
  75. }
  76. void* xcalloc(size_t nmemb, size_t size, const char* file, const int line, const char* func) {
  77. void* ptr = calloc(nmemb, size);
  78. if (ptr == NULL) {
  79. log(LOG_ERR, "%s:%d: %s(): calloc(%zu, %zu) failed: %s\n", file, line, func, nmemb, size, strerror(errno));
  80. error();
  81. }
  82. return ptr;
  83. }
  84. void* xrealloc(void* ptr, size_t size, const char* file, const int line, const char* func) {
  85. ptr = realloc(ptr, size);
  86. if (ptr == NULL) {
  87. log(LOG_ERR, "%s:%d: %s(): realloc(%zu) failed: %s\n", file, line, func, size, strerror(errno));
  88. error();
  89. }
  90. return ptr;
  91. }
  92. static float sin_lut[257], cos_lut[257];
  93. void sincosf_lut_init() {
  94. for (uint32_t i = 0; i < 256; i++)
  95. SINCOSF(2.0F * M_PI * (float)i / 256.0f, sin_lut + i, cos_lut + i);
  96. sin_lut[256] = sin_lut[0];
  97. cos_lut[256] = cos_lut[0];
  98. }
  99. // phi range must be (0..1), rescaled to 0x0-0xFFFFFF
  100. void sincosf_lut(uint32_t phi, float* sine, float* cosine) {
  101. float v1, v2, fract;
  102. uint32_t idx;
  103. // get LUT index
  104. idx = phi >> 16;
  105. // cast fixed point fraction to float
  106. fract = (float)(phi & 0xffff) / 65536.0f;
  107. // get two adjacent values from LUT and interpolate
  108. v1 = sin_lut[idx];
  109. v2 = sin_lut[idx + 1];
  110. *sine = v1 + (v2 - v1) * fract;
  111. v1 = cos_lut[idx];
  112. v2 = cos_lut[idx + 1];
  113. *cosine = v1 + (v2 - v1) * fract;
  114. }
  115. /* librtlsdr-keenerd, (c) Kyle Keen */
  116. double atofs(char* s) {
  117. char last;
  118. int len;
  119. double suff = 1.0;
  120. len = strlen(s);
  121. last = s[len - 1];
  122. s[len - 1] = '\0';
  123. switch (last) {
  124. case 'g':
  125. case 'G':
  126. suff *= 1e3;
  127. [[fallthrough]];
  128. case 'm':
  129. case 'M':
  130. suff *= 1e3;
  131. [[fallthrough]];
  132. case 'k':
  133. case 'K':
  134. suff *= 1e3;
  135. suff *= atof(s);
  136. s[len - 1] = last;
  137. return suff;
  138. }
  139. s[len - 1] = last;
  140. return atof(s);
  141. }
  142. double delta_sec(const timeval* start, const timeval* stop) {
  143. timeval delta;
  144. timersub(stop, start, &delta);
  145. return delta.tv_sec + delta.tv_usec / 1000000.0;
  146. }
  147. // level to/from dBFS conversion assumes level is nomalized to 1 and is based on:
  148. // https://kluedo.ub.uni-kl.de/frontdoor/deliver/index/docId/4293/file/exact_fft_measurements.pdf
  149. //
  150. // expanded form:
  151. // 20.0f * log10f(level / fft_size) + 7.54f + 10.0f * log10f(fft_size/2) - 2.38f
  152. const float& dBFS_offset(void) {
  153. static const float offset = 7.54f + 10.0f * log10f(fft_size / 2) - 2.38f;
  154. return offset;
  155. }
  156. float dBFS_to_level(const float& dBFS) {
  157. return pow(10.0, (dBFS - dBFS_offset()) / 20.0f) * fft_size;
  158. }
  159. float level_to_dBFS(const float& level) {
  160. return std::min(0.0f, 20.0f * log10f(level / fft_size) + dBFS_offset());
  161. }