0

I'm trying to open a wav file, read it, convert the buffer to an integer array, then convert it back and write it.

int main(){

    ifstream file ("C:\\Documents\\ParadigmE3-shortened.wav",std::ios_base::out | std::ios_base::binary);

    char * header = new char[50000044];
    file.read(header, 50000044);

    cout << header[0] << endl;

    unsigned int * header_int = new unsigned int[50000044];

    for(unsigned int i = 0; i < sizeof(header); i++){
        header_int[i] = header[i];
    }



    char * writefile = new char[50000044];

    for(unsigned int i = 0; i < sizeof(header); i++){
        itoa(header_int[i], &writefile[i], 10);
    }


    cout << writefile[0] << endl;
    ofstream newfile ("C:\\Documents\\ParadigmE3-modified.wav", std::ios_base::out | std::ios_base::binary);



    newfile.write(writefile, 50000044);

}

Currently, this prints:

R
8

Indicating that it changed the data in the process of converting it. How would I get this to work properly?


After some suggestions, and learning I can perform calculations on char variables, I reformulated the code, and now it is:

int main(){

    // Create file variable with file
    ifstream file ("C:\\Documents\\ParadigmE3-shortened.wav",std::ios_base::out | std::ios_base::binary);

    // Read the first 15040512 bytes to char array pointer, called header
    char * header = new char[15040512];
    file.read(header, 15040512);

    // Copy contents of header to writefile, after the 44'th byte, multiply the value by 2
    char * writefile = new char[15040512];
    for(int i = 0; i < sizeof(header); i++){
        if(i<44) writefile[i] = header[i];
        if(i>=44) writefile[i] = 2 * header[i];
    }

    // Copy the contents of writefile, but at the 44th byte, divide it by 2, returning it to its original value
    for(int i = 0; i < sizeof(header); i++){
        if(i<44) writefile[i] = writefile[i];
        if(i>=44) writefile[i] = .5 * writefile[i];
    }

    // Create file to write to
    ofstream newfile ("C:\\Documents\\ParadigmE3-modified.wav", std::ios_base::out | std::ios_base::binary);

    // Write writefile to file
    newfile.write(writefile, 15040512);

}

However, upon playing (in Windows Media Player), it does not play, so it is clearly not the original file, as I was going for.

JVE999
  • 3,327
  • 10
  • 54
  • 89
  • 4
    There are so many things wrong with this I don't even know where to start. What are you actually trying to achieve? – Jonathan Potter Sep 07 '13 at 00:37
  • It's unclear. Do you want the output to be "binary", or a human-readable representation? – Hot Licks Sep 07 '13 at 00:38
  • I'm trying to open an audio file, convert it to an int array for manipulation, then save it back to the file. @HotLicks I want it to be the same as original, so binary. – JVE999 Sep 07 '13 at 00:38
  • If you want to save it back, why convert to character form with itoa? – Hot Licks Sep 07 '13 at 00:39
  • 1
    `50000044` can not be divided in blocks of `8` without a remainder. – Alexandru Barbarosie Sep 07 '13 at 00:39
  • @HotLicks - `ofstream write` requires a char array pointer – JVE999 Sep 07 '13 at 00:41
  • You need to understand the difference between `char` as a numeric datatype and "character" as a human-meaningful token. – Hot Licks Sep 07 '13 at 00:42
  • @AlexandruBarbarosie - I changed all instances of 50000044 to 15040512 – JVE999 Sep 07 '13 at 00:42
  • @HotLicks - `char` as in 1 byte, or 8 bits of binary data? I'm confused – JVE999 Sep 07 '13 at 00:43
  • `char` is one byte, which on most architectures is 8 bits. It is a numeric value. A "character" is something like "A" or "%" or "Q". In computers we often store a series of numeric quantities and pass them to a display or printer to be printed as characters. The numeric quantities that represent a character may be (on modern systems) 8, 16, or 32 bits. Often characters are stored as an array of `char`. But other types of data (such as sound data) can be stored as sequences of `char` values. This doesn't make them characters. – Hot Licks Sep 07 '13 at 00:47
  • So, are you saying I need to specify the specific size of the char? I have not seen that specification. – JVE999 Sep 07 '13 at 00:49
  • No, I'm saying that a `char` is a numeric value, with no inherent meaning. You give it the meaning based on how you use it. It makes no sense to apply a conversion that converts a pure numeric value to a sequence of bytes which represent characters, when you want to store the original numeric value. A `char` may contain a value which we humans would write as "100" (decimal) or "0x64" (hex) or "01100100" (binary). But it's not any of those human representations, it's the pure numeric value. – Hot Licks Sep 07 '13 at 00:55
  • Or a `char` may contain the numeric value we humans would write as "107", or "0x6B", but we may know that it's *meaning* (which is not somehow stored in the `char` but must be kept track of separately) is a *character*, which happens to be the letter "k". – Hot Licks Sep 07 '13 at 00:58
  • If you want to present a numeric value in a way that humans can understand it, you use a conversion routine such as itoa (though there are better ones) to convert the pure numeric value into a sequence of human-readable characters. But if the intent is to pass the data on to some other computer process that expects pure numeric data then you leave it well enough alone. – Hot Licks Sep 07 '13 at 01:00
  • I still don't quite follow. `ifstream read` reads to a character array buffer. I have to convert it from a character array to integer array to perform calculations (not in the the program yet), and then I have to convert it from an integer array to character array for `ofstream` to write it. – JVE999 Sep 07 '13 at 01:00
  • 1
    No, it reads a `char` array buffer. And you do not have to convert it to an `int` array to perform calculations on it, you can perfectly well do numeric operations on `char` values. In a way a `char` is just a small `int`. – Hot Licks Sep 07 '13 at 01:02
  • @HotLicks I did not know I could perform calculations on `char` values. Does this include all of the mathematical operators that I can use on `int` values? – JVE999 Sep 07 '13 at 01:03
  • 1
    Yes. Like I said, a `char` is just a small `int`. (You do need to beware of the fact that `char` may be "signed" or "unsigned" -- ie, it may represent the values -128 to 127, or it may represent 0 to 255, depending on the specific compiler you use.) – Hot Licks Sep 07 '13 at 01:24
  • 1
    (And for some operations you need to "cast" the numeric result to `char` to assign it back to a `char`: `char result = (char) some + mathematical * expression;`. This is because the `char` is "widened" to `int` to perform most mathematical operations.) – Hot Licks Sep 07 '13 at 01:26
  • And take care in calculations that would overflow or underflow the char (ie: that can give a result out of the range of the numerical values Hot Licks said) – Diego C Nascimento Sep 07 '13 at 01:32

