view tests/plrtest.c @ 2298:b5abfff07ca9

Add new DMGrowBuf helper functions dmGrowBufCopyOffsSize() and dmGrowBufConstCopyOffsSize().
author Matti Hamalainen <ccr@tnsp.org>
date Thu, 04 Jul 2019 10:54:16 +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;
}