<repo_name>linocontreras/paralell-drc<file_sep>/src/sequential/SequentialCompressor.java
/**
 * Programación avanzada: Proyecto final
 * Fecha: 2019-12-03
 * Autor: A01700457 - <NAME>
 */

package sequential;

import java.io.*;
import java.nio.*;

public class SequentialCompressor {
    double[] frames;
    double threshold;
    double ratio;
    double gain;

    public SequentialCompressor(double[] frames, double threshold, double ratio, double gain) {
        this.frames = frames;
        this.threshold = threshold;
        this.ratio = ratio;
        this.gain = gain;
    }

    public double[] compress() {
        for (int i = 0; i < frames.length; i++) {
            if (frames[i] == 0)
                continue;

            int sign = frames[i] < 0 ? -1 : 1;
            frames[i] = frames[i] < 0 ? -frames[i] : frames[i];

            frames[i] *= Math.log10(10 + this.gain);
            if (frames[i] > threshold) {
                frames[i] = threshold + ((frames[i] - threshold) * (1 / ratio));
            }
            frames[i] = frames[i] <= 1 ? frames[i] : 1;
            frames[i] = frames[i] * sign;
        }
        return frames;
    }

    public static void main(String[] args) {
        if (args.length != 4) {
            PrintUsage();
            System.exit(1);
        }

        File inputFile = new File(args[0]);

        if (!inputFile.exists()) {
            System.err.println("El archivo especificado no existe.");
            System.exit(2);
        }

        double threshold = Double.parseDouble(args[1]);

        if (threshold < 0 || threshold > 1) {
            System.err.println("El threshold debe ser entre 0 y 1.");
            System.exit(3);
        }

        double ratio = Double.parseDouble(args[2]);

        if (ratio < 1) {
            System.err.println("El ratio debe ser a partir de 1.");
            System.exit(4);
        }

        double gain = Double.parseDouble(args[3]);

        if (gain < 0) {
            System.err.println("La ganancia debe ser mayor o igual a 0.");
            System.exit(5);
        }

        try {

            FileInputStream input = new FileInputStream(inputFile);
            byte[] dataBytes = input.readAllBytes();
            ByteBuffer dataBytesBuffer = ByteBuffer.wrap(dataBytes);//.order(ByteOrder.BIG_ENDIAN);
            DoubleBuffer dataBuffer = DoubleBuffer.allocate(dataBytes.length / Double.BYTES);
            double[] data = dataBuffer.put(dataBytesBuffer.asDoubleBuffer()).array();
            input.close();

            SequentialCompressor sc = new SequentialCompressor(data, threshold, ratio, gain);

            System.out.println("SequentialCompressor Starting...");
            long start = System.nanoTime();

            double[] compressed = sc.compress();

            System.out.println("Time elapsed: " + ((System.nanoTime() - start) / 1000000) + "ms");

            String outputFilePath = args[0].substring(0, args[0].lastIndexOf("."));
            FileOutputStream output = new FileOutputStream(new File(outputFilePath + ".cps"));

            ByteBuffer compressedData = ByteBuffer.allocate(compressed.length * Double.BYTES);

            compressedData.asDoubleBuffer().put(compressed);

            output.write(compressedData.array());
            output.close();
        } catch (Exception ex) {
            ex.printStackTrace();
            System.exit(100);
        }
    }

    private static void PrintUsage() {
        System.err.println("Usage: java sequential.SequentialCompressor file.frames threshold ratio gain");
    }
}<file_sep>/src/tbb/tbbcompressor.cpp
/**
 * Programación avanzada: Proyecto final
 * Fecha: 2019-12-03
 * Autor: A01700457 - <NAME>
 */

#include <iostream>
#include <cstring>
#include <tbb/task_scheduler_init.h>
#include <tbb/parallel_for.h>
#include <tbb/blocked_range.h>
#include "cppheader.h"
#include <cmath>

using namespace std;
using namespace tbb;

#define N 10
#define GRAIN 200

class Compressor {
private:
	double *frames;
	int size;
    double threshold;
    double ratio;
    double gain;

public:
	Compressor(double *frames, int size, double threshold, double ratio, double gain) 
		: frames(frames), size(size), threshold(threshold), ratio(ratio), gain(gain) {}

	void operator() 
		(const blocked_range<int> &r) const {
        int sign;
		for (int i = r.begin(); i != r.end(); i++) {
            if (frames[i] == 0)
                continue;

            sign = frames[i] < 0 ? -1 : 1;
            frames[i] = frames[i] < 0 ? -frames[i] : frames[i];

            frames[i] *= log10(10 + gain);
            if (frames[i] > threshold) {
                frames[i] = threshold + ((frames[i] - threshold) * (1 / ratio));
            }
            frames[i] = frames[i] <= 1 ? frames[i] : 1;
            frames[i] = frames[i] * sign;
		}
	}
};

void printUsage(char *program) {
    printf("Usage: %s file.frames threshold ratio gain\n", program);
}

typedef union
{
    double d;
    unsigned char s[8];
} Union_t;