1 Answers1

0

I figured it out. A couple things I learned were that you can perform calculations on 8-bit char variables (with a max value of 255 unsigned), so I didn't need to change it to an int array, however, I did because it gave me more headroom to work with (without worrying about clipping the values at 255).

I have included the entire program (with the header include list), as I also think this is a common question, and this by far is the simplest way I've seen to do it (the other ways I couldn't figure out -- they were much more complicated than this to do the same thing).

It reads the wav file, then it performs an operation on the data portion (beginning at the 45'th byte), then it does the reverse, and writes the file, which is a copy of the original.

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <fstream>
#include <string>
#include <bitset>
#include <string.h>

using namespace std;

int main(){


    ifstream file ("C:\\Documents\\ParadigmE3-shortened.wav",std::ios_base::out | std::ios_base::binary);

    char * header = new char[15040512];
    file.read(header, 15040512);


    int * writefile = new int[15040512];
    for(int i = 0; i < 15040512; i++){
        if(i<44) writefile[i] = header[i];
        if(i>=44) writefile[i] = 2 * header[i];
    }

    for(int i = 0; i < 15040512; i++){
        if(i<44) header[i] = writefile[i];
        if(i>=44) header[i] = .5 * writefile[i];
    }

    ofstream newfile ("C:\\Documents\\ParadigmE3-modified.wav", std::ios_base::out | std::ios_base::binary);


    newfile.write(header, 15040512);

}
JVE999
  • 3,327
  • 10
  • 54
  • 89
  • What are you trying to do with this? Make it louder? It doesn't really work that way. – Retired Ninja Sep 07 '13 at 01:47
  • It worked fine for me (in the example I reverse it, so it's the original, but just halving it lowers the volume). – JVE999 Sep 07 '13 at 01:49
  • 1
    Uhm... Still so many things wrong! Basics: mixing C and C++ header files together, leaking memory, etc. Subtle bugs waiting to happen: multiplying by 0.5 is **not** the inverse operation of multiplying by two when you are dealing with integers. I could go on. This is just *bad*. – Nik Bougalis Sep 07 '13 at 01:54
  • @NikBougalis Sounds terrible. I'm guessing 0.5 is a float, so it has to cast the float as an integer, but it doesn't always? – JVE999 Sep 07 '13 at 01:56
  • 1
    It also pays no attention to the number of bits per sample or the fact that 8 bit data is unsigned but 16 bit is signed. – Retired Ninja Sep 07 '13 at 01:57
  • @Jamil plenty of things "work" but aren't right. Given a screwdriver, you can paint: use it to open the the can of paint, stir the paint, and then impale a kitchen sponge to move paint onto a wall. It works – it's not *right*. There's a difference. – Nik Bougalis Sep 07 '13 at 01:58
  • @NikBougalis I know. Reading, changing data, and writing a wav file are new to me. +1 for pointing out things to look for. – JVE999 Sep 07 '13 at 02:00