aboutsummaryrefslogtreecommitdiffstats
path: root/src/utils.cpp
blob: 525f05ea45f82a165a3f5d4ccbce6576c16db08a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
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;
}