view testpl.c @ 69:7b97df6f8a97

Add jssClose() in the shutdown.
author Matti Hamalainen <ccr@tnsp.org>
date Mon, 01 Oct 2012 13:42:20 +0300
parents b51c7fc264ab
children c6cdaa675801
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;
    int buflen = 4096;

    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)) == 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  = buflen;
    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_PauseAudio(0);
    while (plr->isPlaying)
    {
        int r = plr->row;
        while (r == plr->row && plr->isPlaying)
            SDL_Delay(50);

        printRow(stdout, plr->pattern, plr->row);
        printf("\n");
    }
    
    printf("----------------------------------------------------\n");

    SDL_PauseAudio(1);

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

    SDL_Quit();

    jssClose();

    return 0;
}