view tests/plrtest.c @ 2208:90ec1ec89c56

Revamp the palette handling in lib64gfx somewhat, add helper functions to lib64util for handling external palette file options and add support for specifying one of the "internal" palettes or external (.act) palette file to gfxconv and 64vw.
author Matti Hamalainen <ccr@tnsp.org>
date Fri, 14 Jun 2019 05:01:12 +0300
parents 186cf6a7d634
children aacf3bd1cceb
line wrap: on
line source

#include "jss.h"
#include "jssmod.h"
#include "jssmix.h"
#include "jssplr.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 * fh, const JSSPattern * pat, const int row)
{
    const JSSNote *note = &(pat->data[pat->nchannels * row]);
    int width = pat->nchannels < 5 ? pat->nchannels : 5;

    fprintf(fh, "%.2x: ", row);

    for (int channel = 0; channel < width; channel++)
    {
        switch (note->note)
        {
            case jsetNotSet:
                fprintf(fh, "... ");
                break;
            case jsetNoteOff:
                fprintf(fh, "=== ");
                break;
            default:
                fprintf(fh, "%s%d ",
                    patNoteTable[note->note % 12],
                    note->note / 12);
                break;
        }

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

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

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

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

        note++;
    }
}


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 *inFilename = NULL;
    int result = -1;
    JSSModule *mod = NULL;
    JSSMixer *dev = NULL;
    JSSPlayer *plr = NULL;

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

    // Open the files
    if (inFilename == NULL)
        result = dmf_open_stdio_stream(stdin, &file);
    else
        result = dmf_open_stdio(inFilename, "rb", &file);

    if (result != DMERR_OK)
    {
        fprintf(stderr, "Error opening input file '%s', #%d: %s\n",
            inFilename, result, dmErrorStr(result));
        return 1;
    }

    // Initialize miniJSS
    fprintf(stderr, "Initializing miniJSS\n");
    jssInit();


    // Read module file
    dmMsg(1, "Reading file: %s\n", inFilename);
#ifdef JSS_SUP_XM
    result = jssLoadXM(file, &mod, TRUE);
#endif
#ifdef JSS_SUP_JSSMOD
    dmfreset(file);
    if (result != DMERR_OK)
    {
        dmMsg(1, "* Trying JSSMOD ...\n");
        result = jssLoadJSSMOD(file, &mod, TRUE);
        dmfreset(file);
        if (result == DMERR_OK)
            result = jssLoadJSSMOD(file, &mod, FALSE);
    }
    else
    {
        dmMsg(2, "* Trying XM...\n");
        result = jssLoadXM(file, &mod, FALSE);
    }
#endif
    dmf_close(file);

    // Check for errors, we still might have some data tho
    if (result != DMERR_OK)
    {
        dmErrorMsg("Error loading module file, %d: %s\n",
            result, dmErrorStr(result));
    }

    // Check if we have anything
    if (mod == NULL)
        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, 100);

    // 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 = NULL;
        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 && pattern != NULL)
        {
            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;
}