view testpl.c @ 510:43ea59887c69

Start work on making C64 formats encoding possible by changing DMDecodeOps to DMEncDecOps and adding fields and op enums for custom encode functions, renaming, etc. Split generic op sanity checking into a separate function in preparation for its use in generic encoding function.
author Matti Hamalainen <ccr@tnsp.org>
date Mon, 19 Nov 2012 15:06:01 +0200
parents 2b5472173355
children
line wrap: on
line source

#include "jss.h"
#include "jssmod.h"
#include "jssmix.h"
#include "jssplr.h"
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <SDL.h>


static const char patNoteTable[12][3] =
{
    "C-", "C#", "D-",
    "D#", "E-", "F-",
    "F#", "G-", "G#",
    "A-", "A#", "B-"
};


#define jmpNMODEffectTable (36)
static const char jmpMODEffectTable[jmpNMODEffectTable] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";


void printRow(FILE * f, JSSPattern * p, int row)
{
    int j, k;
    char c;
    JSSNote *n;

    if (!p)
        return;

    n = &(p->data[p->nchannels * row]);

    fprintf(f, "%.2x: ", row);
    
    k = p->nchannels < 5 ? p->nchannels : 5;

    for (j = 0; j < k; j++)
    {
        switch (n->note)
        {
            case jsetNotSet:
                fprintf(f, "... ");
                break;
            case jsetNoteOff:
                fprintf(f, "=== ");
                break;
            default:
                fprintf(f, "%s%i ", patNoteTable[n->note % 12], n->note / 12);
                break;
        }

        if (n->instrument != jsetNotSet)
            fprintf(f, "%.2x ", n->instrument + 1);
        else
            fprintf(f, ".. ");

        if (n->volume == jsetNotSet)
            fprintf(f, ".. ");
        else if (n->volume >= 0x00 && n->volume <= 0x40)
            fprintf(f, "%.2x ", n->volume);
        else
        {
            switch (n->volume & 0xf0)
            {
                case 0x50: c = '-'; break;
                case 0x60: c = '+'; break;
                case 0x70: c = '/'; break;
                case 0x80: c = '\\'; break;
                case 0x90: c = 'S'; break;
                case 0xa0: c = 'V'; break;
                case 0xb0: c = 'P'; break;
                case 0xc0: c = '<'; break;
                case 0xd0: c = '>'; break;
                case 0xe0: c = 'M'; break;
                default:   c = '?'; break;
            }
            fprintf(f, "%c%x ", c, (n->volume & 0x0f));
        }

        if (n->effect >= 0 && n->effect < jmpNMODEffectTable)
            fprintf(f, "%c", jmpMODEffectTable[n->effect]);
        else if (n->effect == jsetNotSet)
            fprintf(f, ".");
        else
            fprintf(f, "?");

        if (n->param != jsetNotSet)
            fprintf(f, "%.2x|", n->param);
        else
            fprintf(f, "..|");

        n++;
    }
}


void audioCallback(void *userdata, Uint8 *stream, int len)
{
    JSSMixer *d = (JSSMixer *) userdata;

    if (d != NULL)
    {
        jvmRenderAudio(d, stream, len / jvmGetSampleSize(d));
    }
}


