// music module to wav writer
// - rlyeh, public domain
//
// based on modplug123 by Konstanty Bialkowski - 2010 
// based on modplug play ( gurkan@linuks.mine.nu www.linuks.mine.nu - Copyright (C) 2003 Gürkan Sengün)

#define MODPLUG_STATIC
#define MODPLUG_CPP
#include "3rd_modplug.hpp"

#include <stdio.h>
#include <string.h>
#include <vector>

// Tiny WAV writer: original code by jon olick, public domain
// Floating point support + pure C version by rlyeh, public domain | wtrmrkrlyeh
#include <stdio.h>
static void tinywav(FILE *fp, short numChannels, short bitsPerSample, int sampleRateHz, const void *data, int size, int is_floating) {
    short bpsamp;
    int length, bpsec;
    fwrite("RIFF", 1, 4, fp);
    length = size + 44 - 8;
    fwrite(&length, 1, 4, fp);
    fwrite(is_floating ? "WAVEfmt \x10\x00\x00\x00\x03\x00" : "WAVEfmt \x10\x00\x00\x00\x01\x00", 1, 14, fp);
    fwrite(&numChannels, 1, 2, fp);
    fwrite(&sampleRateHz, 1, 4, fp);
    bpsec = numChannels * sampleRateHz * bitsPerSample/8;
    fwrite(&bpsec, 1, 4, fp);
    bpsamp = numChannels * bitsPerSample/8;
    fwrite(&bpsamp, 1, 2, fp);
    fwrite(&bitsPerSample, 1, 2, fp);
    fwrite("data", 1, 4, fp);
    fwrite(&size, 1, 4, fp);
    fwrite(data, 1, size, fp);
}

char *read_file(char *filename, long *size) {
    FILE *f = fopen(filename, "rb");
    if (f) {
        fseek(f, 0L, SEEK_END);
        (*size) = ftell(f);
        rewind(f);
        char *data = (char*)malloc(*size);
        if( fread(data, *size, 1, f) == 1 ) {
            fclose(f);
            return data;
        }
        free(data);
        fclose(f);
    }
    return NULL;
}

int main(int argc, char* argv[]) {
    if(argc != 3) exit(-printf("%s\n", "mod2wav infile.mod outfile.wav"));

    char *filename = argv[1];
    long size; char *bin = read_file(filename, &size);
    if (!bin) exit(-printf("%s\n", "cannot read input file"));

    ModPlug_Settings settings;
    ModPlug_GetSettings(&settings);

    // settings must be set before ModPlug_Load()
    settings.mResamplingMode = MODPLUG_RESAMPLE_FIR; /* RESAMP */
    settings.mChannels = 2; // 1 if mono
    settings.mBits = 16;
    settings.mFrequency = 44100;
    settings.mStereoSeparation = 128;
    settings.mMaxMixChannels = 256;
#if 0
    settings.mFlags=MODPLUG_ENABLE_OVERSAMPLING | \
                    MODPLUG_ENABLE_NOISE_REDUCTION | \
            MODPLUG_ENABLE_REVERB | \
            MODPLUG_ENABLE_MEGABASS | \
            MODPLUG_ENABLE_SURROUND;
    settings.mReverbDepth = 100;   //  0 - 100     [REV--DLY--]
    settings.mReverbDelay = 200;   // 40 - 200 ms  00-FF  
    settings.mSurroundDepth = 100; //  0 - 100     [SUR--DLY--]
    settings.mSurroundDelay = 40;  //  5 -  40 ms   
    settings.mBassAmount  = 100;   //  0 - 100     [BAS--RNG--]
    settings.mBassRange   = 100;   // 10 - 100 hz  
#endif

    ModPlug_SetSettings(&settings);
    ModPlugFile *f2 = ModPlug_Load(bin, size);
    if (!f2) {
        // free(bin); // @leak
        exit(-printf("could not load %s\n", filename));
    }

    std::vector<unsigned char> raw;

    for( int mlen = 1; mlen > 0; ) {
        enum { BUF_SIZE = 4096 };
        unsigned char audio_buffer[BUF_SIZE];
        mlen = ModPlug_Read(f2,audio_buffer,sizeof(audio_buffer));

        if( mlen > 0 ) for( int i = 0; i < mlen; ++i ) {
            raw.push_back( audio_buffer[i] );
        }
    }

    if( raw.size() ) {
        FILE *fp = fopen(argv[2], "wb");
        if (!fp) exit(-printf("%s\n", "cannot open output file"));
        tinywav(fp, 2, 16, 44100, raw.data(), raw.size(), false /*is_floating*/);
        fclose(fp);
    }

    puts(ModPlug_GetName(f2));    
    // ModPlug_Unload(f2); // @leak
    // free(bin); // @leak

    return raw.size() ? 0 : -1;
}