2

I'm trying to convert 32 bit audio data into 24 bit audio. However, when I try to play it all I get is noise. It seems I'm missing something very basic?

It should be little endian raw PCM.

template<typename T>
static std::vector<int8_t> audio_32_to_24(const T& audio_data)
{   
    auto size        = std::distance(std::begin(audio_data), std::end(audio_data));
    auto input8      = reinterpret_cast<const int8_t*>(&(*std::begin(audio_data)));
    auto output8     = std::vector<int8_t>();

    output8.reserve(size*3);
    for(int n = 0; n < size; ++n)
    {
        output8.push_back(input8[n*4+1]);
        output8.push_back(input8[n*4+2]);
        output8.push_back(input8[n*4+3]);
    }

    return output8;
}
Kevin Panko
  • 8,356
  • 19
  • 50
  • 61
ronag
  • 49,529
  • 25
  • 126
  • 221
  • Have you tried stepping through the code in a debugger, or simply inspecting the input and output to your function?# – Oliver Charlesworth Nov 29 '11 at 23:04
  • 1
    you may want to specify (a) encoding (assuming raw PCM) (b) endianness (assuming big-endian); Also, may I suggest using a library (like **[`libsox`](http://sox.sourceforge.net)**); Did you try reversing the byte ordering for output? It seems wrong, but I can't tell from the info – sehe Nov 29 '11 at 23:04
  • Very unusual to have 32-bit integer PCM. Surely it is a float? – Hans Passant Nov 29 '11 at 23:07
  • @Oli Charlesworth: Difficult to make much sense of the values since it's displayed as bytes instead of 24 bit. – ronag Nov 29 '11 at 23:07
  • @Hans: It is a 32-bit integer. – ronag Nov 29 '11 at 23:08
  • @sehe: I would prefer not using a library for such a simple thing. I've tried reversing. – ronag Nov 29 '11 at 23:08
  • @ronag: The conversion isn't difficult... (`a << 16 + b << 8 + c`). You probably only need to do this once to establish what the problem is. – Oliver Charlesworth Nov 29 '11 at 23:09
  • Also, C++ has rules on what can alias to what, and I think you might be violating them. http://stackoverflow.com/questions/98650/what-is-the-strict-aliasing-rule. Specifically in this case, you're casting directly from audio_data's type to int8_t*. I think you have to go through char* first. Not sure if int8_t counts as a char* type or not for this rule, which is why I'm leaving a comment, not an answer :P – Nathan Monteleone Nov 29 '11 at 23:11
  • 2
    FWIW some (many?) audio libraries expect each 24-bit audio sample to be stored with 1 byte of padding while the audio is in memory, so that the audio samples will be 32-bit-aligned for better performance. That is, it's only when the file is on disk that the 4th byte of each sample is omitted to save space. If that's true, and you're handing 24-bit packed audio to one of those libraries to play, that would explain why it comes out as white noise. – Jeremy Friesner Nov 29 '11 at 23:11

1 Answers1

3

If the input is LE too, the output byte ordering seems inverted:

    output8.push_back(input8[n*4+3]);
    output8.push_back(input8[n*4+2]);
    output8.push_back(input8[n*4+1]);

Edit For sheer fun, I'd consider replacing it with this (since it looks like you might be using C++0x:

size_t i = 0;

std::copy_if(
    reinterpret_cast<const int8_t*>(&*std::begin(audio_data)),
    reinterpret_cast<const int8_t*>(&*std::end(audio_data)),
    std::back_inserter(output),
    [&i] (int) { return 0 == (i++ % 4); });

Also, consider replacing the

  • reserve with resize
  • the push_back or output iterator with a direct iterator into the target container
sehe
  • 374,641
  • 47
  • 450
  • 633