view tests/plrtest.c @ 2530:aacf3bd1cceb

Cleanups.
author Matti Hamalainen <ccr@tnsp.org>
date Sat, 16 May 2020 06:38:52 +0300
parents 186cf6a7d634
children 9807ae37ad69
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 res = -1;
    JSSModule *mod = NULL;
    JSSMixer *dev = NULL;
    JSSPlayer *plr = NULL;

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

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

    if (res != DMERR_OK)
    {
        dmErrorMsg("Error opening input file '%s': %s\n",
            inFilename, dmErrorStr(res));
        goto exit;
    }

    // Initialize miniJSS
    printf("Initializing miniJSS\n");
    jssInit();

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

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

    // Check if we have anything
    if (mod == NULL)
    {
        res = dmError(DMERR_INIT_FAIL,
            "Could not load module file.\n");
        goto exit;
    }

    // Try to convert it
    if ((res = jssConvertModuleForPlaying(mod)) != DMERR_OK)
    {
        dmErrorMsg("Could not convert module for playing: %s\n",
            dmErrorStr(res));
        goto exit;
    }

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

    // Initialize mixing device
    printf("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)
    {
        res = dmError(DMERR_INIT_FAIL,
            "jvmInit() returned NULL\n");
        goto exit;
    }

    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)
    {
        res = dmError(DMERR_INIT_FAIL,
            "Couldn't open audio: %s\n",
            SDL_GetError());
        goto exit;
    }

    // Initialize player
    if ((plr = jmpInit(dev)) == NULL)
    {
        res = dmError(DMERR_INIT_FAIL,
            "jmpInit() returned NULL\n");
        goto exit;
    }

    // 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");

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

    SDL_Quit();

    jssClose();

    return res;
}