// reverse little to big endian or vice versa as per requirement
double reverse_endian(double in)
{
    int i, j;
    unsigned char t;
    Union_t val;

    val.d = in;
    // swap MSB with LSB etc.
    for(i=0, j=7; i < j; i++, j--)
    {
        t = val.s[i];
        val.s[i] = val.s[j];
        val.s[j] = t;
    }
    return val.d;
}

int main(int argc, char* argv[]) {
    if (argc != 5) {
        printUsage(argv[0]);
        return 1;
    }
    FILE *file = fopen(argv[1], "rb");

    if (file == NULL) {
        perror(argv[0]);
        return 2;
    }

    double threshold = strtod(argv[2], NULL);

    if (threshold < 0 || threshold > 1) {
        fprintf(stderr, "El threshold debe ser entre 0 y 1.");
        return 3;
    }

    double ratio = strtod(argv[3], NULL);

    if (ratio < 1) {
        fprintf(stderr, "El ratio debe ser a partir de 1.");
        return 4;
    }

    double gain = strtod(argv[4], NULL);

    if (gain < 0) {
        fprintf(stderr, "La ganancia debe ser mayor o igual a 0.");
        return 5;
    }

    fseek(file, 0L, SEEK_END);
    int size = ftell(file) / sizeof (double);
    rewind(file);

    double *frames = new double[size * sizeof *frames];

    fread(frames, sizeof *frames, size, file);

    int i;
    for (i = 0;i < size; i++) {
        frames[i] = reverse_endian(frames[i]);
    }

    
	Timer t;
	double ms = 0;
	
    printf("Starting TBB...\n");
	for (int i = 0; i < N; i++) {
		t.start();

		parallel_for(
			blocked_range<int>(0, size, GRAIN),
			Compressor(frames, size, threshold, ratio, gain));

		ms += t.stop();
	}
    printf("Elapsed time: %lf ms.\n", (ms /N));

    char newpath[FILENAME_MAX];

    int lastindex = strrchr(argv[1], '.') - argv[1];

    strcpy(newpath, argv[1]);
    strcpy(newpath + lastindex, ".cps");

    FILE *newfile = fopen(newpath, "wb");

    for (i = 0;i < size; i++) {
        frames[i] = reverse_endian(frames[i]);
    }
    fwrite(frames, sizeof *frames, size, newfile);

    delete[] frames;
    fclose(file);
    fclose(newfile);
    return 0;
}

<file_sep>/README.md
# Compresor de rango dinámico para archivos wav

Implementación con diferentes tecnologías de una paralelización del algoritmo de compresión de rango dinámico.

## Librerías de terceros

