• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mixxxdj / mixxx / 11661349135

04 Nov 2024 09:21AM CUT coverage: 31.893% (-0.04%) from 31.928%
11661349135

Pull #13427

github

web-flow
Merge cc7d68117 into 6a9c602f2
Pull Request #13427: Library scan: log summary and show popup

19 of 90 new or added lines in 5 files covered. (21.11%)

3361 existing lines in 42 files now uncovered.

33266 of 104306 relevant lines covered (31.89%)

48430.24 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/encoder/encoderwave.cpp
1
#include "encoder/encoderwave.h"
2

3
#include <QtDebug>
4

5
#include "audio/types.h"
6
#include "encoder/encodercallback.h"
7
#include "encoder/encoderwavesettings.h"
8
#include "recording/defs_recording.h"
9

10
// The virtual file context must return the length of the virtual file in bytes.
11
static sf_count_t  sf_f_get_filelen (void *user_data)
×
12
{
13
    EncoderCallback* pCallback = static_cast<EncoderCallback*>(user_data);
×
14
    return pCallback->filelen();
×
15
}
16
// The virtual file context must seek to offset using the seek mode provided
17
// by whence which is one of
18
//      SEEK_CUR
19
//      SEEK_SET
20
//      SEEK_END
21
// The return value must contain the new offset in the file.
22
static sf_count_t  sf_f_seek (sf_count_t offset, int whence, void *user_data)
×
23
{
24
    sf_count_t new_offset;
25
    EncoderCallback* pCallback = static_cast<EncoderCallback*>(user_data);
×
26
    if (whence == SEEK_SET) {
×
27
        new_offset = offset;
×
28
        pCallback->seek(static_cast<int>(new_offset));
×
29
    } else if (whence == SEEK_CUR) {
×
30
        new_offset = pCallback->tell()+offset;
×
31
        pCallback->seek(static_cast<int>(new_offset));
×
32
    } else {
33
        new_offset =  pCallback->filelen()-offset;
×
34
        pCallback->seek(static_cast<int>(new_offset));
×
35
    }
36
    return new_offset;
×
37
}
38
// The virtual file context must copy ("read") "count" bytes into the buffer
39
// provided by ptr and return the count of actually copied bytes.
40
static sf_count_t  sf_f_read (void *ptr, sf_count_t count, void *user_data)
×
41
{
42
    Q_UNUSED(ptr);
43
    Q_UNUSED(count);
44
    Q_UNUSED(user_data);
45
    qWarning() << "sf_f_read called for EncoderWave. Call not implemented!";
×
46
    return 0;
×
47
}
48

49
// The virtual file context must process "count" bytes stored in the buffer passed
50
//  with ptr and return the count of actually processed bytes.
51
static sf_count_t sf_f_write (const void *ptr, sf_count_t count, void *user_data)
×
52
{
53
    EncoderCallback* pCallback = static_cast<EncoderCallback*>(user_data);
×
54
    pCallback->write(nullptr, static_cast<const unsigned char*>(ptr), 0, static_cast<int>(count));
×
55
    return count;
×
56
}
57

58
// Return the current position of the virtual file context.
59
static sf_count_t  sf_f_tell (void *user_data)
×
60
{
61
    EncoderCallback* pCallback = static_cast<EncoderCallback*>(user_data);
×
62
    return pCallback->tell();
×
63
}
64

65

66

67

68
EncoderWave::EncoderWave(EncoderCallback* pCallback)
×
69
        : m_pCallback(pCallback),
×
70
          m_pSndfile(nullptr) {
×
71
    m_sfInfo.frames = 0;
×
72
    m_sfInfo.samplerate = 0;
×
73
    m_sfInfo.channels = 0;
×
74
    m_sfInfo.format = 0;
×
75
    m_sfInfo.sections = 0;
×
76
    m_sfInfo.seekable = 0;
×
77

78
    // Libsndfile calls the callbacks provided by the SF_VIRTUAL_IO structure
79
    // when opening, reading and writing to the virtual file context. The user_data
80
    // pointer is a user defined context which will be available in the callbacks.
81
    m_virtualIo.get_filelen = sf_f_get_filelen;
×
82
    m_virtualIo.seek = sf_f_seek;
×
83
    m_virtualIo.read = sf_f_read;
×
84
    m_virtualIo.write = sf_f_write;
×
85
    m_virtualIo.tell = sf_f_tell;
×
86
}
×
87

