endianness in written files seems to change

Discussion in 'C++' started by Fabian Lenzen, May 4, 2009.

  1. Hi,

    I am currently working on a program that writes a RIFF wave file. The
    big problem is writing the data chunk: Wikipedia told me that a wave
    file has to be encoded in little endian, and I found out that my machine
    also uses little endian, so simply copying the memory containing the
    sample values to a file should be enough. This also seems to work.

    My Code:

    *********
    typedef uint16_t sample_format;
    class WaveStream{
    public: // Only for testing purposes
    char header[44];
    sample_format* samples;
    int size;
    int index;
    public:
    WaveStream(int _size): size(_size){
    samples = new sample_format[_size];
    for(int i = 0; i < size; i++)
    samples = 0;
    index = 0;
    }
    void operator<<(sample_format i){
    samples[index++] = i;
    }
    void write(ostream& out){
    uint32_t filesize = size *
    sizeof(sample_format) + 44 - 8;
    uint32_t chunksize = 16;
    uint16_t datasize = size * sizeof(sample_format);
    uint16_t format = 0x0001;
    uint16_t channels = 1;
    uint32_t samplerate = 11025;
    uint32_t bitsps = 16;
    uint16_t blockalign = bitsps * channels / 8;
    uint32_t bytesps = samplerate * blockalign;
    out.write("RIFF", 4);
    out.write((char*)&filesize, 4);
    out.write("WAVE", 4);
    out.write("fmt ", 4);
    out.write((char*)&chunksize, 4);
    out.write((char*)&format, 2);
    out.write((char*)&channels, 2);
    out.write((char*)&samplerate, 4);
    out.write((char*)&bytesps, 4);
    out.write((char*)&blockalign, 2);
    out.write((char*)&bitsps, 2);
    out.write("data", 4);
    out.write((char*)&datasize, 4);
    out.write((char*)samples, size * sizeof(sample_format));
    }
    };
    *********

    I write the data to the wave-file with the following code:


    *********
    ofstream file("test.wav");
    WaveStream w(11025);
    cout << hex;

    for(int i = 0; i < 11025; i++){
    sample_format s = (sample_format)(cos(((float)i)*2*M_PI/11025
    * 220) * (1 << 6));

    cout.width(4);
    cout.fill('0');
    w << s;
    cout << w.samples << ' ';
    }
    w.write(file);
    file.close();
    *********

    The Code writes the sample values to the samples[]-memory, and puts the
    values stored in samples[] out so that I can control the output. But if
    I compare the program's output on stdout and the file's content,
    something strange happens (only the sample data section of the data
    chunk is displayed, display in human readable Big Endian format):

    file:
    *********
    0040 003f 003d 003b 0038 0033 002e 0028
    0022 001b 0013 000c 0004 fffd fff5 ffed
    ffe6 ffde ffd8 ffd2 ffcd ffc9 ffc5 ffc3
    ffc1 ffc1 ffc1 ffc2 ffc5 ffc8 ffcc ffd1
    ffd7 ffde ffe5 ffec fff4 fffc 0003 000b
    0013 001a 0021 0028 002e 0033 0037 003b
    003d 003f 003f 003f 003e 003b 0038 0034
    002f 0029 0023 001c 0014 000d 0005 fffe
    fff6 ffee ffe6 ffdf ffd9 ffd3 ffcd ffc9
    ffc5 ffc3 ffc1 ffc1 ffc1 ffc2 ffc4 ffc8
    ffcc ffd1 ffd7 ffdd ffe4 ffeb fff3 fffb
    0002 0a0d 1200 1900 2000 2700 ...
    *********

    stdout:

    *********
    0040 003f 003d 003b 0038 0033 002e 0028
    0022 001b 0013 000c 0004 fffd fff5 ffed
    ffe6 ffde ffd8 ffd2 ffcd ffc9 ffc5 ffc3
    ffc1 ffc1 ffc1 ffc2 ffc5 ffc8 ffcc ffd1
    ffd7 ffde ffe5 ffec fff4 fffc 0003 000b
    0013 001a 0021 0028 002e 0033 0037 003b
    003d 003f 003f 003f 003e 003b 0038 0034
    002f 0029 0023 001c 0014 000d 0005 fffe
    fff6 ffee ffe6 ffdf ffd9 ffd3 ffcd ffc9
    ffc5 ffc3 ffc1 ffc1 ffc1 ffc2 ffc4 ffc8
    ffcc ffd1 ffd7 ffdd ffe4 ffeb fff3 fffb
    0002 000a 0012 0019 0020 0027
    *********

    If you have a look at the output and the output a hex editor displayed
    (opening the file as little endian), you will see that the endianness is
    saved correctly, the output is equal. Except for the last line: 0020
    still with the output, 000a/0a0d is completely strange (where does this
    0d come from?!) and all bytes afterwards are reversed (1200 instead of
    0012, 1900 instead of 0019 and so on).

    The interesting thing: this happens exactly after one cycle of the
    cosine-function that generates the sample data. One cycle later, the
    endianness is correct again, and so on.

    Where does this strange behaviour come from?

    Best regards,
    Fabian Lenzen
     
    Fabian Lenzen, May 4, 2009
    #1
    1. Advertisements

  2. Fabian Lenzen

    Jerry Coffin Guest

    [ ... ]
    Not really reversed -- just offset by a byte (because of the 0d that got
    inserted). They just look reversed because in this part of the file,
    every other byte is a zero.

    As far as the 0d byte, my guess is that you opened the file in text mode
    (i.e. you didn't specify std::binary when you opened it). You're
    probably also running on Windows, where the end of a line is normally
    marked by a carriage return/line feed combination. When you tried to
    write a new-line (the 0a) the standard library turned it into an end-of-
    line marker, though a rather oddball one. Right now, it has the line-
    feed followed by the carriage return; you more often see the carriage
    return first, though in the end it makes little real difference.

    Anyway, as implied above, the cure is to specify std::binary when you
    open the file(s).
     
    Jerry Coffin, May 4, 2009
    #2
    1. Advertisements

  3. As far as the 0d byte, my guess is that you opened the file in text mode
    Ah, thank you very much! I didn't know that ios really treats binary and
    text data in different ways.
     
    Fabian Lenzen, May 4, 2009
    #3
  4. It's not the ios itself, it's the system that can introduce differences.
    AFAIK, for instance on Un*x systems 'text' and 'binary' are not
    different. On MSDOS, Windows, Mac, they are, IIRC.

    V
     
    Victor Bazarov, May 4, 2009
    #4
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.