0

I'm trying to apply the u-law algorithm to a wav file file.wav, and then create a new file file2.wav. file.wav has 16 bits/sample, and I want to obtain a file2.wav that has 8 bits/sample.

This is my code:

#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>
#include <iostream>
#include <string>
#include <fstream>

using namespace std;
using std::string;
using std::fstream;

typedef struct  WAV_HEADER {
    char                RIFF[4];
    unsigned long       ChunkSize;
    char                WAVE[4];
    char                fmt[4];
    unsigned long       Subchunk1Size;
    unsigned short      AudioFormat;
    unsigned short      NumOfChan;
    unsigned long       SamplesPerSec;
    unsigned long       bytesPerSec;
    unsigned short      blockAlign;
    unsigned short      bitsPerSample;
    char                Subchunk2ID[4];
    unsigned long       Subchunk2Size;

} wav_hdr;

int headerSize = 0;
string path = "file.wav";
wav_hdr wavHeader;

FILE* openFile() {
    const char* filePath;
    FILE *wavFile;

    headerSize = sizeof(wav_hdr);
    filePath = path.c_str();
    wavFile = fopen(filePath, "rb");

    if (wavFile == NULL) {
        printf("Error\n");
    }

    fread(&wavHeader, headerSize, 1, wavFile);

    return wavFile;
}

int8_t MuLaw_Encode(int16_t number)
{
    const uint16_t MULAW_MAX = 0x1FFF;
    const uint16_t MULAW_BIAS = 33;
    uint16_t mask = 0x1000;
    uint8_t sign = 0;
    uint8_t position = 12;
    uint8_t lsb = 0;
    if (number < 0)
    {
        number = -number;
        sign = 0x80;
    }
    number += MULAW_BIAS;
    if (number > MULAW_MAX)
    {
        number = MULAW_MAX;
    }
    for (; ((number & mask) != mask && position >= 5); mask >>= 1, position--)
        ;
    lsb = (number >> (position - 4)) & 0x0f;
    return (~(sign | ((position - 5) << 4) | lsb));
}

int fileSize(FILE *file) {
    int fileSize = 0;

    fseek(file, 0, SEEK_END);
    fileSize = ftell(file);
    fseek(file, 0, SEEK_SET);

    return fileSize;
}

double bitsPerSample() {
    double bitsPerE;

    bitsPerE = wavHeader.bitsPerSample;
    return bitsPerE;
}

int main() {
    FILE *wavFile;
    wavFile = openFile();
    FILE* fptr2;
    fptr2 = fopen("file2.wav", "wb");

    int samples_count = fileSize(wavFile) / bitsPerSample();
    short int *value = new short int[samples_count];

    for (int16_t i = 0; i < samples_count; i++)
    {
        fread(&value[i], samples_count, 1, wavFile);
        cout << value[i] << " "; // the output is in the attached picture
        MuLaw_Encode(value[i]);
    }
        fwrite(value, sizeof(char), samples_count, fptr2);

    return 0;
}

I took the u-law algorithm from here (2.1. µ-Law Compression (Encoding) Algorithm)

Am I doing something wrong? Because I obtain a corrupt file.

value[i]

Mr. Wizard
  • 1,093
  • 1
  • 12
  • 19

1 Answers1

0

No header is ever written to the result file, so the first part of the data would get interpreted as a header, and it would be wrong. You can see in the file that it does not start with RIFFþR�WAVEfmt or something sufficiently similar.

The data written to the result file is value, the original data read from the input file, not the µ-law encoded data (which is only cout'ed and not saved).

The loop that reads the samples reads some wrong samples, because the computation of samples_count puts the current position back at the start, where the header is.

harold
  • 61,398
  • 6
  • 86
  • 164
  • I understand, and how do I obtain the size of the header so I can do something like `samples_count-header_size` and start the `for` loop from this value? – Mr. Wizard Mar 08 '20 at 22:01
  • `sizeof(wavHeader)` is it ok? – Mr. Wizard Mar 08 '20 at 22:02
  • @Mr.Wizard you could `fseek` to `sizeof(wavHeader)`, there are various other solutions.. for example you could use the size found in the header, rather than using the `fseek`/`ftell` stuff to find the length, that seems simpler anyway – harold Mar 08 '20 at 22:06