Para la lectura y escritura de los archivos de audio se ha utilizado una librería obtenida de aquí: [http://www.labbookpages.co.uk](http://www.labbookpages.co.uk).

## Build
Para generar los archivos executables ejecuta el programa ```make```

<file_sep>/src/copenmp/copenmp.c
/**
 * Programación avanzada: Proyecto final
 * Fecha: 2019-12-03
 * Autor: A01700457 - <NAME>
 */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <sys/time.h>
#include <sys/types.h>
#include <omp.h>
#include <string.h>

struct timeval startTime, stopTime;
int started = 0;

void start_timer() {
	started = 1;
	gettimeofday(&startTime, NULL);
}

double stop_timer() {
	long seconds, useconds;
	double duration = -1;

	if (started) {
		gettimeofday(&stopTime, NULL);
		seconds  = stopTime.tv_sec  - startTime.tv_sec;
		useconds = stopTime.tv_usec - startTime.tv_usec;
		duration = (seconds * 1000.0) + (useconds / 1000.0);
		started = 0;
	}
	return duration;
}

typedef union
{
    double d;
    unsigned char s[8];
} Union_t;

// reverse little to big endian or vice versa as per requirement
double reverse_endian(double in)
{
    int i, j;
    unsigned char t;
    Union_t val;

    val.d = in;
    // swap MSB with LSB etc.
    for(i=0, j=7; i < j; i++, j--)
    {
        t = val.s[i];
        val.s[i] = val.s[j];
        val.s[j] = t;
    }
    return val.d;
}

void compress(double *frames, int size, double threshold, double ratio, double gain) {
    int i, sign;
    #pragma omp parallel for shared(frames, threshold, ratio, gain) private(sign)
    for (i = 0; i < size; i++) {
        if (frames[i] == 0)
                continue;

        sign = frames[i] < 0 ? -1 : 1;
        frames[i] = frames[i] < 0 ? -frames[i] : frames[i];

        frames[i] *= log10(10 + gain);
        if (frames[i] > threshold) {
            frames[i] = threshold + ((frames[i] - threshold) * (1 / ratio));
        }
        frames[i] = frames[i] <= 1 ? frames[i] : 1;
        frames[i] = frames[i] * sign;
    }
}

void printUsage(char *program) {
    printf("Usage: %s file.frames threshold ratio gain\n", program);
}

int main(int argc, char **argv) {
    if (argc != 5) {
        printUsage(argv[0]);
        return 1;
    }
    FILE *file = fopen(argv[1], "rb");

    if (file == NULL) {
        perror(argv[0]);
        return 2;
    }

    double threshold = strtod(argv[2], NULL);

    if (threshold < 0 || threshold > 1) {
        fprintf(stderr, "El threshold debe ser entre 0 y 1.");
        return 3;
    }

    double ratio = strtod(argv[3], NULL);

    if (ratio < 1) {
        fprintf(stderr, "El ratio debe ser a partir de 1.");
        return 4;
    }

    double gain = strtod(argv[4], NULL);

    if (gain < 0) {
        fprintf(stderr, "La ganancia debe ser mayor o igual a 0.");
        return 5;
    }

    fseek(file, 0L, SEEK_END);
    int size = ftell(file) / sizeof (double);
    rewind(file);

    double *frames = malloc(size * sizeof *frames);

    fread(frames, sizeof *frames, size, file);

    int i;
    for (i = 0;i < size; i++) {
        frames[i] = reverse_endian(frames[i]);
    }
    start_timer();
    double ms;

    printf("Starting OpenMP...\n");
    compress(frames, size, threshold, ratio, gain);
    ms = stop_timer();
    printf("Elapsed time: %lf ms.\n", ms);

    char newpath[FILENAME_MAX];

    int lastindex = strrchr(argv[1], '.') - argv[1];

    strcpy(newpath, argv[1]);
    strcpy(newpath + lastindex, ".cps");

    FILE *newfile = fopen(newpath, "wb");

    for (i = 0;i < size; i++) {
        frames[i] = reverse_endian(frames[i]);
    }
    fwrite(frames, sizeof *frames, size, newfile);

    free(frames);
    fclose(file);
    fclose(newfile);
    return 0;
}<file_sep>/src/tbb/cppheader.h
/**
 * Programación avanzada: Proyecto final
 * Fecha: 2019-12-03
 * Autor: A01700457 - <NAME>
 * Archivo compartido por el profesor durante la clase.
 */

#ifndef TIMER_H
#define TIMER_H

#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <sys/time.h>
#include <sys/types.h>

const int N = 10;

class Timer {
private:
    timeval startTime;
    bool 	started;

public:
    Timer() :started(false) {}

    void start(){
    	started = true;
        gettimeofday(&startTime, NULL);
    }

    double stop(){
        timeval endTime;
        long seconds, useconds;
        double duration = -1;

        if (started) {
			gettimeofday(&endTime, NULL);

			seconds  = endTime.tv_sec  - startTime.tv_sec;
			useconds = endTime.tv_usec - startTime.tv_usec;

			duration = (seconds * 1000.0) + (useconds / 1000.0);
			started = false;
        }
		return duration;
    }
};

#endif
<file_sep>/src/parser/ExtractFrames.java
/**
 * Programación avanzada: Proyecto final
 * Fecha: 2019-12-03
 * Autor: A01700457 - <NAME>
 */
package parser;

import java.io.*;
import java.nio.ByteBuffer;

public class ExtractFrames {
    private WavFile wav;

    public ExtractFrames(String inputFile) throws WavFileException, IOException {
        this.wav = WavFile.openWavFile(new File(inputFile));
    }

    public ByteBuffer extract() throws WavFileException, IOException {
        ByteBuffer data = ByteBuffer.allocate((int) wav.getNumFrames() * wav.getNumChannels() * Double.BYTES);
        this.wav.readFrames(data.asDoubleBuffer(), (int)wav.getNumFrames() * wav.getNumChannels());
        return data;
    }

    public void close() throws IOException
    {
        this.wav.close();
    }

    public static void main(String[] args) {
        if (args.length != 1) {
            PrintUsage();
            System.exit(1);
        }
        try {
            ExtractFrames extractFrames = new ExtractFrames(args[0]);
            ByteBuffer data = extractFrames.extract();
            extractFrames.close();
    
            DataOutputStream out = new DataOutputStream(new FileOutputStream(args[0] + ".frames"));
            out.write(data.array());
            out.close();   
        } catch(Exception ex) {
            System.err.println("Ha ocurrido un error al intentar extraer los frames.");
            System.err.print(ex);
            ex.printStackTrace();
            System.exit(2);
        }
    }

    private static void PrintUsage() {
        System.out.println("Usage: java parser.ExtractFrames audiofile.wav");
    }
}<file_sep>/Makefile
all: Parser SequentialCompressor ThreadsCompressor FJCompressor CSequentialCompressor TBBCompressor

Parser:
	javac -d ./bin ./src/parser/*

SequentialCompressor: Parser
	javac -d ./bin ./src/sequential/*

ThreadsCompressor: Parser
	javac -d ./bin ./src/threads/*

FJCompressor: Parser
	javac -d ./bin ./src/forkjoin/*

CSequentialCompressor: Parser
	gcc -o ./bin/csequential ./src/csequential/csequential.c -lm -ggdb -Wall

COpenMPCompressor: Parser
	gcc -o ./bin/copenmp ./src/copenmp/copenmp.c -lm -Wall -fopenmp

TBBCompressor: Parser
	gcc -o ./bin/tbbcompressor ./src/tbb/tbbcompressor.cpp -lm -Wall -ltbb