88
EncoderWave::~EncoderWave() {
×
89
    if (m_pSndfile != nullptr) {
×
90
        sf_close(m_pSndfile);
×
91
    }
92
}
×
93

94
void EncoderWave::setEncoderSettings(const EncoderSettings& settings) {
×
95
    const EncoderWaveSettings& wavesettings = reinterpret_cast<const EncoderWaveSettings&>(settings);
×
96
    QString format = wavesettings.getFormat();
×
97
    if (format == ENCODING_WAVE) {
×
98
        m_sfInfo.format = SF_FORMAT_WAV;
×
99
    } else if (format == ENCODING_AIFF) {
×
100
        m_sfInfo.format = SF_FORMAT_AIFF;
×
101
    } else {
102
        qWarning() << "Unexpected Format when setting EncoderWave: " << format << ". Reverting to wav";
×
103
        // Other possibly interesting formats
104
        // There is a n option for RF64 to automatically downgrade to RIFF WAV if less than 4GB using an
105
        // sf_command, so it could be interesting to use it in place of FORMAT_WAVE.
106
        // SF_FORMAT_W64          = 0x0B0000,     /* Sonic Foundry's 64 bit RIFF/WAV */
107
        // SF_FORMAT_RF64         = 0x220000,     /* RF64 WAV file */
108

109
        // I guess this one is WAVEFORMATEXTENSIBLE, not WAVEFORMATEX.
110
        // Not really useful for us since it's mostly for multichannel setups.
111
        // SF_FORMAT_WAVEX        = 0x130000,     /* MS WAVE with WAVEFORMATEX */
112

113
        // SF_FORMAT_CAF          = 0x180000,     /* Core Audio File format */
114
    }
115
    int radio = settings.getSelectedOption(EncoderWaveSettings::BITS_GROUP);
×
116
    switch(radio) {
×
117
        case 0:
×
118
            m_sfInfo.format |= SF_FORMAT_PCM_16;
×
119
            break;
×
120
        case 1:
×
121
            m_sfInfo.format |= SF_FORMAT_PCM_24;
×
122
            break;
×
123
        case 2:
×
124
            m_sfInfo.format |= SF_FORMAT_FLOAT;
×
125
            break;
×
126
        default:
×
127
            m_sfInfo.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
×
128
            qWarning() << " Unexpected radio index on EncoderWave: "
×
129
                    << radio << ". reverting to PCM 16bits";
×
130
            break;
×
131
    }
132
}
×
133

134
// call sendPackages() or write() after 'flush()' as outlined in enginebroadcast.cpp
135
void EncoderWave::flush() {
×
136
    sf_write_sync(m_pSndfile);
×
137
}
×
138

UNCOV
139
void EncoderWave::encodeBuffer(const CSAMPLE* pBuffer, const std::size_t bufferSize) {
×
140
    sf_write_float(m_pSndfile, pBuffer, bufferSize);
×
141
}
×
142

143
/* Originally called from enginebroadcast.cpp to update metadata information
144
 * when streaming, however, this causes pops
145
 *
146
 * Currently this method is used before init() once to save artist, title and album
147
*/
UNCOV
148
void EncoderWave::updateMetaData(const QString& artist, const QString& title, const QString& album) {
×
149
    m_metaDataTitle = title;
×
150
    m_metaDataArtist = artist;
×
151
    m_metaDataAlbum = album;
×
152
}
×
153