int main(int argc, char *argv[])
{
    SDL_AudioSpec afmt;
    DMResource *file = NULL;
    char *sname = NULL;
    int result = -1;
    JSSModule *mod = NULL;
    JSSMixer *dev = NULL;
    JSSPlayer *plr = NULL;

    if (argc > 1)
        sname = argv[1];

    // Open the files
    if (sname == NULL)
        file = dmf_create_stdio_stream(stdin);
    else if ((file = dmf_create_stdio(sname, "rb")) == NULL)
    {
        fprintf(stderr, "Error opening input file '%s'. (%s)\n",
            sname, strerror(errno));
        return 1;
    }
        
    // Initialize miniJSS
    fprintf(stderr, "Initializing miniJSS\n");
    jssInit();

    
    // Read module file
    fprintf(stderr, "Reading file: %s\n", sname);
#ifdef JSS_SUP_XM
    fprintf(stderr, "* Trying XM...\n");
    result = jssLoadXM(file, &mod);
#endif
#ifdef JSS_SUP_JSSMOD
    if (result != 0)
    {
        size_t bufgot, bufsize = dmfsize(file);
        Uint8 *buf = dmMalloc(bufsize);
        dmfseek(file, 0L, SEEK_SET);
        fprintf(stderr, "* Trying JSSMOD (%d bytes, %p)...\n", bufsize, buf);
        if ((bufgot = dmfread(buf, 1, bufsize, file)) != bufsize)
        {
            fprintf(stderr, "Error reading file (not enough data %d), #%d: %s\n",
                bufgot, dmferror(file), dmErrorStr(dmferror(file)));
            return 2;
        }
        result = jssLoadJSSMOD(buf, bufsize, &mod);
        dmFree(buf);
    }
#endif
    dmf_close(file);

    if (result != DMERR_OK)
    {
        fprintf(stderr, "Error loading module file, %d: %s\n",
            result, dmErrorStr(result));
        return 3;
    }

    // Try to convert it
    if ((result = jssConvertModuleForPlaying(mod)) != DMERR_OK)
    {
        fprintf(stderr, "Could not convert module for playing, %d: %s\n",
            result, dmErrorStr(result));
        return 3;
    }

    // Initialize SDL audio
    afmt.freq     = 48000;
    afmt.format   = AUDIO_S16SYS;
    afmt.channels = 2;

    // Initialize mixing device
    fprintf(stderr, "Initializing miniJSS mixer with: %d, %d, %d\n",
        JSS_AUDIO_S16, afmt.channels, afmt.freq);

    dev = jvmInit(JSS_AUDIO_S16, afmt.channels, afmt.freq, JMIX_AUTO);
    if (dev == NULL)
    {
        fprintf(stderr, "jvmInit() returned NULL\n");
        return 3;
    }
    
    afmt.samples  = afmt.freq / 4;
    afmt.callback = audioCallback;
    afmt.userdata = (void *) dev;

    // Open the audio device
    fprintf(stderr, "Trying to init SDL with: %d, %d, %d\n",
        afmt.format, afmt.channels, afmt.freq);
    
    if (SDL_OpenAudio(&afmt, NULL) < 0)
    {
        fprintf(stderr, "Couldn't open audio: %s\n", SDL_GetError());
        return 4;
    }
    
    // Initialize player
    if ((plr = jmpInit(dev)) == NULL)
    {
        fprintf(stderr, "jmpInit() returned NULL\n");
        return 4;
    }
    
    // Initialize playing
    jvmSetCallback(dev, jmpExec, plr);
    jmpSetModule(plr, mod);
    jmpPlayOrder(plr, 0);
    jvmSetGlobalVol(dev, 60);

    // okay, main loop here ... "play" module and print out info
    printf("----------------------------------------------------\n");
    SDL_LockAudio();
    SDL_PauseAudio(0);
    SDL_UnlockAudio();
    BOOL playing = TRUE;
    while (playing)
    {
        JSSPattern *pattern;
        int currRow, prevRow;

        JSS_LOCK(plr);
        currRow = prevRow = plr->row;
        JSS_UNLOCK(plr);

        while (currRow == prevRow && playing)
        {
            JSS_LOCK(plr);
            currRow = plr->row;
            playing = plr->isPlaying;
            pattern = plr->pattern;
            JSS_UNLOCK(plr);
            SDL_Delay(50);
        }

        if (playing)
        {
            printRow(stdout, pattern, currRow);
            printf("\n");
        }
    }
    
    printf("----------------------------------------------------\n");

    SDL_LockAudio();
    SDL_PauseAudio(1);
    jmpClose(plr);
    jvmClose(dev);
    jssFreeModule(mod);
    SDL_UnlockAudio();

    SDL_Quit();

    jssClose();

    return 0;
}