~aleteoryx/muditaos

muditaos/module-audio/Audio/encoder/EncoderWAV.cpp -rw-r--r-- 6.2 KiB
a405cad6Aleteoryx trim readme 6 days ago
                                                                                
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/blob/master/LICENSE.md

#include "EncoderWAV.hpp"
#include <log/log.hpp>

namespace audio
{

    EncoderWAV::EncoderWAV(const std::string &filePath, const Encoder::Format &frmt) : Encoder(filePath, frmt)
    {

        WAVE_FormatTypeDef WaveFormat = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

        /* Initialize the encoder structure */
        WaveFormat.SampleRate    = format.sampleRate; /* Audio sampling frequency */
        WaveFormat.NbrChannels   = format.chanNr;     /* Number of channels: 1:Mono or 2:Stereo */
        WaveFormat.BitPerSample  = 16;                /* Number of bits per sample (16, 24 or 32) */
        WaveFormat.FileSize      = 0x001D4C00;        /* Total length of useful audio data (payload) */
        WaveFormat.SubChunk1Size = 44;                /* The file header chunk size */
        WaveFormat.ByteRate      = (WaveFormat.SampleRate * (WaveFormat.BitPerSample / 8) *
                               WaveFormat.NbrChannels); /* Number of bytes per second  (sample rate * block align)  */
        WaveFormat.BlockAlign = WaveFormat.NbrChannels * (WaveFormat.BitPerSample / 8); /* channels * bits/sample / 8 */

        HeaderInit(WaveFormat);
    }

    EncoderWAV::~EncoderWAV()
    {
        std::rewind(fd);
        /* Update the wav file header save it into wav file */
        HeaderUpdate();
        if (std::fwrite(pHeaderBuff, 1, sizeof(WAVE_FormatTypeDef), fd) != sizeof(WAVE_FormatTypeDef)) {
            LOG_ERROR("Updating WAV header failed");
        }
    }

    std::uint32_t EncoderWAV::Encode(std::uint32_t samplesToWrite, std::int16_t *pcmData)
    {
        /*
         * Write int16_t PCM samples to file.
         */
        auto byteswritten = std::fwrite(pcmData, sizeof(std::int16_t), samplesToWrite, fd);
        if (byteswritten != samplesToWrite) {
            return 0;
        }

        /* Calculate frame duration in seconds */
        position += static_cast<float>(samplesToWrite / format.chanNr) / static_cast<float>(format.sampleRate);
        return byteswritten;
    }

    void EncoderWAV::HeaderInit(const EncoderWAV::WAVE_FormatTypeDef &pWaveFormatStruct)
    {
        /* Write chunkID, must be 'RIFF'  ------------------------------------------*/
        memcpy(&pHeaderBuff[0], "RIFF", 4);

        /* Write the file length ---------------------------------------------------*/
        /* The sampling time: this value will be written back at the end of the
           recording operation.  Example: 661500 Btyes = 0x000A17FC, byte[7]=0x00, byte[4]=0xFC */
        pHeaderBuff[4] = 0x00;
        pHeaderBuff[5] = 0x4C;
        pHeaderBuff[6] = 0x1D;
        pHeaderBuff[7] = 0x00;

        /* Write the file format, must be 'WAVE' -----------------------------------*/
        memcpy(&pHeaderBuff[8], "WAVE", 4);

        /* Write the format chunk, must be 'fmt ' -----------------------------------*/
        memcpy(&pHeaderBuff[12], "fmt ", 4);

        /* Write the length of the 'fmt' data, must be 0x10 ------------------------*/
        pHeaderBuff[16] = 0x10;
        pHeaderBuff[17] = 0x00;
        pHeaderBuff[18] = 0x00;
        pHeaderBuff[19] = 0x00;

        /* Write the audio format, must be 0x01 (PCM) ------------------------------*/
        pHeaderBuff[20] = 0x01;
        pHeaderBuff[21] = 0x00;

        /* Write the number of channels, ie. 0x01 (Mono) ---------------------------*/
        pHeaderBuff[22] = pWaveFormatStruct.NbrChannels;
        pHeaderBuff[23] = 0x00;

        /* Write the Sample Rate in Hz ---------------------------------------------*/
        /* Write Little Endian ie. 8000 = 0x00001F40 => byte[24]=0x40, byte[27]=0x00*/
        pHeaderBuff[24] = (std::uint8_t)((pWaveFormatStruct.SampleRate & 0xFF));
        pHeaderBuff[25] = (std::uint8_t)((pWaveFormatStruct.SampleRate >> 8) & 0xFF);
        pHeaderBuff[26] = (std::uint8_t)((pWaveFormatStruct.SampleRate >> 16) & 0xFF);
        pHeaderBuff[27] = (std::uint8_t)((pWaveFormatStruct.SampleRate >> 24) & 0xFF);

        /* Write the Byte Rate -----------------------------------------------------*/
        pHeaderBuff[28] = (std::uint8_t)((pWaveFormatStruct.ByteRate & 0xFF));
        pHeaderBuff[29] = (std::uint8_t)((pWaveFormatStruct.ByteRate >> 8) & 0xFF);
        pHeaderBuff[30] = (std::uint8_t)((pWaveFormatStruct.ByteRate >> 16) & 0xFF);
        pHeaderBuff[31] = (std::uint8_t)((pWaveFormatStruct.ByteRate >> 24) & 0xFF);

        /* Write the block alignment -----------------------------------------------*/
        pHeaderBuff[32] = pWaveFormatStruct.BlockAlign;
        pHeaderBuff[33] = 0x00;

        /* Write the number of bits per sample -------------------------------------*/
        pHeaderBuff[34] = pWaveFormatStruct.BitPerSample;
        pHeaderBuff[35] = 0x00;

        /* Write the Data chunk, must be 'data' ------------------------------------*/
        memcpy(&pHeaderBuff[36], "data", 4);

        /* Write the number of sample data -----------------------------------------*/
        /* This variable will be written back at the end of the recording operation */
        pHeaderBuff[40] = 0x00;
        pHeaderBuff[41] = 0x4C;
        pHeaderBuff[42] = 0x1D;
        pHeaderBuff[43] = 0x00;
    }

    void EncoderWAV::HeaderUpdate()
    {
        /* Write the file length ---------------------------------------------------*/
        /* The sampling time: this value will be written back at the end of the
           recording operation.  Example: 661500 Btyes = 0x000A17FC, byte[7]=0x00, byte[4]=0xFC */
        pHeaderBuff[4] = (std::uint8_t)(fileSize);
        pHeaderBuff[5] = (std::uint8_t)(fileSize >> 8);
        pHeaderBuff[6] = (std::uint8_t)(fileSize >> 16);
        pHeaderBuff[7] = (std::uint8_t)(fileSize >> 24);
        /* Write the number of sample data -----------------------------------------*/
        /* This variable will be written back at the end of the recording operation */
        fileSize -= 44;
        pHeaderBuff[40] = (std::uint8_t)(fileSize);
        pHeaderBuff[41] = (std::uint8_t)(fileSize >> 8);
        pHeaderBuff[42] = (std::uint8_t)(fileSize >> 16);
        pHeaderBuff[43] = (std::uint8_t)(fileSize >> 24);
    }

} // namespace audio