aboutsummaryrefslogtreecommitdiffstats
path: root/src/utils.cpp
diff options
context:
space:
mode:
authorMatthias P. Braendli <matthias.braendli@mpb.li>2020-03-31 17:07:38 +0200
committerMatthias P. Braendli <matthias.braendli@mpb.li>2020-03-31 17:07:38 +0200
commitec75b9e317baf249d67295300bc5308b7c33f4ac (patch)
tree6f43693530b463fc913f7c7153a3f54a43ebd04b /src/utils.cpp
parenta1eb6cf861d3c1cbd4e6c016be3cbd2a1e3d797d (diff)
downloadODR-AudioEnc-ec75b9e317baf249d67295300bc5308b7c33f4ac.tar.gz
ODR-AudioEnc-ec75b9e317baf249d67295300bc5308b7c33f4ac.tar.bz2
ODR-AudioEnc-ec75b9e317baf249d67295300bc5308b7c33f4ac.zip
Fix GStreamer input, rework ICY-Text write
Diffstat (limited to 'src/utils.cpp')
-rw-r--r--src/utils.cpp96
1 files changed, 96 insertions, 0 deletions
diff --git a/src/utils.cpp b/src/utils.cpp
new file mode 100644
index 0000000..525f05e
--- /dev/null
+++ b/src/utils.cpp
@@ -0,0 +1,96 @@
+#include <cmath>
+#include <cstdint>
+#include <cstddef>
+#include <sstream>
+
+#include "utils.h"
+#include <unistd.h>
+
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#define MAX(a,b) (((a)>(b))?(a):(b))
+
+/* Taken from sox */
+const char* level(int channel, int peak)
+{
+ static char const * const text[][2] = {
+ /* White: 2dB steps */
+ {"", ""}, {"-", "-"}, {"=", "="}, {"-=", "=-"},
+ {"==", "=="}, {"-==", "==-"}, {"===", "==="}, {"-===", "===-"},
+ {"====", "===="}, {"-====", "====-"}, {"=====", "====="},
+ {"-=====", "=====-"}, {"======", "======"},
+ /* Red: 1dB steps */
+ {"!=====", "=====!"},
+ };
+ int const red = 1, white = NUMOF(text) - red;
+
+ double linear = ((double)peak) / INT16_MAX;
+
+ int vu_dB = linear ? floor(2 * white + red + linear_to_dB(linear)) : 0;
+
+ int index = vu_dB < 2 * white ?
+ MAX(vu_dB / 2, 0) :
+ MIN(vu_dB - white, red + white - 1);
+
+ return text[index][channel];
+}
+
+size_t strlen_utf8(const char *s) {
+ size_t result = 0;
+
+ // ignore continuation bytes - only count single/leading bytes
+ while (*s)
+ if ((*s++ & 0xC0) != 0x80)
+ result++;
+
+ return result;
+}
+
+static const std::string ICY_TEXT_SEPARATOR = " - ";
+
+bool write_icy_to_file(const ICY_TEXT_t text, const std::string& filename, bool dl_plus)
+{
+ FILE* fd = fopen(filename.c_str(), "wb");
+ if (fd) {
+ bool ret = true;
+ bool artist_title_used = !text.artist.empty() and !text.title.empty();
+
+ // if desired, prepend DL Plus information
+ if (dl_plus) {
+ std::stringstream ss;
+ ss << "##### parameters { #####\n";
+ ss << "DL_PLUS=1\n";
+
+ // if non-empty text, add tag
+ if (artist_title_used) {
+ size_t artist_len = strlen_utf8(text.artist.c_str());
+ size_t title_start = artist_len + strlen_utf8(ICY_TEXT_SEPARATOR.c_str());
+
+ // ITEM.ARTIST
+ ss << "DL_PLUS_TAG=4 0 " << (artist_len - 1) << "\n"; // -1 !
+
+ // ITEM.TITLE
+ ss << "DL_PLUS_TAG=1 " << title_start << " " << (strlen_utf8(text.title.c_str()) - 1) << "\n"; // -1 !
+ } else if (!text.now_playing.empty()) {
+ // PROGRAMME.NOW
+ ss << "DL_PLUS_TAG=33 0 " << (strlen_utf8(text.now_playing.c_str()) - 1) << "\n"; // -1 !
+ }
+
+ ss << "##### parameters } #####\n";
+ ret &= fputs(ss.str().c_str(), fd) >= 0;
+ }
+
+ if (artist_title_used) {
+ ret &= fputs(text.artist.c_str(), fd) >= 0;
+ ret &= fputs(ICY_TEXT_SEPARATOR.c_str(), fd) >= 0;
+ ret &= fputs(text.title.c_str(), fd) >= 0;
+ }
+ else {
+ ret &= fputs(text.now_playing.c_str(), fd) >= 0;
+ }
+ fclose(fd);
+
+ return ret;
+ }
+
+ return false;
+}