UNCOV
154
void EncoderWave::initStream() {
×
155

156
    // Tell the encoder to automatically convert float input range to the correct output range.
UNCOV
157
    sf_command(m_pSndfile, SFC_SET_NORM_FLOAT, nullptr, SF_TRUE);
×
158
    // Tell the encoder that, when converting to integer formats, clip
159
    // automatically the values that go outside of the allowed range.
160
    // Warning! Depending on how libsndfile is compiled autoclip may not work.
161
    // Ensure CPU_CLIPS_NEGATIVE and CPU_CLIPS_POSITIVE is setup properly in the build.
UNCOV
162
    sf_command(m_pSndfile, SFC_SET_CLIPPING, nullptr, SF_TRUE);
×
163

164
    // Strings passed to and retrieved from sf_get_string/sf_set_string are assumed to be utf-8.
165
    // However, while formats like Ogg/Vorbis and FLAC fully support utf-8, others like WAV and
166
    // AIFF officially only support ASCII. Writing utf-8 strings to WAV and AIF files with
167
    // libsndfile will work when read back with libsndfile, but may not work with other programs.
168
    int ret;
UNCOV
169
    if (!m_metaDataTitle.isEmpty()) {
×
170
        ret = sf_set_string(m_pSndfile, SF_STR_TITLE, m_metaDataTitle.toUtf8().constData());
×
171
        if (ret != 0) {
×
172
            qWarning("libsndfile error: %s", sf_error_number(ret));
×
173
        }
174
    }
175

UNCOV
176
    if (!m_metaDataArtist.isEmpty()) {
×
177
        ret = sf_set_string(m_pSndfile, SF_STR_ARTIST, m_metaDataArtist.toUtf8().constData());
×
178
        if (ret != 0) {
×
179
            qWarning("libsndfile error: %s", sf_error_number(ret));
×
180
        }
181
    }
UNCOV
182
    if (!m_metaDataAlbum.isEmpty()) {
×
183
        int strType = SF_STR_ALBUM;
×
184
        if (m_sfInfo.format == SF_FORMAT_AIFF) {
×
185
            // There is no AIFF text chunk for "Album". But libsndfile is able to
186
            // write the SF_STR_COMMENT string into the text chunk with id "ANNO".
UNCOV
187
            strType = SF_STR_COMMENT;
×
188
        }
UNCOV
189
        ret = sf_set_string(m_pSndfile, strType, m_metaDataAlbum.toUtf8().constData());
×
190
        if (ret != 0) {
×
191
            qWarning("libsndfile error: %s", sf_error_number(ret));
×
192
        }
193
    }
UNCOV
194
}
×
195

UNCOV
196
int EncoderWave::initEncoder(mixxx::audio::SampleRate sampleRate, QString* pUserErrorMessage) {
×
197
    Q_UNUSED(pUserErrorMessage);
198
    // set sfInfo.
199
    // m_sfInfo.format is setup on setEncoderSettings previous to calling initEncoder.
UNCOV
200
    m_sfInfo.samplerate = sampleRate;
×
201
    m_sfInfo.channels = 2;
×
202
    m_sfInfo.frames = 0;
×
203
    m_sfInfo.sections = 0;
×
204
    m_sfInfo.seekable = 0;
×
205

206
    // Opens a soundfile from a virtual file I/O context which is provided by the caller.
207
    // This is usually used to interface libsndfile to a stream or buffer based system.
208
    // Apart from the sfvirtual and the user_data parameters this function behaves like sf_open.
UNCOV
209
    m_pSndfile = sf_open_virtual (&m_virtualIo, SFM_WRITE, &m_sfInfo, m_pCallback) ;
×
210

UNCOV
211
    int ret=0;
×
212
    if (m_pSndfile == nullptr) {
×
213
        qDebug()
×
214
                << "Error initializing Wave encoding. sf_open_virtual returned:"
×
215
                << sf_strerror(nullptr);
×
216
        ret = -1;
×
217
    } else {
UNCOV
218
        initStream();
×
219
    };
UNCOV
220
    return ret;
×
221
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc