What's wrong with GCC (sgdk)? Why it crashes 10% of runs?

SGDK only sub forum

Moderator: Stef

Chilly Willy
Very interested
Posts: 2984
Joined: Fri Aug 17, 2007 9:33 pm

Post by Chilly Willy » Fri Jul 20, 2012 8:15 pm

Okay, here's a debugged/tested version of bintos.c:

Code: Select all

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <malloc.h>
#include <inttypes.h>


static int min(int x, int y)
{
    return (x < y) ? x : y;
}

static int vdpcolor(char b, char g, char r)
{
   // genesis only define on 3 bits (but shifted to 1 left)
    r = (r >> 4) & 0xE;
    g = (g >> 4) & 0xE;
    b = (b >> 4) & 0xE;

    return (r << 0) | (g << 4) | (b << 8);
}

int main(int argc, char **argv)
{
    int bitmap;
    int ii, jj, kk, ll;
    int w, h;
    int len;
    int total;
    int align;
    int sizealign;
    int formatint;
    int nullfill;
    char *format;
    char *formatasm;
    char *shortname;
    char *FileName;
    char *FileNameOut;
    FILE *FileInput;
    FILE *FileOutput;
    char temp[512];

    // default
    bitmap = 0;
    FileName = "";
    FileNameOut = "";
    format = "u8 ";
    formatasm = "b";
    formatint = 1;
    total = 0;
    align = 4;
    sizealign = 1;
    nullfill = 0;

    // parse parmeters
    for (ii=1; ii<argc; ii++)
    {
        if (!strcmp(argv[ii], "-u8"))
        {
            format = "u8 ";
            formatasm = "b";
            formatint = 1;
        }
        else if (!strcmp(argv[ii], "-s8"))
        {
            format = "s8 ";
            formatasm = "b";
            formatint = 1;
        }
        else if (!strcmp(argv[ii], "-u16"))
        {
            format = "u16 ";
            formatasm = "w";
            formatint = 2;
        }
        else if (!strcmp(argv[ii], "-s16"))
        {
            format = "s16 ";
            formatasm = "w";
            formatint = 2;
        }
        else if (!strcmp(argv[ii], "-u32"))
        {
            format = "u32 ";
            formatasm = "l";
            formatint = 4;
        }
        else if (!strcmp(argv[ii], "-s32"))
        {
            format = "s32 ";
            formatasm = "l";
            formatint = 4;
        }
        else if (!strcmp(argv[ii], "-bmp"))
        {
            bitmap = 1;
            format = "u16 ";
            formatasm = "w";
            formatint = 2;
        }
        else if (!strcmp(argv[ii], "-align"))
        {
            ii++;
            align = strtoimax(argv[ii], NULL, 0);
            if (!align) align = 4;
        }
        else if (!strcmp(argv[ii], "-sizealign"))
        {
            ii++;
            sizealign = strtoimax(argv[ii], NULL, 0);
            if (!sizealign) sizealign = 1;
        }
        else if (!strcmp(argv[ii], "-nullfill"))
        {
            ii++;
            nullfill = strtoimax(argv[ii], NULL, 0);
        }
        else if (!FileName[0]) FileName = argv[ii];
        else if (!FileNameOut[0]) FileNameOut = argv[ii];
    }

    if (!FileNameOut[0]) FileNameOut = FileName;

    if (!strcasecmp(&FileName[strlen(FileName)-4], ".bmp"))
    {
        bitmap = 1;
        format = "u16 ";
        formatasm = "w";
        formatint = 2;
        align = 16;
    }

    FileInput = fopen(FileName, "rb");
    if (!FileInput)
    {
        printf("Couldn't open input file %s\n", FileName);
        return 1;
    }

    // make .s file
    strncpy(temp, FileNameOut, 512);
    temp[511] = 0;
    for (ii=strlen(temp)-1; ii>0; ii--)
        if (temp[ii] == '.')
            break;
    temp[ii] = 0; // remove extension
    shortname = strdup(temp);
    strcat(temp, ".s");
    FileOutput = fopen(temp, "w");
    if (!FileOutput)
    {
        fclose(FileInput);
        printf("Couldn't open output file %s\n", temp);
        return 1;
    }

    fprintf(FileOutput, "    .text\n\n");
    fprintf(FileOutput, "    .align  %d\n\n", align);
    fprintf(FileOutput, "    .global %s\n", shortname);
    fprintf(FileOutput, "%s:\n", shortname);

    if (bitmap)
    {
        char *mem;

        // process header
        fread(temp, 1, 0x36, FileInput); // read header
        w = (unsigned char)temp[18] | (temp[19]<<8); // only need two bytes, but is really four byte LE
        h = (unsigned char)temp[22] | (temp[23]<<8); // only need two bytes, but is really four byte LE

        fprintf(FileOutput, "    dc.w    %d, %d\n\n", w, h);
        total += 4;

        // process palette (assumes 16 color image)
        fread(temp, 4, 16, FileInput); // read palette
        fprintf(FileOutput, "    dc.w    ");
        for (ii=0; ii<16; ii++)
            fprintf(FileOutput, "0x%04X, ", vdpcolor(temp[ii*4+0], temp[ii*4+1], temp[ii*4+2]));
        fprintf(FileOutput, "\n\n");
        total += 32;

        // process bitmap data (assumes 16 color image)
        mem = malloc(w * h / 2);
        for (ii=0; ii<h; ii++)
            fread(&mem[(h-ii-1)*w/2], 1, w/2, FileInput); // fill from bitmap backwards (BMP is bottom up)
        total += w * h / 2;

        for (jj=0; jj<h; jj++)
        {
            len = w/2/formatint;
            ll = 0;
            while (len > 0)
            {
                fprintf(FileOutput, "    dc.%s    ", formatasm);
                for (ii=0; ii<min(16/formatint, len); ii++)
                {
                    if (ii)
                        fprintf(FileOutput, ", ");
                    fprintf(FileOutput, "0x");
                    for (kk=0; kk<formatint; kk++)
                        fprintf(FileOutput, "%02X", (unsigned char)mem[jj*w/2 + (ii + ll)*formatint + kk]);
                }
                fprintf(FileOutput, "\n");
                ll += ii;
                len -= ii;
            }
        }

        free(mem);

        fprintf(FileOutput, "\n");
        fclose(FileOutput);
        fclose(FileInput);
    }
    else
    {
        // non-BMP is dumped as straight data

        memset(temp, nullfill, sizeof(temp));
        while (1)
        {
            len = fread(temp, 1, 16, FileInput);
            len = (len + (formatint - 1)) & ~(formatint - 1); // align length for size of units
            if (len)
            {
                fprintf(FileOutput, "    dc.%s    ", formatasm);
                for (ii=0; ii<(len/formatint); ii++)
                {
                    if (ii)
                        fprintf(FileOutput, ",");
                    fprintf(FileOutput, "0x");
                    for (jj=0; jj<formatint; jj++)
                        fprintf(FileOutput, "%02X", (unsigned char)temp[ii*formatint + jj]);
                }
                fprintf(FileOutput, "\n");
            }
            total += len;
            if (len < 16)
                break;
            memset(temp, nullfill, sizeof(temp));
        }
        fprintf(FileOutput, "\n");
        fclose(FileOutput);
        fclose(FileInput);
    }

    // now make .h file
    strcpy(temp, shortname);
    strcat(temp, ".h");
    FileOutput = fopen(temp, "w");
    if (!FileOutput)
    {
        printf("Couldn't open output file %s\n", temp);
        return 1;
    }

    for (ii=0; ii<strlen(shortname); ii++)
        temp[ii] = toupper(shortname[ii]);
    temp[ii] = 0;
    fprintf(FileOutput, "#ifndef _%s_H_\n", temp);
    fprintf(FileOutput, "#define _%s_H_\n\n", temp);
    fprintf(FileOutput, "extern const %s%s[0x%X];\n\n", format, shortname, total / formatint);
    fprintf(FileOutput, "#endif // _%s_H_\n", temp);

    fclose(FileOutput);
    return 0;
}

Stef
Very interested
Posts: 3131
Joined: Thu Nov 30, 2006 9:46 pm
Location: France - Sevres
Contact:

Post by Stef » Fri Jul 20, 2012 9:55 pm

Thanks Chilly Willy, i tested it and it worked almost perfectly :p I only got problem with file path (you do not remove directory information from path which cause troubles in variable name).

Here is the final version of the bintos tool converted to C :

Code: Select all

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <malloc.h>
#include <inttypes.h>
#include <ctype.h>


static int min(int x, int y)
{
    return (x < y) ? x : y;
}

static int vdpcolor(char b, char g, char r)
{
    // genesis only define on 3 bits (but shifted to 1 left)
    r = (r >> 4) & 0xE;
    g = (g >> 4) & 0xE;
    b = (b >> 4) & 0xE;

    return (r << 0) | (g << 4) | (b << 8);
}

static char *getFilename(char *pathname)
{
    char* fname = strrchr(pathname, '/');

    if (fname) return fname + 1;

    return pathname;
}

static void removeExtension(char *pathname)
{
    char* fname = strrchr(pathname, '.');

    if (fname) *fname = 0;
}


int main(int argc, char **argv)
{
    int bitmap;
    int ii, jj, kk, ll;
    int w, h;
    int len;
    int total;
    int align;
    int sizealign;
    int formatint;
    int nullfill;
    char *format;
    char *formatasm;
    char *shortname;
    char *FileName;
    char *FileNameOut;
    FILE *FileInput;
    FILE *FileOutput;
    char temp[512];

    // default
    bitmap = 0;
    FileName = "";
    FileNameOut = "";
    format = "u8 ";
    formatasm = "b";
    formatint = 1;
    total = 0;
    align = 4;
    sizealign = 1;
    nullfill = 0;

    // parse parmeters
    for (ii = 1; ii < argc; ii++)
    {
        if (!strcmp(argv[ii], "-u8"))
        {
            format = "u8 ";
            formatasm = "b";
            formatint = 1;
        }
        else if (!strcmp(argv[ii], "-s8"))
        {
            format = "s8 ";
            formatasm = "b";
            formatint = 1;
        }
        else if (!strcmp(argv[ii], "-u16"))
        {
            format = "u16 ";
            formatasm = "w";
            formatint = 2;
        }
        else if (!strcmp(argv[ii], "-s16"))
        {
            format = "s16 ";
            formatasm = "w";
            formatint = 2;
        }
        else if (!strcmp(argv[ii], "-u32"))
        {
            format = "u32 ";
            formatasm = "l";
            formatint = 4;
        }
        else if (!strcmp(argv[ii], "-s32"))
        {
            format = "s32 ";
            formatasm = "l";
            formatint = 4;
        }
        else if (!strcmp(argv[ii], "-bmp"))
        {
            bitmap = 1;
            format = "u16 ";
            formatasm = "w";
            formatint = 2;
        }
        else if (!strcmp(argv[ii], "-align"))
        {
            ii++;
            align = strtoimax(argv[ii], NULL, 0);

            if (!align) align = 4;
        }
        else if (!strcmp(argv[ii], "-sizealign"))
        {
            ii++;
            sizealign = strtoimax(argv[ii], NULL, 0);

            if (!sizealign) sizealign = 1;
        }
        else if (!strcmp(argv[ii], "-nullfill"))
        {
            ii++;
            nullfill = strtoimax(argv[ii], NULL, 0);
        }
        else if (!FileName[0]) FileName = argv[ii];
        else if (!FileNameOut[0]) FileNameOut = argv[ii];
    }

    if (!FileNameOut[0]) FileNameOut = FileName;

    if (!strcasecmp(&FileName[strlen(FileName)-4], ".bmp"))
    {
        bitmap = 1;
        format = "u16 ";
        formatasm = "w";
        formatint = 2;
        align = 16;
    }

    FileInput = fopen(FileName, "rb");

    if (!FileInput)
    {
        printf("Couldn't open input file %s\n", FileName);
        return 1;
    }

    // remove extension
    removeExtension(FileNameOut);
    // keep only file name
    shortname = getFilename(FileNameOut);

    // build output .s file
    strcpy(temp, FileNameOut);
    strcat(temp, ".s");
    FileOutput = fopen(temp, "w");

    if (!FileOutput)
    {
        fclose(FileInput);
        printf("Couldn't open output file %s\n", temp);
        return 1;
    }

    fprintf(FileOutput, ".text\n\n");
    fprintf(FileOutput, "    .align  %d\n\n", align);
    fprintf(FileOutput, "    .global %s\n", shortname);
    fprintf(FileOutput, "%s:\n", shortname);

    if (bitmap)
    {
        char *mem;

        // process header
        fread(temp, 1, 0x36, FileInput); // read header
        w = (unsigned char)temp[18] | (temp[19] << 8); // only need two bytes, but is really four byte LE
        h = (unsigned char)temp[22] | (temp[23] << 8); // only need two bytes, but is really four byte LE

        fprintf(FileOutput, "    dc.w    %d, %d\n\n", w, h);
        total += 4;

        // process palette (assumes 16 color image)
        fread(temp, 4, 16, FileInput); // read palette
        fprintf(FileOutput, "    dc.w    ");

        for (ii = 0; ii < 16; ii++)
            fprintf(FileOutput, "0x%04X, ", vdpcolor(temp[ii*4+0], temp[ii*4+1], temp[ii*4+2]));

        fprintf(FileOutput, "\n\n");
        total += 32;

        // process bitmap data (assumes 16 color image)
        mem = malloc(w * h / 2);

        for (ii = 0; ii < h; ii++)
            fread(&mem[(h-ii-1)*w/2], 1, w / 2, FileInput); // fill from bitmap backwards (BMP is bottom up)

        total += w * h / 2;

        for (jj = 0; jj < h; jj++)
        {
            len = w / 2 / formatint;
            ll = 0;

            while (len > 0)
            {
                fprintf(FileOutput, "    dc.%s    ", formatasm);

                for (ii = 0; ii < min(16 / formatint, len); ii++)
                {
                    if (ii)
                        fprintf(FileOutput, ", ");

                    fprintf(FileOutput, "0x");

                    for (kk = 0; kk < formatint; kk++)
                        fprintf(FileOutput, "%02X", (unsigned char)mem[jj*w/2 + (ii + ll)*formatint + kk]);
                }

                fprintf(FileOutput, "\n");
                ll += ii;
                len -= ii;
            }
        }

        free(mem);

        fprintf(FileOutput, "\n");
        fclose(FileOutput);
        fclose(FileInput);
    }
    else
    {
        // non-BMP is dumped as straight data

        memset(temp, nullfill, sizeof(temp));

        while (1)
        {
            len = fread(temp, 1, 16, FileInput);
            len = (len + (formatint - 1)) & ~(formatint - 1); // align length for size of units

            if (len)
            {
                fprintf(FileOutput, "    dc.%s    ", formatasm);

                for (ii = 0; ii < (len / formatint); ii++)
                {
                    if (ii)
                        fprintf(FileOutput, ",");

                    fprintf(FileOutput, "0x");

                    for (jj = 0; jj < formatint; jj++)
                        fprintf(FileOutput, "%02X", (unsigned char)temp[ii*formatint + jj]);
                }

                fprintf(FileOutput, "\n");
            }

            total += len;

            if (len < 16)
                break;

            memset(temp, nullfill, sizeof(temp));
        }

        fprintf(FileOutput, "\n");
        fclose(FileOutput);
        fclose(FileInput);
    }

    // now make .h file
    strcpy(temp, FileNameOut);
    strcat(temp, ".h");
    FileOutput = fopen(temp, "w");

    if (!FileOutput)
    {
        printf("Couldn't open output file %s\n", temp);
        return 1;
    }

    for (ii = 0; ii < strlen(shortname); ii++)
        temp[ii] = toupper(shortname[ii]);

    temp[ii] = 0;
    fprintf(FileOutput, "#ifndef _%s_H_\n", temp);
    fprintf(FileOutput, "#define _%s_H_\n\n", temp);
    fprintf(FileOutput, "extern const %s%s[0x%X];\n\n", format, shortname, total / formatint);
    fprintf(FileOutput, "#endif // _%s_H_\n", temp);

    fclose(FileOutput);
    return 0;
}

Chilly Willy
Very interested
Posts: 2984
Joined: Fri Aug 17, 2007 9:33 pm

Post by Chilly Willy » Sat Jul 21, 2012 12:58 am

Stef wrote:Thanks Chilly Willy, i tested it and it worked almost perfectly :p I only got problem with file path (you do not remove directory information from path which cause troubles in variable name).
Oh! Duh... sorry about that. Wasn't thinking and didn't see it since I ran it on a test file in the same directory. :lol:

So, on to the next one. What do you think should be next? I did bintos first because I noticed it's called by quite a few things.

Stef
Very interested
Posts: 3131
Joined: Thu Nov 30, 2006 9:46 pm
Location: France - Sevres
Contact:

Post by Stef » Sat Jul 21, 2012 9:40 am

Hehe no problems, it was a very minor mistake easy to fix :)
You already made it and thanks for that.
The only 2 others tools we can translate are "sizebnd" and "pcmtoraw".
I just sizebnd to pad the binary size, pcmtoraw is less important as it is used only for pcm to dpcm conversion.
I updated the repository as i reworked a bit the tools directory and included last bintos changes ;)

I guess later we will need to put sources of others tools as genres, mac68k, wavtoraw, tfmcom...

djcouchycouch
Very interested
Posts: 710
Joined: Sat Feb 18, 2012 2:44 am

Post by djcouchycouch » Sat Jul 21, 2012 1:53 pm

Stef wrote:I guess later we will need to put sources of others tools as genres, mac68k, wavtoraw, tfmcom...
I'm definitely looking forward to seeing the genres source! It's quite handy and I've sometimes wanted to add my own types :)

Chilly Willy
Very interested
Posts: 2984
Joined: Fri Aug 17, 2007 9:33 pm

Post by Chilly Willy » Sat Jul 21, 2012 4:52 pm

Wow, sizebnd was EASY.

sizebnd.c

Code: Select all

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <inttypes.h>
#include <malloc.h>

int main(int argc, char **argv)
{
    int ii;
    int needed;
    int sizealign;
    int nullfill;
    char *FileName;
    FILE *FileInput;

    // default
    FileName = "";
    sizealign = 256;
    nullfill = 0;

    // parse parmeters
    for (ii=1; ii<argc; ii++)
    {
        if (!strcmp(argv[ii], "-sizealign"))
        {
            ii++;
            sizealign = strtoimax(argv[ii], NULL, 0);
            if (!sizealign) sizealign = 1;
        }
        else if (!strcmp(argv[ii], "-nullfill"))
        {
            ii++;
            nullfill = strtoimax(argv[ii], NULL, 0);
        }
        else if (!FileName[0]) FileName = argv[ii];
    }

    FileInput = fopen(FileName, "rb");
    if (!FileInput)
    {
        printf("Couldn't open input file %s\n", FileName);
        return 1;
    }
    else
    {
        // file exists, close and reopen for appending
        fclose(FileInput);
        fopen(FileName, "ab");
    }

    // calculate how many extra byte are needed
    needed = ftell(FileInput) & (sizealign - 1);
    if (needed)
    {
        unsigned char *mem;
        // complete missing bytes
        needed = sizealign - needed;
        mem = malloc(needed);
        if (mem)
        {
            memset(mem, nullfill, needed);
            fwrite(mem, needed, 1, FileInput);
            free(mem);
        }
        else
            for (ii=0; ii<needed; ii++) fputc(nullfill, FileInput);
    }

    fclose(FileInput);

    return 0;
}
It's ULTRA fast because I added code to allocate a buffer the size of what's needed, fill it with the nullfill value, then write it all at once. If the memory cannot be allocated, it uses the original slow method of padding the file one byte at a time. So far in my tests, it's never had to do that, so I have instant padding. 8)

Chilly Willy
Very interested
Posts: 2984
Joined: Fri Aug 17, 2007 9:33 pm

Post by Chilly Willy » Sat Jul 21, 2012 6:13 pm

Err - I can't tell from the source what pcmtoraw is working on... is it 8-bit, 16-bit, signed, or unsigned? The code seems to read shorts and operate on shorts, which would lead me to believe it's 16-bit signed samples, but the output of the Windows version doesn't seem to support that. Also, the deltas seem to be for 8-bit values. I then guessed that it's all 8-bit unsigned DAC data, but that also doesn't generate the right results. Just a bit puzzled here...
:?

EDIT: Figured it out... it's signed 8-bit samples. Figures it would be the last one I tried. :lol:

Chilly Willy
Very interested
Posts: 2984
Joined: Fri Aug 17, 2007 9:33 pm

Post by Chilly Willy » Sat Jul 21, 2012 6:27 pm

Okay, here's pcmtoraw. It produces identical output to the Windows binary.

pcmtoraw.c

Code: Select all

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <malloc.h>
#include <inttypes.h>
#include <ctype.h>

const short delta_tab[16] =
    { -34,-21,-13,-8,-5,-3,-2,-1,0,1,2,3,5,8,13,21 };

int sample_over;
int sample_loss;

static short GetBestDelta(int pWantedLevel, int pCurLevel)
{
    int i;
    int ind;
    int diff;
    int mindiff;
    int wdelta;
    short result;

    wdelta = pWantedLevel - pCurLevel;
    ind = 0;
    mindiff = abs(wdelta - delta_tab[ind]);

    for (i=1; i<16; i++)
    {
        diff = abs(wdelta - delta_tab[i]);
        if (diff < mindiff)
        {
            mindiff = diff;
            ind = i;
        }
    }

    if (mindiff)
    {
        sample_over++;
        sample_loss += mindiff;
    }

    // check for overflow
    if ((delta_tab[ind] + pCurLevel) > 127)
        result = ind - 1;
    else if ((delta_tab[ind] + pCurLevel) < -128)
        result = ind + 1;
    else
        result = ind;

    return result;
}

static char *getFilename(char *pathname)
{
    char* fname = strrchr(pathname, '/');

    if (fname) return fname + 1;

    return pathname;
}

static void removeExtension(char *pathname)
{
    char* fname = strrchr(pathname, '.');

    if (fname) *fname = 0;
}


int main(int argc, char **argv)
{
    int ii;
    int size;
    int diff_ind;
    short curlevel;
    short data_sb;
    short diff_sb;
    short out_sb;
    char *FileName;
    char *FileNameOut;
    FILE *FileInput;
    FILE *FileOutput;
    FILE *FileOutputLoss;
    char temp[512];

    // default
    FileName = "";
    FileNameOut = "";

    // parse parmeters
    for (ii = 1; ii < argc; ii++)
    {
        if (!FileName[0]) FileName = argv[ii];
        else if (!FileNameOut[0]) FileNameOut = argv[ii];
    }

    if (!FileNameOut[0]) FileNameOut = FileName;

    FileInput = fopen(FileName, "rb");

    if (!FileInput)
    {
        printf("Couldn't open input file %s\n", FileName);
        return 1;
    }

    // remove extension
    removeExtension(FileNameOut);

    // build output .raw file
    strcpy(temp, FileNameOut);
    strcat(temp, ".raw");
    FileOutput = fopen(temp, "w");

    if (!FileOutput)
    {
        fclose(FileInput);
        printf("Couldn't open output file %s\n", temp);
        return 1;
    }

    FileOutputLoss = fopen("loss", "w");

    sample_over = 0;
    sample_loss = 0;

    ii = 0;
    curlevel = 0;
    fseek(FileInput, 0, SEEK_END);
    size = ftell(FileInput);
    fseek(FileInput, 0, SEEK_SET);

    while (ii < size)
    {
        data_sb = (char)fgetc(FileInput);
        diff_ind = GetBestDelta(data_sb, curlevel);
        diff_sb = delta_tab[diff_ind];
        curlevel = curlevel + diff_sb;
        fputc(curlevel & 0x00FF, FileOutputLoss);

        out_sb = diff_ind;

        data_sb = (char)fgetc(FileInput);
        diff_ind = GetBestDelta(data_sb, curlevel);
        diff_sb = delta_tab[diff_ind];
        curlevel = curlevel + diff_sb;
        fputc(curlevel & 0x00FF, FileOutputLoss);

        out_sb = out_sb | (diff_ind << 4);

        fputc(out_sb & 0x00FF, FileOutput);

        ii += 2;
    }

    fclose(FileOutputLoss);
    fclose(FileOutput);
    fclose(FileInput);

    return 0;
}

Stef
Very interested
Posts: 3131
Joined: Thu Nov 30, 2006 9:46 pm
Location: France - Sevres
Contact:

Post by Stef » Sat Jul 21, 2012 9:02 pm

Wow you are very fast !!
Sorry yeah it was 8 bits signed samples for pcmtoraw.
I called it pcmtoraw because it takes PCM as input and output as RAW.
This way files with pcm extension are automatically handled in SGDK to be converted in DPCM 4 bits...
Thanks a lot =) i will test and update SGDK quickly.

Chilly Willy
Very interested
Posts: 2984
Joined: Fri Aug 17, 2007 9:33 pm

Post by Chilly Willy » Sat Jul 21, 2012 9:30 pm

Stef wrote:Wow you are very fast !!
Didn't have much to do today, and they were pretty simple. :D
Sorry yeah it was 8 bits signed samples for pcmtoraw.
I called it pcmtoraw because it takes PCM as input and output as RAW.
This way files with pcm extension are automatically handled in SGDK to be converted in DPCM 4 bits...
Thanks a lot =) i will test and update SGDK quickly.


No problem. Glad to help.

Stef
Very interested
Posts: 3131
Joined: Thu Nov 30, 2006 9:46 pm
Location: France - Sevres
Contact:

Post by Stef » Sat Jul 21, 2012 11:33 pm

Ok, i included them but the new pcmtoraw suffers from a bug it was not present before. I modified it a bit to fix a minor problem with output name but i cannot get rid of the conversion bug, it seems sample overflow sometime... You can test it with the sound sample in SGDK, the ADPCM 2 channels drivers uses pcmtoraw for sample conversion and the first sample seems to overflow sometime...

Chilly Willy
Very interested
Posts: 2984
Joined: Fri Aug 17, 2007 9:33 pm

Post by Chilly Willy » Sun Jul 22, 2012 1:07 am

Stef wrote:Ok, i included them but the new pcmtoraw suffers from a bug it was not present before. I modified it a bit to fix a minor problem with output name but i cannot get rid of the conversion bug, it seems sample overflow sometime... You can test it with the sound sample in SGDK, the ADPCM 2 channels drivers uses pcmtoraw for sample conversion and the first sample seems to overflow sometime...
Which sample exactly? I'll work the bug out. Really odd though, I have the same code for preventing overflows that's in the original.

original

Code: Select all

      // check for overflow
      if (delta_tab[ind] + pCurLevel > High(result)) then
         result := Pred(ind)
      else if (delta_tab[ind] + pCurLevel < Low(result)) then
         result := Succ(ind)
      else
         result := ind;
new

Code: Select all

    // check for overflow
    if ((delta_tab[ind] + pCurLevel) > 127)
        result = ind - 1;
    else if ((delta_tab[ind] + pCurLevel) < -128)
        result = ind + 1;
    else
        result = ind;

The only thing I can think of off hand is somehow the ind is more than 1 away from overflow since the check only bumps the ind up/down by 1. My guess is the minimum delta sometimes can be well outside the overflow. The overflow check should probably be a while() instead of an if().

Chilly Willy
Very interested
Posts: 2984
Joined: Fri Aug 17, 2007 9:33 pm

Post by Chilly Willy » Sun Jul 22, 2012 1:18 am

I think I found it. You made a change in the code that I put in SPECIFICALLY to avoid this problem.

your changed code

Code: Select all

        data_sb = fgetc(FileInput);
        diff_ind = GetBestDelta(data_sb, curlevel);
        diff_sb = delta_tab[diff_ind];
        curlevel = curlevel + diff_sb;
        fputc(curlevel, FileOutputLoss);
my original code

Code: Select all

        data_sb = (char)fgetc(FileInput);
        diff_ind = GetBestDelta(data_sb, curlevel);
        diff_sb = delta_tab[diff_ind];
        curlevel = curlevel + diff_sb;
        fputc(curlevel & 0x00FF, FileOutputLoss);
See that (char) in front of the fgetc()? That is MANDATORY since fgetc() returns an int, not a char. We are inputting one signed byte, but it's being returned by fgetc as a byte in an int... which appears as unsigned to the rest of the code. The (char) forces the int to be interpreted as a signed byte which is then sign extended when stored in the short variable. I didn't have the (char) in there originally and had bad conversions. Adding the (char) gave me identical output to the pascal code.

Stef
Very interested
Posts: 3131
Joined: Thu Nov 30, 2006 9:46 pm
Location: France - Sevres
Contact:

Post by Stef » Sun Jul 22, 2012 10:33 am

Chilly Willy wrote:I think I found it. You made a change in the code that I put in SPECIFICALLY to avoid this problem.

your changed code

Code: Select all

        data_sb = fgetc(FileInput);
        diff_ind = GetBestDelta(data_sb, curlevel);
        diff_sb = delta_tab[diff_ind];
        curlevel = curlevel + diff_sb;
        fputc(curlevel, FileOutputLoss);
my original code

Code: Select all

        data_sb = (char)fgetc(FileInput);
        diff_ind = GetBestDelta(data_sb, curlevel);
        diff_sb = delta_tab[diff_ind];
        curlevel = curlevel + diff_sb;
        fputc(curlevel & 0x00FF, FileOutputLoss);
See that (char) in front of the fgetc()? That is MANDATORY since fgetc() returns an int, not a char. We are inputting one signed byte, but it's being returned by fgetc as a byte in an int... which appears as unsigned to the rest of the code. The (char) forces the int to be interpreted as a signed byte which is then sign extended when stored in the short variable. I didn't have the (char) in there originally and had bad conversions. Adding the (char) gave me identical output to the pascal code.

No unfortunately that is not the problem here, i modified the code later when trying to fix it the bug... actually that doesn't make any difference to use & 0xFF here as even if the fputc take an "integer" as input, it only writes a char and so the lower byte of int value. Also i changed the type of variable to char (as it was originally in delphi) but again that did not me any differences...

The sample i was talking about is india_22k_pcm or something like that. This is the sound drivers exemple you can find in SGDK under "sample" directory. Try to compile it, you should experience the problem ;)

Chilly Willy
Very interested
Posts: 2984
Joined: Fri Aug 17, 2007 9:33 pm

Post by Chilly Willy » Sun Jul 22, 2012 4:37 pm

I'll check into it. As far as the (char) goes, my system NEEDS it. There may be a difference between how your system handles a byte in fgetc compared to the latest gcc on linux.

EDIT - The code I posted gives IDENTICAL raw and loss files compared to the original Windows pcmtoraw.exe on india_pcm_22k.pcm. I don't see/hear a difference on the loss file in a sound editor, and a diff program shows every byte of the raw files are identical, so if my code makes any overflows, so would the original Windows code.

Isn't the loss file what the reconstructed audio would be? So if I don't see any overflows in the sound editor, there shouldn't be any on the Genesis either.

Did you hear the overflow on the Genesis, or did you check the resulting loss file? Maybe the overflow was something else - a problem in playback, not the data.

Post Reply